@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,212 @@
1
+ import OpenAI from 'openai'
2
+ import {
3
+ FirecrawlHandler,
4
+ FirecrawlHandlerType,
5
+ Assistant,
6
+ Thread,
7
+ LogRequestMethod,
8
+ LogRequestRoute,
9
+ LogLevel,
10
+ } from '@prisma/client'
11
+ import FirecrawlApp from '@mendable/firecrawl-js'
12
+ import { omit } from 'radash'
13
+ import { createLog } from '@/lib/logs/createLog'
14
+
15
+ export const handleFirecrawl = async ({
16
+ firecrawlHandler,
17
+ toolCall,
18
+ assistant,
19
+ thread,
20
+ }: {
21
+ firecrawlHandler: FirecrawlHandler
22
+ toolCall: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall
23
+ assistant: Assistant
24
+ thread: Thread
25
+ }) => {
26
+ let args
27
+
28
+ try {
29
+ args = JSON.parse(toolCall.function.arguments)
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ } catch (e: any) {
32
+ createLog({
33
+ log: {
34
+ requestMethod: LogRequestMethod.POST,
35
+ requestRoute: LogRequestRoute.MESSAGES,
36
+ level: LogLevel.ERROR,
37
+ status: 400,
38
+ message: `Failed parsing Firecrawl function arguments: ${e.message}`,
39
+ workspaceId: assistant.workspaceId,
40
+ assistantId: assistant.id,
41
+ threadId: thread.id,
42
+ },
43
+ })
44
+
45
+ return {
46
+ tool_call_id: toolCall.id,
47
+ output: 'Invalid arguments.',
48
+ }
49
+ }
50
+
51
+ const firecrawl = new FirecrawlApp({ apiKey: firecrawlHandler.apiKey })
52
+
53
+ if (firecrawlHandler.type === FirecrawlHandlerType.SCRAPE) {
54
+ try {
55
+ const result = await firecrawl.scrapeUrl(args.url, {
56
+ ...firecrawlHandler.body,
57
+ ...omit(args, ['url']),
58
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
+ formats: (firecrawlHandler.body.formats as any) ?? [
60
+ 'markdown' as const,
61
+ ],
62
+ })
63
+
64
+ return {
65
+ tool_call_id: toolCall.id,
66
+ output: JSON.stringify(result),
67
+ }
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ } catch (e: any) {
70
+ createLog({
71
+ log: {
72
+ requestMethod: LogRequestMethod.POST,
73
+ requestRoute: LogRequestRoute.MESSAGES,
74
+ level: LogLevel.ERROR,
75
+ status: 400,
76
+ message: `Failed calling Firecrawl function: ${e.message}`,
77
+ workspaceId: assistant.workspaceId,
78
+ assistantId: assistant.id,
79
+ threadId: thread.id,
80
+ },
81
+ })
82
+
83
+ return {
84
+ tool_call_id: toolCall.id,
85
+ output: 'Function call failed.',
86
+ }
87
+ }
88
+ } else if (firecrawlHandler.type === FirecrawlHandlerType.CRAWL) {
89
+ try {
90
+ const result = await firecrawl.crawlUrl(args.url, {
91
+ ...firecrawlHandler.body,
92
+ ...omit(args, ['url']),
93
+ })
94
+
95
+ return {
96
+ tool_call_id: toolCall.id,
97
+ output: JSON.stringify(result),
98
+ }
99
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
+ } catch (e: any) {
101
+ createLog({
102
+ log: {
103
+ requestMethod: LogRequestMethod.POST,
104
+ requestRoute: LogRequestRoute.MESSAGES,
105
+ level: LogLevel.ERROR,
106
+ status: 400,
107
+ message: `Failed calling Firecrawl function: ${e.message}`,
108
+ workspaceId: assistant.workspaceId,
109
+ assistantId: assistant.id,
110
+ threadId: thread.id,
111
+ },
112
+ })
113
+
114
+ return {
115
+ tool_call_id: toolCall.id,
116
+ output: 'Function call failed.',
117
+ }
118
+ }
119
+ } else if (firecrawlHandler.type === FirecrawlHandlerType.EXTRACT) {
120
+ try {
121
+ const result = await firecrawl.scrapeUrl(args.url, {
122
+ formats: ['extract'],
123
+ ...omit(args, ['url']),
124
+ })
125
+
126
+ return {
127
+ tool_call_id: toolCall.id,
128
+ output: JSON.stringify(result),
129
+ }
130
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
131
+ } catch (e: any) {
132
+ createLog({
133
+ log: {
134
+ requestMethod: LogRequestMethod.POST,
135
+ requestRoute: LogRequestRoute.MESSAGES,
136
+ level: LogLevel.ERROR,
137
+ status: 400,
138
+ message: `Failed calling Firecrawl function: ${e.message}`,
139
+ workspaceId: assistant.workspaceId,
140
+ assistantId: assistant.id,
141
+ threadId: thread.id,
142
+ },
143
+ })
144
+
145
+ return {
146
+ tool_call_id: toolCall.id,
147
+ output: 'Function call failed.',
148
+ }
149
+ }
150
+ } else if (firecrawlHandler.type === FirecrawlHandlerType.SEARCH) {
151
+ try {
152
+ const response = await fetch('https://api.firecrawl.dev/v0/search', {
153
+ method: 'POST',
154
+ headers: {
155
+ Authorization: `Bearer ${firecrawlHandler.apiKey}`,
156
+ 'Content-Type': 'application/json',
157
+ },
158
+ body: JSON.stringify({
159
+ ...firecrawlHandler.body,
160
+ ...args,
161
+ }),
162
+ })
163
+
164
+ const result = await response.json()
165
+
166
+ return {
167
+ tool_call_id: toolCall.id,
168
+ output: JSON.stringify(result),
169
+ }
170
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
171
+ } catch (e: any) {
172
+ createLog({
173
+ log: {
174
+ requestMethod: LogRequestMethod.POST,
175
+ requestRoute: LogRequestRoute.MESSAGES,
176
+ level: LogLevel.ERROR,
177
+ status: 400,
178
+ message: `Failed calling Firecrawl function: ${e.message}`,
179
+ workspaceId: assistant.workspaceId,
180
+ assistantId: assistant.id,
181
+ threadId: thread.id,
182
+ },
183
+ })
184
+
185
+ return {
186
+ tool_call_id: toolCall.id,
187
+ output: 'Function call failed.',
188
+ }
189
+ }
190
+ } else {
191
+ createLog({
192
+ log: {
193
+ requestMethod: LogRequestMethod.POST,
194
+ requestRoute: LogRequestRoute.MESSAGES,
195
+ level: LogLevel.ERROR,
196
+ status: 400,
197
+ message: `Invalid Firecrawl handler type: ${firecrawlHandler.type}`,
198
+ workspaceId: assistant.workspaceId,
199
+ assistantId: assistant.id,
200
+ threadId: thread.id,
201
+ },
202
+ })
203
+
204
+ return {
205
+ tool_call_id: toolCall.id,
206
+ output: JSON.stringify({
207
+ success: false,
208
+ message: 'Invalid Firecrawl handler type',
209
+ }),
210
+ }
211
+ }
212
+ }
@@ -0,0 +1,109 @@
1
+ import OpenAI from 'openai'
2
+ import {
3
+ ReplicateHandler,
4
+ ReplicateHandlerType,
5
+ Assistant,
6
+ Thread,
7
+ LogRequestMethod,
8
+ LogRequestRoute,
9
+ LogLevel,
10
+ } from '@prisma/client'
11
+ import Replicate from 'replicate'
12
+ import { createLog } from '@/lib/logs/createLog'
13
+ import { merge } from '@/lib/misc/merge'
14
+
15
+ export const handleReplicate = async ({
16
+ replicateHandler,
17
+ toolCall,
18
+ assistant,
19
+ thread,
20
+ }: {
21
+ replicateHandler: ReplicateHandler
22
+ toolCall: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall
23
+ assistant: Assistant
24
+ thread: Thread
25
+ }) => {
26
+ let args
27
+
28
+ try {
29
+ args = JSON.parse(toolCall.function.arguments)
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ } catch (e: any) {
32
+ createLog({
33
+ log: {
34
+ requestMethod: LogRequestMethod.POST,
35
+ requestRoute: LogRequestRoute.MESSAGES,
36
+ level: LogLevel.ERROR,
37
+ status: 400,
38
+ message: `Failed parsing Replicate function arguments: ${e.message}`,
39
+ workspaceId: assistant.workspaceId,
40
+ assistantId: assistant.id,
41
+ threadId: thread.id,
42
+ },
43
+ })
44
+
45
+ return {
46
+ tool_call_id: toolCall.id,
47
+ output: 'Invalid arguments.',
48
+ }
49
+ }
50
+
51
+ const replicate = new Replicate({
52
+ auth: replicateHandler.apiKey,
53
+ useFileOutput: false,
54
+ })
55
+
56
+ if (replicateHandler.type === ReplicateHandlerType.RUN) {
57
+ try {
58
+ const result = await replicate.run(
59
+ replicateHandler.identifier as '`${string}/${string}',
60
+ merge(replicateHandler.body, args),
61
+ )
62
+
63
+ return {
64
+ tool_call_id: toolCall.id,
65
+ output: JSON.stringify(result),
66
+ }
67
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
68
+ } catch (e: any) {
69
+ createLog({
70
+ log: {
71
+ requestMethod: LogRequestMethod.POST,
72
+ requestRoute: LogRequestRoute.MESSAGES,
73
+ level: LogLevel.ERROR,
74
+ status: 400,
75
+ message: `Failed calling Replicate RUN function: ${e.message}`,
76
+ workspaceId: assistant.workspaceId,
77
+ assistantId: assistant.id,
78
+ threadId: thread.id,
79
+ },
80
+ })
81
+
82
+ return {
83
+ tool_call_id: toolCall.id,
84
+ output: 'Function call failed.',
85
+ }
86
+ }
87
+ } else {
88
+ createLog({
89
+ log: {
90
+ requestMethod: LogRequestMethod.POST,
91
+ requestRoute: LogRequestRoute.MESSAGES,
92
+ level: LogLevel.ERROR,
93
+ status: 400,
94
+ message: `Invalid Replicate handler type: ${replicateHandler.type}`,
95
+ workspaceId: assistant.workspaceId,
96
+ assistantId: assistant.id,
97
+ threadId: thread.id,
98
+ },
99
+ })
100
+
101
+ return {
102
+ tool_call_id: toolCall.id,
103
+ output: JSON.stringify({
104
+ success: false,
105
+ message: 'Invalid Replicate handler type',
106
+ }),
107
+ }
108
+ }
109
+ }
@@ -0,0 +1,272 @@
1
+ import OpenAI from 'openai'
2
+ import {
3
+ RequestHandler,
4
+ Assistant,
5
+ Thread,
6
+ LogRequestMethod,
7
+ LogRequestRoute,
8
+ LogLevel,
9
+ } from '@prisma/client'
10
+ import { createLog } from '@/lib/logs/createLog'
11
+ import { interpolateFunctionValue } from '../interpolateFunctionValue'
12
+
13
+ const url = ({
14
+ requestHandler,
15
+ args,
16
+ thread,
17
+ assistant,
18
+ }: {
19
+ requestHandler: RequestHandler
20
+ args: Record<string, unknown>
21
+ thread: Thread
22
+ assistant: Assistant
23
+ }) => {
24
+ const { value, missing } = interpolateFunctionValue({
25
+ value: requestHandler.url,
26
+ args,
27
+ thread,
28
+ assistant,
29
+ })
30
+
31
+ if (requestHandler.method === 'GET') {
32
+ if (!Object.keys(args).length) return { url: value, missing }
33
+ const params = new URLSearchParams(
34
+ Object.entries(args).reduce<Record<string, string>>(
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ (acc, [k, v]) => ({ ...acc, [k]: String(v as any) }),
37
+ {},
38
+ ),
39
+ )
40
+ return { url: `${value}?${params.toString()}`, missing }
41
+ }
42
+
43
+ return { url: value, missing }
44
+ }
45
+
46
+ const body = ({
47
+ requestHandler,
48
+ args,
49
+ thread,
50
+ assistant,
51
+ }: {
52
+ requestHandler: RequestHandler
53
+ args: Record<string, unknown>
54
+ thread: Thread
55
+ assistant: Assistant
56
+ }) => {
57
+ if (requestHandler.method === 'GET') {
58
+ return { body: undefined, missing: [] as string[] }
59
+ }
60
+
61
+ const merged = { ...requestHandler.body, ...args }
62
+
63
+ const missing: string[] = []
64
+
65
+ for (const [k, v] of Object.entries(requestHandler.body)) {
66
+ if (k in (args || {})) continue
67
+ if (typeof v === 'string') {
68
+ const res = interpolateFunctionValue({
69
+ value: v,
70
+ args,
71
+ thread,
72
+ assistant,
73
+ })
74
+ merged[k] = res.value
75
+ missing.push(...res.missing)
76
+ }
77
+ }
78
+
79
+ return { body: merged, missing }
80
+ }
81
+
82
+ const headers = ({
83
+ requestHandler,
84
+ args,
85
+ thread,
86
+ assistant,
87
+ }: {
88
+ requestHandler: RequestHandler
89
+ args: Record<string, unknown>
90
+ thread: Thread
91
+ assistant: Assistant
92
+ }) => {
93
+ const result: Record<string, string> = {}
94
+ const missing: string[] = []
95
+
96
+ for (const [k, v] of Object.entries(requestHandler.headers)) {
97
+ const res = interpolateFunctionValue({ value: v, args, thread, assistant })
98
+ result[k] = res.value
99
+ missing.push(...res.missing)
100
+ }
101
+
102
+ return { headers: result, missing }
103
+ }
104
+
105
+ export const handleRequest = async ({
106
+ requestHandler,
107
+ toolCall,
108
+ assistant,
109
+ thread,
110
+ }: {
111
+ requestHandler: RequestHandler
112
+ toolCall: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall
113
+ assistant: Assistant
114
+ thread: Thread
115
+ }) => {
116
+ let args: Record<string, unknown> = {}
117
+
118
+ try {
119
+ args = JSON.parse(toolCall.function.arguments) as Record<string, unknown>
120
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
121
+ } catch (e: any) {
122
+ createLog({
123
+ log: {
124
+ requestMethod: LogRequestMethod.POST,
125
+ requestRoute: LogRequestRoute.MESSAGES,
126
+ level: LogLevel.ERROR,
127
+ status: 500,
128
+ message: `Failed parsing request function arguments: ${e.message}`,
129
+ workspaceId: assistant.workspaceId,
130
+ assistantId: assistant.id,
131
+ threadId: thread.id,
132
+ },
133
+ })
134
+
135
+ return {
136
+ tool_call_id: toolCall.id,
137
+ output: JSON.stringify({
138
+ error: e.message,
139
+ }),
140
+ }
141
+ }
142
+
143
+ const urlRes = url({ requestHandler, args, thread, assistant })
144
+ const bodyRes = body({ requestHandler, args, thread, assistant })
145
+ const headersRes = headers({ requestHandler, args, thread, assistant })
146
+
147
+ const missing = [...urlRes.missing, ...bodyRes.missing, ...headersRes.missing]
148
+
149
+ if (missing.length) {
150
+ const message = `Missing variables in request handler: ${missing.join(', ')}`
151
+
152
+ createLog({
153
+ log: {
154
+ requestMethod: LogRequestMethod.POST,
155
+ requestRoute: LogRequestRoute.MESSAGES,
156
+ level: LogLevel.ERROR,
157
+ status: 400,
158
+ message,
159
+ workspaceId: assistant.workspaceId,
160
+ assistantId: assistant.id,
161
+ threadId: thread.id,
162
+ },
163
+ })
164
+
165
+ return { tool_call_id: toolCall.id, output: message }
166
+ }
167
+
168
+ const opts = {
169
+ method: requestHandler.method,
170
+ headers: {
171
+ Accept: 'application/json',
172
+ 'Content-Type': 'application/json',
173
+ ...headersRes.headers,
174
+ },
175
+ body: bodyRes.body ? JSON.stringify(bodyRes.body) : undefined,
176
+ }
177
+
178
+ let response
179
+
180
+ try {
181
+ response = await fetch(urlRes.url, opts)
182
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
183
+ } catch (e: any) {
184
+ createLog({
185
+ log: {
186
+ requestMethod: LogRequestMethod.POST,
187
+ requestRoute: LogRequestRoute.MESSAGES,
188
+ level: LogLevel.ERROR,
189
+ status: 500,
190
+ message: `Request failed: ${e.message}`,
191
+ workspaceId: assistant.workspaceId,
192
+ assistantId: assistant.id,
193
+ threadId: thread.id,
194
+ },
195
+ })
196
+
197
+ return {
198
+ tool_call_id: toolCall.id,
199
+ output: JSON.stringify({
200
+ error: e.message,
201
+ }),
202
+ }
203
+ }
204
+
205
+ const contentType = response.headers.get('content-type')
206
+
207
+ if (contentType && contentType.includes('application/json')) {
208
+ let jsonResult
209
+
210
+ try {
211
+ jsonResult = await response.json()
212
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
213
+ } catch (e: any) {
214
+ createLog({
215
+ log: {
216
+ requestMethod: LogRequestMethod.POST,
217
+ requestRoute: LogRequestRoute.MESSAGES,
218
+ level: LogLevel.ERROR,
219
+ status: 500,
220
+ message: `Failed parsing request response: ${e.message}`,
221
+ workspaceId: assistant.workspaceId,
222
+ assistantId: assistant.id,
223
+ threadId: thread.id,
224
+ },
225
+ })
226
+
227
+ return {
228
+ tool_call_id: toolCall.id,
229
+ output: JSON.stringify({
230
+ error: e.message,
231
+ }),
232
+ }
233
+ }
234
+
235
+ return {
236
+ tool_call_id: toolCall.id,
237
+ output: JSON.stringify(jsonResult),
238
+ }
239
+ } else {
240
+ let textResult
241
+
242
+ try {
243
+ textResult = await response.text()
244
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
245
+ } catch (e: any) {
246
+ createLog({
247
+ log: {
248
+ requestMethod: LogRequestMethod.POST,
249
+ requestRoute: LogRequestRoute.MESSAGES,
250
+ level: LogLevel.ERROR,
251
+ status: 500,
252
+ message: `Failed parsing request response: ${e.message}`,
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: JSON.stringify({
262
+ error: e.message,
263
+ }),
264
+ }
265
+ }
266
+
267
+ return {
268
+ tool_call_id: toolCall.id,
269
+ output: textResult,
270
+ }
271
+ }
272
+ }