From 487bc7820c2f51fb6ed6daa99b100f31bbb00274 Mon Sep 17 00:00:00 2001 From: thucpn <thucsh2@gmail.com> Date: Tue, 18 Mar 2025 20:32:38 +0700 Subject: [PATCH] feat: @llamaindex/server-next --- packages/server-next/next/.gitignore | 41 +++ packages/server-next/next/.prettierrc.json | 3 + packages/server-next/next/app/favicon.ico | Bin 0 -> 25931 bytes packages/server-next/next/app/globals.css | 153 ++++++++++ packages/server-next/next/app/layout.tsx | 19 ++ packages/server-next/next/app/page.tsx | 15 + packages/server-next/next/eslint.config.mjs | 16 + packages/server-next/next/next.config.ts | 7 + packages/server-next/next/postcss.config.mjs | 5 + packages/server-next/next/tsconfig.json | 33 +++ packages/server-next/package.json | 59 ++++ packages/server-next/src/index.ts | 4 + packages/server-next/src/server.ts | 62 ++++ packages/server-next/src/workflow/stream.ts | 115 ++++++++ packages/server-next/src/workflow/tools.ts | 294 +++++++++++++++++++ packages/server-next/src/workflow/type.ts | 29 ++ packages/server-next/tsconfig.json | 15 + pnpm-lock.yaml | 256 +++++++++++++++- tsconfig.json | 3 + 19 files changed, 1126 insertions(+), 3 deletions(-) create mode 100644 packages/server-next/next/.gitignore create mode 100644 packages/server-next/next/.prettierrc.json create mode 100644 packages/server-next/next/app/favicon.ico create mode 100644 packages/server-next/next/app/globals.css create mode 100644 packages/server-next/next/app/layout.tsx create mode 100644 packages/server-next/next/app/page.tsx create mode 100644 packages/server-next/next/eslint.config.mjs create mode 100644 packages/server-next/next/next.config.ts create mode 100644 packages/server-next/next/postcss.config.mjs create mode 100644 packages/server-next/next/tsconfig.json create mode 100644 packages/server-next/package.json create mode 100644 packages/server-next/src/index.ts create mode 100644 packages/server-next/src/server.ts create mode 100644 packages/server-next/src/workflow/stream.ts create mode 100644 packages/server-next/src/workflow/tools.ts create mode 100644 packages/server-next/src/workflow/type.ts create mode 100644 packages/server-next/tsconfig.json diff --git a/packages/server-next/next/.gitignore b/packages/server-next/next/.gitignore new file mode 100644 index 000000000..5ef6a5207 --- /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 000000000..bf357fbbc --- /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 GIT binary patch literal 25931 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 literal 0 HcmV?d00001 diff --git a/packages/server-next/next/app/globals.css b/packages/server-next/next/app/globals.css new file mode 100644 index 000000000..7f6e07757 --- /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 000000000..756fcce4a --- /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 000000000..48c85c6f9 --- /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 000000000..c85fb67c4 --- /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 000000000..7aee1c485 --- /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 000000000..c7bcb4b1e --- /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 000000000..46419c89f --- /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 000000000..0e83ddabf --- /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 000000000..2f3a0aec6 --- /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 000000000..68a5fdb4c --- /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 000000000..2838ccfcc --- /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 000000000..4e4633661 --- /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 000000000..3f08d1f31 --- /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 000000000..a93775d95 --- /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 6cafdbf19..abd23c247 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 4326a2120..46fc7a20e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -196,6 +196,9 @@ }, { "path": "./packages/server/tsconfig.json" + }, + { + "path": "./packages/server-next/tsconfig.json" } ] } -- GitLab