@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,139 @@
1
+ import type { Organization, Workspace } from '@prisma/client'
2
+ import { headers } from 'next/headers'
3
+ import { NextResponse, type NextRequest } from 'next/server'
4
+ import { z } from 'zod'
5
+ import { cacheHeaders } from '@/lib/cache/cacheHeaders'
6
+ import { prisma } from '@/lib/prisma'
7
+ import { serializeApiWorkspace } from '@/lib/workspaces/serializeApiWorkspace'
8
+ import { getOrganizationApiKey } from '@/lib/organizationApiKeys/getOrganizationApiKey'
9
+
10
+ const createWorkspaceSchema = z.object({
11
+ name: z.string().optional(),
12
+ })
13
+
14
+ export const GET = async () => {
15
+ const headersList = await headers()
16
+ const authorization = headersList.get('authorization')
17
+
18
+ if (!authorization) {
19
+ return NextResponse.json(
20
+ { error: 'No authorization header found' },
21
+ { status: 400 },
22
+ )
23
+ }
24
+
25
+ const organizationApiKey = await getOrganizationApiKey({
26
+ authorization,
27
+ })
28
+
29
+ if (!organizationApiKey) {
30
+ return NextResponse.json(
31
+ { error: 'Invalid organization api key' },
32
+ { status: 400 },
33
+ )
34
+ }
35
+
36
+ const workspaces = await prisma.workspace.findMany({
37
+ where: {
38
+ organizationId: organizationApiKey.organizationId,
39
+ },
40
+ })
41
+
42
+ return NextResponse.json(
43
+ {
44
+ workspaces: workspaces.map((workspace) =>
45
+ serializeApiWorkspace({ workspace }),
46
+ ),
47
+ },
48
+ { headers: cacheHeaders },
49
+ )
50
+ }
51
+
52
+ export const buildPOST =
53
+ ({
54
+ createWorkspace = ({
55
+ parsedData,
56
+ organization,
57
+ }: {
58
+ parsedData: z.infer<typeof createWorkspaceSchema>
59
+ organization: Organization
60
+ }) =>
61
+ prisma.workspace.create({
62
+ data: {
63
+ name: parsedData.name ?? '',
64
+ organizationId: organization.id,
65
+ },
66
+ }),
67
+ }: {
68
+ createWorkspace?: ({
69
+ parsedData,
70
+ organization,
71
+ }: {
72
+ parsedData: z.infer<typeof createWorkspaceSchema>
73
+ organization: Organization
74
+ }) => Promise<Workspace>
75
+ }) =>
76
+ async (request: NextRequest) => {
77
+ const headersList = await headers()
78
+ const authorization = headersList.get('authorization')
79
+
80
+ if (!authorization) {
81
+ return NextResponse.json(
82
+ { error: 'No authorization header found' },
83
+ { status: 400 },
84
+ )
85
+ }
86
+
87
+ const organizationApiKey = await getOrganizationApiKey({
88
+ authorization,
89
+ })
90
+
91
+ if (!organizationApiKey) {
92
+ return NextResponse.json(
93
+ { error: 'Invalid organization api key' },
94
+ { status: 400 },
95
+ )
96
+ }
97
+
98
+ const body = await request.json()
99
+ const parsed = createWorkspaceSchema.safeParse(body)
100
+
101
+ if (!parsed.success) {
102
+ return NextResponse.json({ error: 'Invalid payload' }, { status: 400 })
103
+ }
104
+
105
+ const organization = await prisma.organization.findUnique({
106
+ where: {
107
+ id: organizationApiKey.organizationId,
108
+ },
109
+ })
110
+
111
+ if (!organization) {
112
+ return NextResponse.json(
113
+ { error: 'Organization not found' },
114
+ { status: 404 },
115
+ )
116
+ }
117
+
118
+ const workspace = await createWorkspace({
119
+ parsedData: parsed.data,
120
+ organization,
121
+ })
122
+
123
+ return NextResponse.json(
124
+ {
125
+ workspace: serializeApiWorkspace({ workspace }),
126
+ },
127
+ { headers: cacheHeaders },
128
+ )
129
+ }
130
+
131
+ export const POST = buildPOST({})
132
+
133
+ export const OPTIONS = () =>
134
+ NextResponse.json(
135
+ {},
136
+ {
137
+ headers: cacheHeaders,
138
+ },
139
+ )
@@ -0,0 +1,9 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ export default function RootLayout({ children }: { children: ReactNode }) {
4
+ return (
5
+ <html lang="en">
6
+ <body>{children}</body>
7
+ </html>
8
+ )
9
+ }
@@ -0,0 +1,3 @@
1
+ export default function Page() {
2
+ return <div>@superinterface/server is running.</div>
3
+ }
@@ -0,0 +1,13 @@
1
+ import { isEmpty } from 'radash'
2
+
3
+ export const formatApiKeyName = ({
4
+ name,
5
+ }: {
6
+ name: string | undefined | null
7
+ }) => {
8
+ if (isEmpty(name)) {
9
+ return 'Untitled API key'
10
+ }
11
+
12
+ return name ?? 'Untitled API key'
13
+ }
@@ -0,0 +1,25 @@
1
+ import { ApiKeyType, ApiKey } from '@prisma/client'
2
+ import { validate } from 'uuid'
3
+ import { prisma } from '@/lib/prisma'
4
+
5
+ export const getApiKey = async ({
6
+ authorization,
7
+ type,
8
+ }: {
9
+ authorization: string | null
10
+ type: ApiKeyType
11
+ }): Promise<ApiKey | null> => {
12
+ if (!authorization) {
13
+ return null
14
+ }
15
+
16
+ const [, apiKeyValue] = authorization.split('Bearer ')
17
+
18
+ if (!validate(apiKeyValue)) {
19
+ return null
20
+ }
21
+
22
+ return prisma.apiKey.findFirst({
23
+ where: { type, value: apiKeyValue },
24
+ })
25
+ }
@@ -0,0 +1,11 @@
1
+ import type { ApiKey } from '@prisma/client'
2
+ import { formatApiKeyName } from '@/lib/apiKeys/formatApiKeyName'
3
+
4
+ export const serializeApiKey = ({ apiKey }: { apiKey: ApiKey }) => ({
5
+ id: apiKey.id,
6
+ type: apiKey.type,
7
+ name: formatApiKeyName({ name: apiKey.name }),
8
+ value: apiKey.value,
9
+ createdAt: apiKey.createdAt.toISOString(),
10
+ updatedAt: apiKey.updatedAt.toISOString(),
11
+ })
@@ -0,0 +1,21 @@
1
+ import { ApiKeyType } from '@prisma/client'
2
+ import { getApiKey } from './getApiKey'
3
+
4
+ export const workspaceAccessWhere = async ({
5
+ publicApiKey,
6
+ }: {
7
+ publicApiKey: string | null
8
+ }) => {
9
+ const apiKey = await getApiKey({
10
+ authorization: publicApiKey ? `Bearer ${publicApiKey}` : null,
11
+ type: ApiKeyType.PUBLIC,
12
+ })
13
+
14
+ if (!apiKey) return null
15
+
16
+ return {
17
+ apiKeys: {
18
+ some: { id: apiKey.id },
19
+ },
20
+ }
21
+ }
@@ -0,0 +1,96 @@
1
+ import type { OpenAI } from 'openai'
2
+ import { Prisma, Thread, Assistant, TruncationType } from '@prisma/client'
3
+ import dayjs from 'dayjs'
4
+ import { tools as getTools } from '@/lib/tools/tools'
5
+
6
+ type Args = {
7
+ select?: {
8
+ id?: boolean
9
+ }
10
+ }
11
+
12
+ type NormalizedArgs = {
13
+ select: {
14
+ id: boolean
15
+ }
16
+ }
17
+
18
+ const truncationStrategy = ({
19
+ assistant,
20
+ }: {
21
+ assistant: Assistant
22
+ }): OpenAI.Beta.Threads.Runs.Run.TruncationStrategy => {
23
+ if (assistant.truncationType === TruncationType.LAST_MESSAGES) {
24
+ return {
25
+ type: 'last_messages' as const,
26
+ last_messages: assistant.truncationLastMessagesCount,
27
+ }
28
+ } else if (assistant.truncationType === TruncationType.DISABLED) {
29
+ // @ts-expect-error - compat
30
+ return {
31
+ type: 'disabled' as const,
32
+ } as OpenAI.Beta.Threads.Runs.Run.TruncationStrategy
33
+ } else {
34
+ return {
35
+ type: 'auto' as const,
36
+ }
37
+ }
38
+ }
39
+
40
+ export const buildGetOpenaiAssistant =
41
+ ({
42
+ assistant,
43
+ thread,
44
+ }: {
45
+ assistant: Prisma.AssistantGetPayload<{
46
+ include: {
47
+ tools: {
48
+ include: {
49
+ fileSearchTool: true
50
+ webSearchTool: true
51
+ imageGenerationTool: true
52
+ codeInterpreterTool: true
53
+ computerUseTool: true
54
+ }
55
+ }
56
+ mcpServers: {
57
+ include: {
58
+ computerUseTool: true
59
+ stdioTransport: true
60
+ sseTransport: true
61
+ httpTransport: true
62
+ }
63
+ }
64
+ functions: true
65
+ modelProvider: true
66
+ }
67
+ }>
68
+ thread: Thread | null
69
+ }) =>
70
+ async ({ select: { id = false } = {} }: Args = {}) => {
71
+ const args: NormalizedArgs = { select: { id } }
72
+
73
+ if (args.select.id) {
74
+ return {
75
+ id: assistant.id,
76
+ }
77
+ }
78
+
79
+ return {
80
+ id: assistant.id,
81
+ object: 'assistant' as const,
82
+ created_at: dayjs().unix(),
83
+ model: assistant.modelSlug,
84
+ name: assistant.name,
85
+ instructions: assistant.instructions,
86
+ description: null,
87
+ tools: thread
88
+ ? ((await getTools({ assistant, thread }))?.tools ?? [])
89
+ : [],
90
+ metadata: {},
91
+ top_p: 1.0,
92
+ temperature: 1.0,
93
+ response_format: { type: 'text' as const },
94
+ truncation_strategy: truncationStrategy({ assistant }),
95
+ }
96
+ }
@@ -0,0 +1,165 @@
1
+ import type { OpenAI } from 'openai'
2
+ import {
3
+ PrismaClient,
4
+ Prisma,
5
+ StorageProviderType,
6
+ Thread,
7
+ } from '@prisma/client'
8
+ import {
9
+ supercompat,
10
+ prismaStorageAdapter,
11
+ completionsRunAdapter,
12
+ responsesRunAdapter,
13
+ responsesStorageAdapter,
14
+ } from 'supercompat'
15
+ import { isOpenaiAssistantsStorageProvider } from '@/lib/storageProviders/isOpenaiAssistantsStorageProvider'
16
+ import { isResponsesStorageProvider } from '@/lib/storageProviders/isResponsesStorageProvider'
17
+ import { clientAdapter } from '@/lib/modelProviders/clientAdapter'
18
+ import { buildGetOpenaiAssistant } from './buildGetOpenaiAssistant'
19
+ import { waitUntil } from '@vercel/functions'
20
+
21
+ type AssistantWithModelProvider = Prisma.AssistantGetPayload<{
22
+ include: { modelProvider: true }
23
+ }>
24
+
25
+ const storageAdapter = ({
26
+ assistant,
27
+ prisma,
28
+ }: {
29
+ assistant: AssistantWithModelProvider
30
+ prisma: PrismaClient
31
+ }) => {
32
+ if (
33
+ assistant.storageProviderType === StorageProviderType.SUPERINTERFACE_CLOUD
34
+ ) {
35
+ return prismaStorageAdapter({
36
+ prisma,
37
+ })
38
+ }
39
+
40
+ if (
41
+ isOpenaiAssistantsStorageProvider({
42
+ storageProviderType: assistant.storageProviderType,
43
+ })
44
+ ) {
45
+ return undefined
46
+ }
47
+
48
+ if (
49
+ isResponsesStorageProvider({
50
+ storageProviderType: assistant.storageProviderType,
51
+ })
52
+ ) {
53
+ return responsesStorageAdapter()
54
+ }
55
+
56
+ throw new Error(
57
+ `Invalid storage provider type: ${assistant.storageProviderType}`,
58
+ )
59
+ }
60
+
61
+ const runAdapter = ({
62
+ assistant,
63
+ thread,
64
+ }: {
65
+ assistant: Prisma.AssistantGetPayload<{
66
+ include: {
67
+ tools: {
68
+ include: {
69
+ fileSearchTool: true
70
+ webSearchTool: true
71
+ imageGenerationTool: true
72
+ codeInterpreterTool: true
73
+ computerUseTool: true
74
+ }
75
+ }
76
+ mcpServers: {
77
+ include: {
78
+ computerUseTool: true
79
+ stdioTransport: true
80
+ sseTransport: true
81
+ httpTransport: true
82
+ }
83
+ }
84
+ functions: true
85
+ modelProvider: true
86
+ }
87
+ }>
88
+ thread: Thread | null
89
+ }) => {
90
+ if (
91
+ assistant.storageProviderType === StorageProviderType.SUPERINTERFACE_CLOUD
92
+ ) {
93
+ return completionsRunAdapter()
94
+ }
95
+
96
+ if (
97
+ isOpenaiAssistantsStorageProvider({
98
+ storageProviderType: assistant.storageProviderType,
99
+ })
100
+ ) {
101
+ return undefined
102
+ }
103
+
104
+ if (
105
+ isResponsesStorageProvider({
106
+ storageProviderType: assistant.storageProviderType,
107
+ })
108
+ ) {
109
+ return responsesRunAdapter({
110
+ getOpenaiAssistant: buildGetOpenaiAssistant({ assistant, thread }),
111
+ waitUntil,
112
+ })
113
+ }
114
+
115
+ throw new Error(
116
+ `Invalid storage provider type: ${assistant.storageProviderType}`,
117
+ )
118
+ }
119
+
120
+ export const assistantClientAdapter = ({
121
+ assistant,
122
+ prisma,
123
+ thread = null,
124
+ }: {
125
+ assistant: Prisma.AssistantGetPayload<{
126
+ include: {
127
+ tools: {
128
+ include: {
129
+ fileSearchTool: true
130
+ webSearchTool: true
131
+ imageGenerationTool: true
132
+ codeInterpreterTool: true
133
+ computerUseTool: true
134
+ }
135
+ }
136
+ mcpServers: {
137
+ include: {
138
+ computerUseTool: true
139
+ stdioTransport: true
140
+ sseTransport: true
141
+ httpTransport: true
142
+ }
143
+ }
144
+ functions: true
145
+ modelProvider: true
146
+ }
147
+ }>
148
+ prisma: PrismaClient
149
+ thread?: Thread | null
150
+ }): OpenAI =>
151
+ supercompat({
152
+ client: clientAdapter({
153
+ modelProvider: assistant.modelProvider,
154
+ }),
155
+ // @ts-expect-error - storageAdapter can return undefined
156
+ storage: storageAdapter({
157
+ assistant,
158
+ prisma,
159
+ }),
160
+ // @ts-expect-error - storageAdapter can return undefined
161
+ runAdapter: runAdapter({
162
+ assistant,
163
+ thread,
164
+ }),
165
+ }) as unknown as OpenAI
@@ -0,0 +1,9 @@
1
+ import { isEmpty } from 'radash'
2
+
3
+ export const formatName = ({ name }: { name: string | undefined | null }) => {
4
+ if (isEmpty(name)) {
5
+ return 'Untitled assistant'
6
+ }
7
+
8
+ return name ?? 'Untitled assistant'
9
+ }
@@ -0,0 +1,40 @@
1
+ import type { Prisma } from '@prisma/client'
2
+ import { ToolType } from '@prisma/client'
3
+ import { serializeAvatar } from '@/lib/avatars/serializeAvatar'
4
+ import { defaultAvatar } from '@/lib/avatars/defaultAvatar'
5
+
6
+ export const serializeApiAssistant = ({
7
+ assistant,
8
+ }: {
9
+ assistant: Prisma.AssistantGetPayload<{
10
+ include: {
11
+ tools: true
12
+ avatar: {
13
+ include: {
14
+ iconAvatar: true
15
+ imageAvatar: true
16
+ }
17
+ }
18
+ }
19
+ }>
20
+ }) => ({
21
+ id: assistant.id,
22
+ storageProviderType: assistant.storageProviderType,
23
+ storageProviderAssistantId: assistant.openaiAssistantId,
24
+ modelProviderId: assistant.modelProviderId,
25
+ model: assistant.modelSlug,
26
+ name: assistant.name,
27
+ description: assistant.description,
28
+ instructions: assistant.instructions,
29
+ codeInterpreterEnabled: assistant.tools.some(
30
+ (tool) => tool.type === ToolType.CODE_INTERPRETER,
31
+ ),
32
+ fileSearchEnabled: assistant.tools.some(
33
+ (tool) => tool.type === ToolType.FILE_SEARCH,
34
+ ),
35
+ createdAt: assistant.createdAt.toISOString(),
36
+ updatedAt: assistant.updatedAt.toISOString(),
37
+ avatar: serializeAvatar({
38
+ avatar: assistant.avatar ?? defaultAvatar,
39
+ }),
40
+ })
@@ -0,0 +1,31 @@
1
+ import { Prisma } from '@prisma/client'
2
+ import { formatName } from '@/lib/assistants/formatName'
3
+ import { serializeTheme } from '@/lib/themes/serializeTheme'
4
+ import { serializeAvatar } from '@/lib/avatars/serializeAvatar'
5
+ import { defaultAvatar } from '@/lib/avatars/defaultAvatar'
6
+ import { defaultTheme } from '@/lib/themes/defaultTheme'
7
+
8
+ export const serializeAssistant = ({
9
+ assistant,
10
+ }: {
11
+ assistant: Prisma.AssistantGetPayload<{
12
+ include: {
13
+ avatar: {
14
+ include: {
15
+ iconAvatar: true
16
+ imageAvatar: true
17
+ }
18
+ }
19
+ }
20
+ }>
21
+ }) => ({
22
+ id: assistant.id,
23
+ name: formatName({ name: assistant.name }),
24
+ description: assistant.description,
25
+ theme: serializeTheme({
26
+ theme: defaultTheme,
27
+ }),
28
+ avatar: serializeAvatar({
29
+ avatar: assistant.avatar ?? defaultAvatar,
30
+ }),
31
+ })
@@ -0,0 +1,29 @@
1
+ import { Assistant, StorageProviderType } from '@prisma/client'
2
+ import { isOpenaiAssistantsStorageProvider } from '@/lib/storageProviders/isOpenaiAssistantsStorageProvider'
3
+ import { isResponsesStorageProvider } from '@/lib/storageProviders/isResponsesStorageProvider'
4
+
5
+ export const storageAssistantId = ({ assistant }: { assistant: Assistant }) => {
6
+ if (
7
+ isOpenaiAssistantsStorageProvider({
8
+ storageProviderType: assistant.storageProviderType,
9
+ })
10
+ ) {
11
+ return assistant.openaiAssistantId!
12
+ }
13
+
14
+ if (
15
+ isResponsesStorageProvider({
16
+ storageProviderType: assistant.storageProviderType,
17
+ })
18
+ ) {
19
+ return assistant.id
20
+ }
21
+
22
+ if (
23
+ assistant.storageProviderType === StorageProviderType.SUPERINTERFACE_CLOUD
24
+ ) {
25
+ return assistant.id
26
+ }
27
+
28
+ throw new Error('Invalid storage type')
29
+ }
@@ -0,0 +1,15 @@
1
+ import { Prisma } from '@prisma/client'
2
+ import { AvatarType, IconAvatarName } from '@prisma/client'
3
+
4
+ export const defaultAvatar = {
5
+ type: AvatarType.ICON,
6
+ iconAvatar: {
7
+ name: IconAvatarName.LIGHTNING_BOLT,
8
+ },
9
+ imageAvatar: null,
10
+ } as Prisma.AvatarGetPayload<{
11
+ include: {
12
+ imageAvatar: true
13
+ iconAvatar: true
14
+ }
15
+ }>
@@ -0,0 +1,26 @@
1
+ import { Prisma } from '@prisma/client'
2
+ import { serializeImageAvatar } from '@/lib/imageAvatars/serializeImageAvatar'
3
+ import { serializeIconAvatar } from '@/lib/iconAvatars/serializeIconAvatar'
4
+
5
+ export const serializeAvatar = ({
6
+ avatar,
7
+ }: {
8
+ avatar: Prisma.AvatarGetPayload<{
9
+ include: {
10
+ imageAvatar: true
11
+ iconAvatar: true
12
+ }
13
+ }>
14
+ }) => ({
15
+ type: avatar.type,
16
+ imageAvatar: avatar.imageAvatar
17
+ ? serializeImageAvatar({
18
+ imageAvatar: avatar.imageAvatar,
19
+ })
20
+ : null,
21
+ iconAvatar: avatar.iconAvatar
22
+ ? serializeIconAvatar({
23
+ iconAvatar: avatar.iconAvatar,
24
+ })
25
+ : null,
26
+ })
@@ -0,0 +1,5 @@
1
+ export const cacheHeaders = {
2
+ 'Access-Control-Allow-Origin': '*',
3
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
4
+ 'Access-Control-Allow-Headers': 'Content-Type',
5
+ }