소스 검색

feat: invoke app

Yeuoly 11 달 전
부모
커밋
24836759f2

+ 4 - 0
internal/core/dify_invocation/http_request.go

@@ -58,3 +58,7 @@ func InvokeModeration(payload *InvokeModerationRequest) (*model_entities.Moderat
 func InvokeTool(payload *InvokeToolRequest) (*stream.StreamResponse[tool_entities.ToolResponseChunk], error) {
 	return StreamResponse[tool_entities.ToolResponseChunk]("POST", "invoke/tool", http_requests.HttpPayloadJson(payload))
 }
+
+func InvokeApp(payload *InvokeAppRequest) (*stream.StreamResponse[map[string]any], error) {
+	return StreamResponse[map[string]any]("POST", "invoke/app", http_requests.HttpPayloadJson(payload))
+}

+ 19 - 0
internal/core/dify_invocation/types.go

@@ -1,6 +1,7 @@
 package dify_invocation
 
 import (
+	"github.com/langgenius/dify-plugin-daemon/internal/types/entities/app_entities"
 	"github.com/langgenius/dify-plugin-daemon/internal/types/entities/requests"
 )
 
@@ -21,6 +22,7 @@ const (
 	INVOKE_TYPE_MODERATION     InvokeType = "moderation"
 	INVOKE_TYPE_TOOL           InvokeType = "tool"
 	INVOKE_TYPE_NODE           InvokeType = "node"
+	INVOKE_TYPE_APP            InvokeType = "app"
 )
 
 type InvokeLLMRequest struct {
@@ -59,6 +61,23 @@ type InvokeModerationRequest struct {
 	requests.InvokeModerationSchema
 }
 
+type InvokeAppSchema struct {
+	AppId          string                  `json:"app_id" validate:"required"`
+	Inputs         map[string]any          `json:"inputs" validate:"omitempty"`
+	Query          string                  `json:"query" validate:"omitempty"`
+	ResponseMode   string                  `json:"response_mode"`
+	ConversationId string                  `json:"conversation_id"`
+	User           string                  `json:"user" validate:"omitempty"`
+	Files          []*app_entities.FileVar `json:"files" validate:"omitempty,dive"`
+}
+
+type InvokeAppRequest struct {
+	BaseInvokeDifyRequest
+	requests.BaseRequestInvokeModel
+
+	InvokeAppSchema
+}
+
 type InvokeToolRequest struct {
 	BaseInvokeDifyRequest
 	ToolType requests.ToolType `json:"tool_type" validate:"required,tool_type"`

+ 32 - 0
internal/core/plugin_daemon/backwards_invocation/task.go

@@ -108,6 +108,12 @@ var (
 			},
 			"error": "permission denied, you need to enable node access in plugin manifest",
 		},
+		dify_invocation.INVOKE_TYPE_APP: {
+			"func": func(declaration *plugin_entities.PluginDeclaration) bool {
+				return declaration.Resource.Permission.AllowInvokeApp()
+			},
+			"error": "permission denied, you need to enable app access in plugin manifest",
+		},
 	}
 )
 
@@ -183,6 +189,9 @@ var (
 		dify_invocation.INVOKE_TYPE_MODERATION: func(handle *BackwardsInvocation) {
 			genericDispatchTask[dify_invocation.InvokeModerationRequest](handle, executeDifyInvocationModerationTask)
 		},
+		dify_invocation.INVOKE_TYPE_APP: func(handle *BackwardsInvocation) {
+			genericDispatchTask[dify_invocation.InvokeAppRequest](handle, executeDifyInvocationAppTask)
+		},
 	}
 )
 
@@ -324,3 +333,26 @@ func executeDifyInvocationModerationTask(
 
 	handle.WriteResponse("struct", response)
 }
+
+func executeDifyInvocationAppTask(
+	handle *BackwardsInvocation,
+	request *dify_invocation.InvokeAppRequest,
+) {
+	response, err := dify_invocation.InvokeApp(request)
+	if err != nil {
+		handle.WriteError(fmt.Errorf("invoke app failed: %s", err.Error()))
+		return
+	}
+
+	user_id, err := handle.UserID()
+	if err != nil {
+		handle.WriteError(fmt.Errorf("get user id failed: %s", err.Error()))
+		return
+	}
+
+	request.User = user_id
+
+	response.Wrap(func(t map[string]any) {
+		handle.WriteResponse("stream", t)
+	})
+}

+ 12 - 0
internal/core/plugin_daemon/backwards_invocation/task_test.go

@@ -56,6 +56,9 @@ func TestBackwardsInvocationAllPermittedPermission(t *testing.T) {
 				Node: &plugin_entities.PluginPermissionNodeRequirement{
 					Enabled: true,
 				},
+				App: &plugin_entities.PluginPermissionAppRequirement{
+					Enabled: true,
+				},
 			},
 		},
 	}
@@ -99,6 +102,11 @@ func TestBackwardsInvocationAllPermittedPermission(t *testing.T) {
 	if err := checkPermission(&all_permitted_runtime, invoke_node_request); err != nil {
 		t.Errorf("checkPermission failed: %s", err.Error())
 	}
+
+	invoke_app_request := NewBackwardsInvocation(dify_invocation.INVOKE_TYPE_APP, "", nil, nil, nil)
+	if err := checkPermission(&all_permitted_runtime, invoke_app_request); err != nil {
+		t.Errorf("checkPermission failed: %s", err.Error())
+	}
 }
 
 func TestBackwardsInvocationAllDeniedPermission(t *testing.T) {
@@ -146,4 +154,8 @@ func TestBackwardsInvocationAllDeniedPermission(t *testing.T) {
 		t.Errorf("checkPermission failed: expected error, got nil")
 	}
 
+	invoke_app_request := NewBackwardsInvocation(dify_invocation.INVOKE_TYPE_APP, "", nil, nil, nil)
+	if err := checkPermission(&all_denied_runtime, invoke_app_request); err == nil {
+		t.Errorf("checkPermission failed: expected error, got nil")
+	}
 }

+ 1 - 2
internal/server/http_server.go

@@ -21,7 +21,7 @@ func (app *App) server(config *app.Config) func() {
 	app.pluginInvokeGroup(engine.Group("/plugin"), config)
 	app.remoteDebuggingGroup(engine.Group("/plugin/debugging"), config)
 	app.webhookGroup(engine.Group("/webhook"), config)
-	app.awsLambdaTransactionGroup(engine.Group("/aws-lambda"), config)
+	app.awsLambdaTransactionGroup(engine.Group("/backwards-invocation"), config)
 
 	srv := &http.Server{
 		Addr:    fmt.Sprintf(":%d", config.ServerPort),
@@ -82,7 +82,6 @@ func (appRef *App) awsLambdaTransactionGroup(group *gin.RouterGroup, config *app
 		)
 		group.POST(
 			"/transaction",
-			appRef.RedirectAWSLambdaTransaction,
 			service.HandleAWSPluginTransaction(appRef.aws_transaction_handler),
 		)
 	}

+ 0 - 10
internal/server/middleware.go

@@ -118,16 +118,6 @@ func (app *App) redirectPluginInvokeByPluginID(ctx *gin.Context, plugin_id strin
 	}
 }
 
-func (app *App) RedirectAWSLambdaTransaction(ctx *gin.Context) {
-	session_id := ctx.GetHeader("Dify-Plugin-Session-ID")
-	if session_id == "" {
-		ctx.AbortWithStatusJSON(404, gin.H{"error": "Session not found"})
-		return
-	}
-
-	// TODO: check if session_id is valid
-}
-
 func (app *App) InitClusterID() gin.HandlerFunc {
 	return func(ctx *gin.Context) {
 		ctx.Set("cluster_id", app.cluster.ID())

+ 1 - 1
internal/service/aws_transaction.go

@@ -11,7 +11,7 @@ import (
 func HandleAWSPluginTransaction(handler *transaction.AWSTransactionHandler) gin.HandlerFunc {
 	return func(c *gin.Context) {
 		// get session id from the context
-		session_id := c.GetString("session_id")
+		session_id := c.Request.Header.Get("Dify-Plugin-Session-ID")
 		session := session_manager.GetSession(session_id)
 		if session == nil {
 			c.JSON(http.StatusBadRequest, gin.H{"error": "session not found"})

+ 5 - 0
internal/types/entities/app_entities/file.go

@@ -0,0 +1,5 @@
+package app_entities
+
+// TODO
+type FileVar struct {
+}

+ 9 - 0
internal/types/entities/plugin_entities/plugin_declaration.go

@@ -21,6 +21,7 @@ type PluginPermissionRequirement struct {
 	Model   *PluginPermissionModelRequirement   `json:"model" yaml:"model" validate:"omitempty"`
 	Node    *PluginPermissionNodeRequirement    `json:"node" yaml:"node" validate:"omitempty"`
 	Webhook *PluginPermissionWebhookRequirement `json:"webhook" yaml:"webhook" validate:"omitempty"`
+	App     *PluginPermissionAppRequirement     `json:"app" yaml:"app" validate:"omitempty"`
 }
 
 func (p *PluginPermissionRequirement) AllowInvokeTool() bool {
@@ -55,6 +56,10 @@ func (p *PluginPermissionRequirement) AllowInvokeNode() bool {
 	return p != nil && p.Node != nil && p.Node.Enabled
 }
 
+func (p *PluginPermissionRequirement) AllowInvokeApp() bool {
+	return p != nil && p.App != nil && p.App.Enabled
+}
+
 func (p *PluginPermissionRequirement) AllowRegistryWebhook() bool {
 	return p != nil && p.Webhook != nil && p.Webhook.Enabled
 }
@@ -81,6 +86,10 @@ type PluginPermissionWebhookRequirement struct {
 	Enabled bool `json:"enabled" yaml:"enabled"`
 }
 
+type PluginPermissionAppRequirement struct {
+	Enabled bool `json:"enabled" yaml:"enabled"`
+}
+
 type PluginResourceRequirement struct {
 	// Memory in bytes
 	Memory int64 `json:"memory" yaml:"memory" validate:"required"`