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