@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,101 @@
1
+ import OpenAI from 'openai'
2
+ import {
3
+ Assistant,
4
+ Thread,
5
+ LogRequestMethod,
6
+ LogRequestRoute,
7
+ LogLevel,
8
+ } from '@prisma/client'
9
+ import { createLog } from '@/lib/logs/createLog'
10
+ import { scheduleSchema } from './scheduleSchema'
11
+ import { getNextOccurrence } from './getNextOccurrence'
12
+ import dayjs from 'dayjs'
13
+ import utc from 'dayjs/plugin/utc'
14
+ import timezone from 'dayjs/plugin/timezone'
15
+
16
+ dayjs.extend(utc)
17
+ dayjs.extend(timezone)
18
+
19
+ const formatCurrentTime = ({
20
+ schedule,
21
+ }: {
22
+ schedule: PrismaJson.TaskSchedule
23
+ }) => {
24
+ if (schedule.timeZone) {
25
+ return `${dayjs().tz(schedule.timeZone).format()} in timezone ${schedule.timeZone}`
26
+ }
27
+
28
+ return `${dayjs().toISOString()} in UTC`
29
+ }
30
+
31
+ export const parseTaskToolArgs = ({
32
+ toolCall,
33
+ assistant,
34
+ thread,
35
+ }: {
36
+ toolCall: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall
37
+ assistant: Assistant
38
+ thread: Thread
39
+ }) => {
40
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
+ let args: any = {}
42
+ try {
43
+ args = JSON.parse(toolCall.function.arguments || '{}')
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ } catch (e: any) {
46
+ createLog({
47
+ log: {
48
+ requestMethod: LogRequestMethod.POST,
49
+ requestRoute: LogRequestRoute.MESSAGES,
50
+ level: LogLevel.ERROR,
51
+ status: 400,
52
+ message: `Failed parsing task function arguments: ${e.message}`,
53
+ workspaceId: assistant.workspaceId,
54
+ assistantId: assistant.id,
55
+ threadId: thread.id,
56
+ },
57
+ })
58
+ return { ok: false as const, error: 'Invalid arguments.' }
59
+ }
60
+
61
+ if (args && typeof args === 'object' && args.schedule !== undefined) {
62
+ const parsed = scheduleSchema.safeParse(args.schedule)
63
+ if (!parsed.success) {
64
+ createLog({
65
+ log: {
66
+ requestMethod: LogRequestMethod.POST,
67
+ requestRoute: LogRequestRoute.MESSAGES,
68
+ level: LogLevel.ERROR,
69
+ status: 400,
70
+ message: 'Invalid schedule provided.',
71
+ workspaceId: assistant.workspaceId,
72
+ assistantId: assistant.id,
73
+ threadId: thread.id,
74
+ },
75
+ })
76
+ return { ok: false as const, error: parsed.error.toString() }
77
+ }
78
+
79
+ const next = getNextOccurrence({ schedule: args.schedule })
80
+ if (!next) {
81
+ const message = `Schedule must be in the future. Current time: ${formatCurrentTime({ schedule: args.schedule })}`
82
+
83
+ createLog({
84
+ log: {
85
+ requestMethod: LogRequestMethod.POST,
86
+ requestRoute: LogRequestRoute.MESSAGES,
87
+ level: LogLevel.ERROR,
88
+ status: 400,
89
+ message,
90
+ workspaceId: assistant.workspaceId,
91
+ assistantId: assistant.id,
92
+ threadId: thread.id,
93
+ },
94
+ })
95
+
96
+ return { ok: false as const, error: message }
97
+ }
98
+ }
99
+
100
+ return { ok: true as const, args }
101
+ }
@@ -0,0 +1,34 @@
1
+ import { z } from 'zod'
2
+
3
+ const isoLoose =
4
+ /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?)(Z|[+-]\d{2}:\d{2})?$/
5
+
6
+ export const recurrenceRuleSchema = z
7
+ .object({
8
+ frequency: z.enum([
9
+ 'yearly',
10
+ 'monthly',
11
+ 'weekly',
12
+ 'daily',
13
+ 'hourly',
14
+ 'minutely',
15
+ 'secondly',
16
+ ]),
17
+ interval: z.number().int().min(1).optional(),
18
+ byDay: z.array(z.string()).optional(),
19
+ byMonth: z.array(z.number()).optional(),
20
+ byHour: z.array(z.number()).optional(),
21
+ byMinute: z.array(z.number()).optional(),
22
+ bySecond: z.array(z.number()).optional(),
23
+ until: z.string().regex(isoLoose).optional(),
24
+ count: z.number().int().optional(),
25
+ })
26
+ .passthrough()
27
+
28
+ export const scheduleSchema = z
29
+ .object({
30
+ start: z.string().regex(isoLoose),
31
+ due: z.string().regex(isoLoose).optional(),
32
+ recurrenceRules: z.array(recurrenceRuleSchema).optional(),
33
+ })
34
+ .passthrough()
@@ -0,0 +1,37 @@
1
+ import dayjs from 'dayjs'
2
+ import utc from 'dayjs/plugin/utc'
3
+ import timezone from 'dayjs/plugin/timezone'
4
+
5
+ import { qstash } from '@/lib/upstash/qstash'
6
+ import { prisma } from '@/lib/prisma'
7
+ import { type Task } from '@prisma/client'
8
+ import { getNextOccurrence } from './getNextOccurrence'
9
+
10
+ dayjs.extend(utc)
11
+ dayjs.extend(timezone)
12
+
13
+ export const scheduleTask = async ({ task }: { task: Task }) => {
14
+ if (!task.schedule || typeof task.schedule !== 'object') return
15
+
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ const nextIso = getNextOccurrence({ schedule: task.schedule as any })
18
+ if (!nextIso) return
19
+
20
+ const next = dayjs.utc(nextIso)
21
+ if (!next.isValid()) return
22
+
23
+ const delay = Math.max(0, next.diff(dayjs.utc(), 'second'))
24
+
25
+ const { messageId } = await qstash.publishJSON({
26
+ url: `${process.env.NEXT_PUBLIC_SUPERINTERFACE_BASE_URL}/api/cloud/tasks/callback`,
27
+ body: { taskId: task.id },
28
+ delay,
29
+ })
30
+
31
+ if (!messageId) throw new Error('Failed to schedule task: missing QStash ID')
32
+
33
+ await prisma.task.update({
34
+ where: { id: task.id },
35
+ data: { qstashMessageId: messageId },
36
+ })
37
+ }
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod'
2
+
3
+ export const createTaskSchema = z.object({
4
+ title: z.string(),
5
+ message: z.string(),
6
+ schedule: z.any(),
7
+ threadId: z.string(),
8
+ key: z.string().optional(),
9
+ })
10
+
11
+ export const createTaskToolSchema = createTaskSchema.omit({ threadId: true })
12
+
13
+ export const updateTaskSchema = z.object({
14
+ taskId: z.string(),
15
+ title: z.string().optional(),
16
+ message: z.string().optional(),
17
+ schedule: z.any().optional(),
18
+ key: z.string().optional(),
19
+ })
20
+
21
+ export const deleteTaskSchema = z.object({
22
+ taskId: z.string(),
23
+ })
24
+
25
+ export const listTasksSchema = z.object({})
@@ -0,0 +1,14 @@
1
+ import type { Task } from '@prisma/client'
2
+
3
+ export const serializeTask = ({ task }: { task: Task }) => ({
4
+ id: task.id,
5
+ title: task.title,
6
+ message: task.message,
7
+ schedule: task.schedule,
8
+ threadId: task.threadId,
9
+ key: task.key,
10
+ createdAt: task.createdAt.toISOString(),
11
+ updatedAt: task.updatedAt.toISOString(),
12
+ })
13
+
14
+ export type SerializedTask = ReturnType<typeof serializeTask>
@@ -0,0 +1,23 @@
1
+ import { scheduleSchema } from './scheduleSchema'
2
+ import { getNextOccurrence } from './getNextOccurrence'
3
+
4
+ export const validateSchedule = (
5
+ schedule: PrismaJson.TaskSchedule,
6
+ ): boolean => {
7
+ const parsed = scheduleSchema.safeParse(schedule)
8
+ if (!parsed.success) return false
9
+ try {
10
+ const next = getNextOccurrence({ schedule })
11
+ if (
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ Array.isArray((schedule as any).recurrenceRules) &&
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
+ (schedule as any).recurrenceRules.length
16
+ ) {
17
+ return next !== null
18
+ }
19
+ return true
20
+ } catch {
21
+ return false
22
+ }
23
+ }
@@ -0,0 +1,7 @@
1
+ export const defaultTheme = {
2
+ accentColor: 'BLUE',
3
+ grayColor: 'GRAY',
4
+ appearance: 'LIGHT',
5
+ radius: 'MEDIUM',
6
+ scaling: 'SCALING_100',
7
+ }
@@ -0,0 +1,9 @@
1
+ import type { themePropDefs } from '@radix-ui/themes/props'
2
+
3
+ export const serializeAccentColor = ({
4
+ accentColor,
5
+ }: {
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ accentColor: any
8
+ }) =>
9
+ accentColor.toLowerCase() as (typeof themePropDefs.accentColor.values)[number]
@@ -0,0 +1,25 @@
1
+ import { themePropDefs } from '@radix-ui/themes/props'
2
+ import { serializeAccentColor } from '@/lib/themes/serializeAccentColor'
3
+ import { serializeScaling } from './serializeScaling'
4
+
5
+ type Args = {
6
+ theme: {
7
+ accentColor: string
8
+ grayColor: string
9
+ appearance: string
10
+ radius: string
11
+ scaling: string
12
+ }
13
+ }
14
+
15
+ export const serializeTheme = ({ theme }: Args) => ({
16
+ accentColor: serializeAccentColor({ accentColor: theme.accentColor }),
17
+ grayColor:
18
+ theme.grayColor.toLowerCase() as (typeof themePropDefs.grayColor.values)[number],
19
+ appearance:
20
+ theme.appearance.toLowerCase() as (typeof themePropDefs.appearance.values)[number],
21
+ radius:
22
+ theme.radius.toLowerCase() as (typeof themePropDefs.radius.values)[number],
23
+ scaling: serializeScaling({ scaling: theme.scaling }),
24
+ panelBackground: 'solid' as const,
25
+ })
@@ -0,0 +1,14 @@
1
+ import type { themePropDefs } from '@radix-ui/themes/props'
2
+
3
+ const scalingMap = {
4
+ SCALING_90: '90%',
5
+ SCALING_95: '95%',
6
+ SCALING_100: '100%',
7
+ SCALING_105: '105%',
8
+ SCALING_110: '110%',
9
+ } as const
10
+
11
+ export const serializeScaling = ({ scaling }: { scaling: string }) =>
12
+ scalingMap[
13
+ scaling as keyof typeof scalingMap
14
+ ] as (typeof themePropDefs.scaling.values)[number]
@@ -0,0 +1,185 @@
1
+ import OpenAI from 'openai'
2
+ import { StorageProviderType } from '@prisma/client'
3
+ import { PrismaClient, Prisma } from '@prisma/client'
4
+ import { isOpenaiAssistantsStorageProvider } from '@/lib/storageProviders/isOpenaiAssistantsStorageProvider'
5
+ import { initialMessages } from './initialMessages'
6
+ import { serializeMetadata } from '@/lib/metadata/serializeMetadata'
7
+
8
+ export const createThread = async ({
9
+ client,
10
+ assistant,
11
+ prisma,
12
+ variables = {},
13
+ }: {
14
+ client: OpenAI
15
+ assistant: Prisma.AssistantGetPayload<{
16
+ include: {
17
+ initialMessages: true
18
+ modelProvider: true
19
+ }
20
+ }>
21
+ prisma: PrismaClient
22
+ variables?: Record<string, string>
23
+ }) => {
24
+ const serializedMetadata = serializeMetadata({
25
+ variables,
26
+ workspaceId: assistant.workspaceId,
27
+ })
28
+
29
+ let thread
30
+
31
+ if (
32
+ isOpenaiAssistantsStorageProvider({
33
+ storageProviderType: assistant.storageProviderType,
34
+ })
35
+ ) {
36
+ const newThread = await prisma.thread.create({
37
+ data: {
38
+ assistantId: assistant.id,
39
+ metadata: serializedMetadata,
40
+ },
41
+ })
42
+
43
+ const storageProviderThread = await client.beta.threads.create({
44
+ messages: initialMessages({ assistant }),
45
+ metadata: {
46
+ assistantId: assistant.id,
47
+ threadId: newThread.id,
48
+ ...serializedMetadata,
49
+ },
50
+ })
51
+
52
+ thread = await prisma.thread.update({
53
+ where: {
54
+ id: newThread.id,
55
+ },
56
+ include: {
57
+ assistant: {
58
+ select: {
59
+ storageProviderType: true,
60
+ },
61
+ },
62
+ },
63
+ data: {
64
+ openaiThreadId: storageProviderThread.id,
65
+ metadata: {
66
+ assistantId: assistant.id,
67
+ threadId: newThread.id,
68
+ ...serializedMetadata,
69
+ },
70
+ },
71
+ })
72
+ } else if (
73
+ assistant.storageProviderType === StorageProviderType.OPENAI_RESPONSES
74
+ ) {
75
+ const newThread = await prisma.thread.create({
76
+ data: {
77
+ assistantId: assistant.id,
78
+ metadata: serializedMetadata,
79
+ },
80
+ })
81
+
82
+ const storageProviderThread = await client.beta.threads.create({
83
+ messages: initialMessages({ assistant }),
84
+ metadata: {
85
+ assistantId: assistant.id,
86
+ threadId: newThread.id,
87
+ ...serializedMetadata,
88
+ },
89
+ })
90
+
91
+ thread = await prisma.thread.update({
92
+ where: {
93
+ id: newThread.id,
94
+ },
95
+ include: {
96
+ assistant: {
97
+ select: {
98
+ storageProviderType: true,
99
+ },
100
+ },
101
+ },
102
+ data: {
103
+ openaiConversationId: storageProviderThread.id,
104
+ metadata: {
105
+ assistantId: assistant.id,
106
+ threadId: newThread.id,
107
+ ...serializedMetadata,
108
+ },
109
+ },
110
+ })
111
+ } else if (
112
+ assistant.storageProviderType === StorageProviderType.AZURE_OPENAI_RESPONSES
113
+ ) {
114
+ const newThread = await prisma.thread.create({
115
+ data: {
116
+ assistantId: assistant.id,
117
+ metadata: serializedMetadata,
118
+ },
119
+ })
120
+
121
+ const storageProviderThread = await client.beta.threads.create({
122
+ messages: initialMessages({ assistant }),
123
+ metadata: {
124
+ assistantId: assistant.id,
125
+ threadId: newThread.id,
126
+ ...serializedMetadata,
127
+ },
128
+ })
129
+
130
+ thread = await prisma.thread.update({
131
+ where: {
132
+ id: newThread.id,
133
+ },
134
+ include: {
135
+ assistant: {
136
+ select: {
137
+ storageProviderType: true,
138
+ },
139
+ },
140
+ },
141
+ data: {
142
+ azureOpenaiConversationId: storageProviderThread.id,
143
+ metadata: {
144
+ assistantId: assistant.id,
145
+ threadId: newThread.id,
146
+ ...serializedMetadata,
147
+ },
148
+ },
149
+ })
150
+ } else {
151
+ const storageProviderThread = await client.beta.threads.create({
152
+ messages: initialMessages({ assistant }),
153
+ metadata: {
154
+ assistantId: assistant.id,
155
+ ...serializedMetadata,
156
+ },
157
+ })
158
+
159
+ thread = await prisma.thread.update({
160
+ where: {
161
+ id: storageProviderThread.id,
162
+ },
163
+ include: {
164
+ assistant: {
165
+ select: {
166
+ storageProviderType: true,
167
+ },
168
+ },
169
+ },
170
+ data: {
171
+ metadata: {
172
+ assistantId: assistant.id,
173
+ threadId: storageProviderThread.id,
174
+ ...serializedMetadata,
175
+ },
176
+ },
177
+ })
178
+ }
179
+
180
+ if (!thread) {
181
+ throw new Error('Failed to create thread')
182
+ }
183
+
184
+ return thread
185
+ }
@@ -0,0 +1,36 @@
1
+ import { Prisma, InitialMessage, Assistant } from '@prisma/client'
2
+ import { isOpenaiAssistantsStorageProvider } from '@/lib/storageProviders/isOpenaiAssistantsStorageProvider'
3
+
4
+ const role = ({
5
+ message,
6
+ assistant,
7
+ }: {
8
+ message: InitialMessage
9
+ assistant: Assistant
10
+ }) => {
11
+ if (
12
+ isOpenaiAssistantsStorageProvider({
13
+ storageProviderType: assistant.storageProviderType,
14
+ })
15
+ ) {
16
+ return message.role.toLowerCase() as 'user' | 'assistant'
17
+ }
18
+
19
+ return message.role as 'user' | 'assistant'
20
+ }
21
+
22
+ export const initialMessages = ({
23
+ assistant,
24
+ }: {
25
+ assistant: Prisma.AssistantGetPayload<{
26
+ include: {
27
+ initialMessages: true
28
+ }
29
+ }>
30
+ }) =>
31
+ assistant.initialMessages.map((message) => ({
32
+ role: role({ message, assistant }),
33
+ content: message.content,
34
+ attachments: message.attachments,
35
+ metadata: message.metadata,
36
+ }))
@@ -0,0 +1,72 @@
1
+ import { Prisma, StorageProviderType } from '@prisma/client'
2
+ import { assistantClientAdapter } from '@/lib/assistants/assistantClientAdapter'
3
+ import { prisma } from '@/lib/prisma'
4
+ import { isOpenaiAssistantsStorageProvider } from '@/lib/storageProviders/isOpenaiAssistantsStorageProvider'
5
+
6
+ export const managedOpenaiThreadId = async ({
7
+ assistant,
8
+ threadId,
9
+ }: {
10
+ assistant: Prisma.AssistantGetPayload<{
11
+ include: {
12
+ tools: {
13
+ include: {
14
+ fileSearchTool: true
15
+ webSearchTool: true
16
+ imageGenerationTool: true
17
+ codeInterpreterTool: true
18
+ computerUseTool: true
19
+ }
20
+ }
21
+ mcpServers: {
22
+ include: {
23
+ computerUseTool: true
24
+ stdioTransport: true
25
+ sseTransport: true
26
+ httpTransport: true
27
+ }
28
+ }
29
+ functions: true
30
+ modelProvider: true
31
+ }
32
+ }>
33
+ threadId: string
34
+ }) => {
35
+ const newStorageThread = await assistantClientAdapter({
36
+ assistant,
37
+ prisma,
38
+ }).beta.threads.create({
39
+ metadata: {
40
+ assistantId: assistant.id,
41
+ threadId,
42
+ },
43
+ })
44
+
45
+ await prisma.thread.update({
46
+ where: {
47
+ id: threadId,
48
+ },
49
+ data: {
50
+ ...(isOpenaiAssistantsStorageProvider({
51
+ storageProviderType: assistant.storageProviderType,
52
+ })
53
+ ? {
54
+ openaiThreadId: newStorageThread.id,
55
+ }
56
+ : {}),
57
+ ...(assistant.storageProviderType === StorageProviderType.OPENAI_RESPONSES
58
+ ? {
59
+ openaiConversationId: newStorageThread.id,
60
+ }
61
+ : {}),
62
+ ...(assistant.storageProviderType ===
63
+ StorageProviderType.AZURE_OPENAI_RESPONSES
64
+ ? {
65
+ azureOpenaiConversationId: newStorageThread.id,
66
+ }
67
+ : {}),
68
+ },
69
+ })
70
+
71
+ return newStorageThread.id
72
+ }
@@ -0,0 +1,49 @@
1
+ import { Prisma, StorageProviderType } from '@prisma/client'
2
+ import { isOpenaiAssistantsStorageProvider } from '@/lib/storageProviders/isOpenaiAssistantsStorageProvider'
3
+
4
+ export const storageThreadId = ({
5
+ thread,
6
+ }: {
7
+ thread: Prisma.ThreadGetPayload<{
8
+ include: {
9
+ assistant: {
10
+ select: {
11
+ storageProviderType: true
12
+ }
13
+ }
14
+ }
15
+ }>
16
+ }) => {
17
+ if (
18
+ isOpenaiAssistantsStorageProvider({
19
+ storageProviderType: thread.assistant.storageProviderType,
20
+ })
21
+ ) {
22
+ return thread.openaiThreadId
23
+ }
24
+
25
+ if (
26
+ thread.assistant.storageProviderType ===
27
+ StorageProviderType.OPENAI_RESPONSES
28
+ ) {
29
+ return thread.openaiConversationId
30
+ }
31
+
32
+ if (
33
+ thread.assistant.storageProviderType ===
34
+ StorageProviderType.AZURE_OPENAI_RESPONSES
35
+ ) {
36
+ return thread.azureOpenaiConversationId
37
+ }
38
+
39
+ if (
40
+ thread.assistant.storageProviderType ===
41
+ StorageProviderType.SUPERINTERFACE_CLOUD
42
+ ) {
43
+ return thread.id
44
+ }
45
+
46
+ throw new Error(
47
+ `Invalid storage type: ${thread.assistant.storageProviderType}`,
48
+ )
49
+ }
@@ -0,0 +1,10 @@
1
+ import { validate } from 'uuid'
2
+
3
+ const fallbackUuid = '00000000-0000-0000-0000-000000000000'
4
+
5
+ export const validThreadId = ({ threadId }: { threadId: string | null }) => {
6
+ if (!threadId) return fallbackUuid
7
+ if (!validate(threadId)) return fallbackUuid
8
+
9
+ return threadId
10
+ }