@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,113 @@
1
+ import type { Prisma, Thread, Assistant } from '@prisma/client'
2
+ import {
3
+ LogRequestMethod,
4
+ LogRequestRoute,
5
+ LogLevel,
6
+ TransportType,
7
+ } from '@prisma/client'
8
+ import { dash } from 'radash'
9
+ import { interpolateFunctionValue } from '@/lib/functions/interpolateFunctionValue'
10
+ import { createLog } from '@/lib/logs/createLog'
11
+
12
+ const transportHeaders = ({
13
+ mcpServer,
14
+ }: {
15
+ mcpServer: Prisma.McpServerGetPayload<{
16
+ include: {
17
+ httpTransport: true
18
+ sseTransport: true
19
+ }
20
+ }>
21
+ }) => {
22
+ if (mcpServer.transportType === TransportType.HTTP) {
23
+ return mcpServer.httpTransport!.headers
24
+ } else if (mcpServer.transportType === TransportType.SSE) {
25
+ return mcpServer.sseTransport!.headers
26
+ }
27
+
28
+ return {}
29
+ }
30
+
31
+ const interpolatedTransportHeaders = ({
32
+ mcpServer,
33
+ thread,
34
+ metadata,
35
+ assistant,
36
+ }: {
37
+ mcpServer: Prisma.McpServerGetPayload<{
38
+ include: {
39
+ httpTransport: true
40
+ sseTransport: true
41
+ }
42
+ }>
43
+ thread: Thread
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ metadata?: Record<string, any>
46
+ assistant: Assistant
47
+ }) => {
48
+ const result: Record<string, string> = {}
49
+ const missing: string[] = []
50
+
51
+ for (const [k, v] of Object.entries(transportHeaders({ mcpServer }))) {
52
+ const res = interpolateFunctionValue({
53
+ value: v,
54
+ args: metadata,
55
+ thread,
56
+ assistant,
57
+ })
58
+ result[k] = res.value
59
+ missing.push(...res.missing)
60
+ }
61
+
62
+ return { headers: result, missing }
63
+ }
64
+
65
+ export const headers = ({
66
+ thread,
67
+ mcpServer,
68
+ assistant,
69
+ }: {
70
+ thread: Thread
71
+ mcpServer: Prisma.McpServerGetPayload<{
72
+ include: {
73
+ httpTransport: true
74
+ sseTransport: true
75
+ }
76
+ }>
77
+ assistant: Assistant
78
+ }) => {
79
+ const { headers, missing } = interpolatedTransportHeaders({
80
+ mcpServer,
81
+ thread,
82
+ metadata: thread.metadata ?? {},
83
+ assistant,
84
+ })
85
+
86
+ if (missing.length) {
87
+ const message = `Missing variables in MCP server: ${missing.join(', ')}`
88
+
89
+ createLog({
90
+ log: {
91
+ requestMethod: LogRequestMethod.POST,
92
+ requestRoute: LogRequestRoute.MESSAGES,
93
+ level: LogLevel.ERROR,
94
+ status: 400,
95
+ message,
96
+ workspaceId: assistant.workspaceId,
97
+ assistantId: assistant.id,
98
+ threadId: thread.id,
99
+ },
100
+ })
101
+
102
+ throw new Error(message)
103
+ }
104
+
105
+ const data = {
106
+ ...headers,
107
+ ...(thread.metadata ?? {}),
108
+ }
109
+
110
+ return Object.fromEntries(
111
+ Object.entries(data).map(([key, value]) => [dash(key), value]),
112
+ )
113
+ }
@@ -0,0 +1,77 @@
1
+ import { z } from 'zod'
2
+ import { TransportType } from '@prisma/client'
3
+ import { isJSON } from '@/lib/misc/isJSON'
4
+
5
+ const stdioTransportSchema = z.object({
6
+ command: z.string().min(1),
7
+ args: z.string().min(1),
8
+ })
9
+
10
+ const sseTransportSchema = z.object({
11
+ url: z.string().min(1).url(),
12
+ headers: z.string().min(1).refine(isJSON, {
13
+ message: 'Must be a valid JSON string.',
14
+ }),
15
+ })
16
+
17
+ const httpTransportSchema = z.object({
18
+ url: z.string().min(1).url(),
19
+ headers: z.string().min(1).refine(isJSON, {
20
+ message: 'Must be a valid JSON string.',
21
+ }),
22
+ })
23
+
24
+ export const baseSchema = z.object({
25
+ transportType: z
26
+ .nativeEnum(TransportType)
27
+ .refine((t) => t !== TransportType.STDIO, {
28
+ message: `transportType cannot be ${TransportType.STDIO}`,
29
+ }),
30
+ sseTransport: sseTransportSchema.nullable().optional(),
31
+ httpTransport: httpTransportSchema.nullable().optional(),
32
+ })
33
+
34
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
+ export const superRefine = (values: any, ctx: any) => {
36
+ if (values.transportType === TransportType.STDIO) {
37
+ ctx.addIssue({
38
+ code: z.ZodIssueCode.custom,
39
+ message: `Transport type ${TransportType.STDIO} is not allowed.`,
40
+ })
41
+
42
+ const result = stdioTransportSchema.safeParse(values.stdioTransport)
43
+
44
+ if (result.success) return
45
+
46
+ result.error.issues.forEach((issue) =>
47
+ ctx.addIssue({
48
+ ...issue,
49
+ path: ['stdioTransport', ...issue.path],
50
+ }),
51
+ )
52
+ } else if (values.transportType === TransportType.SSE) {
53
+ const result = sseTransportSchema.safeParse(values.sseTransport)
54
+
55
+ if (result.success) return
56
+
57
+ result.error.issues.forEach((issue) =>
58
+ ctx.addIssue({
59
+ ...issue,
60
+ path: ['sseTransport', ...issue.path],
61
+ }),
62
+ )
63
+ } else if (values.transportType === TransportType.HTTP) {
64
+ const result = httpTransportSchema.safeParse(values.httpTransport)
65
+
66
+ if (result.success) return
67
+
68
+ result.error.issues.forEach((issue) =>
69
+ ctx.addIssue({
70
+ ...issue,
71
+ path: ['httpTransport', ...issue.path],
72
+ }),
73
+ )
74
+ }
75
+ }
76
+
77
+ export const mcpServerSchema = baseSchema.superRefine(superRefine)
@@ -0,0 +1,51 @@
1
+ import type { Prisma, SseTransport, HttpTransport } from '@prisma/client'
2
+
3
+ const serializeApiSseTransport = ({
4
+ sseTransport,
5
+ }: {
6
+ sseTransport: SseTransport
7
+ }) => ({
8
+ id: sseTransport.id,
9
+ url: sseTransport.url,
10
+ headers: sseTransport.headers,
11
+ createdAt: sseTransport.createdAt.toISOString(),
12
+ updatedAt: sseTransport.updatedAt.toISOString(),
13
+ })
14
+
15
+ const serializeApiHttpTransport = ({
16
+ httpTransport,
17
+ }: {
18
+ httpTransport: HttpTransport
19
+ }) => ({
20
+ id: httpTransport.id,
21
+ url: httpTransport.url,
22
+ headers: httpTransport.headers,
23
+ createdAt: httpTransport.createdAt.toISOString(),
24
+ updatedAt: httpTransport.updatedAt.toISOString(),
25
+ })
26
+
27
+ export const serializeApiMcpServer = ({
28
+ mcpServer,
29
+ }: {
30
+ mcpServer: Prisma.McpServerGetPayload<{
31
+ include: {
32
+ sseTransport: true
33
+ httpTransport: true
34
+ }
35
+ }>
36
+ }) => ({
37
+ id: mcpServer.id,
38
+ transportType: mcpServer.transportType,
39
+ sseTransport: mcpServer.sseTransport
40
+ ? serializeApiSseTransport({
41
+ sseTransport: mcpServer.sseTransport,
42
+ })
43
+ : null,
44
+ httpTransport: mcpServer.httpTransport
45
+ ? serializeApiHttpTransport({
46
+ httpTransport: mcpServer.httpTransport,
47
+ })
48
+ : null,
49
+ createdAt: mcpServer.createdAt.toISOString(),
50
+ updatedAt: mcpServer.updatedAt.toISOString(),
51
+ })
@@ -0,0 +1,98 @@
1
+ import type { Prisma, Thread, Assistant } from '@prisma/client'
2
+ import {
3
+ LogRequestMethod,
4
+ LogRequestRoute,
5
+ LogLevel,
6
+ TransportType,
7
+ } from '@prisma/client'
8
+ import { interpolateFunctionValue } from '@/lib/functions/interpolateFunctionValue'
9
+ import { createLog } from '@/lib/logs/createLog'
10
+
11
+ const transportUrl = ({
12
+ mcpServer,
13
+ }: {
14
+ mcpServer: Prisma.McpServerGetPayload<{
15
+ include: {
16
+ httpTransport: true
17
+ sseTransport: true
18
+ }
19
+ }>
20
+ }) => {
21
+ if (mcpServer.transportType === TransportType.HTTP) {
22
+ return mcpServer.httpTransport!.url
23
+ } else if (mcpServer.transportType === TransportType.SSE) {
24
+ return mcpServer.sseTransport!.url
25
+ }
26
+
27
+ return ''
28
+ }
29
+
30
+ const interpolatedTransportUrl = ({
31
+ mcpServer,
32
+ thread,
33
+ metadata,
34
+ assistant,
35
+ }: {
36
+ mcpServer: Prisma.McpServerGetPayload<{
37
+ include: {
38
+ httpTransport: true
39
+ sseTransport: true
40
+ }
41
+ }>
42
+ thread: Thread
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ metadata?: Record<string, any>
45
+ assistant: Assistant
46
+ }) => {
47
+ const { value, missing } = interpolateFunctionValue({
48
+ value: transportUrl({ mcpServer }),
49
+ args: metadata,
50
+ thread,
51
+ assistant,
52
+ })
53
+
54
+ return { url: value, missing }
55
+ }
56
+
57
+ export const url = ({
58
+ thread,
59
+ mcpServer,
60
+ assistant,
61
+ }: {
62
+ thread: Thread
63
+ mcpServer: Prisma.McpServerGetPayload<{
64
+ include: {
65
+ httpTransport: true
66
+ sseTransport: true
67
+ }
68
+ }>
69
+ assistant: Assistant
70
+ }) => {
71
+ const { url, missing } = interpolatedTransportUrl({
72
+ mcpServer,
73
+ thread,
74
+ metadata: thread.metadata ?? {},
75
+ assistant,
76
+ })
77
+
78
+ if (missing.length) {
79
+ const message = `Missing variables in MCP server: ${missing.join(', ')}`
80
+
81
+ createLog({
82
+ log: {
83
+ requestMethod: LogRequestMethod.POST,
84
+ requestRoute: LogRequestRoute.MESSAGES,
85
+ level: LogLevel.ERROR,
86
+ status: 400,
87
+ message,
88
+ workspaceId: assistant.workspaceId,
89
+ assistantId: assistant.id,
90
+ threadId: thread.id,
91
+ },
92
+ })
93
+
94
+ throw new Error(message)
95
+ }
96
+
97
+ return url
98
+ }
@@ -0,0 +1,60 @@
1
+ import { ModelProviderType, Prisma } from '@prisma/client'
2
+ import { toFile } from 'openai'
3
+ import { buildOpenaiClient } from '@/lib/modelProviders/buildOpenaiClient'
4
+ import { isEmpty } from 'radash'
5
+
6
+ type Args = {
7
+ textContent?: string
8
+ audioContent?: string
9
+ assistant: Prisma.AssistantGetPayload<{
10
+ include: {
11
+ workspace: {
12
+ include: {
13
+ modelProviders: true
14
+ }
15
+ }
16
+ }
17
+ }>
18
+ }
19
+
20
+ export const content = async ({
21
+ textContent,
22
+ audioContent,
23
+ assistant,
24
+ }: Args) => {
25
+ if (textContent) {
26
+ return textContent
27
+ }
28
+
29
+ if (audioContent) {
30
+ const openaiModelProvider = assistant.workspace.modelProviders.find(
31
+ (mp) => mp.type === ModelProviderType.OPENAI,
32
+ )
33
+
34
+ if (!openaiModelProvider?.apiKey) {
35
+ throw new Error('No OpenAI API key found')
36
+ }
37
+
38
+ const client = buildOpenaiClient({
39
+ modelProvider: openaiModelProvider,
40
+ })
41
+
42
+ const base64Content = audioContent.split(',')[1]
43
+
44
+ if (isEmpty(base64Content)) {
45
+ return '-'
46
+ }
47
+
48
+ const audioBuffer = Buffer.from(base64Content, 'base64')
49
+ const file = await toFile(audioBuffer, 'message.mp3')
50
+
51
+ const transcription = await client.audio.transcriptions.create({
52
+ file,
53
+ model: 'whisper-1',
54
+ })
55
+
56
+ return transcription.text
57
+ }
58
+
59
+ throw new Error('No content found')
60
+ }
@@ -0,0 +1,13 @@
1
+ import type OpenAI from 'openai'
2
+
3
+ export const textContent = ({
4
+ message,
5
+ }: {
6
+ message: OpenAI.Beta.Threads.Messages.Message
7
+ }) => {
8
+ const textContents = message.content.filter(
9
+ (content) => content.type === 'text',
10
+ ) as OpenAI.Beta.Threads.Messages.TextContentBlock[]
11
+
12
+ return textContents.map((textContent) => textContent.text.value).join('\n\n')
13
+ }
@@ -0,0 +1,34 @@
1
+ import { LogRequestMethod, LogRequestRoute, LogLevel } from '@prisma/client'
2
+ import { createLog } from '@/lib/logs/createLog'
3
+
4
+ export const serializeMetadata = ({
5
+ variables,
6
+ workspaceId,
7
+ }: {
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ variables: Record<string, any>
10
+ workspaceId: string
11
+ }): Record<string, string> => {
12
+ const metadata: Record<string, string> = {}
13
+
14
+ for (const [key, value] of Object.entries(variables)) {
15
+ try {
16
+ metadata[key] = String(value)
17
+ } catch (error) {
18
+ createLog({
19
+ log: {
20
+ requestMethod: LogRequestMethod.POST,
21
+ requestRoute: LogRequestRoute.MESSAGES,
22
+ level: LogLevel.ERROR,
23
+ status: 500,
24
+ message: `Failed to serialize key "${key}": ${
25
+ error instanceof Error ? error.message : String(error)
26
+ }`,
27
+ workspaceId,
28
+ },
29
+ })
30
+ }
31
+ }
32
+
33
+ return metadata
34
+ }
@@ -0,0 +1,9 @@
1
+ export const isJSON = (value: string) => {
2
+ try {
3
+ JSON.parse(value)
4
+ return true
5
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
6
+ } catch (e) {
7
+ return false
8
+ }
9
+ }
@@ -0,0 +1,8 @@
1
+ import _ from 'lodash'
2
+
3
+ // @ts-expect-error broad type
4
+ export const customizer = (objectValue, srcValue) => {
5
+ if (!_.isArray(objectValue)) return
6
+
7
+ return srcValue
8
+ }
@@ -0,0 +1,6 @@
1
+ import _ from 'lodash'
2
+ import { customizer } from './customizer'
3
+
4
+ // @ts-expect-error broad type
5
+ export const merge = (obj, ...sources) =>
6
+ _.mergeWith(_.cloneDeep(obj), ...sources, customizer)
@@ -0,0 +1,33 @@
1
+ import { ModelProvider } from '@prisma/client'
2
+ import { AzureOpenAI } from 'openai'
3
+ import { azureOpenaiClientAdapter } from 'supercompat'
4
+
5
+ export const buildAzureOpenaiClientAdapter = ({
6
+ modelProvider,
7
+ baseURL,
8
+ }: {
9
+ modelProvider: ModelProvider
10
+ baseURL?: string
11
+ }) => {
12
+ const azureOpenai = new AzureOpenAI({
13
+ apiKey: modelProvider.apiKey,
14
+ endpoint: modelProvider.endpoint!,
15
+ apiVersion: modelProvider.apiVersion || '2025-04-01-preview',
16
+ ...(baseURL ? { baseURL } : {}),
17
+ defaultHeaders: {
18
+ 'HTTP-Referer': 'https://superinterface.ai',
19
+ 'X-Title': 'Superinterface',
20
+ },
21
+ // @ts-expect-error duplex is not yet in the types
22
+ fetch: (url: RequestInfo, init?: RequestInit): Promise<Response> =>
23
+ fetch(url, {
24
+ ...(init || {}),
25
+ // @ts-expect-error duplex is not yet in the types
26
+ duplex: 'half',
27
+ }),
28
+ })
29
+
30
+ return azureOpenaiClientAdapter({
31
+ azureOpenai,
32
+ })
33
+ }
@@ -0,0 +1,14 @@
1
+ import { ModelProvider } from '@prisma/client'
2
+ import { clientAdapter } from '@/lib/modelProviders/clientAdapter'
3
+ import { supercompat } from 'supercompat'
4
+
5
+ export const buildOpenaiClient = ({
6
+ modelProvider,
7
+ }: {
8
+ modelProvider: ModelProvider
9
+ }) =>
10
+ supercompat({
11
+ client: clientAdapter({
12
+ modelProvider,
13
+ }),
14
+ })
@@ -0,0 +1,30 @@
1
+ import { ModelProvider } from '@prisma/client'
2
+ import OpenAI from 'openai'
3
+ import { openaiClientAdapter } from 'supercompat'
4
+
5
+ export const buildOpenaiClientAdapter = ({
6
+ modelProvider,
7
+ baseURL,
8
+ apiKey,
9
+ }: {
10
+ modelProvider: ModelProvider
11
+ baseURL?: string
12
+ apiKey?: string
13
+ }) =>
14
+ openaiClientAdapter({
15
+ openai: new OpenAI({
16
+ apiKey: apiKey ?? modelProvider.apiKey,
17
+ ...(baseURL ? { baseURL } : {}),
18
+ defaultHeaders: {
19
+ 'HTTP-Referer': 'https://superinterface.ai',
20
+ 'X-Title': 'Superinterface',
21
+ },
22
+ // @ts-expect-error duplex is not yet in the types
23
+ fetch: (url: RequestInfo, init?: RequestInit): Promise<Response> =>
24
+ fetch(url, {
25
+ ...(init || {}),
26
+ // @ts-expect-error duplex is not yet in the types
27
+ duplex: 'half',
28
+ }),
29
+ }),
30
+ })
@@ -0,0 +1,121 @@
1
+ import Groq from 'groq-sdk'
2
+ import OpenAI from 'openai'
3
+ import { Mistral } from '@mistralai/mistralai'
4
+ import Anthropic from '@anthropic-ai/sdk'
5
+ import {
6
+ mistralClientAdapter,
7
+ groqClientAdapter,
8
+ perplexityClientAdapter,
9
+ humirisClientAdapter,
10
+ googleClientAdapter,
11
+ togetherClientAdapter,
12
+ anthropicClientAdapter,
13
+ } from 'supercompat'
14
+ import { ModelProvider, ModelProviderType } from '@prisma/client'
15
+ import { buildOpenaiClientAdapter } from '@/lib/modelProviders/buildOpenaiClientAdapter'
16
+ import { buildAzureOpenaiClientAdapter } from '@/lib/modelProviders/buildAzureOpenaiClientAdapter'
17
+
18
+ export const clientAdapter = ({
19
+ modelProvider,
20
+ }: {
21
+ modelProvider: ModelProvider
22
+ }) => {
23
+ if (modelProvider.type === ModelProviderType.OPENAI) {
24
+ return buildOpenaiClientAdapter({
25
+ modelProvider,
26
+ })
27
+ }
28
+
29
+ if (modelProvider.type === ModelProviderType.AZURE_OPENAI) {
30
+ return buildAzureOpenaiClientAdapter({
31
+ modelProvider,
32
+ })
33
+ }
34
+
35
+ if (modelProvider.type === ModelProviderType.PERPLEXITY) {
36
+ return perplexityClientAdapter({
37
+ perplexity: new OpenAI({
38
+ apiKey: modelProvider.apiKey,
39
+ baseURL: 'https://api.perplexity.ai/',
40
+ // @ts-expect-error duplex is not yet in the types
41
+ fetch: (url: RequestInfo, init?: RequestInit): Promise<Response> =>
42
+ fetch(url, {
43
+ ...(init || {}),
44
+ // @ts-expect-error duplex is not yet in the types
45
+ duplex: 'half',
46
+ }),
47
+ }),
48
+ })
49
+ }
50
+
51
+ if (modelProvider.type === ModelProviderType.TOGETHER) {
52
+ return togetherClientAdapter({
53
+ together: new OpenAI({
54
+ apiKey: modelProvider.apiKey,
55
+ baseURL: 'https://api.together.xyz/v1',
56
+ }),
57
+ })
58
+ }
59
+
60
+ if (modelProvider.type === ModelProviderType.OPEN_ROUTER) {
61
+ return buildOpenaiClientAdapter({
62
+ modelProvider,
63
+ baseURL: 'https://openrouter.ai/api/v1',
64
+ })
65
+ }
66
+
67
+ if (modelProvider.type === ModelProviderType.MISTRAL) {
68
+ return mistralClientAdapter({
69
+ mistral: new Mistral({
70
+ apiKey: modelProvider.apiKey,
71
+ }),
72
+ })
73
+ }
74
+
75
+ if (modelProvider.type === ModelProviderType.ANTHROPIC) {
76
+ return anthropicClientAdapter({
77
+ anthropic: new Anthropic({
78
+ apiKey: modelProvider.apiKey,
79
+ }),
80
+ })
81
+ }
82
+
83
+ if (modelProvider.type === ModelProviderType.GROQ) {
84
+ return groqClientAdapter({
85
+ groq: new Groq({
86
+ apiKey: modelProvider.apiKey || process.env.COMMUNITY_TEST_GROQ_API_KEY,
87
+ }),
88
+ })
89
+ }
90
+
91
+ if (modelProvider.type === ModelProviderType.OLLAMA) {
92
+ return buildOpenaiClientAdapter({
93
+ modelProvider,
94
+ baseURL: modelProvider.endpoint ?? '',
95
+ apiKey: 'ollama',
96
+ })
97
+ }
98
+
99
+ if (modelProvider.type === ModelProviderType.HUMIRIS) {
100
+ return humirisClientAdapter({
101
+ humiris: new OpenAI({
102
+ apiKey: modelProvider.apiKey,
103
+ baseURL: 'https://moai-service-app.humiris.ai/api/openai/v1/',
104
+ defaultHeaders: {
105
+ 'moai-api-key': modelProvider.apiKey,
106
+ },
107
+ }),
108
+ })
109
+ }
110
+
111
+ if (modelProvider.type === ModelProviderType.GOOGLE) {
112
+ return googleClientAdapter({
113
+ google: new OpenAI({
114
+ apiKey: modelProvider.apiKey,
115
+ baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai/',
116
+ }),
117
+ })
118
+ }
119
+
120
+ throw new Error(`Invalid model provider type: ${modelProvider.type}`)
121
+ }
@@ -0,0 +1,23 @@
1
+ import { ModelProvider, ModelProviderType } from '@prisma/client'
2
+
3
+ export const isModelProviderValid = ({
4
+ modelProvider,
5
+ }: {
6
+ modelProvider: ModelProvider
7
+ }) => {
8
+ if (modelProvider.type === ModelProviderType.OLLAMA) {
9
+ return !!modelProvider.endpoint
10
+ }
11
+
12
+ if (!modelProvider.apiKey) {
13
+ return false
14
+ }
15
+
16
+ if (modelProvider.type === ModelProviderType.AZURE_OPENAI) {
17
+ if (!modelProvider.endpoint) {
18
+ return false
19
+ }
20
+ }
21
+
22
+ return true
23
+ }