@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,710 @@
1
+ import { type NextRequest, NextResponse } from 'next/server'
2
+ import OpenAI from 'openai'
3
+ import { LogRequestMethod, LogRequestRoute, LogLevel } from '@prisma/client'
4
+ import type { Thread } from '@prisma/client'
5
+ import {
6
+ messagesResponse,
7
+ createMessageResponse,
8
+ } from '@superinterface/react/server'
9
+ import { enqueueJson } from '@superinterface/react/utils'
10
+ import { cacheHeaders } from '@/lib/cache/cacheHeaders'
11
+ import { z } from 'zod'
12
+ import { storageThreadId as getStorageThreadId } from '@/lib/threads/storageThreadId'
13
+ import { assistantClientAdapter } from '@/lib/assistants/assistantClientAdapter'
14
+ import { content as getContent } from '@/lib/messages/content'
15
+ import { workspaceAccessWhere as getWorkspaceAccessWhere } from '@/lib/apiKeys/workspaceAccessWhere'
16
+ import { initialMessagesResponse } from './lib/initialMessagesResponse'
17
+ import { createRunOpts } from '@/lib/runs/createRunOpts'
18
+ import { handleToolCall } from '@/lib/toolCalls/handleToolCall'
19
+ import { createThread } from '@/lib/threads/createThread'
20
+ import { managedOpenaiThreadId } from '@/lib/threads/managedOpenaiThreadId'
21
+ import { prisma } from '@/lib/prisma'
22
+ import { createLog } from '@/lib/logs/createLog'
23
+ import { serializeThread } from './lib/serializeThread'
24
+ import { getWorkspaceId } from './lib/getWorkspaceId'
25
+ import { validThreadId } from '@/lib/threads/validThreadId'
26
+ import { isOpenaiAssistantsStorageProvider } from '@/lib/storageProviders/isOpenaiAssistantsStorageProvider'
27
+ import { serializeMetadata } from '@/lib/metadata/serializeMetadata'
28
+ import { isResponsesStorageProvider } from '@/lib/storageProviders/isResponsesStorageProvider'
29
+ import { serializeError } from '@/lib/errors/serializeError'
30
+
31
+ export const maxDuration = 800
32
+
33
+ export const GET = async (request: NextRequest) => {
34
+ const paramsResult = z
35
+ .object({
36
+ publicApiKey: z.string().optional(),
37
+ assistantId: z.string().optional(),
38
+ threadId: z.string().optional(),
39
+ pageParam: z.string().optional(),
40
+ })
41
+ .parse(Object.fromEntries(request.nextUrl.searchParams.entries()))
42
+
43
+ const workspaceAccessWhere = await getWorkspaceAccessWhere({
44
+ publicApiKey: paramsResult.publicApiKey ?? null,
45
+ })
46
+
47
+ if (!workspaceAccessWhere) {
48
+ return NextResponse.json({ error: 'Invalid api key' }, { status: 400 })
49
+ }
50
+
51
+ const assistantId = paramsResult.assistantId
52
+
53
+ if (!assistantId) {
54
+ createLog({
55
+ log: {
56
+ requestMethod: LogRequestMethod.POST,
57
+ requestRoute: LogRequestRoute.MESSAGES,
58
+ level: LogLevel.ERROR,
59
+ status: 400,
60
+ message: 'No assistantId found.',
61
+ workspaceId: await getWorkspaceId({ workspaceAccessWhere, prisma }),
62
+ },
63
+ })
64
+
65
+ return NextResponse.json(
66
+ { error: 'No assistant id found' },
67
+ { status: 400 },
68
+ )
69
+ }
70
+
71
+ const { threadId, pageParam } = paramsResult
72
+
73
+ const assistant = await prisma.assistant.findFirst({
74
+ where: {
75
+ id: assistantId,
76
+ workspace: workspaceAccessWhere,
77
+ },
78
+ include: {
79
+ threads: {
80
+ where: {
81
+ id: validThreadId({ threadId: threadId ?? null }),
82
+ },
83
+ take: 1,
84
+ include: {
85
+ assistant: {
86
+ select: {
87
+ storageProviderType: true,
88
+ },
89
+ },
90
+ },
91
+ },
92
+ workspace: {
93
+ include: {
94
+ modelProviders: true,
95
+ },
96
+ },
97
+ modelProvider: true,
98
+ initialMessages: {
99
+ orderBy: {
100
+ orderNumber: 'desc',
101
+ },
102
+ },
103
+ mcpServers: {
104
+ include: {
105
+ computerUseTool: true,
106
+ stdioTransport: true,
107
+ sseTransport: true,
108
+ httpTransport: true,
109
+ },
110
+ },
111
+ tools: {
112
+ include: {
113
+ fileSearchTool: true,
114
+ webSearchTool: true,
115
+ imageGenerationTool: true,
116
+ codeInterpreterTool: true,
117
+ computerUseTool: true,
118
+ },
119
+ },
120
+ functions: true,
121
+ },
122
+ })
123
+
124
+ if (!assistant) {
125
+ createLog({
126
+ log: {
127
+ requestMethod: LogRequestMethod.POST,
128
+ requestRoute: LogRequestRoute.MESSAGES,
129
+ level: LogLevel.ERROR,
130
+ status: 400,
131
+ message: 'No assistant found.',
132
+ workspaceId: await getWorkspaceId({ workspaceAccessWhere, prisma }),
133
+ },
134
+ })
135
+
136
+ return NextResponse.json({ error: 'No assistant found' }, { status: 400 })
137
+ }
138
+
139
+ if (!threadId) {
140
+ return NextResponse.json(await initialMessagesResponse({ assistant }), {
141
+ headers: cacheHeaders,
142
+ })
143
+ }
144
+
145
+ const thread = assistant.threads[0]
146
+
147
+ if (!thread) {
148
+ return NextResponse.json(await initialMessagesResponse({ assistant }), {
149
+ headers: cacheHeaders,
150
+ })
151
+ }
152
+
153
+ const client = assistantClientAdapter({ assistant, prisma, thread })
154
+
155
+ const storageThreadId = getStorageThreadId({
156
+ thread,
157
+ })
158
+
159
+ if (!storageThreadId) {
160
+ return NextResponse.json(await initialMessagesResponse({ assistant }), {
161
+ headers: cacheHeaders,
162
+ })
163
+ }
164
+
165
+ try {
166
+ return NextResponse.json(
167
+ await messagesResponse({
168
+ threadId: storageThreadId,
169
+ client,
170
+ ...(pageParam ? { pageParam } : {}),
171
+ }),
172
+ {
173
+ headers: cacheHeaders,
174
+ },
175
+ )
176
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
177
+ } catch (error: any) {
178
+ console.dir({ error }, { depth: null })
179
+ createLog({
180
+ log: {
181
+ requestMethod: LogRequestMethod.GET,
182
+ requestRoute: LogRequestRoute.MESSAGES,
183
+ level: LogLevel.ERROR,
184
+ status: 500,
185
+ message: `Failed to load messages: ${error.message}`,
186
+ workspaceId: assistant.workspaceId,
187
+ assistantId: assistant.id,
188
+ threadId: thread.id,
189
+ },
190
+ })
191
+ return NextResponse.json(
192
+ { error: 'Failed to load messages.' },
193
+ { status: 500 },
194
+ )
195
+ }
196
+ }
197
+
198
+ export const buildPOST =
199
+ ({
200
+ onSuccessCreateThread = () => void 0,
201
+ }: {
202
+ onSuccessCreateThread?: ({
203
+ thread,
204
+ }: {
205
+ thread: Thread
206
+ }) => void | Promise<void>
207
+ }) =>
208
+ async (request: NextRequest) => {
209
+ const bodyResult = z
210
+ .object({
211
+ audioContent: z.any().optional(),
212
+ content: z.any().optional(),
213
+ attachments: z.array(z.any()).optional(),
214
+ assistantId: z.string().optional(),
215
+ publicApiKey: z.string().optional(),
216
+ threadId: z.string().optional(),
217
+ })
218
+ .passthrough()
219
+ .parse(await request.json())
220
+
221
+ const {
222
+ audioContent,
223
+ content: textContent,
224
+ attachments,
225
+ assistantId,
226
+ publicApiKey,
227
+ ...variables
228
+ } = bodyResult
229
+
230
+ const workspaceAccessWhere = await getWorkspaceAccessWhere({
231
+ publicApiKey: publicApiKey ?? null,
232
+ })
233
+
234
+ if (!workspaceAccessWhere) {
235
+ return NextResponse.json({ error: 'Invalid api key' }, { status: 400 })
236
+ }
237
+
238
+ if (!assistantId) {
239
+ createLog({
240
+ log: {
241
+ requestMethod: LogRequestMethod.POST,
242
+ requestRoute: LogRequestRoute.MESSAGES,
243
+ level: LogLevel.ERROR,
244
+ status: 400,
245
+ message: 'No assistantId found.',
246
+ workspaceId: await getWorkspaceId({ workspaceAccessWhere, prisma }),
247
+ },
248
+ })
249
+
250
+ return NextResponse.json(
251
+ { error: 'No assistantId found.' },
252
+ { status: 400 },
253
+ )
254
+ }
255
+
256
+ if (!textContent && !audioContent && !attachments?.length) {
257
+ createLog({
258
+ log: {
259
+ requestMethod: LogRequestMethod.POST,
260
+ requestRoute: LogRequestRoute.MESSAGES,
261
+ level: LogLevel.ERROR,
262
+ status: 400,
263
+ message: 'No content found.',
264
+ workspaceId: await getWorkspaceId({ workspaceAccessWhere, prisma }),
265
+ },
266
+ })
267
+
268
+ return NextResponse.json({ error: 'No content found.' }, { status: 400 })
269
+ }
270
+
271
+ const assistant = await prisma.assistant.findFirst({
272
+ where: {
273
+ id: assistantId,
274
+ workspace: workspaceAccessWhere,
275
+ },
276
+ include: {
277
+ threads: {
278
+ where: {
279
+ id: validThreadId({ threadId: bodyResult.threadId ?? null }),
280
+ },
281
+ include: {
282
+ assistant: {
283
+ select: {
284
+ storageProviderType: true,
285
+ },
286
+ },
287
+ },
288
+ take: 1,
289
+ },
290
+ workspace: {
291
+ include: {
292
+ modelProviders: true,
293
+ },
294
+ },
295
+ mcpServers: {
296
+ include: {
297
+ computerUseTool: true,
298
+ stdioTransport: true,
299
+ sseTransport: true,
300
+ httpTransport: true,
301
+ },
302
+ },
303
+ tools: {
304
+ include: {
305
+ fileSearchTool: true,
306
+ webSearchTool: true,
307
+ imageGenerationTool: true,
308
+ codeInterpreterTool: true,
309
+ computerUseTool: {
310
+ include: {
311
+ mcpServer: {
312
+ include: {
313
+ stdioTransport: true,
314
+ sseTransport: true,
315
+ httpTransport: true,
316
+ },
317
+ },
318
+ },
319
+ },
320
+ },
321
+ },
322
+ functions: {
323
+ include: {
324
+ handler: {
325
+ include: {
326
+ requestHandler: true,
327
+ firecrawlHandler: true,
328
+ replicateHandler: true,
329
+ clientToolHandler: true,
330
+ assistantHandler: true,
331
+ createTaskHandler: true,
332
+ listTasksHandler: true,
333
+ updateTaskHandler: true,
334
+ deleteTaskHandler: true,
335
+ },
336
+ },
337
+ },
338
+ },
339
+ modelProvider: true,
340
+ initialMessages: {
341
+ orderBy: {
342
+ orderNumber: 'asc',
343
+ },
344
+ },
345
+ },
346
+ })
347
+
348
+ if (!assistant) {
349
+ createLog({
350
+ log: {
351
+ requestMethod: LogRequestMethod.POST,
352
+ requestRoute: LogRequestRoute.MESSAGES,
353
+ level: LogLevel.ERROR,
354
+ status: 400,
355
+ message: 'No assistant found.',
356
+ workspaceId: await getWorkspaceId({ workspaceAccessWhere, prisma }),
357
+ },
358
+ })
359
+
360
+ return NextResponse.json(
361
+ { error: 'No assistant found.' },
362
+ { status: 400 },
363
+ )
364
+ }
365
+
366
+ if (
367
+ isOpenaiAssistantsStorageProvider({
368
+ storageProviderType: assistant.storageProviderType,
369
+ }) &&
370
+ !assistant.openaiAssistantId
371
+ ) {
372
+ createLog({
373
+ log: {
374
+ requestMethod: LogRequestMethod.POST,
375
+ requestRoute: LogRequestRoute.MESSAGES,
376
+ level: LogLevel.ERROR,
377
+ status: 400,
378
+ message: 'Assistant setup is not done.',
379
+ workspaceId: assistant.workspaceId,
380
+ assistantId: assistant.id,
381
+ },
382
+ })
383
+
384
+ return NextResponse.json(
385
+ { error: 'Assistant setup is not done.' },
386
+ { status: 400 },
387
+ )
388
+ }
389
+
390
+ let thread = assistant.threads[0]
391
+ let isThreadCreated = false
392
+
393
+ if (!thread) {
394
+ const createThreadClient = assistantClientAdapter({ assistant, prisma })
395
+
396
+ try {
397
+ thread = await createThread({
398
+ client: createThreadClient,
399
+ assistant,
400
+ prisma,
401
+ variables: variables as Record<string, string>,
402
+ })
403
+
404
+ onSuccessCreateThread({ thread })
405
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
406
+ } catch (error: any) {
407
+ console.error(error)
408
+ createLog({
409
+ log: {
410
+ requestMethod: LogRequestMethod.POST,
411
+ requestRoute: LogRequestRoute.MESSAGES,
412
+ level: LogLevel.ERROR,
413
+ status: 500,
414
+ message: `Failed to create thread: ${error.message}`,
415
+ workspaceId: assistant.workspaceId,
416
+ assistantId: assistant.id,
417
+ },
418
+ })
419
+
420
+ return NextResponse.json(
421
+ { error: 'Failed to create thread.' },
422
+ { status: 500 },
423
+ )
424
+ }
425
+
426
+ isThreadCreated = true
427
+ }
428
+
429
+ let storageThreadId
430
+
431
+ try {
432
+ storageThreadId = getStorageThreadId({
433
+ thread,
434
+ })
435
+ } catch (error) {
436
+ console.error(error)
437
+ createLog({
438
+ log: {
439
+ requestMethod: LogRequestMethod.POST,
440
+ requestRoute: LogRequestRoute.MESSAGES,
441
+ level: LogLevel.ERROR,
442
+ status: 500,
443
+ message: 'Failed to get storage thread id.',
444
+ workspaceId: assistant.workspaceId,
445
+ assistantId: assistant.id,
446
+ threadId: thread.id,
447
+ },
448
+ })
449
+
450
+ return NextResponse.json(
451
+ { error: 'Failed to get storage thread id.' },
452
+ { status: 500 },
453
+ )
454
+ }
455
+
456
+ if (
457
+ !storageThreadId &&
458
+ (isOpenaiAssistantsStorageProvider({
459
+ storageProviderType: assistant.storageProviderType,
460
+ }) ||
461
+ isResponsesStorageProvider({
462
+ storageProviderType: assistant.storageProviderType,
463
+ }))
464
+ ) {
465
+ try {
466
+ storageThreadId = await managedOpenaiThreadId({
467
+ assistant,
468
+ threadId: thread.id,
469
+ })
470
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
471
+ } catch (error: any) {
472
+ createLog({
473
+ log: {
474
+ requestMethod: LogRequestMethod.POST,
475
+ requestRoute: LogRequestRoute.MESSAGES,
476
+ level: LogLevel.ERROR,
477
+ status: 500,
478
+ message: `Failed to get managed openai thread id: ${error.message}`,
479
+ workspaceId: assistant.workspaceId,
480
+ assistantId: assistant.id,
481
+ threadId: thread.id,
482
+ },
483
+ })
484
+
485
+ return NextResponse.json(
486
+ { error: 'Failed to get managed openai thread id.' },
487
+ { status: 500 },
488
+ )
489
+ }
490
+ }
491
+
492
+ if (!storageThreadId) {
493
+ createLog({
494
+ log: {
495
+ requestMethod: LogRequestMethod.POST,
496
+ requestRoute: LogRequestRoute.MESSAGES,
497
+ level: LogLevel.ERROR,
498
+ status: 500,
499
+ message: 'Invalid thread configuration.',
500
+ workspaceId: assistant.workspaceId,
501
+ assistantId: assistant.id,
502
+ threadId: thread.id,
503
+ },
504
+ })
505
+
506
+ return NextResponse.json(
507
+ { error: 'Invalid thread configuration.' },
508
+ { status: 500 },
509
+ )
510
+ }
511
+
512
+ let content
513
+
514
+ try {
515
+ content = await getContent({
516
+ audioContent,
517
+ textContent,
518
+ assistant,
519
+ })
520
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
521
+ } catch (error: any) {
522
+ console.error(error)
523
+ createLog({
524
+ log: {
525
+ requestMethod: LogRequestMethod.POST,
526
+ requestRoute: LogRequestRoute.MESSAGES,
527
+ level: LogLevel.ERROR,
528
+ status: 500,
529
+ message: `Failed to get content: ${error.message}`,
530
+ workspaceId: assistant.workspaceId,
531
+ assistantId: assistant.id,
532
+ threadId: thread.id,
533
+ },
534
+ })
535
+
536
+ return NextResponse.json(
537
+ { error: 'Failed to get content.' },
538
+ { status: 500 },
539
+ )
540
+ }
541
+
542
+ const client = assistantClientAdapter({
543
+ assistant,
544
+ prisma,
545
+ thread,
546
+ })
547
+
548
+ try {
549
+ await client.beta.threads.messages.create(storageThreadId, {
550
+ role: 'user',
551
+ content,
552
+ ...(attachments?.length ? { attachments } : {}),
553
+ metadata: serializeMetadata({
554
+ variables,
555
+ workspaceId: assistant.workspaceId,
556
+ }),
557
+ })
558
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
559
+ } catch (error: any) {
560
+ console.log({ error })
561
+ createLog({
562
+ log: {
563
+ requestMethod: LogRequestMethod.POST,
564
+ requestRoute: LogRequestRoute.MESSAGES,
565
+ level: LogLevel.ERROR,
566
+ status: 500,
567
+ message: `Failed to create message: ${error.message}`,
568
+ workspaceId: assistant.workspaceId,
569
+ assistantId: assistant.id,
570
+ threadId: thread.id,
571
+ },
572
+ })
573
+
574
+ return NextResponse.json(
575
+ { error: 'Failed to create message.' },
576
+ { status: 500 },
577
+ )
578
+ }
579
+
580
+ let createRunStream
581
+
582
+ try {
583
+ createRunStream = await client.beta.threads.runs.create(
584
+ storageThreadId,
585
+ await createRunOpts({ assistant, thread }),
586
+ )
587
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
588
+ } catch (error: any) {
589
+ console.error(error)
590
+ createLog({
591
+ log: {
592
+ requestMethod: LogRequestMethod.POST,
593
+ requestRoute: LogRequestRoute.MESSAGES,
594
+ level: LogLevel.ERROR,
595
+ status: 500,
596
+ message: `Failed to create run stream: ${serializeError({ error })}`,
597
+ workspaceId: assistant.workspaceId,
598
+ assistantId: assistant.id,
599
+ threadId: thread.id,
600
+ },
601
+ })
602
+
603
+ return NextResponse.json(
604
+ { error: 'Failed to create run stream.' },
605
+ { status: 500 },
606
+ )
607
+ }
608
+
609
+ let latestInProgressRunData: OpenAI.Beta.Threads.Runs.Run | null = null
610
+ let latestCompletedRunData: OpenAI.Beta.Threads.Runs.Run | null = null
611
+
612
+ return new Response(
613
+ createMessageResponse({
614
+ client,
615
+ createRunStream,
616
+ handleToolCall: handleToolCall({ assistant, thread }),
617
+ onStart: ({
618
+ controller,
619
+ }: {
620
+ controller: ReadableStreamDefaultController
621
+ }) => {
622
+ if (!isThreadCreated) return
623
+
624
+ return enqueueJson({
625
+ controller,
626
+ value: {
627
+ event: 'thread.created',
628
+ data: serializeThread({
629
+ thread,
630
+ }),
631
+ },
632
+ })
633
+ },
634
+ onError: async ({ error }) => {
635
+ if (request.signal.aborted) return
636
+
637
+ createLog({
638
+ log: {
639
+ requestMethod: LogRequestMethod.POST,
640
+ requestRoute: LogRequestRoute.MESSAGES,
641
+ level: LogLevel.ERROR,
642
+ status: 500,
643
+ message: `Thread Run failed: ${error.message}`,
644
+ workspaceId: assistant.workspaceId,
645
+ assistantId: assistant.id,
646
+ threadId: thread.id,
647
+ },
648
+ })
649
+
650
+ // if (latestInProgressRunData) {
651
+ // await client.beta.threads.runs.cancel(
652
+ // latestInProgressRunData.thread_id,
653
+ // latestInProgressRunData.id,
654
+ // )
655
+ // }
656
+ },
657
+ onEvent: ({ event, data }) => {
658
+ if (event === 'thread.run.failed') {
659
+ createLog({
660
+ log: {
661
+ requestMethod: LogRequestMethod.POST,
662
+ requestRoute: LogRequestRoute.MESSAGES,
663
+ level: LogLevel.ERROR,
664
+ status: 500,
665
+ message: `Thread Run failed: ${data.last_error?.message}`,
666
+ workspaceId: assistant.workspaceId,
667
+ assistantId: assistant.id,
668
+ threadId: thread.id,
669
+ },
670
+ })
671
+ } else if (event === 'thread.run.in_progress') {
672
+ latestInProgressRunData = data
673
+ } else if (event === 'thread.run.completed') {
674
+ latestCompletedRunData = data
675
+ }
676
+ },
677
+ onClose: async () => {
678
+ if (latestCompletedRunData) return
679
+ if (
680
+ !isOpenaiAssistantsStorageProvider({
681
+ storageProviderType: assistant.storageProviderType,
682
+ })
683
+ )
684
+ return
685
+
686
+ if (latestInProgressRunData) {
687
+ await client.beta.threads.runs.cancel(latestInProgressRunData.id, {
688
+ thread_id: latestInProgressRunData.thread_id,
689
+ })
690
+ }
691
+ },
692
+ }),
693
+ {
694
+ status: 200,
695
+ headers: {
696
+ 'Content-Type': 'application/json; charset=utf-8',
697
+ },
698
+ },
699
+ )
700
+ }
701
+
702
+ export const POST = buildPOST({})
703
+
704
+ export const OPTIONS = () =>
705
+ NextResponse.json(
706
+ {},
707
+ {
708
+ headers: cacheHeaders,
709
+ },
710
+ )