diff --git a/packages/server-next/next/.gitignore b/packages/server-next/next/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5ef6a520780202a1d6addd833d800ccb1ecac0bb --- /dev/null +++ b/packages/server-next/next/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/packages/server-next/next/.prettierrc.json b/packages/server-next/next/.prettierrc.json new file mode 100644 index 0000000000000000000000000000000000000000..bf357fbbc081d991705e0ed49539c433b003b6f3 --- /dev/null +++ b/packages/server-next/next/.prettierrc.json @@ -0,0 +1,3 @@ +{ + "trailingComma": "all" +} diff --git a/packages/server-next/next/app/favicon.ico b/packages/server-next/next/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c Binary files /dev/null and b/packages/server-next/next/app/favicon.ico differ diff --git a/packages/server-next/next/app/globals.css b/packages/server-next/next/app/globals.css new file mode 100644 index 0000000000000000000000000000000000000000..7f6e077570c338bba6d9b15d610f5fdac36f023d --- /dev/null +++ b/packages/server-next/next/app/globals.css @@ -0,0 +1,153 @@ +@import "tailwindcss"; + +@source '../../node_modules/@llamaindex/chat-ui/**/*.{ts,tsx}'; + +@custom-variant dark (&:is(.dark *)); + +@theme { + --color-border: hsl(var(--border)); + --color-input: hsl(var(--input)); + --color-ring: hsl(var(--ring)); + --color-background: hsl(var(--background)); + --color-foreground: hsl(var(--foreground)); + + --color-primary: hsl(var(--primary)); + --color-primary-foreground: hsl(var(--primary-foreground)); + + --color-secondary: hsl(var(--secondary)); + --color-secondary-foreground: hsl(var(--secondary-foreground)); + + --color-destructive: hsl(var(--destructive)); + --color-destructive-foreground: hsl(var(--destructive-foreground)); + + --color-muted: hsl(var(--muted)); + --color-muted-foreground: hsl(var(--muted-foreground)); + + --color-accent: hsl(var(--accent)); + --color-accent-foreground: hsl(var(--accent-foreground)); + + --color-popover: hsl(var(--popover)); + --color-popover-foreground: hsl(var(--popover-foreground)); + + --color-card: hsl(var(--card)); + --color-card-foreground: hsl(var(--card-foreground)); + + --radius-xl: calc(var(--radius) + 4px); + --radius-lg: var(--radius); + --radius-md: calc(var(--radius) - 2px); + --radius-sm: calc(var(--radius) - 4px); + + --font-sans: + var(--font-sans), ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + + --animate-accordion-down: accordion-down 0.2s ease-out; + --animate-accordion-up: accordion-up 0.2s ease-out; + + --background-image-glow-conic: + radial-gradient(at 21% 11%, rgba(186, 186, 233, 0.53) 0, transparent 50%), + radial-gradient(at 85% 0, hsla(46, 57%, 78%, 0.52) 0, transparent 50%), + radial-gradient(at 91% 36%, rgba(194, 213, 255, 0.68) 0, transparent 50%), + radial-gradient(at 8% 40%, rgba(251, 218, 239, 0.46) 0, transparent 50%); + + @keyframes accordion-down { + from { + height: 0; + } + to { + height: var(--radix-accordion-content-height); + } + } + @keyframes accordion-up { + from { + height: var(--radix-accordion-content-height); + } + to { + height: 0; + } + } +} + +/* + The default border color has changed to `currentColor` in Tailwind CSS v4, + so we've added these compatibility styles to make sure everything still + looks the same as it did with Tailwind CSS v3. + + If we ever want to remove these styles, we need to add an explicit border + color utility to any element that depends on these defaults. +*/ +@layer base { + *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + border-color: var(--color-gray-200, currentColor); + } +} + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 10% 3.9%; + --radius: 0.5rem; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + } + + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/packages/server-next/next/app/layout.tsx b/packages/server-next/next/app/layout.tsx new file mode 100644 index 0000000000000000000000000000000000000000..756fcce4af9b0702da8027635a235f9f5eed6772 --- /dev/null +++ b/packages/server-next/next/app/layout.tsx @@ -0,0 +1,19 @@ +import type { Metadata } from "next"; +import "./globals.css"; + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + <html lang="en"> + <body>{children}</body> + </html> + ); +} diff --git a/packages/server-next/next/app/page.tsx b/packages/server-next/next/app/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..48c85c6f970e61028eb99c516c9e9fc0318fd23f --- /dev/null +++ b/packages/server-next/next/app/page.tsx @@ -0,0 +1,15 @@ +"use client"; +import { ChatSection } from "@llamaindex/chat-ui"; +import { useChat } from "ai/react"; + +export default function Page() { + const handler = useChat(); + return ( + <div className="h-screen flex items-center justify-center"> + <ChatSection + className="h-[72vh] w-[72vw] shadow-2xl rounded-2xl" + handler={handler} + /> + </div> + ); +} diff --git a/packages/server-next/next/eslint.config.mjs b/packages/server-next/next/eslint.config.mjs new file mode 100644 index 0000000000000000000000000000000000000000..c85fb67c463f20d1ee449b0ffee725a61dfb9259 --- /dev/null +++ b/packages/server-next/next/eslint.config.mjs @@ -0,0 +1,16 @@ +import { dirname } from "path"; +import { fileURLToPath } from "url"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, +}); + +const eslintConfig = [ + ...compat.extends("next/core-web-vitals", "next/typescript"), +]; + +export default eslintConfig; diff --git a/packages/server-next/next/next.config.ts b/packages/server-next/next/next.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..7aee1c485c8173a74650c1058472da8b373eda4c --- /dev/null +++ b/packages/server-next/next/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + distDir: "../.next", +}; + +export default nextConfig; diff --git a/packages/server-next/next/postcss.config.mjs b/packages/server-next/next/postcss.config.mjs new file mode 100644 index 0000000000000000000000000000000000000000..c7bcb4b1ee14cd5e25078c2c934529afdd2a7df9 --- /dev/null +++ b/packages/server-next/next/postcss.config.mjs @@ -0,0 +1,5 @@ +const config = { + plugins: ["@tailwindcss/postcss"], +}; + +export default config; diff --git a/packages/server-next/next/tsconfig.json b/packages/server-next/next/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..46419c89f575bab7ed5e3c72791875002e8cfa87 --- /dev/null +++ b/packages/server-next/next/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + "next-env.d.ts", + "../.next/types/**/*.ts" + ], + "exclude": ["node_modules"] +} diff --git a/packages/server-next/package.json b/packages/server-next/package.json new file mode 100644 index 0000000000000000000000000000000000000000..0e83ddabf75a46a40b88cceb0a67898859a6051b --- /dev/null +++ b/packages/server-next/package.json @@ -0,0 +1,59 @@ +{ + "name": "@llamaindex/server-next", + "description": "LlamaIndex Server", + "version": "0.0.1", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "exports": { + ".": { + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + }, + "import": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + } + }, + "files": [ + "dist", + ".next" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/run-llama/LlamaIndexTS.git", + "directory": "packages/server" + }, + "scripts": { + "dev:next": "cd ./next && next dev", + "start:next": "cd ./next && next start", + "build:next": "cd ./next && next build", + "start:server": "tsx ./src/server.ts", + "dev:server": "tsx ./src/server.ts --watch", + "build": "pnpm run build:next && bunchee", + "dev": "bunchee --watch" + }, + "devDependencies": { + "bunchee": "6.4.0", + "vitest": "^2.1.5", + "@types/node": "^22.9.0", + "@types/react": "^19", + "@types/react-dom": "^19", + "@tailwindcss/postcss": "^4", + "tailwindcss": "^4", + "eslint": "^9", + "eslint-config-next": "15.2.3", + "@eslint/eslintrc": "^3", + "tsx": "^4.19.3" + }, + "dependencies": { + "llamaindex": "workspace:*", + "@llamaindex/chat-ui": "0.3.1", + "ai": "^4.0.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "next": "15.2.3" + } +} diff --git a/packages/server-next/src/index.ts b/packages/server-next/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f3a0aec6b3c3605c87c2c93bcd5474b2e033292 --- /dev/null +++ b/packages/server-next/src/index.ts @@ -0,0 +1,4 @@ +export * from "./server"; +export * from "./workflow/stream"; +export * from "./workflow/tools"; +export * from "./workflow/type"; diff --git a/packages/server-next/src/server.ts b/packages/server-next/src/server.ts new file mode 100644 index 0000000000000000000000000000000000000000..68a5fdb4cf8d7e276697a3d6c1117ed9792240a0 --- /dev/null +++ b/packages/server-next/src/server.ts @@ -0,0 +1,62 @@ +import { createServer, IncomingMessage, ServerResponse } from "http"; +import { type ChatMessage } from "llamaindex"; +import next from "next"; +import path from "path"; +import { parse } from "url"; +import { + chatWithWorkflow, + parseRequestBody, + pipeResponse, +} from "./workflow/stream"; +import type { ServerWorkflow } from "./workflow/type"; + +type NextAppOptions = Omit<Parameters<typeof next>[0], "dir">; + +export type LlamaIndexServerOptions = NextAppOptions & { + workflow: ServerWorkflow; +}; + +export class LlamaIndexServer { + port: number; + app: ReturnType<typeof next>; + workflow: ServerWorkflow; + + constructor({ workflow, ...nextAppOptions }: LlamaIndexServerOptions) { + const nextDir = path.join(__dirname, ".."); // location of the .next after build next app + this.app = next({ ...nextAppOptions, dir: nextDir }); + this.port = nextAppOptions.port ?? 3000; + this.workflow = workflow; + } + + async handleChat(req: IncomingMessage, res: ServerResponse) { + try { + const body = await parseRequestBody(req); + const { messages } = body as { messages: ChatMessage[] }; + const streamResponse = await chatWithWorkflow(this.workflow, messages); + pipeResponse(res, streamResponse); + } catch (error) { + console.error("Chat error:", error); + res.end("Internal server error"); + } + } + + async start() { + await this.app.prepare(); + + const server = createServer((req, res) => { + const parsedUrl = parse(req.url!, true); + const pathname = parsedUrl.pathname; + + if (pathname === "/api/chat" && req.method === "POST") { + return this.handleChat(req, res); + } + + const handle = this.app.getRequestHandler(); + handle(req, res, parsedUrl); + }); + + server.listen(this.port, () => { + console.log(`> Server listening at http://localhost:${this.port}`); + }); + } +} diff --git a/packages/server-next/src/workflow/stream.ts b/packages/server-next/src/workflow/stream.ts new file mode 100644 index 0000000000000000000000000000000000000000..2838ccfcc0aa0aef89476d99c206418a8c9c1de1 --- /dev/null +++ b/packages/server-next/src/workflow/stream.ts @@ -0,0 +1,115 @@ +import { LlamaIndexAdapter, StreamData, type JSONValue } from "ai"; +import type { IncomingMessage, ServerResponse } from "http"; +import { + EngineResponse, + StopEvent, + Workflow, + WorkflowContext, + WorkflowEvent, + type ChatMessage, + type ChatResponseChunk, +} from "llamaindex"; +import { ReadableStream } from "stream/web"; +import { AgentRunEvent, type AgentInput } from "./type"; + +export async function chatWithWorkflow( + workflow: Workflow<null, AgentInput, ChatResponseChunk>, + messages: ChatMessage[], +): Promise<Response> { + const context = workflow.run({ messages }); + const { stream, dataStream } = await createStreamFromWorkflowContext(context); + const response = LlamaIndexAdapter.toDataStreamResponse(stream, { + data: dataStream, + }); + return response; +} + +async function createStreamFromWorkflowContext<Input, Output, Context>( + context: WorkflowContext<Input, Output, Context>, +): Promise<{ stream: ReadableStream<EngineResponse>; dataStream: StreamData }> { + const dataStream = new StreamData(); + let generator: AsyncGenerator<ChatResponseChunk> | undefined; + + const closeStreams = (controller: ReadableStreamDefaultController) => { + controller.close(); + dataStream.close(); + }; + + const stream = new ReadableStream<EngineResponse>({ + async start(controller) { + // Kickstart the stream by sending an empty string + controller.enqueue({ delta: "" } as EngineResponse); + }, + async pull(controller) { + while (!generator) { + // get next event from workflow context + const { value: event, done } = + await context[Symbol.asyncIterator]().next(); + if (done) { + closeStreams(controller); + return; + } + generator = handleEvent(event, dataStream); + } + + const { value: chunk, done } = await generator.next(); + if (done) { + closeStreams(controller); + return; + } + const delta = chunk.delta ?? ""; + if (delta) { + controller.enqueue({ delta } as EngineResponse); + } + }, + }); + + return { stream, dataStream }; +} + +function handleEvent( + event: WorkflowEvent<unknown>, + dataStream: StreamData, +): AsyncGenerator<ChatResponseChunk> | undefined { + // Handle for StopEvent + if (event instanceof StopEvent) { + return event.data as AsyncGenerator<ChatResponseChunk>; + } + // Handle for AgentRunEvent + if (event instanceof AgentRunEvent) { + dataStream.appendMessageAnnotation({ + type: "agent", + data: event.data as JSONValue, + }); + } +} + +export async function pipeResponse( + response: ServerResponse, + streamResponse: Response, +) { + if (!streamResponse.body) return; + const reader = streamResponse.body.getReader(); + while (true) { + const { done, value } = await reader.read(); + if (done) return response.end(); + response.write(value); + } +} + +export async function parseRequestBody(request: IncomingMessage) { + const body = new Promise((resolve) => { + const bodyParts: Buffer[] = []; + let body: string; + request + .on("data", (chunk) => { + bodyParts.push(chunk); + }) + .on("end", () => { + body = Buffer.concat(bodyParts).toString(); + resolve(body); + }); + }) as Promise<string>; + const data = await body; + return JSON.parse(data); +} diff --git a/packages/server-next/src/workflow/tools.ts b/packages/server-next/src/workflow/tools.ts new file mode 100644 index 0000000000000000000000000000000000000000..4e46336616efb52bc9c94ada10ab72d1ce3cf2f1 --- /dev/null +++ b/packages/server-next/src/workflow/tools.ts @@ -0,0 +1,294 @@ +import { + type BaseToolWithCall, + callTool, + type ChatMessage, + type ChatResponse, + type ChatResponseChunk, + type HandlerContext, + type PartialToolCall, + type ToolCall, + ToolCallLLM, + type ToolCallLLMMessageOptions, +} from "llamaindex"; +import crypto from "node:crypto"; +import { AgentRunEvent } from "./type"; + +/** + * Call multiple tools and return the tool messages + */ +export const callTools = async <T>({ + tools, + toolCalls, + ctx, + agentName, + writeEvent = true, +}: { + toolCalls: ToolCall[]; + tools: BaseToolWithCall[]; + ctx: HandlerContext<T>; + agentName: string; + writeEvent?: boolean; +}): Promise<ChatMessage[]> => { + const toolMsgs: ChatMessage[] = []; + if (toolCalls.length === 0) { + return toolMsgs; + } + if (toolCalls.length === 1 && toolCalls[0]) { + const tool = tools.find( + (tool) => tool.metadata.name === toolCalls[0]!.name, + ); + if (!tool) { + throw new Error(`Tool ${toolCalls[0].name} not found`); + } + return [ + await callSingleTool( + tool, + toolCalls[0], + writeEvent + ? (msg: string) => { + ctx.sendEvent( + new AgentRunEvent({ + agent: agentName, + text: msg, + type: "text", + }), + ); + } + : undefined, + ), + ]; + } + // Multiple tool calls, show events in progress + const progressId = crypto.randomUUID(); + const totalSteps = toolCalls.length; + let currentStep = 0; + for (const toolCall of toolCalls) { + const tool = tools.find((tool) => tool.metadata.name === toolCall.name); + if (!tool) { + throw new Error(`Tool ${toolCall.name} not found`); + } + const toolMsg = await callSingleTool(tool, toolCall, (msg: string) => { + ctx.sendEvent( + new AgentRunEvent({ + agent: agentName, + text: msg, + type: "progress", + data: { + id: progressId, + total: totalSteps, + current: currentStep, + }, + }), + ); + currentStep++; + }); + toolMsgs.push(toolMsg); + } + return toolMsgs; +}; + +export const callSingleTool = async ( + tool: BaseToolWithCall, + toolCall: ToolCall, + eventEmitter?: (msg: string) => void, +): Promise<ChatMessage> => { + if (eventEmitter) { + eventEmitter( + `Calling tool ${toolCall.name} with input: ${JSON.stringify(toolCall.input)}`, + ); + } + + const toolOutput = await callTool(tool, toolCall, { + log: () => {}, + error: (...args: unknown[]) => { + console.error(`Tool ${toolCall.name} got error:`, ...args); + if (eventEmitter) { + eventEmitter(`Tool ${toolCall.name} got error: ${args.join(" ")}`); + } + return { + content: JSON.stringify({ + error: args.join(" "), + }), + role: "user", + options: { + toolResult: { + id: toolCall.id, + result: JSON.stringify({ + error: args.join(" "), + }), + isError: true, + }, + }, + }; + }, + warn: () => {}, + }); + + return { + content: JSON.stringify(toolOutput.output), + role: "user", + options: { + toolResult: { + result: toolOutput.output, + isError: toolOutput.isError, + id: toolCall.id, + }, + }, + }; +}; + +class ChatWithToolsResponse { + toolCalls: ToolCall[]; + toolCallMessage?: ChatMessage; + responseGenerator?: AsyncGenerator<ChatResponseChunk>; + + constructor(options: { + toolCalls: ToolCall[]; + toolCallMessage?: ChatMessage; + responseGenerator?: AsyncGenerator<ChatResponseChunk>; + }) { + this.toolCalls = options.toolCalls; + if (options.toolCallMessage) { + this.toolCallMessage = options.toolCallMessage; + } + if (options.responseGenerator) { + this.responseGenerator = options.responseGenerator; + } + } + + hasMultipleTools() { + const uniqueToolNames = new Set(this.getToolNames()); + return uniqueToolNames.size > 1; + } + + hasToolCall() { + return this.toolCalls.length > 0; + } + + getToolNames() { + return this.toolCalls.map((toolCall) => toolCall.name); + } + + async asFullResponse(): Promise<ChatMessage> { + if (!this.responseGenerator) { + throw new Error("No response generator"); + } + let fullResponse = ""; + for await (const chunk of this.responseGenerator) { + fullResponse += chunk.delta; + } + return { + role: "assistant", + content: fullResponse, + }; + } +} + +export const chatWithTools = async ( + llm: ToolCallLLM, + tools: BaseToolWithCall[], + messages: ChatMessage[], +): Promise<ChatWithToolsResponse> => { + const responseGenerator = async function* (): AsyncGenerator< + boolean | ChatResponseChunk, + void, + unknown + > { + const responseStream = await llm.chat({ messages, tools, stream: true }); + + let fullResponse = null; + let yieldedIndicator = false; + const toolCallMap = new Map(); + for await (const chunk of responseStream) { + const hasToolCalls = chunk.options && "toolCall" in chunk.options; + if (!hasToolCalls) { + if (!yieldedIndicator) { + yield false; + yieldedIndicator = true; + } + yield chunk; + } else if (!yieldedIndicator) { + yield true; + yieldedIndicator = true; + } + + if (chunk.options && "toolCall" in chunk.options) { + for (const toolCall of chunk.options.toolCall as PartialToolCall[]) { + if (toolCall.id) { + toolCallMap.set(toolCall.id, toolCall); + } + } + } + + if ( + hasToolCalls && + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (chunk.raw as any)?.choices?.[0]?.finish_reason !== null + ) { + // Update the fullResponse with the tool calls + const toolCalls = Array.from(toolCallMap.values()); + fullResponse = { + ...chunk, + options: { + ...chunk.options, + toolCall: toolCalls, + }, + }; + } + } + + if (fullResponse) { + yield fullResponse; + } + }; + + const generator = responseGenerator(); + const isToolCall = await generator.next(); + + if (isToolCall.value) { + // If it's a tool call, we need to wait for the full response + let fullResponse = null; + for await (const chunk of generator) { + fullResponse = chunk; + } + + if (fullResponse) { + const responseChunk = fullResponse as ChatResponseChunk; + const toolCalls = getToolCallsFromResponse(responseChunk); + return new ChatWithToolsResponse({ + toolCalls, + toolCallMessage: { + options: responseChunk.options, + role: "assistant", + content: "", + }, + }); + } else { + throw new Error("Cannot get tool calls from response"); + } + } + + return new ChatWithToolsResponse({ + toolCalls: [], + responseGenerator: generator as AsyncGenerator<ChatResponseChunk>, + }); +}; + +export const getToolCallsFromResponse = ( + response: + | ChatResponse<ToolCallLLMMessageOptions> + | ChatResponseChunk<ToolCallLLMMessageOptions>, +): ToolCall[] => { + let options; + + if ("message" in response) { + options = response.message.options; + } else { + options = response.options; + } + + if (options && "toolCall" in options) { + return options.toolCall as ToolCall[]; + } + return []; +}; diff --git a/packages/server-next/src/workflow/type.ts b/packages/server-next/src/workflow/type.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f08d1f314e21213c5bed836f0eeb3f4c790fdc0 --- /dev/null +++ b/packages/server-next/src/workflow/type.ts @@ -0,0 +1,29 @@ +import { + Workflow, + WorkflowEvent, + type ChatMessage, + type ChatResponseChunk, +} from "llamaindex"; + +export type AgentInput = { + messages: ChatMessage[]; +}; + +export type AgentRunEventType = "text" | "progress"; + +export type ProgressEventData = { + id: string; + total: number; + current: number; +}; + +export type AgentRunEventData = ProgressEventData; + +export class AgentRunEvent extends WorkflowEvent<{ + agent: string; + text: string; + type: AgentRunEventType; + data?: AgentRunEventData; +}> {} + +export type ServerWorkflow = Workflow<null, AgentInput, ChatResponseChunk>; diff --git a/packages/server-next/tsconfig.json b/packages/server-next/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..a93775d954ab510bbae6d3aaabe2c7204f557e2b --- /dev/null +++ b/packages/server-next/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist/type", + "tsBuildInfoFile": "./dist/.tsbuildinfo", + "emitDeclarationOnly": true, + "moduleResolution": "Bundler", + "skipLibCheck": true, + "strict": true, + "types": ["node"] + }, + "include": ["./src"], + "exclude": ["node_modules"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6cafdbf191d7bf1c7e12aa66f655a97067466a1d..abd23c24722029c5b89696e7fbd66c5f36fff443 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1761,6 +1761,61 @@ importers: specifier: ^2.1.5 version: 2.1.5(@edge-runtime/vm@4.0.4)(@types/node@22.9.0)(happy-dom@15.11.7)(lightningcss@1.29.1)(msw@2.7.0(@types/node@22.9.0)(typescript@5.7.3))(terser@5.38.2) + packages/server-next: + dependencies: + '@llamaindex/chat-ui': + specifier: 0.3.1 + version: 0.3.1(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + ai: + specifier: ^4.0.3 + version: 4.1.34(react@19.0.0)(zod@3.24.2) + llamaindex: + specifier: workspace:* + version: link:../llamaindex + next: + specifier: 15.2.3 + version: 15.2.3(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: + specifier: ^19.0.0 + version: 19.0.0 + react-dom: + specifier: ^19.0.0 + version: 19.0.0(react@19.0.0) + devDependencies: + '@eslint/eslintrc': + specifier: ^3 + version: 3.3.0 + '@tailwindcss/postcss': + specifier: ^4 + version: 4.0.9 + '@types/node': + specifier: ^22.9.0 + version: 22.9.0 + '@types/react': + specifier: ^19 + version: 19.0.10 + '@types/react-dom': + specifier: ^19 + version: 19.0.4(@types/react@19.0.10) + bunchee: + specifier: 6.4.0 + version: 6.4.0(typescript@5.7.3) + eslint: + specifier: ^9 + version: 9.22.0(jiti@2.4.2) + eslint-config-next: + specifier: 15.2.3 + version: 15.2.3(eslint@9.22.0(jiti@2.4.2))(typescript@5.7.3) + tailwindcss: + specifier: ^4 + version: 4.0.9 + tsx: + specifier: ^4.19.3 + version: 4.19.3 + vitest: + specifier: ^2.1.5 + version: 2.1.5(@edge-runtime/vm@4.0.4)(@types/node@22.9.0)(happy-dom@15.11.7)(lightningcss@1.29.1)(msw@2.7.0(@types/node@22.9.0)(typescript@5.7.3))(terser@5.38.2) + packages/tools: dependencies: '@apidevtools/swagger-parser': @@ -3615,6 +3670,11 @@ packages: peerDependencies: react: ^18.2.0 || ^19.0.0 || ^19.0.0-rc + '@llamaindex/chat-ui@0.3.1': + resolution: {integrity: sha512-sF6axN9LviewAxvBbqkF3u3K0yvIt74prio7uiVruFVT/AYkRlIk721QXTPBscf+ZvyzAqjh0Nx0BoGiZUzBCw==} + peerDependencies: + react: ^18.2.0 || ^19.0.0 || ^19.0.0-rc + '@llamaindex/pdf-viewer@1.3.0': resolution: {integrity: sha512-HJtjzmxn+erb3Vq89W5atPq0q6uyZMMCgzOnmstxudzaHW/Yj1dp1ojCuBh/wlP1tUnIRoe9RmvC0ahmqSwRUA==} peerDependencies: @@ -3765,9 +3825,15 @@ packages: '@next/env@15.2.1': resolution: {integrity: sha512-JmY0qvnPuS2NCWOz2bbby3Pe0VzdAQ7XpEB6uLIHmtXNfAsAO0KLQLkuAoc42Bxbo3/jMC3dcn9cdf+piCcG2Q==} + '@next/env@15.2.3': + resolution: {integrity: sha512-a26KnbW9DFEUsSxAxKBORR/uD9THoYoKbkpFywMN/AFvboTt94b8+g/07T8J6ACsdLag8/PDU60ov4rPxRAixw==} + '@next/eslint-plugin-next@15.1.0': resolution: {integrity: sha512-+jPT0h+nelBT6HC9ZCHGc7DgGVy04cv4shYdAe6tKlEbjQUtwU3LzQhzbDHQyY2m6g39m6B0kOFVuLGBrxxbGg==} + '@next/eslint-plugin-next@15.2.3': + resolution: {integrity: sha512-eNSOIMJtjs+dp4Ms1tB1PPPJUQHP3uZK+OQ7iFY9qXpGO6ojT6imCL+KcUOqE/GXGidWbBZJzYdgAdPHqeCEPA==} + '@next/swc-darwin-arm64@15.2.0': resolution: {integrity: sha512-rlp22GZwNJjFCyL7h5wz9vtpBVuCt3ZYjFWpEPBGzG712/uL1bbSkS675rVAUCRZ4hjoTJ26Q7IKhr5DfJrHDA==} engines: {node: '>= 10'} @@ -3780,6 +3846,12 @@ packages: cpu: [arm64] os: [darwin] + '@next/swc-darwin-arm64@15.2.3': + resolution: {integrity: sha512-uaBhA8aLbXLqwjnsHSkxs353WrRgQgiFjduDpc7YXEU0B54IKx3vU+cxQlYwPCyC8uYEEX7THhtQQsfHnvv8dw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + '@next/swc-darwin-x64@15.2.0': resolution: {integrity: sha512-DiU85EqSHogCz80+sgsx90/ecygfCSGl5P3b4XDRVZpgujBm5lp4ts7YaHru7eVTyZMjHInzKr+w0/7+qDrvMA==} engines: {node: '>= 10'} @@ -3792,6 +3864,12 @@ packages: cpu: [x64] os: [darwin] + '@next/swc-darwin-x64@15.2.3': + resolution: {integrity: sha512-pVwKvJ4Zk7h+4hwhqOUuMx7Ib02u3gDX3HXPKIShBi9JlYllI0nU6TWLbPT94dt7FSi6mSBhfc2JrHViwqbOdw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + '@next/swc-linux-arm64-gnu@15.2.0': resolution: {integrity: sha512-VnpoMaGukiNWVxeqKHwi8MN47yKGyki5q+7ql/7p/3ifuU2341i/gDwGK1rivk0pVYbdv5D8z63uu9yMw0QhpQ==} engines: {node: '>= 10'} @@ -3804,6 +3882,12 @@ packages: cpu: [arm64] os: [linux] + '@next/swc-linux-arm64-gnu@15.2.3': + resolution: {integrity: sha512-50ibWdn2RuFFkOEUmo9NCcQbbV9ViQOrUfG48zHBCONciHjaUKtHcYFiCwBVuzD08fzvzkWuuZkd4AqbvKO7UQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + '@next/swc-linux-arm64-musl@15.2.0': resolution: {integrity: sha512-ka97/ssYE5nPH4Qs+8bd8RlYeNeUVBhcnsNUmFM6VWEob4jfN9FTr0NBhXVi1XEJpj3cMfgSRW+LdE3SUZbPrw==} engines: {node: '>= 10'} @@ -3816,6 +3900,12 @@ packages: cpu: [arm64] os: [linux] + '@next/swc-linux-arm64-musl@15.2.3': + resolution: {integrity: sha512-2gAPA7P652D3HzR4cLyAuVYwYqjG0mt/3pHSWTCyKZq/N/dJcUAEoNQMyUmwTZWCJRKofB+JPuDVP2aD8w2J6Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + '@next/swc-linux-x64-gnu@15.2.0': resolution: {integrity: sha512-zY1JduE4B3q0k2ZCE+DAF/1efjTXUsKP+VXRtrt/rJCTgDlUyyryx7aOgYXNc1d8gobys/Lof9P9ze8IyRDn7Q==} engines: {node: '>= 10'} @@ -3828,6 +3918,12 @@ packages: cpu: [x64] os: [linux] + '@next/swc-linux-x64-gnu@15.2.3': + resolution: {integrity: sha512-ODSKvrdMgAJOVU4qElflYy1KSZRM3M45JVbeZu42TINCMG3anp7YCBn80RkISV6bhzKwcUqLBAmOiWkaGtBA9w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + '@next/swc-linux-x64-musl@15.2.0': resolution: {integrity: sha512-QqvLZpurBD46RhaVaVBepkVQzh8xtlUN00RlG4Iq1sBheNugamUNPuZEH1r9X1YGQo1KqAe1iiShF0acva3jHQ==} engines: {node: '>= 10'} @@ -3840,6 +3936,12 @@ packages: cpu: [x64] os: [linux] + '@next/swc-linux-x64-musl@15.2.3': + resolution: {integrity: sha512-ZR9kLwCWrlYxwEoytqPi1jhPd1TlsSJWAc+H/CJHmHkf2nD92MQpSRIURR1iNgA/kuFSdxB8xIPt4p/T78kwsg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + '@next/swc-win32-arm64-msvc@15.2.0': resolution: {integrity: sha512-ODZ0r9WMyylTHAN6pLtvUtQlGXBL9voljv6ujSlcsjOxhtXPI1Ag6AhZK0SE8hEpR1374WZZ5w33ChpJd5fsjw==} engines: {node: '>= 10'} @@ -3852,6 +3954,12 @@ packages: cpu: [arm64] os: [win32] + '@next/swc-win32-arm64-msvc@15.2.3': + resolution: {integrity: sha512-+G2FrDcfm2YDbhDiObDU/qPriWeiz/9cRR0yMWJeTLGGX6/x8oryO3tt7HhodA1vZ8r2ddJPCjtLcpaVl7TE2Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + '@next/swc-win32-x64-msvc@15.2.0': resolution: {integrity: sha512-8+4Z3Z7xa13NdUuUAcpVNA6o76lNPniBd9Xbo02bwXQXnZgFvEopwY2at5+z7yHl47X9qbZpvwatZ2BRo3EdZw==} engines: {node: '>= 10'} @@ -3864,6 +3972,12 @@ packages: cpu: [x64] os: [win32] + '@next/swc-win32-x64-msvc@15.2.3': + resolution: {integrity: sha512-gHYS9tc+G2W0ZC8rBL+H6RdtXIyk40uLiaos0yj5US85FNhbFEndMA2nW3z47nzOWiSvXTZ5kBClc3rD0zJg0w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -7230,6 +7344,15 @@ packages: typescript: optional: true + eslint-config-next@15.2.3: + resolution: {integrity: sha512-VDQwbajhNMFmrhLWVyUXCqsGPN+zz5G8Ys/QwFubfsxTIrkqdx3N3x3QPW+pERz8bzGPP0IgEm8cNbZcd8PFRQ==} + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + eslint-config-prettier@9.1.0: resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true @@ -9681,6 +9804,27 @@ packages: sass: optional: true + next@15.2.3: + resolution: {integrity: sha512-x6eDkZxk2rPpu46E1ZVUWIBhYCLszmUY6fvHBFcbzJ9dD+qRX6vcHusaqqDlnY+VngKzKbAiG2iRCkPbmi8f7w==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.41.2 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + nice-grpc-client-middleware-retry@3.1.9: resolution: {integrity: sha512-BgbsNjuppxD6hoeCfO5gkBA/G69Tq5d9QX35QLdA46NSjKllelC+FlcgSPMlO9VQKCAPDfp4zzzDJZTNtbvzVw==} @@ -14616,6 +14760,36 @@ snapshots: - react-dom - supports-color + '@llamaindex/chat-ui@0.3.1(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@llamaindex/pdf-viewer': 1.3.0(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-collapsible': 1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-hover-card': 1.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-icons': 1.3.2(react@19.0.0) + '@radix-ui/react-progress': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-select': 2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-tabs': 1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + class-variance-authority: 0.7.1 + clsx: 2.1.1 + highlight.js: 11.11.1 + katex: 0.16.21 + lucide-react: 0.453.0(react@19.0.0) + react: 19.0.0 + react-markdown: 8.0.7(@types/react@19.0.10)(react@19.0.0) + rehype-katex: 7.0.1 + remark: 14.0.3 + remark-code-import: 1.2.0 + remark-gfm: 3.0.1 + remark-math: 5.1.1 + tailwind-merge: 2.6.0 + vaul: 0.9.9(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + - react-dom + - supports-color + '@llamaindex/pdf-viewer@1.3.0(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@wojtekmaj/react-hooks': 1.17.2(react@19.0.0) @@ -14800,58 +14974,88 @@ snapshots: '@next/env@15.2.1': {} + '@next/env@15.2.3': {} + '@next/eslint-plugin-next@15.1.0': dependencies: fast-glob: 3.3.1 + '@next/eslint-plugin-next@15.2.3': + dependencies: + fast-glob: 3.3.1 + '@next/swc-darwin-arm64@15.2.0': optional: true '@next/swc-darwin-arm64@15.2.1': optional: true + '@next/swc-darwin-arm64@15.2.3': + optional: true + '@next/swc-darwin-x64@15.2.0': optional: true '@next/swc-darwin-x64@15.2.1': optional: true + '@next/swc-darwin-x64@15.2.3': + optional: true + '@next/swc-linux-arm64-gnu@15.2.0': optional: true '@next/swc-linux-arm64-gnu@15.2.1': optional: true + '@next/swc-linux-arm64-gnu@15.2.3': + optional: true + '@next/swc-linux-arm64-musl@15.2.0': optional: true '@next/swc-linux-arm64-musl@15.2.1': optional: true + '@next/swc-linux-arm64-musl@15.2.3': + optional: true + '@next/swc-linux-x64-gnu@15.2.0': optional: true '@next/swc-linux-x64-gnu@15.2.1': optional: true + '@next/swc-linux-x64-gnu@15.2.3': + optional: true + '@next/swc-linux-x64-musl@15.2.0': optional: true '@next/swc-linux-x64-musl@15.2.1': optional: true + '@next/swc-linux-x64-musl@15.2.3': + optional: true + '@next/swc-win32-arm64-msvc@15.2.0': optional: true '@next/swc-win32-arm64-msvc@15.2.1': optional: true + '@next/swc-win32-arm64-msvc@15.2.3': + optional: true + '@next/swc-win32-x64-msvc@15.2.0': optional: true '@next/swc-win32-x64-msvc@15.2.1': optional: true + '@next/swc-win32-x64-msvc@15.2.3': + optional: true + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -18861,7 +19065,7 @@ snapshots: eslint: 9.16.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@2.4.2)) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.24.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.16.0(jiti@2.4.2)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.24.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.16.0(jiti@2.4.2)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.16.0(jiti@2.4.2)) eslint-plugin-react: 7.37.2(eslint@9.16.0(jiti@2.4.2)) eslint-plugin-react-hooks: 5.1.0(eslint@9.16.0(jiti@2.4.2)) @@ -18892,6 +19096,26 @@ snapshots: - eslint-plugin-import-x - supports-color + eslint-config-next@15.2.3(eslint@9.22.0(jiti@2.4.2))(typescript@5.7.3): + dependencies: + '@next/eslint-plugin-next': 15.2.3 + '@rushstack/eslint-patch': 1.10.5 + '@typescript-eslint/eslint-plugin': 8.24.0(@typescript-eslint/parser@8.24.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.22.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/parser': 8.24.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.7.3) + eslint: 9.22.0(jiti@2.4.2) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.24.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.22.0(jiti@2.4.2)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.22.0(jiti@2.4.2)) + eslint-plugin-react: 7.37.2(eslint@9.22.0(jiti@2.4.2)) + eslint-plugin-react-hooks: 5.1.0(eslint@9.22.0(jiti@2.4.2)) + optionalDependencies: + typescript: 5.7.3 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + eslint-config-prettier@9.1.0(eslint@9.22.0(jiti@2.4.2)): dependencies: eslint: 9.22.0(jiti@2.4.2) @@ -18922,7 +19146,7 @@ snapshots: is-glob: 4.0.3 stable-hash: 0.0.4 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.24.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.16.0(jiti@2.4.2)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.24.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.16.0(jiti@2.4.2)) transitivePeerDependencies: - supports-color @@ -18964,7 +19188,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.24.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.16.0(jiti@2.4.2)): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.24.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.16.0(jiti@2.4.2)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -22409,6 +22633,32 @@ snapshots: - '@babel/core' - babel-plugin-macros + next@15.2.3(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + '@next/env': 15.2.3 + '@swc/counter': 0.1.3 + '@swc/helpers': 0.5.15 + busboy: 1.6.0 + caniuse-lite: 1.0.30001701 + postcss: 8.4.31 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + styled-jsx: 5.1.6(react@19.0.0) + optionalDependencies: + '@next/swc-darwin-arm64': 15.2.3 + '@next/swc-darwin-x64': 15.2.3 + '@next/swc-linux-arm64-gnu': 15.2.3 + '@next/swc-linux-arm64-musl': 15.2.3 + '@next/swc-linux-x64-gnu': 15.2.3 + '@next/swc-linux-x64-musl': 15.2.3 + '@next/swc-win32-arm64-msvc': 15.2.3 + '@next/swc-win32-x64-msvc': 15.2.3 + '@opentelemetry/api': 1.9.0 + sharp: 0.33.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + nice-grpc-client-middleware-retry@3.1.9: dependencies: abort-controller-x: 0.4.3 diff --git a/tsconfig.json b/tsconfig.json index 4326a21209bfb258b0bbb04d155ce99c2ba2dd61..46fc7a20eb7bca789b75dfeb0d52c53b5689dbd9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -196,6 +196,9 @@ }, { "path": "./packages/server/tsconfig.json" + }, + { + "path": "./packages/server-next/tsconfig.json" } ] }