task.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. package backwards_invocation
  2. import (
  3. "fmt"
  4. "github.com/langgenius/dify-plugin-daemon/internal/core/dify_invocation"
  5. "github.com/langgenius/dify-plugin-daemon/internal/core/plugin_daemon/access_types"
  6. "github.com/langgenius/dify-plugin-daemon/internal/core/session_manager"
  7. "github.com/langgenius/dify-plugin-daemon/internal/types/entities/model_entities"
  8. "github.com/langgenius/dify-plugin-daemon/internal/types/entities/plugin_entities"
  9. "github.com/langgenius/dify-plugin-daemon/internal/types/entities/tool_entities"
  10. "github.com/langgenius/dify-plugin-daemon/internal/utils/parser"
  11. "github.com/langgenius/dify-plugin-daemon/internal/utils/routine"
  12. )
  13. func InvokeDify(
  14. declaration *plugin_entities.PluginDeclaration,
  15. invoke_from access_types.PluginAccessType,
  16. session *session_manager.Session,
  17. writer BackwardsInvocationWriter,
  18. data []byte,
  19. ) error {
  20. // unmarshal invoke data
  21. request, err := parser.UnmarshalJsonBytes2Map(data)
  22. if err != nil {
  23. return fmt.Errorf("unmarshal invoke request failed: %s", err.Error())
  24. }
  25. if request == nil {
  26. return fmt.Errorf("invoke request is empty")
  27. }
  28. // prepare invocation arguments
  29. request_handle, err := prepareDifyInvocationArguments(session, writer, request)
  30. if err != nil {
  31. return err
  32. }
  33. if invoke_from == access_types.PLUGIN_ACCESS_TYPE_MODEL {
  34. request_handle.WriteError(fmt.Errorf("you can not invoke dify from %s", invoke_from))
  35. request_handle.EndResponse()
  36. return nil
  37. }
  38. // check permission
  39. if err := checkPermission(declaration, request_handle); err != nil {
  40. request_handle.WriteError(err)
  41. request_handle.EndResponse()
  42. return nil
  43. }
  44. // dispatch invocation task
  45. routine.Submit(func() {
  46. dispatchDifyInvocationTask(request_handle)
  47. defer request_handle.EndResponse()
  48. })
  49. return nil
  50. }
  51. var (
  52. permissionMapping = map[dify_invocation.InvokeType]map[string]any{
  53. dify_invocation.INVOKE_TYPE_TOOL: {
  54. "func": func(declaration *plugin_entities.PluginDeclaration) bool {
  55. return declaration.Resource.Permission.AllowInvokeTool()
  56. },
  57. "error": "permission denied, you need to enable tool access in plugin manifest",
  58. },
  59. dify_invocation.INVOKE_TYPE_LLM: {
  60. "func": func(declaration *plugin_entities.PluginDeclaration) bool {
  61. return declaration.Resource.Permission.AllowInvokeLLM()
  62. },
  63. "error": "permission denied, you need to enable llm access in plugin manifest",
  64. },
  65. dify_invocation.INVOKE_TYPE_TEXT_EMBEDDING: {
  66. "func": func(declaration *plugin_entities.PluginDeclaration) bool {
  67. return declaration.Resource.Permission.AllowInvokeTextEmbedding()
  68. },
  69. "error": "permission denied, you need to enable text-embedding access in plugin manifest",
  70. },
  71. dify_invocation.INVOKE_TYPE_RERANK: {
  72. "func": func(declaration *plugin_entities.PluginDeclaration) bool {
  73. return declaration.Resource.Permission.AllowInvokeRerank()
  74. },
  75. "error": "permission denied, you need to enable rerank access in plugin manifest",
  76. },
  77. dify_invocation.INVOKE_TYPE_TTS: {
  78. "func": func(declaration *plugin_entities.PluginDeclaration) bool {
  79. return declaration.Resource.Permission.AllowInvokeTTS()
  80. },
  81. "error": "permission denied, you need to enable tts access in plugin manifest",
  82. },
  83. dify_invocation.INVOKE_TYPE_SPEECH2TEXT: {
  84. "func": func(declaration *plugin_entities.PluginDeclaration) bool {
  85. return declaration.Resource.Permission.AllowInvokeSpeech2Text()
  86. },
  87. "error": "permission denied, you need to enable speech2text access in plugin manifest",
  88. },
  89. dify_invocation.INVOKE_TYPE_MODERATION: {
  90. "func": func(declaration *plugin_entities.PluginDeclaration) bool {
  91. return declaration.Resource.Permission.AllowInvokeModeration()
  92. },
  93. "error": "permission denied, you need to enable moderation access in plugin manifest",
  94. },
  95. dify_invocation.INVOKE_TYPE_NODE: {
  96. "func": func(declaration *plugin_entities.PluginDeclaration) bool {
  97. return declaration.Resource.Permission.AllowInvokeNode()
  98. },
  99. "error": "permission denied, you need to enable node access in plugin manifest",
  100. },
  101. dify_invocation.INVOKE_TYPE_APP: {
  102. "func": func(declaration *plugin_entities.PluginDeclaration) bool {
  103. return declaration.Resource.Permission.AllowInvokeApp()
  104. },
  105. "error": "permission denied, you need to enable app access in plugin manifest",
  106. },
  107. }
  108. )
  109. func checkPermission(runtime *plugin_entities.PluginDeclaration, request_handle *BackwardsInvocation) error {
  110. permission, ok := permissionMapping[request_handle.Type()]
  111. if !ok {
  112. return fmt.Errorf("unsupported invoke type: %s", request_handle.Type())
  113. }
  114. permission_func, ok := permission["func"].(func(runtime *plugin_entities.PluginDeclaration) bool)
  115. if !ok {
  116. return fmt.Errorf("permission function not found: %s", request_handle.Type())
  117. }
  118. if !permission_func(runtime) {
  119. return fmt.Errorf(permission["error"].(string))
  120. }
  121. return nil
  122. }
  123. func prepareDifyInvocationArguments(
  124. session *session_manager.Session,
  125. writer BackwardsInvocationWriter,
  126. request map[string]any,
  127. ) (*BackwardsInvocation, error) {
  128. typ, ok := request["type"].(string)
  129. if !ok {
  130. return nil, fmt.Errorf("invoke request missing type: %s", request)
  131. }
  132. // get request id
  133. backwards_request_id, ok := request["backwards_request_id"].(string)
  134. if !ok {
  135. return nil, fmt.Errorf("invoke request missing request_id: %s", request)
  136. }
  137. // get request
  138. detailed_request, ok := request["request"].(map[string]any)
  139. if !ok {
  140. return nil, fmt.Errorf("invoke request missing request: %s", request)
  141. }
  142. return NewBackwardsInvocation(
  143. BackwardsInvocationType(typ),
  144. backwards_request_id,
  145. session,
  146. writer,
  147. detailed_request,
  148. ), nil
  149. }
  150. var (
  151. dispatchMapping = map[dify_invocation.InvokeType]func(handle *BackwardsInvocation){
  152. dify_invocation.INVOKE_TYPE_TOOL: func(handle *BackwardsInvocation) {
  153. genericDispatchTask[dify_invocation.InvokeToolRequest](handle, executeDifyInvocationToolTask)
  154. },
  155. dify_invocation.INVOKE_TYPE_LLM: func(handle *BackwardsInvocation) {
  156. genericDispatchTask[dify_invocation.InvokeLLMRequest](handle, executeDifyInvocationLLMTask)
  157. },
  158. dify_invocation.INVOKE_TYPE_TEXT_EMBEDDING: func(handle *BackwardsInvocation) {
  159. genericDispatchTask[dify_invocation.InvokeTextEmbeddingRequest](handle, executeDifyInvocationTextEmbeddingTask)
  160. },
  161. dify_invocation.INVOKE_TYPE_RERANK: func(handle *BackwardsInvocation) {
  162. genericDispatchTask[dify_invocation.InvokeRerankRequest](handle, executeDifyInvocationRerankTask)
  163. },
  164. dify_invocation.INVOKE_TYPE_TTS: func(handle *BackwardsInvocation) {
  165. genericDispatchTask[dify_invocation.InvokeTTSRequest](handle, executeDifyInvocationTTSTask)
  166. },
  167. dify_invocation.INVOKE_TYPE_SPEECH2TEXT: func(handle *BackwardsInvocation) {
  168. genericDispatchTask[dify_invocation.InvokeSpeech2TextRequest](handle, executeDifyInvocationSpeech2TextTask)
  169. },
  170. dify_invocation.INVOKE_TYPE_MODERATION: func(handle *BackwardsInvocation) {
  171. genericDispatchTask[dify_invocation.InvokeModerationRequest](handle, executeDifyInvocationModerationTask)
  172. },
  173. dify_invocation.INVOKE_TYPE_APP: func(handle *BackwardsInvocation) {
  174. genericDispatchTask[dify_invocation.InvokeAppRequest](handle, executeDifyInvocationAppTask)
  175. },
  176. }
  177. )
  178. func genericDispatchTask[T any](
  179. handle *BackwardsInvocation,
  180. dispatch func(
  181. handle *BackwardsInvocation,
  182. request *T,
  183. ),
  184. ) {
  185. r, err := parser.MapToStruct[T](handle.RequestData())
  186. if err != nil {
  187. handle.WriteError(fmt.Errorf("unmarshal invoke tool request failed: %s", err.Error()))
  188. return
  189. }
  190. dispatch(handle, r)
  191. }
  192. func dispatchDifyInvocationTask(handle *BackwardsInvocation) {
  193. request_data := handle.RequestData()
  194. tenant_id, err := handle.TenantID()
  195. if err != nil {
  196. handle.WriteError(fmt.Errorf("get tenant id failed: %s", err.Error()))
  197. return
  198. }
  199. request_data["tenant_id"] = tenant_id
  200. user_id, err := handle.UserID()
  201. if err != nil {
  202. handle.WriteError(fmt.Errorf("get user id failed: %s", err.Error()))
  203. return
  204. }
  205. request_data["user_id"] = user_id
  206. typ := handle.Type()
  207. request_data["type"] = typ
  208. for t, v := range dispatchMapping {
  209. if t == handle.Type() {
  210. v(handle)
  211. return
  212. }
  213. }
  214. handle.WriteError(fmt.Errorf("unsupported invoke type: %s", handle.Type()))
  215. }
  216. func executeDifyInvocationToolTask(
  217. handle *BackwardsInvocation,
  218. request *dify_invocation.InvokeToolRequest,
  219. ) {
  220. response, err := dify_invocation.InvokeTool(request)
  221. if err != nil {
  222. handle.WriteError(fmt.Errorf("invoke tool failed: %s", err.Error()))
  223. return
  224. }
  225. response.Wrap(func(t tool_entities.ToolResponseChunk) {
  226. handle.WriteResponse("stream", t)
  227. })
  228. }
  229. func executeDifyInvocationLLMTask(
  230. handle *BackwardsInvocation,
  231. request *dify_invocation.InvokeLLMRequest,
  232. ) {
  233. response, err := dify_invocation.InvokeLLM(request)
  234. if err != nil {
  235. handle.WriteError(fmt.Errorf("invoke llm model failed: %s", err.Error()))
  236. return
  237. }
  238. response.Wrap(func(t model_entities.LLMResultChunk) {
  239. handle.WriteResponse("stream", t)
  240. })
  241. }
  242. func executeDifyInvocationTextEmbeddingTask(
  243. handle *BackwardsInvocation,
  244. request *dify_invocation.InvokeTextEmbeddingRequest,
  245. ) {
  246. response, err := dify_invocation.InvokeTextEmbedding(request)
  247. if err != nil {
  248. handle.WriteError(fmt.Errorf("invoke text-embedding model failed: %s", err.Error()))
  249. return
  250. }
  251. handle.WriteResponse("struct", response)
  252. }
  253. func executeDifyInvocationRerankTask(
  254. handle *BackwardsInvocation,
  255. request *dify_invocation.InvokeRerankRequest,
  256. ) {
  257. response, err := dify_invocation.InvokeRerank(request)
  258. if err != nil {
  259. handle.WriteError(fmt.Errorf("invoke rerank model failed: %s", err.Error()))
  260. return
  261. }
  262. handle.WriteResponse("struct", response)
  263. }
  264. func executeDifyInvocationTTSTask(
  265. handle *BackwardsInvocation,
  266. request *dify_invocation.InvokeTTSRequest,
  267. ) {
  268. response, err := dify_invocation.InvokeTTS(request)
  269. if err != nil {
  270. handle.WriteError(fmt.Errorf("invoke tts model failed: %s", err.Error()))
  271. return
  272. }
  273. response.Wrap(func(t model_entities.TTSResult) {
  274. handle.WriteResponse("struct", t)
  275. })
  276. }
  277. func executeDifyInvocationSpeech2TextTask(
  278. handle *BackwardsInvocation,
  279. request *dify_invocation.InvokeSpeech2TextRequest,
  280. ) {
  281. response, err := dify_invocation.InvokeSpeech2Text(request)
  282. if err != nil {
  283. handle.WriteError(fmt.Errorf("invoke speech2text model failed: %s", err.Error()))
  284. return
  285. }
  286. handle.WriteResponse("struct", response)
  287. }
  288. func executeDifyInvocationModerationTask(
  289. handle *BackwardsInvocation,
  290. request *dify_invocation.InvokeModerationRequest,
  291. ) {
  292. response, err := dify_invocation.InvokeModeration(request)
  293. if err != nil {
  294. handle.WriteError(fmt.Errorf("invoke moderation model failed: %s", err.Error()))
  295. return
  296. }
  297. handle.WriteResponse("struct", response)
  298. }
  299. func executeDifyInvocationAppTask(
  300. handle *BackwardsInvocation,
  301. request *dify_invocation.InvokeAppRequest,
  302. ) {
  303. response, err := dify_invocation.InvokeApp(request)
  304. if err != nil {
  305. handle.WriteError(fmt.Errorf("invoke app failed: %s", err.Error()))
  306. return
  307. }
  308. user_id, err := handle.UserID()
  309. if err != nil {
  310. handle.WriteError(fmt.Errorf("get user id failed: %s", err.Error()))
  311. return
  312. }
  313. request.User = user_id
  314. response.Wrap(func(t map[string]any) {
  315. handle.WriteResponse("stream", t)
  316. })
  317. }