@superinterface/server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/README.md +36 -0
  2. package/eslint.config.mjs +31 -0
  3. package/next.config.ts +7 -0
  4. package/package.json +176 -0
  5. package/prisma/Account.prisma +18 -0
  6. package/prisma/ApiKey.prisma +13 -0
  7. package/prisma/Assistant.prisma +32 -0
  8. package/prisma/AssistantHandler.prisma +12 -0
  9. package/prisma/Avatar.prisma +10 -0
  10. package/prisma/ClientToolHandler.prisma +13 -0
  11. package/prisma/CodeInterpreterTool.prisma +7 -0
  12. package/prisma/ComputerUseTool.prisma +12 -0
  13. package/prisma/CreateTaskHandler.prisma +10 -0
  14. package/prisma/DeleteTaskHandler.prisma +10 -0
  15. package/prisma/FileSearchTool.prisma +9 -0
  16. package/prisma/FirecrawlHandler.prisma +13 -0
  17. package/prisma/Function.prisma +13 -0
  18. package/prisma/Handler.prisma +19 -0
  19. package/prisma/HttpTransport.prisma +12 -0
  20. package/prisma/IconAvatar.prisma +8 -0
  21. package/prisma/ImageAvatar.prisma +8 -0
  22. package/prisma/ImageGenerationTool.prisma +11 -0
  23. package/prisma/InitialMessage.prisma +17 -0
  24. package/prisma/Invitation.prisma +15 -0
  25. package/prisma/ListTasksHandler.prisma +10 -0
  26. package/prisma/Log.prisma +21 -0
  27. package/prisma/McpServer.prisma +14 -0
  28. package/prisma/Message.prisma +30 -0
  29. package/prisma/ModelProvider.prisma +15 -0
  30. package/prisma/Organization.prisma +10 -0
  31. package/prisma/OrganizationApiKey.prisma +12 -0
  32. package/prisma/OrganizationInvitation.prisma +15 -0
  33. package/prisma/OrganizationUserRole.prisma +14 -0
  34. package/prisma/ReplicateHandler.prisma +14 -0
  35. package/prisma/RequestHandler.prisma +15 -0
  36. package/prisma/Run.prisma +36 -0
  37. package/prisma/RunStep.prisma +30 -0
  38. package/prisma/Session.prisma +7 -0
  39. package/prisma/SseTransport.prisma +12 -0
  40. package/prisma/StdioTransport.prisma +11 -0
  41. package/prisma/Task.prisma +15 -0
  42. package/prisma/Thread.prisma +20 -0
  43. package/prisma/Tool.prisma +13 -0
  44. package/prisma/UpdateTaskHandler.prisma +10 -0
  45. package/prisma/User.prisma +16 -0
  46. package/prisma/UserRole.prisma +14 -0
  47. package/prisma/VerificationToken.prisma +7 -0
  48. package/prisma/WebSearchTool.prisma +7 -0
  49. package/prisma/Workspace.prisma +14 -0
  50. package/prisma/enums/ApiKeyType.prisma +4 -0
  51. package/prisma/enums/AvatarType.prisma +5 -0
  52. package/prisma/enums/ClientToolHandlerType.prisma +3 -0
  53. package/prisma/enums/ComputerUseToolEnvironment.prisma +6 -0
  54. package/prisma/enums/FirecrawlHandlerType.prisma +6 -0
  55. package/prisma/enums/HandlerType.prisma +11 -0
  56. package/prisma/enums/IconAvatarName.prisma +14 -0
  57. package/prisma/enums/ImageGenerationToolOutputFormat.prisma +5 -0
  58. package/prisma/enums/ImageGenerationToolQuality.prisma +6 -0
  59. package/prisma/enums/ImageGenerationToolSize.prisma +6 -0
  60. package/prisma/enums/LogLevel.prisma +5 -0
  61. package/prisma/enums/LogRequestMethod.prisma +7 -0
  62. package/prisma/enums/LogRequestRoute.prisma +6 -0
  63. package/prisma/enums/MessageRole.prisma +4 -0
  64. package/prisma/enums/MessageStatus.prisma +5 -0
  65. package/prisma/enums/MethodType.prisma +7 -0
  66. package/prisma/enums/ModelProviderType.prisma +13 -0
  67. package/prisma/enums/OrganizationUserRoleType.prisma +3 -0
  68. package/prisma/enums/ReplicateHandlerType.prisma +3 -0
  69. package/prisma/enums/RunStatus.prisma +10 -0
  70. package/prisma/enums/RunStepStatus.prisma +7 -0
  71. package/prisma/enums/RunStepType.prisma +4 -0
  72. package/prisma/enums/StorageProviderType.prisma +7 -0
  73. package/prisma/enums/ToolType.prisma +7 -0
  74. package/prisma/enums/TransportType.prisma +5 -0
  75. package/prisma/enums/TruncationType.prisma +5 -0
  76. package/prisma/enums/UserRoleType.prisma +3 -0
  77. package/prisma/migrations/20251006235143_initial_setup/migration.sql +986 -0
  78. package/prisma/migrations/20251007163926_add_truncation_type/migration.sql +6 -0
  79. package/prisma/migrations/20251007190703_add_organizations/migration.sql +97 -0
  80. package/prisma/migrations/migration_lock.toml +3 -0
  81. package/prisma/schema.prisma +13 -0
  82. package/prisma.config.ts +6 -0
  83. package/scripts/cli.ts +84 -0
  84. package/scripts/commands/organizations/api-keys/create.ts +159 -0
  85. package/scripts/commands/organizations/create.ts +82 -0
  86. package/scripts/utils/env.ts +31 -0
  87. package/scripts/utils/errors.ts +6 -0
  88. package/src/app/api/api-keys/[apiKeyId]/route.ts +178 -0
  89. package/src/app/api/api-keys/route.ts +147 -0
  90. package/src/app/api/assistants/[assistantId]/functions/[functionId]/route.ts +245 -0
  91. package/src/app/api/assistants/[assistantId]/functions/route.ts +157 -0
  92. package/src/app/api/assistants/[assistantId]/initial-messages/route.ts +127 -0
  93. package/src/app/api/assistants/[assistantId]/mcp-servers/[mcpServerId]/route.ts +243 -0
  94. package/src/app/api/assistants/[assistantId]/mcp-servers/route.ts +163 -0
  95. package/src/app/api/assistants/[assistantId]/route.ts +336 -0
  96. package/src/app/api/assistants/route.ts +196 -0
  97. package/src/app/api/files/[fileId]/contents/route.ts +145 -0
  98. package/src/app/api/files/route.ts +117 -0
  99. package/src/app/api/messages/lib/getWorkspaceId.ts +12 -0
  100. package/src/app/api/messages/lib/initialMessagesResponse.ts +90 -0
  101. package/src/app/api/messages/lib/serializeThread.ts +22 -0
  102. package/src/app/api/messages/route.ts +710 -0
  103. package/src/app/api/providers/[modelProviderId]/assistants/route.ts +68 -0
  104. package/src/app/api/providers/[modelProviderId]/models/route.ts +68 -0
  105. package/src/app/api/providers/[modelProviderId]/route.ts +202 -0
  106. package/src/app/api/providers/route.ts +105 -0
  107. package/src/app/api/tasks/[taskId]/route.ts +213 -0
  108. package/src/app/api/tasks/callback/route.ts +280 -0
  109. package/src/app/api/tasks/route.ts +121 -0
  110. package/src/app/api/threads/runs/submit-client-tool-outputs/route.ts +54 -0
  111. package/src/app/api/workspaces/[workspaceId]/route.ts +137 -0
  112. package/src/app/api/workspaces/route.ts +139 -0
  113. package/src/app/layout.tsx +9 -0
  114. package/src/app/page.tsx +3 -0
  115. package/src/lib/apiKeys/formatApiKeyName.ts +13 -0
  116. package/src/lib/apiKeys/getApiKey.ts +25 -0
  117. package/src/lib/apiKeys/serializeApiKey.ts +11 -0
  118. package/src/lib/apiKeys/workspaceAccessWhere.ts +21 -0
  119. package/src/lib/assistants/assistantClientAdapter/buildGetOpenaiAssistant.ts +96 -0
  120. package/src/lib/assistants/assistantClientAdapter/index.ts +165 -0
  121. package/src/lib/assistants/formatName.ts +9 -0
  122. package/src/lib/assistants/serializeApiAssistant.ts +40 -0
  123. package/src/lib/assistants/serializeAssistant.ts +31 -0
  124. package/src/lib/assistants/storageAssistantId.ts +29 -0
  125. package/src/lib/avatars/defaultAvatar.ts +15 -0
  126. package/src/lib/avatars/serializeAvatar.ts +26 -0
  127. package/src/lib/cache/cacheHeaders.ts +5 -0
  128. package/src/lib/computerCalls/handleComputerCall/index.ts +173 -0
  129. package/src/lib/errors/index.ts +10 -0
  130. package/src/lib/errors/serializeError.ts +11 -0
  131. package/src/lib/functions/createFunction.ts +32 -0
  132. package/src/lib/functions/functionSchema.ts +201 -0
  133. package/src/lib/functions/handleFunction/getFunction.ts +43 -0
  134. package/src/lib/functions/handleFunction/handleAssistant.ts +399 -0
  135. package/src/lib/functions/handleFunction/handleClientTool.ts +127 -0
  136. package/src/lib/functions/handleFunction/handleFirecrawl.ts +212 -0
  137. package/src/lib/functions/handleFunction/handleReplicate.ts +109 -0
  138. package/src/lib/functions/handleFunction/handleRequest.ts +272 -0
  139. package/src/lib/functions/handleFunction/index.ts +474 -0
  140. package/src/lib/functions/handleFunction/tasks/handleCreateTask.ts +58 -0
  141. package/src/lib/functions/handleFunction/tasks/handleDeleteTask.ts +62 -0
  142. package/src/lib/functions/handleFunction/tasks/handleListTasks.ts +53 -0
  143. package/src/lib/functions/handleFunction/tasks/handleUpdateTask.ts +70 -0
  144. package/src/lib/functions/interpolateFunctionValue.ts +26 -0
  145. package/src/lib/functions/serializeApiFunction.ts +32 -0
  146. package/src/lib/functions/updateFunction.ts +42 -0
  147. package/src/lib/handlers/handlerPrismaInput.tsx +141 -0
  148. package/src/lib/handlers/serializeApiHandler.ts +94 -0
  149. package/src/lib/iconAvatars/serializeIconAvatar.ts +9 -0
  150. package/src/lib/imageAvatars/serializeImageAvatar.ts +9 -0
  151. package/src/lib/initialMessages/schema.ts +11 -0
  152. package/src/lib/initialMessages/serializeApiInitialMessage.ts +15 -0
  153. package/src/lib/initialMessages/updateInitialMessages.ts +33 -0
  154. package/src/lib/logs/createLog.ts +17 -0
  155. package/src/lib/mcpServers/closeMcpConnection.ts +16 -0
  156. package/src/lib/mcpServers/connectMcpServer.ts +117 -0
  157. package/src/lib/mcpServers/getToolCallMcpServer.ts +62 -0
  158. package/src/lib/mcpServers/headers.ts +113 -0
  159. package/src/lib/mcpServers/mcpServerSchema.ts +77 -0
  160. package/src/lib/mcpServers/serializeApiMcpServer.ts +51 -0
  161. package/src/lib/mcpServers/url.ts +98 -0
  162. package/src/lib/messages/content.ts +60 -0
  163. package/src/lib/messages/textContent.ts +13 -0
  164. package/src/lib/metadata/serializeMetadata.ts +34 -0
  165. package/src/lib/misc/isJSON.ts +9 -0
  166. package/src/lib/misc/merge/customizer.ts +8 -0
  167. package/src/lib/misc/merge/index.ts +6 -0
  168. package/src/lib/modelProviders/buildAzureOpenaiClientAdapter.ts +33 -0
  169. package/src/lib/modelProviders/buildOpenaiClient.ts +14 -0
  170. package/src/lib/modelProviders/buildOpenaiClientAdapter.ts +30 -0
  171. package/src/lib/modelProviders/clientAdapter.ts +121 -0
  172. package/src/lib/modelProviders/isModelProviderValid.ts +23 -0
  173. package/src/lib/modelProviders/modelProviderConfigs.ts +221 -0
  174. package/src/lib/modelProviders/serializeModelProvider.ts +19 -0
  175. package/src/lib/models/getModels.ts +27 -0
  176. package/src/lib/models/serializeApiModel.ts +5 -0
  177. package/src/lib/openai/getOpenaiAssistants.ts +30 -0
  178. package/src/lib/organizationApiKeys/getOrganizationApiKey.ts +23 -0
  179. package/src/lib/prisma/index.ts +29 -0
  180. package/src/lib/redis/index.ts +3 -0
  181. package/src/lib/runs/createRunOpts.ts +80 -0
  182. package/src/lib/storageProviders/getStorageProviderAssistants.ts +19 -0
  183. package/src/lib/storageProviders/getStorageProviderType.ts +21 -0
  184. package/src/lib/storageProviders/isOpenaiAssistantsStorageProvider.ts +8 -0
  185. package/src/lib/storageProviders/isResponsesStorageProvider.ts +8 -0
  186. package/src/lib/storageProviders/openaiAssistantsStorageProviderTypes.ts +6 -0
  187. package/src/lib/storageProviders/responsesStorageProviderTypes.ts +6 -0
  188. package/src/lib/storageProviders/serializeApiStorageProviderAssistant.ts +14 -0
  189. package/src/lib/tasks/cancelScheduledTask.ts +13 -0
  190. package/src/lib/tasks/getNextOccurrence.ts +77 -0
  191. package/src/lib/tasks/getTaskToolKey.ts +49 -0
  192. package/src/lib/tasks/parseTaskToolArgs.ts +101 -0
  193. package/src/lib/tasks/scheduleSchema.ts +34 -0
  194. package/src/lib/tasks/scheduleTask.ts +37 -0
  195. package/src/lib/tasks/schemas.ts +25 -0
  196. package/src/lib/tasks/serializeTask.ts +14 -0
  197. package/src/lib/tasks/validateSchedule.ts +23 -0
  198. package/src/lib/themes/defaultTheme.ts +7 -0
  199. package/src/lib/themes/serializeAccentColor.ts +9 -0
  200. package/src/lib/themes/serializeTheme/index.ts +25 -0
  201. package/src/lib/themes/serializeTheme/serializeScaling.ts +14 -0
  202. package/src/lib/threads/createThread/index.ts +185 -0
  203. package/src/lib/threads/createThread/initialMessages.ts +36 -0
  204. package/src/lib/threads/managedOpenaiThreadId.ts +72 -0
  205. package/src/lib/threads/storageThreadId.ts +49 -0
  206. package/src/lib/threads/validThreadId.ts +10 -0
  207. package/src/lib/toolCalls/handleToolCall.ts +121 -0
  208. package/src/lib/toolCalls/messagesToOutput.ts +8 -0
  209. package/src/lib/toolCalls/streamOutput.ts +106 -0
  210. package/src/lib/tools/tools/index.ts +316 -0
  211. package/src/lib/upstash/qstash.ts +5 -0
  212. package/src/lib/upstash/upstashWorkflowClient.ts +5 -0
  213. package/src/lib/workspaces/serializeApiWorkspace.ts +12 -0
  214. package/src/types/index.ts +133 -0
  215. package/tsconfig.build.json +13 -0
  216. package/tsconfig.json +27 -0
  217. package/types/prisma.d.ts +4 -0
@@ -0,0 +1,474 @@
1
+ import OpenAI from 'openai'
2
+ import {
3
+ Prisma,
4
+ HandlerType,
5
+ Thread,
6
+ LogRequestMethod,
7
+ LogRequestRoute,
8
+ LogLevel,
9
+ } from '@prisma/client'
10
+ import { createLog } from '@/lib/logs/createLog'
11
+ import { getFunction } from './getFunction'
12
+ import { handleRequest } from './handleRequest'
13
+ import { handleFirecrawl } from './handleFirecrawl'
14
+ import { handleReplicate } from './handleReplicate'
15
+ import { handleAssistant } from './handleAssistant'
16
+ import { handleClientTool } from './handleClientTool'
17
+ import { handleCreateTask } from './tasks/handleCreateTask'
18
+ import { handleListTasks } from './tasks/handleListTasks'
19
+ import { handleUpdateTask } from './tasks/handleUpdateTask'
20
+ import { handleDeleteTask } from './tasks/handleDeleteTask'
21
+ import { getToolCallMcpServer } from '@/lib/mcpServers/getToolCallMcpServer'
22
+ import { closeMcpConnection } from '@/lib/mcpServers/closeMcpConnection'
23
+ import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js'
24
+
25
+ export const handleFunction = async ({
26
+ assistant,
27
+ toolCall,
28
+ controller,
29
+ run,
30
+ thread,
31
+ }: {
32
+ assistant: Prisma.AssistantGetPayload<{
33
+ include: {
34
+ mcpServers: {
35
+ include: {
36
+ stdioTransport: true
37
+ httpTransport: true
38
+ sseTransport: true
39
+ }
40
+ }
41
+ functions: {
42
+ include: {
43
+ handler: {
44
+ include: {
45
+ requestHandler: true
46
+ firecrawlHandler: true
47
+ replicateHandler: true
48
+ clientToolHandler: true
49
+ assistantHandler: true
50
+ createTaskHandler: true
51
+ listTasksHandler: true
52
+ updateTaskHandler: true
53
+ deleteTaskHandler: true
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }>
60
+ toolCall: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall
61
+ controller: ReadableStreamDefaultController
62
+ run: OpenAI.Beta.Threads.Runs.Run
63
+ thread: Thread
64
+ }) => {
65
+ const fn = getFunction({
66
+ toolCall,
67
+ assistant,
68
+ })
69
+
70
+ if (!fn) {
71
+ const { mcpConnection } = await getToolCallMcpServer({
72
+ toolCall,
73
+ assistant,
74
+ thread,
75
+ })
76
+
77
+ if (!mcpConnection) {
78
+ createLog({
79
+ log: {
80
+ requestMethod: LogRequestMethod.POST,
81
+ requestRoute: LogRequestRoute.MESSAGES,
82
+ level: LogLevel.ERROR,
83
+ status: 500,
84
+ message: `Function ${toolCall.function.name} not found.`,
85
+ workspaceId: assistant.workspaceId,
86
+ assistantId: assistant.id,
87
+ threadId: thread.id,
88
+ },
89
+ })
90
+
91
+ return {
92
+ tool_call_id: toolCall.id,
93
+ output: `Function ${toolCall.function.name} not found.`,
94
+ }
95
+ }
96
+
97
+ let args
98
+
99
+ try {
100
+ args = JSON.parse(toolCall.function.arguments || '{}')
101
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
102
+ } catch (e: any) {
103
+ createLog({
104
+ log: {
105
+ requestMethod: LogRequestMethod.POST,
106
+ requestRoute: LogRequestRoute.MESSAGES,
107
+ level: LogLevel.ERROR,
108
+ status: 400,
109
+ message: `Failed parsing function arguments: ${e.message}`,
110
+ workspaceId: assistant.workspaceId,
111
+ assistantId: assistant.id,
112
+ threadId: thread.id,
113
+ },
114
+ })
115
+
116
+ return {
117
+ tool_call_id: toolCall.id,
118
+ output: `Failed parsing function arguments: ${e.message}`,
119
+ }
120
+ }
121
+
122
+ try {
123
+ const mcpServerToolOutput = await mcpConnection.client.callTool(
124
+ {
125
+ name: toolCall.function.name,
126
+ arguments: args,
127
+ },
128
+ CallToolResultSchema,
129
+ {
130
+ timeout: 300000,
131
+ },
132
+ )
133
+
134
+ await closeMcpConnection({
135
+ mcpConnection,
136
+ })
137
+
138
+ return {
139
+ tool_call_id: toolCall.id,
140
+ output: JSON.stringify(mcpServerToolOutput),
141
+ }
142
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
143
+ } catch (e: any) {
144
+ createLog({
145
+ log: {
146
+ requestMethod: LogRequestMethod.POST,
147
+ requestRoute: LogRequestRoute.MESSAGES,
148
+ level: LogLevel.ERROR,
149
+ status: 500,
150
+ message: `Error calling function ${toolCall.function.name}: ${e.message}`,
151
+ workspaceId: assistant.workspaceId,
152
+ assistantId: assistant.id,
153
+ threadId: thread.id,
154
+ },
155
+ })
156
+
157
+ return {
158
+ tool_call_id: toolCall.id,
159
+ output: `Error calling function ${toolCall.function.name}: ${e.message}`,
160
+ }
161
+ }
162
+ }
163
+
164
+ if (!fn.handler) {
165
+ createLog({
166
+ log: {
167
+ requestMethod: LogRequestMethod.POST,
168
+ requestRoute: LogRequestRoute.MESSAGES,
169
+ level: LogLevel.ERROR,
170
+ status: 500,
171
+ message: `Function ${toolCall.function.name} has no handler.`,
172
+ workspaceId: assistant.workspaceId,
173
+ assistantId: assistant.id,
174
+ threadId: thread.id,
175
+ },
176
+ })
177
+
178
+ return {
179
+ tool_call_id: toolCall.id,
180
+ output: `Function ${toolCall.function.name} has no handler.`,
181
+ }
182
+ }
183
+
184
+ if (fn.handler.type === HandlerType.REQUEST) {
185
+ if (!fn.handler.requestHandler) {
186
+ createLog({
187
+ log: {
188
+ requestMethod: LogRequestMethod.POST,
189
+ requestRoute: LogRequestRoute.MESSAGES,
190
+ level: LogLevel.ERROR,
191
+ status: 500,
192
+ message: `Function ${toolCall.function.name} has no request handler.`,
193
+ workspaceId: assistant.workspaceId,
194
+ assistantId: assistant.id,
195
+ threadId: thread.id,
196
+ },
197
+ })
198
+
199
+ return {
200
+ tool_call_id: toolCall.id,
201
+ output: `Function ${toolCall.function.name} has no request handler.`,
202
+ }
203
+ }
204
+
205
+ return handleRequest({
206
+ requestHandler: fn.handler.requestHandler,
207
+ toolCall,
208
+ assistant,
209
+ thread,
210
+ })
211
+ }
212
+
213
+ if (fn.handler.type === HandlerType.CLIENT_TOOL) {
214
+ if (!fn.handler.clientToolHandler) {
215
+ createLog({
216
+ log: {
217
+ requestMethod: LogRequestMethod.POST,
218
+ requestRoute: LogRequestRoute.MESSAGES,
219
+ level: LogLevel.ERROR,
220
+ status: 500,
221
+ message: `Function ${toolCall.function.name} has no client tool handler.`,
222
+ workspaceId: assistant.workspaceId,
223
+ assistantId: assistant.id,
224
+ threadId: thread.id,
225
+ },
226
+ })
227
+
228
+ return {
229
+ tool_call_id: toolCall.id,
230
+ output: `Function ${toolCall.function.name} has no client tool handler.`,
231
+ }
232
+ }
233
+
234
+ return handleClientTool({
235
+ clientToolHandler: fn.handler.clientToolHandler,
236
+ controller,
237
+ toolCall,
238
+ assistant,
239
+ thread,
240
+ run,
241
+ })
242
+ }
243
+
244
+ if (fn.handler.type === HandlerType.FIRECRAWL) {
245
+ if (!fn.handler.firecrawlHandler) {
246
+ createLog({
247
+ log: {
248
+ requestMethod: LogRequestMethod.POST,
249
+ requestRoute: LogRequestRoute.MESSAGES,
250
+ level: LogLevel.ERROR,
251
+ status: 500,
252
+ message: `Function ${toolCall.function.name} has no Firecrawl handler.`,
253
+ workspaceId: assistant.workspaceId,
254
+ assistantId: assistant.id,
255
+ threadId: thread.id,
256
+ },
257
+ })
258
+
259
+ return {
260
+ tool_call_id: toolCall.id,
261
+ output: `Function ${toolCall.function.name} has no Firecrawl handler.`,
262
+ }
263
+ }
264
+
265
+ return handleFirecrawl({
266
+ firecrawlHandler: fn.handler.firecrawlHandler,
267
+ toolCall,
268
+ assistant,
269
+ thread,
270
+ })
271
+ }
272
+
273
+ if (fn.handler.type === HandlerType.REPLICATE) {
274
+ if (!fn.handler.replicateHandler) {
275
+ createLog({
276
+ log: {
277
+ requestMethod: LogRequestMethod.POST,
278
+ requestRoute: LogRequestRoute.MESSAGES,
279
+ level: LogLevel.ERROR,
280
+ status: 500,
281
+ message: `Function ${toolCall.function.name} has no Replicate handler.`,
282
+ workspaceId: assistant.workspaceId,
283
+ assistantId: assistant.id,
284
+ threadId: thread.id,
285
+ },
286
+ })
287
+
288
+ return {
289
+ tool_call_id: toolCall.id,
290
+ output: `Function ${toolCall.function.name} has no Replicate handler.`,
291
+ }
292
+ }
293
+
294
+ return handleReplicate({
295
+ replicateHandler: fn.handler.replicateHandler,
296
+ toolCall,
297
+ assistant,
298
+ thread,
299
+ })
300
+ }
301
+
302
+ if (fn.handler.type === HandlerType.ASSISTANT) {
303
+ if (!fn.handler.assistantHandler) {
304
+ createLog({
305
+ log: {
306
+ requestMethod: LogRequestMethod.POST,
307
+ requestRoute: LogRequestRoute.MESSAGES,
308
+ level: LogLevel.ERROR,
309
+ status: 500,
310
+ message: `Function ${toolCall.function.name} has no assistant handler.`,
311
+ workspaceId: assistant.workspaceId,
312
+ assistantId: assistant.id,
313
+ threadId: thread.id,
314
+ },
315
+ })
316
+
317
+ return {
318
+ tool_call_id: toolCall.id,
319
+ output: `Function ${toolCall.function.name} has no assistant handler.`,
320
+ }
321
+ }
322
+
323
+ return handleAssistant({
324
+ assistantHandler: fn.handler.assistantHandler,
325
+ toolCall,
326
+ controller,
327
+ run,
328
+ assistant,
329
+ thread,
330
+ })
331
+ }
332
+
333
+ if (fn.handler.type === HandlerType.CREATE_TASK) {
334
+ const taskHandler = fn.handler.createTaskHandler
335
+
336
+ if (!taskHandler) {
337
+ createLog({
338
+ log: {
339
+ requestMethod: LogRequestMethod.POST,
340
+ requestRoute: LogRequestRoute.MESSAGES,
341
+ level: LogLevel.ERROR,
342
+ status: 500,
343
+ message: `Function ${toolCall.function.name} has no task handler.`,
344
+ workspaceId: assistant.workspaceId,
345
+ assistantId: assistant.id,
346
+ threadId: thread.id,
347
+ },
348
+ })
349
+
350
+ return {
351
+ tool_call_id: toolCall.id,
352
+ output: `Function ${toolCall.function.name} has no task handler.`,
353
+ }
354
+ }
355
+
356
+ return handleCreateTask({
357
+ taskHandler,
358
+ toolCall,
359
+ assistant,
360
+ thread,
361
+ })
362
+ }
363
+
364
+ if (fn.handler.type === HandlerType.LIST_TASKS) {
365
+ const taskHandler = fn.handler.listTasksHandler
366
+
367
+ if (!taskHandler) {
368
+ createLog({
369
+ log: {
370
+ requestMethod: LogRequestMethod.POST,
371
+ requestRoute: LogRequestRoute.MESSAGES,
372
+ level: LogLevel.ERROR,
373
+ status: 500,
374
+ message: `Function ${toolCall.function.name} has no task handler.`,
375
+ workspaceId: assistant.workspaceId,
376
+ assistantId: assistant.id,
377
+ threadId: thread.id,
378
+ },
379
+ })
380
+
381
+ return {
382
+ tool_call_id: toolCall.id,
383
+ output: `Function ${toolCall.function.name} has no task handler.`,
384
+ }
385
+ }
386
+
387
+ return handleListTasks({
388
+ taskHandler,
389
+ toolCall,
390
+ assistant,
391
+ thread,
392
+ })
393
+ }
394
+
395
+ if (fn.handler.type === HandlerType.UPDATE_TASK) {
396
+ const taskHandler = fn.handler.updateTaskHandler
397
+
398
+ if (!taskHandler) {
399
+ createLog({
400
+ log: {
401
+ requestMethod: LogRequestMethod.POST,
402
+ requestRoute: LogRequestRoute.MESSAGES,
403
+ level: LogLevel.ERROR,
404
+ status: 500,
405
+ message: `Function ${toolCall.function.name} has no task handler.`,
406
+ workspaceId: assistant.workspaceId,
407
+ assistantId: assistant.id,
408
+ threadId: thread.id,
409
+ },
410
+ })
411
+
412
+ return {
413
+ tool_call_id: toolCall.id,
414
+ output: `Function ${toolCall.function.name} has no task handler.`,
415
+ }
416
+ }
417
+
418
+ return handleUpdateTask({
419
+ taskHandler,
420
+ toolCall,
421
+ assistant,
422
+ thread,
423
+ })
424
+ }
425
+
426
+ if (fn.handler.type === HandlerType.DELETE_TASK) {
427
+ const taskHandler = fn.handler.deleteTaskHandler
428
+
429
+ if (!taskHandler) {
430
+ createLog({
431
+ log: {
432
+ requestMethod: LogRequestMethod.POST,
433
+ requestRoute: LogRequestRoute.MESSAGES,
434
+ level: LogLevel.ERROR,
435
+ status: 500,
436
+ message: `Function ${toolCall.function.name} has no task handler.`,
437
+ workspaceId: assistant.workspaceId,
438
+ assistantId: assistant.id,
439
+ threadId: thread.id,
440
+ },
441
+ })
442
+
443
+ return {
444
+ tool_call_id: toolCall.id,
445
+ output: `Function ${toolCall.function.name} has no task handler.`,
446
+ }
447
+ }
448
+
449
+ return handleDeleteTask({
450
+ taskHandler,
451
+ toolCall,
452
+ assistant,
453
+ thread,
454
+ })
455
+ }
456
+
457
+ createLog({
458
+ log: {
459
+ requestMethod: LogRequestMethod.POST,
460
+ requestRoute: LogRequestRoute.MESSAGES,
461
+ level: LogLevel.ERROR,
462
+ status: 500,
463
+ message: `Function ${toolCall.function.name} handler type ${fn.handler.type} not supported.`,
464
+ workspaceId: assistant.workspaceId,
465
+ assistantId: assistant.id,
466
+ threadId: thread.id,
467
+ },
468
+ })
469
+
470
+ return {
471
+ tool_call_id: toolCall.id,
472
+ output: `Function ${toolCall.function.name} handler type ${fn.handler.type} not supported.`,
473
+ }
474
+ }
@@ -0,0 +1,58 @@
1
+ import OpenAI from 'openai'
2
+ import { CreateTaskHandler, Assistant, Thread } from '@prisma/client'
3
+ import { prisma } from '@/lib/prisma'
4
+ import { serializeTask } from '@/lib/tasks/serializeTask'
5
+ import { validateSchedule } from '@/lib/tasks/validateSchedule'
6
+ import { createTaskToolSchema } from '@/lib/tasks/schemas'
7
+ import { parseTaskToolArgs } from '@/lib/tasks/parseTaskToolArgs'
8
+ import { getTaskToolKey } from '@/lib/tasks/getTaskToolKey'
9
+ import { scheduleTask } from '@/lib/tasks/scheduleTask'
10
+
11
+ export const handleCreateTask = async ({
12
+ taskHandler,
13
+ toolCall,
14
+ assistant,
15
+ thread,
16
+ }: {
17
+ taskHandler: CreateTaskHandler
18
+ toolCall: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall
19
+ assistant: Assistant
20
+ thread: Thread
21
+ }) => {
22
+ const parsedArgs = parseTaskToolArgs({ toolCall, assistant, thread })
23
+ if (!parsedArgs.ok)
24
+ return { tool_call_id: toolCall.id, output: parsedArgs.error }
25
+
26
+ const check = createTaskToolSchema.safeParse(parsedArgs.args)
27
+ if (!check.success)
28
+ return { tool_call_id: toolCall.id, output: check.error.toString() }
29
+ const args = check.data
30
+
31
+ const { ok, key, error } = await getTaskToolKey({
32
+ thread,
33
+ assistant,
34
+ keyTemplate: taskHandler.keyTemplate,
35
+ })
36
+
37
+ if (!ok) return { tool_call_id: toolCall.id, output: error }
38
+
39
+ if (!validateSchedule(args.schedule)) {
40
+ return { tool_call_id: toolCall.id, output: 'Invalid schedule.' }
41
+ }
42
+ const task = await prisma.task.create({
43
+ data: {
44
+ title: args.title,
45
+ message: args.message,
46
+ schedule: args.schedule,
47
+ threadId: thread.id,
48
+ key: key ?? '',
49
+ },
50
+ })
51
+
52
+ await scheduleTask({ task })
53
+
54
+ return {
55
+ tool_call_id: toolCall.id,
56
+ output: JSON.stringify({ task: serializeTask({ task }) }),
57
+ }
58
+ }
@@ -0,0 +1,62 @@
1
+ import OpenAI from 'openai'
2
+ import { DeleteTaskHandler, Assistant, Thread } from '@prisma/client'
3
+ import { prisma } from '@/lib/prisma'
4
+ import { serializeTask } from '@/lib/tasks/serializeTask'
5
+ import { deleteTaskSchema } from '@/lib/tasks/schemas'
6
+ import { parseTaskToolArgs } from '@/lib/tasks/parseTaskToolArgs'
7
+ import { getTaskToolKey } from '@/lib/tasks/getTaskToolKey'
8
+ import { cancelScheduledTask } from '@/lib/tasks/cancelScheduledTask'
9
+
10
+ export const handleDeleteTask = async ({
11
+ taskHandler,
12
+ toolCall,
13
+ assistant,
14
+ thread,
15
+ }: {
16
+ taskHandler: DeleteTaskHandler
17
+ toolCall: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall
18
+ assistant: Assistant
19
+ thread: Thread
20
+ }) => {
21
+ const parsedArgs = parseTaskToolArgs({ toolCall, assistant, thread })
22
+ if (!parsedArgs.ok)
23
+ return { tool_call_id: toolCall.id, output: parsedArgs.error }
24
+
25
+ const check = deleteTaskSchema.safeParse(parsedArgs.args)
26
+ if (!check.success)
27
+ return { tool_call_id: toolCall.id, output: check.error.toString() }
28
+ const args = check.data
29
+
30
+ const { ok, key, error } = await getTaskToolKey({
31
+ thread,
32
+ assistant,
33
+ keyTemplate: taskHandler.keyTemplate,
34
+ })
35
+
36
+ if (!ok) return { tool_call_id: toolCall.id, output: error }
37
+
38
+ const existing = await prisma.task.findFirst({
39
+ where: {
40
+ id: args.taskId,
41
+ key,
42
+ thread: {
43
+ assistant: {
44
+ workspaceId: assistant.workspaceId,
45
+ },
46
+ },
47
+ },
48
+ })
49
+
50
+ if (!existing) {
51
+ return { tool_call_id: toolCall.id, output: 'Task not found.' }
52
+ }
53
+
54
+ await cancelScheduledTask({ task: existing })
55
+
56
+ const task = await prisma.task.delete({ where: { id: args.taskId } })
57
+
58
+ return {
59
+ tool_call_id: toolCall.id,
60
+ output: JSON.stringify({ task: serializeTask({ task }) }),
61
+ }
62
+ }
@@ -0,0 +1,53 @@
1
+ import OpenAI from 'openai'
2
+ import { ListTasksHandler, Assistant, Thread } from '@prisma/client'
3
+ import { prisma } from '@/lib/prisma'
4
+ import { serializeTask } from '@/lib/tasks/serializeTask'
5
+ import { listTasksSchema } from '@/lib/tasks/schemas'
6
+ import { parseTaskToolArgs } from '@/lib/tasks/parseTaskToolArgs'
7
+ import { getTaskToolKey } from '@/lib/tasks/getTaskToolKey'
8
+
9
+ export const handleListTasks = async ({
10
+ taskHandler,
11
+ toolCall,
12
+ assistant,
13
+ thread,
14
+ }: {
15
+ taskHandler: ListTasksHandler
16
+ toolCall: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall
17
+ assistant: Assistant
18
+ thread: Thread
19
+ }) => {
20
+ const parsedArgs = parseTaskToolArgs({ toolCall, assistant, thread })
21
+ if (!parsedArgs.ok)
22
+ return { tool_call_id: toolCall.id, output: parsedArgs.error }
23
+
24
+ const check = listTasksSchema.safeParse(parsedArgs.args)
25
+ if (!check.success)
26
+ return { tool_call_id: toolCall.id, output: check.error.toString() }
27
+
28
+ const { ok, key, error } = await getTaskToolKey({
29
+ thread,
30
+ assistant,
31
+ keyTemplate: taskHandler.keyTemplate,
32
+ })
33
+ if (!ok) return { tool_call_id: toolCall.id, output: error }
34
+
35
+ const tasks = await prisma.task.findMany({
36
+ where: {
37
+ key,
38
+ thread: {
39
+ assistant: {
40
+ workspaceId: assistant.workspaceId,
41
+ },
42
+ },
43
+ },
44
+ orderBy: { createdAt: 'desc' },
45
+ })
46
+
47
+ return {
48
+ tool_call_id: toolCall.id,
49
+ output: JSON.stringify({
50
+ tasks: tasks.map((t) => serializeTask({ task: t })),
51
+ }),
52
+ }
53
+ }
@@ -0,0 +1,70 @@
1
+ import OpenAI from 'openai'
2
+ import { UpdateTaskHandler, Assistant, Thread } from '@prisma/client'
3
+ import { prisma } from '@/lib/prisma'
4
+ import { serializeTask } from '@/lib/tasks/serializeTask'
5
+ import { validateSchedule } from '@/lib/tasks/validateSchedule'
6
+ import { updateTaskSchema } from '@/lib/tasks/schemas'
7
+ import { parseTaskToolArgs } from '@/lib/tasks/parseTaskToolArgs'
8
+ import { getTaskToolKey } from '@/lib/tasks/getTaskToolKey'
9
+ import { scheduleTask } from '@/lib/tasks/scheduleTask'
10
+
11
+ export const handleUpdateTask = async ({
12
+ taskHandler,
13
+ toolCall,
14
+ assistant,
15
+ thread,
16
+ }: {
17
+ taskHandler: UpdateTaskHandler
18
+ toolCall: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall
19
+ assistant: Assistant
20
+ thread: Thread
21
+ }) => {
22
+ const parsedArgs = parseTaskToolArgs({ toolCall, assistant, thread })
23
+ if (!parsedArgs.ok)
24
+ return { tool_call_id: toolCall.id, output: parsedArgs.error }
25
+
26
+ const check = updateTaskSchema.safeParse(parsedArgs.args)
27
+ if (!check.success)
28
+ return { tool_call_id: toolCall.id, output: check.error.toString() }
29
+ const args = check.data
30
+
31
+ const { ok, key, error } = await getTaskToolKey({
32
+ thread,
33
+ assistant,
34
+ keyTemplate: taskHandler.keyTemplate,
35
+ })
36
+
37
+ if (!ok) return { tool_call_id: toolCall.id, output: error }
38
+
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ const updateData: any = {}
41
+ if (args.title !== undefined) updateData.title = args.title
42
+ if (args.message !== undefined) updateData.message = args.message
43
+ if (args.schedule !== undefined) {
44
+ if (!validateSchedule(args.schedule)) {
45
+ return { tool_call_id: toolCall.id, output: 'Invalid schedule.' }
46
+ }
47
+ updateData.schedule = args.schedule
48
+ }
49
+ if (args.key !== undefined) updateData.key = args.key ?? ''
50
+
51
+ const task = await prisma.task.update({
52
+ where: {
53
+ id: args.taskId,
54
+ key,
55
+ thread: {
56
+ assistant: {
57
+ workspaceId: assistant.workspaceId,
58
+ },
59
+ },
60
+ },
61
+ data: updateData,
62
+ })
63
+
64
+ await scheduleTask({ task })
65
+
66
+ return {
67
+ tool_call_id: toolCall.id,
68
+ output: JSON.stringify({ task: serializeTask({ task }) }),
69
+ }
70
+ }