diff --git a/apps/dev-playground/.env.dist b/apps/dev-playground/.env.dist
index 2d3a28f0..aba5db22 100644
--- a/apps/dev-playground/.env.dist
+++ b/apps/dev-playground/.env.dist
@@ -7,6 +7,7 @@ OTEL_EXPORTER_OTLP_ENDPOINT='http://localhost:4318'
OTEL_RESOURCE_ATTRIBUTES='service.sample_attribute=dev'
OTEL_SERVICE_NAME='dev-playground'
DATABRICKS_GENIE_SPACE_ID=
+DATABRICKS_MODEL=
LAKEBASE_ENDPOINT='' # Run: databricks postgres list-endpoints projects/{project-id}/branches/{branch-id} — use the `name` field from the output
PGHOST=
PGUSER=
diff --git a/apps/dev-playground/client/src/routeTree.gen.ts b/apps/dev-playground/client/src/routeTree.gen.ts
index 1f2aff3e..392c354d 100644
--- a/apps/dev-playground/client/src/routeTree.gen.ts
+++ b/apps/dev-playground/client/src/routeTree.gen.ts
@@ -19,6 +19,7 @@ import { Route as DataVisualizationRouteRouteImport } from './routes/data-visual
import { Route as ChartInferenceRouteRouteImport } from './routes/chart-inference.route'
import { Route as ArrowAnalyticsRouteRouteImport } from './routes/arrow-analytics.route'
import { Route as AnalyticsRouteRouteImport } from './routes/analytics.route'
+import { Route as AgentRouteRouteImport } from './routes/agent.route'
import { Route as IndexRouteImport } from './routes/index'
const TypeSafetyRouteRoute = TypeSafetyRouteRouteImport.update({
@@ -71,6 +72,11 @@ const AnalyticsRouteRoute = AnalyticsRouteRouteImport.update({
path: '/analytics',
getParentRoute: () => rootRouteImport,
} as any)
+const AgentRouteRoute = AgentRouteRouteImport.update({
+ id: '/agent',
+ path: '/agent',
+ getParentRoute: () => rootRouteImport,
+} as any)
const IndexRoute = IndexRouteImport.update({
id: '/',
path: '/',
@@ -79,6 +85,7 @@ const IndexRoute = IndexRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
+ '/agent': typeof AgentRouteRoute
'/analytics': typeof AnalyticsRouteRoute
'/arrow-analytics': typeof ArrowAnalyticsRouteRoute
'/chart-inference': typeof ChartInferenceRouteRoute
@@ -92,6 +99,7 @@ export interface FileRoutesByFullPath {
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
+ '/agent': typeof AgentRouteRoute
'/analytics': typeof AnalyticsRouteRoute
'/arrow-analytics': typeof ArrowAnalyticsRouteRoute
'/chart-inference': typeof ChartInferenceRouteRoute
@@ -106,6 +114,7 @@ export interface FileRoutesByTo {
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
+ '/agent': typeof AgentRouteRoute
'/analytics': typeof AnalyticsRouteRoute
'/arrow-analytics': typeof ArrowAnalyticsRouteRoute
'/chart-inference': typeof ChartInferenceRouteRoute
@@ -121,6 +130,7 @@ export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/'
+ | '/agent'
| '/analytics'
| '/arrow-analytics'
| '/chart-inference'
@@ -134,6 +144,7 @@ export interface FileRouteTypes {
fileRoutesByTo: FileRoutesByTo
to:
| '/'
+ | '/agent'
| '/analytics'
| '/arrow-analytics'
| '/chart-inference'
@@ -147,6 +158,7 @@ export interface FileRouteTypes {
id:
| '__root__'
| '/'
+ | '/agent'
| '/analytics'
| '/arrow-analytics'
| '/chart-inference'
@@ -161,6 +173,7 @@ export interface FileRouteTypes {
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
+ AgentRouteRoute: typeof AgentRouteRoute
AnalyticsRouteRoute: typeof AnalyticsRouteRoute
ArrowAnalyticsRouteRoute: typeof ArrowAnalyticsRouteRoute
ChartInferenceRouteRoute: typeof ChartInferenceRouteRoute
@@ -245,6 +258,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AnalyticsRouteRouteImport
parentRoute: typeof rootRouteImport
}
+ '/agent': {
+ id: '/agent'
+ path: '/agent'
+ fullPath: '/agent'
+ preLoaderRoute: typeof AgentRouteRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/': {
id: '/'
path: '/'
@@ -257,6 +277,7 @@ declare module '@tanstack/react-router' {
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
+ AgentRouteRoute: AgentRouteRoute,
AnalyticsRouteRoute: AnalyticsRouteRoute,
ArrowAnalyticsRouteRoute: ArrowAnalyticsRouteRoute,
ChartInferenceRouteRoute: ChartInferenceRouteRoute,
diff --git a/apps/dev-playground/client/src/routes/__root.tsx b/apps/dev-playground/client/src/routes/__root.tsx
index b3ef6233..09364859 100644
--- a/apps/dev-playground/client/src/routes/__root.tsx
+++ b/apps/dev-playground/client/src/routes/__root.tsx
@@ -96,6 +96,14 @@ function RootComponent() {
Chart Inference
+
+
+
diff --git a/apps/dev-playground/client/src/routes/agent.route.tsx b/apps/dev-playground/client/src/routes/agent.route.tsx
new file mode 100644
index 00000000..62b8a580
--- /dev/null
+++ b/apps/dev-playground/client/src/routes/agent.route.tsx
@@ -0,0 +1,31 @@
+import { AgentChat } from "@databricks/appkit-ui/react";
+import { createFileRoute } from "@tanstack/react-router";
+
+export const Route = createFileRoute("/agent")({
+ component: AgentChatRoute,
+});
+
+function AgentChatRoute() {
+ return (
+
+
+
+
+ Agent Chat
+
+
+ Chat with the agent via POST /invocations (Responses
+ API SSE stream).
+
+
+
+
+
+
+ );
+}
diff --git a/apps/dev-playground/client/src/routes/index.tsx b/apps/dev-playground/client/src/routes/index.tsx
index a0aec851..d9d05938 100644
--- a/apps/dev-playground/client/src/routes/index.tsx
+++ b/apps/dev-playground/client/src/routes/index.tsx
@@ -200,6 +200,25 @@ function IndexRoute() {
+
+
+
+
+ Agent Chat
+
+
+ Chat with a LangChain/LangGraph AI agent powered by the AppKit
+ Agent Plugin. Features Responses API SSE streaming and tool call
+ rendering.
+
+
+
+
diff --git a/apps/dev-playground/server/agent-tools.ts b/apps/dev-playground/server/agent-tools.ts
new file mode 100644
index 00000000..e2a1d5ff
--- /dev/null
+++ b/apps/dev-playground/server/agent-tools.ts
@@ -0,0 +1,52 @@
+import { tool } from "@langchain/core/tools";
+import { z } from "zod";
+import { toJSONSchema } from "zod/v4/core";
+
+/**
+ * Workaround: @databricks/langchainjs@0.1.0 calls `schema.toJSONSchema()`
+ * as a method, but zod v4 only exposes it as a standalone function.
+ * Patch the schema so ChatDatabricks can convert it.
+ */
+function patchZodSchema
(schema: T): T {
+ (schema as any).toJSONSchema = () => toJSONSchema(schema);
+ return schema;
+}
+
+export const weatherTool = tool(
+ async ({ location }) => {
+ const conditions = ["sunny", "partly cloudy", "rainy", "windy"];
+ const condition = conditions[Math.floor(Math.random() * conditions.length)];
+ const temp = Math.floor(Math.random() * 30) + 50;
+ return `Weather in ${location}: ${condition}, ${temp}°F`;
+ },
+ {
+ name: "get_weather",
+ description: "Get the current weather for a location",
+ schema: patchZodSchema(
+ z.object({
+ location: z.string().describe("City name, e.g. 'San Francisco'"),
+ }),
+ ),
+ },
+);
+
+export const timeTool = tool(
+ async ({ timezone }) => {
+ const tz = timezone ?? "UTC";
+ return `Current time in ${tz}: ${new Date().toLocaleString("en-US", { timeZone: tz })}`;
+ },
+ {
+ name: "get_current_time",
+ description: "Get the current date and time in a timezone",
+ schema: patchZodSchema(
+ z.object({
+ timezone: z
+ .string()
+ .optional()
+ .describe("IANA timezone, e.g. 'America/New_York'. Defaults to UTC"),
+ }),
+ ),
+ },
+);
+
+export const demoTools = [weatherTool, timeTool];
diff --git a/apps/dev-playground/server/index.ts b/apps/dev-playground/server/index.ts
index d54781ea..2fedf02b 100644
--- a/apps/dev-playground/server/index.ts
+++ b/apps/dev-playground/server/index.ts
@@ -1,6 +1,7 @@
import "reflect-metadata";
-import { analytics, createApp, genie, server } from "@databricks/appkit";
+import { agent, analytics, createApp, genie, server } from "@databricks/appkit";
import { WorkspaceClient } from "@databricks/sdk-experimental";
+import { demoTools } from "./agent-tools";
import { lakebaseExamples } from "./lakebase-examples-plugin";
import { reconnect } from "./reconnect-plugin";
import { telemetryExamples } from "./telemetry-example-plugin";
@@ -25,11 +26,25 @@ createApp({
spaces: { demo: process.env.DATABRICKS_GENIE_SPACE_ID ?? "placeholder" },
}),
lakebaseExamples(),
+ agent({
+ model: process.env.DATABRICKS_MODEL || "databricks-claude-sonnet-4-5",
+ systemPrompt:
+ "You are a helpful assistant. Use tools when appropriate — for example, use get_weather for weather questions, and get_current_time for time queries.",
+ }),
],
...(process.env.APPKIT_E2E_TEST && { client: createMockClient() }),
-}).then((appkit) => {
+}).then(async (appkit) => {
+ // Add tools (and optionally MCP servers) after app creation
+ await appkit.agent.addTools(demoTools);
+
appkit.server
.extend((app) => {
+ // Rewrite to use standard Databricks Apps convention: /invocations at root
+ app.post("/invocations", (req, res) => {
+ req.url = "/api/agent";
+ app(req, res);
+ });
+
app.get("/sp", (_req, res) => {
appkit.analytics
.query("SELECT * FROM samples.nyctaxi.trips;")
diff --git a/docs/docs/api/appkit/Interface.AgentInterface.md b/docs/docs/api/appkit/Interface.AgentInterface.md
new file mode 100644
index 00000000..0736fe32
--- /dev/null
+++ b/docs/docs/api/appkit/Interface.AgentInterface.md
@@ -0,0 +1,43 @@
+# Interface: AgentInterface
+
+Contract that agent implementations must fulfil.
+
+The plugin calls `invoke()` for non-streaming requests and `stream()` for
+SSE streaming. Implementations are responsible for translating their SDK's
+output into Responses API types.
+
+## Methods
+
+### invoke()
+
+```ts
+invoke(params: InvokeParams): Promise;
+```
+
+#### Parameters
+
+| Parameter | Type |
+| ------ | ------ |
+| `params` | [`InvokeParams`](Interface.InvokeParams.md) |
+
+#### Returns
+
+`Promise`\<`ResponseOutputItem`[]\>
+
+***
+
+### stream()
+
+```ts
+stream(params: InvokeParams): AsyncGenerator;
+```
+
+#### Parameters
+
+| Parameter | Type |
+| ------ | ------ |
+| `params` | [`InvokeParams`](Interface.InvokeParams.md) |
+
+#### Returns
+
+`AsyncGenerator`\<[`ResponseStreamEvent`](TypeAlias.ResponseStreamEvent.md)\>
diff --git a/docs/docs/api/appkit/Interface.BasePluginConfig.md b/docs/docs/api/appkit/Interface.BasePluginConfig.md
index a7faffc6..1cf97ca0 100644
--- a/docs/docs/api/appkit/Interface.BasePluginConfig.md
+++ b/docs/docs/api/appkit/Interface.BasePluginConfig.md
@@ -2,6 +2,10 @@
Base configuration interface for AppKit plugins
+## Extended by
+
+- [`IAgentConfig`](Interface.IAgentConfig.md)
+
## Indexable
```ts
diff --git a/docs/docs/api/appkit/Interface.IAgentConfig.md b/docs/docs/api/appkit/Interface.IAgentConfig.md
new file mode 100644
index 00000000..2f288c04
--- /dev/null
+++ b/docs/docs/api/appkit/Interface.IAgentConfig.md
@@ -0,0 +1,138 @@
+# Interface: IAgentConfig
+
+Base configuration interface for AppKit plugins.
+
+When you do **not** set `agentInstance`, the agent is built from `model`, `tools`, and `mcpServers`. You can then add more tools or MCP servers after app creation via `appkit.agent.addTools()` and `appkit.agent.addMcpServers()` (see [agent](Variable.agent.md) Plugin API).
+
+## Extends
+
+- [`BasePluginConfig`](Interface.BasePluginConfig.md)
+
+## Indexable
+
+```ts
+[key: string]: unknown
+```
+
+## Properties
+
+### agentInstance?
+
+```ts
+optional agentInstance: AgentInterface;
+```
+
+Pre-built agent implementing AgentInterface.
+When provided the plugin skips internal LangGraph setup and delegates
+directly to this instance. Use this to bring your own agent
+implementation or a different LangChain variant.
+
+---
+
+### host?
+
+```ts
+optional host: string;
+```
+
+#### Inherited from
+
+[`BasePluginConfig`](Interface.BasePluginConfig.md).[`host`](Interface.BasePluginConfig.md#host)
+
+---
+
+### maxTokens?
+
+```ts
+optional maxTokens: number;
+```
+
+Max tokens to generate (default 2000). Ignored when `agentInstance` is provided.
+
+---
+
+### mcpServers?
+
+```ts
+optional mcpServers: DatabricksMCPServer[];
+```
+
+MCP servers for Databricks tool integration. Ignored when `agentInstance` is provided. You can add more at runtime with `appkit.agent.addMcpServers()`.
+
+---
+
+### model?
+
+```ts
+optional model: string;
+```
+
+Databricks model serving endpoint name (e.g. "databricks-claude-sonnet-4-5").
+Falls back to DATABRICKS_MODEL env var.
+Ignored when `agentInstance` is provided.
+
+---
+
+### name?
+
+```ts
+optional name: string;
+```
+
+#### Inherited from
+
+[`BasePluginConfig`](Interface.BasePluginConfig.md).[`name`](Interface.BasePluginConfig.md#name)
+
+---
+
+### systemPrompt?
+
+```ts
+optional systemPrompt: string;
+```
+
+System prompt injected at the start of every conversation
+
+---
+
+### telemetry?
+
+```ts
+optional telemetry: TelemetryOptions;
+```
+
+#### Inherited from
+
+[`BasePluginConfig`](Interface.BasePluginConfig.md).[`telemetry`](Interface.BasePluginConfig.md#telemetry)
+
+---
+
+### temperature?
+
+```ts
+optional temperature: number;
+```
+
+Sampling temperature (0.0-1.0, default 0.1). Ignored when `agentInstance` is provided.
+
+---
+
+### tools?
+
+```ts
+optional tools: StructuredTool[];
+```
+
+Additional LangChain tools to register alongside MCP tools. Ignored when `agentInstance` is provided. You can add more at runtime with `appkit.agent.addTools()`.
+
+---
+
+### useResponsesApi?
+
+```ts
+optional useResponsesApi: boolean;
+```
+
+Whether ChatDatabricks calls the upstream model using the Responses API
+instead of the Chat Completions API. Default: false.
+Ignored when `agentInstance` is provided.
diff --git a/docs/docs/api/appkit/Interface.InvokeParams.md b/docs/docs/api/appkit/Interface.InvokeParams.md
new file mode 100644
index 00000000..f4f360ea
--- /dev/null
+++ b/docs/docs/api/appkit/Interface.InvokeParams.md
@@ -0,0 +1,38 @@
+# Interface: InvokeParams
+
+Agent interface types for the AppKit Agent Plugin.
+
+These types define the contract between the plugin framework and agent
+implementations. They mirror the OpenAI Responses API SSE format without
+requiring the `openai` package as a dependency.
+
+## Properties
+
+### chat\_history?
+
+```ts
+optional chat_history: {
+ content: string;
+ role: string;
+}[];
+```
+
+#### content
+
+```ts
+content: string;
+```
+
+#### role
+
+```ts
+role: string;
+```
+
+***
+
+### input
+
+```ts
+input: string;
+```
diff --git a/docs/docs/api/appkit/Interface.StandardAgent.md b/docs/docs/api/appkit/Interface.StandardAgent.md
new file mode 100644
index 00000000..c1d483e1
--- /dev/null
+++ b/docs/docs/api/appkit/Interface.StandardAgent.md
@@ -0,0 +1,53 @@
+# Interface: StandardAgent
+
+## Implements
+
+- [`AgentInterface`](Interface.AgentInterface.md)
+
+## Methods
+
+### invoke()
+
+```ts
+invoke(params: InvokeParams): Promise;
+```
+
+#### Parameters
+
+| Parameter | Type |
+| ------ | ------ |
+| `params` | [`InvokeParams`](Interface.InvokeParams.md) |
+
+#### Returns
+
+`Promise`\<`ResponseOutputItem`[]\>
+
+#### Implementation of
+
+```ts
+AgentInterface.invoke
+```
+
+***
+
+### stream()
+
+```ts
+stream(params: InvokeParams): AsyncGenerator;
+```
+
+#### Parameters
+
+| Parameter | Type |
+| ------ | ------ |
+| `params` | [`InvokeParams`](Interface.InvokeParams.md) |
+
+#### Returns
+
+`AsyncGenerator`\<[`ResponseStreamEvent`](TypeAlias.ResponseStreamEvent.md)\>
+
+#### Implementation of
+
+```ts
+AgentInterface.stream
+```
diff --git a/docs/docs/api/appkit/TypeAlias.ResponseStreamEvent.md b/docs/docs/api/appkit/TypeAlias.ResponseStreamEvent.md
new file mode 100644
index 00000000..4a4fb290
--- /dev/null
+++ b/docs/docs/api/appkit/TypeAlias.ResponseStreamEvent.md
@@ -0,0 +1,11 @@
+# Type Alias: ResponseStreamEvent
+
+```ts
+type ResponseStreamEvent =
+ | ResponseOutputItemAddedEvent
+ | ResponseOutputItemDoneEvent
+ | ResponseTextDeltaEvent
+ | ResponseCompletedEvent
+ | ResponseErrorEvent
+ | ResponseFailedEvent;
+```
diff --git a/docs/docs/api/appkit/Variable.agent.md b/docs/docs/api/appkit/Variable.agent.md
new file mode 100644
index 00000000..0a499cf4
--- /dev/null
+++ b/docs/docs/api/appkit/Variable.agent.md
@@ -0,0 +1,20 @@
+# Variable: agent
+
+```ts
+const agent: ToPlugin;
+```
+
+Plugin factory for the AppKit agent (LangChain/LangGraph). Use in `createApp({ plugins: [agent({ ... })] })`. Configuration: [`IAgentConfig`](Interface.IAgentConfig.md).
+
+## Plugin API (runtime)
+
+After `const appkit = await createApp({ plugins: [..., agent(config)] })`, `appkit.agent` exposes:
+
+| Method | Description |
+| ------ | ------ |
+| `invoke(messages)` | Run the agent (non-streaming). Returns the assistant reply text. |
+| `stream(messages)` | Run the agent with streaming. Yields [`ResponseStreamEvent`](TypeAlias.ResponseStreamEvent.md)s. |
+| `addTools(tools)` | Add LangChain tools after app creation. Rebuilds the agent. **Only when not using `agentInstance`.** |
+| `addMcpServers(servers)` | Add MCP servers after app creation. Rebuilds the agent and MCP client. **Only when not using `agentInstance`.** |
+
+When the plugin is configured with `model` and optional `tools` / `mcpServers` (i.e. without `agentInstance`), you can call `appkit.agent.addTools([...])` and `appkit.agent.addMcpServers([...])` in the `.then()` of `createApp()` to register additional tools or MCP servers at runtime.
diff --git a/docs/docs/api/appkit/index.md b/docs/docs/api/appkit/index.md
index 4ad80820..5356bda8 100644
--- a/docs/docs/api/appkit/index.md
+++ b/docs/docs/api/appkit/index.md
@@ -30,10 +30,13 @@ plugin architecture, and React integration.
| Interface | Description |
| ------ | ------ |
+| [AgentInterface](Interface.AgentInterface.md) | Contract that agent implementations must fulfil. |
| [BasePluginConfig](Interface.BasePluginConfig.md) | Base configuration interface for AppKit plugins |
| [CacheConfig](Interface.CacheConfig.md) | Configuration for caching |
| [DatabaseCredential](Interface.DatabaseCredential.md) | Database credentials with OAuth token for Postgres connection |
| [GenerateDatabaseCredentialRequest](Interface.GenerateDatabaseCredentialRequest.md) | Request parameters for generating database OAuth credentials |
+| [IAgentConfig](Interface.IAgentConfig.md) | Base configuration interface for AppKit plugins |
+| [InvokeParams](Interface.InvokeParams.md) | Agent interface types for the AppKit Agent Plugin. |
| [ITelemetry](Interface.ITelemetry.md) | Plugin-facing interface for OpenTelemetry instrumentation. Provides a thin abstraction over OpenTelemetry APIs for plugins. |
| [LakebasePoolConfig](Interface.LakebasePoolConfig.md) | Configuration for creating a Lakebase connection pool |
| [PluginManifest](Interface.PluginManifest.md) | Plugin manifest that declares metadata and resource requirements. Attached to plugin classes as a static property. |
@@ -42,6 +45,7 @@ plugin architecture, and React integration.
| [ResourceEntry](Interface.ResourceEntry.md) | Internal representation of a resource in the registry. Extends ResourceRequirement with resolution state and plugin ownership. |
| [ResourceFieldEntry](Interface.ResourceFieldEntry.md) | Defines a single field for a resource. Each field has its own environment variable and optional description. Single-value types use one key (e.g. id); multi-value types (database, secret) use multiple (e.g. instance_name, database_name or scope, key). |
| [ResourceRequirement](Interface.ResourceRequirement.md) | Declares a resource requirement for a plugin. Can be defined statically in a manifest or dynamically via getResourceRequirements(). |
+| [StandardAgent](Interface.StandardAgent.md) | - |
| [StreamExecutionSettings](Interface.StreamExecutionSettings.md) | Configuration for streaming execution with default and user-scoped settings |
| [TelemetryConfig](Interface.TelemetryConfig.md) | OpenTelemetry configuration for AppKit applications |
| [ValidationResult](Interface.ValidationResult.md) | Result of validating all registered resources against the environment. |
@@ -54,12 +58,14 @@ plugin architecture, and React integration.
| [IAppRouter](TypeAlias.IAppRouter.md) | Express router type for plugin route registration |
| [PluginData](TypeAlias.PluginData.md) | - |
| [ResourcePermission](TypeAlias.ResourcePermission.md) | Union of all possible permission levels across all resource types. |
+| [ResponseStreamEvent](TypeAlias.ResponseStreamEvent.md) | - |
| [ToPlugin](TypeAlias.ToPlugin.md) | - |
## Variables
| Variable | Description |
| ------ | ------ |
+| [agent](Variable.agent.md) | Agent plugin factory; runtime API includes invoke, stream, addTools, addMcpServers. |
| [sql](Variable.sql.md) | SQL helper namespace |
## Functions
diff --git a/docs/docs/api/appkit/typedoc-sidebar.ts b/docs/docs/api/appkit/typedoc-sidebar.ts
index 2f17b1d2..d4718669 100644
--- a/docs/docs/api/appkit/typedoc-sidebar.ts
+++ b/docs/docs/api/appkit/typedoc-sidebar.ts
@@ -82,6 +82,11 @@ const typedocSidebar: SidebarsConfig = {
type: "category",
label: "Interfaces",
items: [
+ {
+ type: "doc",
+ id: "api/appkit/Interface.AgentInterface",
+ label: "AgentInterface"
+ },
{
type: "doc",
id: "api/appkit/Interface.BasePluginConfig",
@@ -102,6 +107,16 @@ const typedocSidebar: SidebarsConfig = {
id: "api/appkit/Interface.GenerateDatabaseCredentialRequest",
label: "GenerateDatabaseCredentialRequest"
},
+ {
+ type: "doc",
+ id: "api/appkit/Interface.IAgentConfig",
+ label: "IAgentConfig"
+ },
+ {
+ type: "doc",
+ id: "api/appkit/Interface.InvokeParams",
+ label: "InvokeParams"
+ },
{
type: "doc",
id: "api/appkit/Interface.ITelemetry",
@@ -142,6 +157,11 @@ const typedocSidebar: SidebarsConfig = {
id: "api/appkit/Interface.ResourceRequirement",
label: "ResourceRequirement"
},
+ {
+ type: "doc",
+ id: "api/appkit/Interface.StandardAgent",
+ label: "StandardAgent"
+ },
{
type: "doc",
id: "api/appkit/Interface.StreamExecutionSettings",
@@ -183,6 +203,11 @@ const typedocSidebar: SidebarsConfig = {
id: "api/appkit/TypeAlias.ResourcePermission",
label: "ResourcePermission"
},
+ {
+ type: "doc",
+ id: "api/appkit/TypeAlias.ResponseStreamEvent",
+ label: "ResponseStreamEvent"
+ },
{
type: "doc",
id: "api/appkit/TypeAlias.ToPlugin",
@@ -194,6 +219,11 @@ const typedocSidebar: SidebarsConfig = {
type: "category",
label: "Variables",
items: [
+ {
+ type: "doc",
+ id: "api/appkit/Variable.agent",
+ label: "agent"
+ },
{
type: "doc",
id: "api/appkit/Variable.sql",
diff --git a/packages/appkit-ui/src/react/agent-chat/agent-chat-message.tsx b/packages/appkit-ui/src/react/agent-chat/agent-chat-message.tsx
new file mode 100644
index 00000000..a8b3df1f
--- /dev/null
+++ b/packages/appkit-ui/src/react/agent-chat/agent-chat-message.tsx
@@ -0,0 +1,45 @@
+import { AgentChatPart } from "./agent-chat-part";
+import type { ChatMessage } from "./types";
+
+export interface AgentChatMessageProps {
+ message: ChatMessage;
+ isLast?: boolean;
+ isStreaming?: boolean;
+}
+
+/** Renders a single chat message bubble (user or assistant with parts). */
+export function AgentChatMessage({
+ message,
+ isLast = false,
+ isStreaming = false,
+}: AgentChatMessageProps) {
+ if (message.role === "user") {
+ return (
+
+
+ You
+
+
+ {message.content}
+
+
+ );
+ }
+
+ return (
+
+
+ Agent
+
+
+ {message.parts.map((part, j) => (
+
+ ))}
+
+
+ );
+}
diff --git a/packages/appkit-ui/src/react/agent-chat/agent-chat-part.tsx b/packages/appkit-ui/src/react/agent-chat/agent-chat-part.tsx
new file mode 100644
index 00000000..4da5a1fa
--- /dev/null
+++ b/packages/appkit-ui/src/react/agent-chat/agent-chat-part.tsx
@@ -0,0 +1,46 @@
+import type { AssistantPart } from "./types";
+import { tryFormatJson } from "./utils";
+
+export interface AgentChatPartProps {
+ part: AssistantPart;
+ showCursor?: boolean;
+}
+
+/** Renders a single assistant part: text, function_call, or function_call_output. */
+export function AgentChatPart({
+ part,
+ showCursor = false,
+}: AgentChatPartProps) {
+ if (part.type === "text") {
+ return (
+
+ {part.content}
+ {showCursor && |}
+
+ );
+ }
+
+ if (part.type === "function_call") {
+ return (
+
+
+ Tool: {part.name}
+
+
+ {tryFormatJson(part.arguments)}
+
+
+ );
+ }
+
+ return (
+
+
+ Result
+
+
+ {tryFormatJson(part.output)}
+
+
+ );
+}
diff --git a/packages/appkit-ui/src/react/agent-chat/agent-chat.tsx b/packages/appkit-ui/src/react/agent-chat/agent-chat.tsx
new file mode 100644
index 00000000..1bda5061
--- /dev/null
+++ b/packages/appkit-ui/src/react/agent-chat/agent-chat.tsx
@@ -0,0 +1,85 @@
+import { useEffect, useRef } from "react";
+import { cn } from "../lib/utils";
+import { Button, Card } from "../ui";
+import { AgentChatMessage } from "./agent-chat-message";
+import type { AgentChatProps, ChatMessage } from "./types";
+import { useAgentChat } from "./use-agent-chat";
+
+/** Agent chat UI: message list + input, wired to POST /invocations SSE streaming. */
+export function AgentChat({
+ invokeUrl = "/invocations",
+ placeholder = "Type a message...",
+ emptyMessage = "Send a message to start.",
+ className,
+}: AgentChatProps) {
+ const scrollRef = useRef(null);
+ const {
+ displayMessages,
+ loading,
+ input,
+ setInput,
+ handleSubmit,
+ isStreamingText,
+ } = useAgentChat({ invokeUrl });
+
+ const contentLength = displayMessages.length;
+ // biome-ignore lint/correctness/useExhaustiveDependencies: deps used as triggers for auto-scroll
+ useEffect(() => {
+ scrollRef.current?.scrollTo({
+ top: scrollRef.current.scrollHeight,
+ behavior: "smooth",
+ });
+ }, [contentLength, isStreamingText]);
+
+ return (
+
+
+
+ {displayMessages.length === 0 && (
+
{emptyMessage}
+ )}
+ {displayMessages.map((msg, i) => (
+
+ ))}
+
+
+
+
+
+ );
+}
+
+function MessageItem({
+ message,
+ isLast,
+ isStreaming,
+}: {
+ message: ChatMessage;
+ isLast: boolean;
+ isStreaming: boolean;
+}) {
+ return (
+
+ );
+}
diff --git a/packages/appkit-ui/src/react/agent-chat/index.ts b/packages/appkit-ui/src/react/agent-chat/index.ts
new file mode 100644
index 00000000..214204b8
--- /dev/null
+++ b/packages/appkit-ui/src/react/agent-chat/index.ts
@@ -0,0 +1,6 @@
+export { AgentChat } from "./agent-chat";
+export { AgentChatMessage } from "./agent-chat-message";
+export { AgentChatPart } from "./agent-chat-part";
+export type * from "./types";
+export { useAgentChat } from "./use-agent-chat";
+export { serializeForApi, tryFormatJson } from "./utils";
diff --git a/packages/appkit-ui/src/react/agent-chat/types.ts b/packages/appkit-ui/src/react/agent-chat/types.ts
new file mode 100644
index 00000000..519b4fd8
--- /dev/null
+++ b/packages/appkit-ui/src/react/agent-chat/types.ts
@@ -0,0 +1,66 @@
+export type TextPart = { type: "text"; content: string };
+export type FunctionCallPart = {
+ type: "function_call";
+ id: string;
+ callId: string;
+ name: string;
+ arguments: string;
+};
+export type FunctionCallOutputPart = {
+ type: "function_call_output";
+ id: string;
+ callId: string;
+ output: string;
+};
+export type AssistantPart =
+ | TextPart
+ | FunctionCallPart
+ | FunctionCallOutputPart;
+
+export type ChatMessage =
+ | { role: "user"; content: string }
+ | { role: "assistant"; parts: AssistantPart[] };
+
+export interface SSEItem {
+ type?: string;
+ id?: string;
+ call_id?: string;
+ name?: string;
+ arguments?: string;
+ output?: string;
+}
+
+export interface SSEEvent {
+ type?: string;
+ delta?: string;
+ error?: string;
+ item?: SSEItem;
+}
+
+export interface UseAgentChatOptions {
+ /** POST URL for invocations (Responses API). Default: "/invocations" */
+ invokeUrl?: string;
+}
+
+export interface UseAgentChatReturn {
+ messages: ChatMessage[];
+ loading: boolean;
+ input: string;
+ setInput: (value: string) => void;
+ handleSubmit: (e: React.FormEvent) => void;
+ /** Messages + current streaming state for display */
+ displayMessages: ChatMessage[];
+ /** True when the last message is still streaming text */
+ isStreamingText: boolean;
+}
+
+export interface AgentChatProps {
+ /** POST URL for invocations. Default: "/invocations" */
+ invokeUrl?: string;
+ /** Placeholder for the message input */
+ placeholder?: string;
+ /** Empty state text when there are no messages */
+ emptyMessage?: string;
+ /** Additional CSS class for the root container */
+ className?: string;
+}
diff --git a/packages/appkit-ui/src/react/agent-chat/use-agent-chat.ts b/packages/appkit-ui/src/react/agent-chat/use-agent-chat.ts
new file mode 100644
index 00000000..0e3ba0f7
--- /dev/null
+++ b/packages/appkit-ui/src/react/agent-chat/use-agent-chat.ts
@@ -0,0 +1,174 @@
+import { useCallback, useMemo, useState } from "react";
+import type {
+ AssistantPart,
+ ChatMessage,
+ SSEEvent,
+ UseAgentChatOptions,
+ UseAgentChatReturn,
+} from "./types";
+import { serializeForApi } from "./utils";
+
+/**
+ * Manages agent chat state and streaming via POST /invocations (Responses API SSE).
+ * Returns messages, loading state, input state, submit handler, and derived display list.
+ */
+export function useAgentChat(
+ options: UseAgentChatOptions = {},
+): UseAgentChatReturn {
+ const { invokeUrl = "/invocations" } = options;
+ const [messages, setMessages] = useState([]);
+ const [streamingParts, setStreamingParts] = useState([]);
+ const [streamingText, setStreamingText] = useState("");
+ const [loading, setLoading] = useState(false);
+ const [input, setInput] = useState("");
+
+ const handleSubmit = useCallback(
+ async (e: React.FormEvent) => {
+ e.preventDefault();
+ const text = input.trim();
+ if (!text || loading) return;
+
+ const userMessage: ChatMessage = { role: "user", content: text };
+ setInput("");
+ setMessages((prev) => [...prev, userMessage]);
+ setLoading(true);
+ setStreamingParts([]);
+ setStreamingText("");
+
+ try {
+ const response = await fetch(invokeUrl, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ input: [...messages, userMessage].map(serializeForApi),
+ stream: true,
+ }),
+ });
+
+ if (!response.ok) {
+ const err = await response.json().catch(() => ({}));
+ throw new Error(
+ (err as { error?: string }).error ?? `HTTP ${response.status}`,
+ );
+ }
+
+ const reader = response.body?.getReader();
+ if (!reader) throw new Error("No response body");
+
+ const decoder = new TextDecoder();
+ let buffer = "";
+ let fullText = "";
+ const parts: AssistantPart[] = [];
+ const seenItemIds = new Set();
+
+ for (;;) {
+ const { done, value } = await reader.read();
+ if (done) break;
+ buffer += decoder.decode(value, { stream: true });
+ const lines = buffer.split("\n");
+ buffer = lines.pop() ?? "";
+
+ for (const line of lines) {
+ if (!line.startsWith("data: ")) continue;
+ const payload = line.slice(6);
+ if (payload === "[DONE]") continue;
+
+ let data: SSEEvent;
+ try {
+ data = JSON.parse(payload);
+ } catch {
+ continue;
+ }
+
+ if (data.type === "response.output_item.added" && data.item) {
+ const item = data.item;
+ const id =
+ item.id ?? `${item.type}_${Date.now()}_${Math.random()}`;
+ if (seenItemIds.has(id)) continue;
+ seenItemIds.add(id);
+
+ if (item.type === "function_call" && item.name != null) {
+ parts.push({
+ type: "function_call",
+ id,
+ callId: item.call_id ?? id,
+ name: item.name,
+ arguments: item.arguments ?? "{}",
+ });
+ } else if (
+ item.type === "function_call_output" &&
+ item.call_id != null
+ ) {
+ parts.push({
+ type: "function_call_output",
+ id,
+ callId: item.call_id,
+ output: item.output ?? "",
+ });
+ }
+ setStreamingParts([...parts]);
+ }
+
+ if (data.type === "response.output_text.delta" && data.delta) {
+ fullText += data.delta;
+ setStreamingText(fullText);
+ }
+ }
+ }
+
+ const finalParts: AssistantPart[] = [...parts];
+ if (fullText) {
+ finalParts.push({ type: "text", content: fullText });
+ }
+
+ setMessages((prev) => [
+ ...prev,
+ { role: "assistant", parts: finalParts },
+ ]);
+ setStreamingParts([]);
+ setStreamingText("");
+ } catch (err) {
+ const errorText =
+ err instanceof Error ? err.message : "Something went wrong";
+ setMessages((prev) => [
+ ...prev,
+ {
+ role: "assistant",
+ parts: [{ type: "text", content: `Error: ${errorText}` }],
+ },
+ ]);
+ setStreamingParts([]);
+ setStreamingText("");
+ } finally {
+ setLoading(false);
+ }
+ },
+ [input, loading, messages, invokeUrl],
+ );
+
+ const displayMessages = useMemo(() => {
+ if (loading && (streamingParts.length > 0 || streamingText)) {
+ const streamingPartList: AssistantPart[] = [...streamingParts];
+ if (streamingText) {
+ streamingPartList.push({ type: "text", content: streamingText });
+ }
+ return [
+ ...messages,
+ { role: "assistant" as const, parts: streamingPartList },
+ ];
+ }
+ return messages;
+ }, [messages, streamingParts, streamingText, loading]);
+
+ const isStreamingText = Boolean(loading && streamingText);
+
+ return {
+ messages,
+ loading,
+ input,
+ setInput,
+ handleSubmit,
+ displayMessages,
+ isStreamingText,
+ };
+}
diff --git a/packages/appkit-ui/src/react/agent-chat/utils.ts b/packages/appkit-ui/src/react/agent-chat/utils.ts
new file mode 100644
index 00000000..497423f7
--- /dev/null
+++ b/packages/appkit-ui/src/react/agent-chat/utils.ts
@@ -0,0 +1,32 @@
+import type { ChatMessage } from "./types";
+
+/** Serialize chat message for the Responses API request body. */
+export function serializeForApi(msg: ChatMessage): Record {
+ if (msg.role === "user") {
+ return { role: "user", content: msg.content };
+ }
+ const content = msg.parts.map((p) => {
+ if (p.type === "text")
+ return { type: "output_text" as const, text: p.content };
+ if (p.type === "function_call")
+ return {
+ type: "function_call" as const,
+ name: p.name,
+ arguments: p.arguments,
+ };
+ return {
+ type: "function_call_output" as const,
+ call_id: p.callId,
+ output: p.output,
+ };
+ });
+ return { role: "assistant", content };
+}
+
+export function tryFormatJson(s: string): string {
+ try {
+ return JSON.stringify(JSON.parse(s), null, 2);
+ } catch {
+ return s;
+ }
+}
diff --git a/packages/appkit-ui/src/react/index.ts b/packages/appkit-ui/src/react/index.ts
index dc52a2f3..52150a5f 100644
--- a/packages/appkit-ui/src/react/index.ts
+++ b/packages/appkit-ui/src/react/index.ts
@@ -1,3 +1,4 @@
+export * from "./agent-chat";
export * from "./charts";
export * from "./genie";
export * from "./hooks";
diff --git a/packages/appkit/package.json b/packages/appkit/package.json
index 699a1986..1d057033 100644
--- a/packages/appkit/package.json
+++ b/packages/appkit/package.json
@@ -44,6 +44,30 @@
"tarball": "rm -rf tmp && pnpm dist && npm pack ./tmp --pack-destination ./tmp",
"typecheck": "tsc --noEmit"
},
+ "peerDependencies": {
+ "@arizeai/openinference-instrumentation-langchain": ">=4.0.0",
+ "@databricks/langchainjs": ">=0.1.0",
+ "@langchain/core": ">=1.0.0",
+ "@langchain/langgraph": ">=1.0.0",
+ "@langchain/mcp-adapters": ">=1.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@arizeai/openinference-instrumentation-langchain": {
+ "optional": true
+ },
+ "@databricks/langchainjs": {
+ "optional": true
+ },
+ "@langchain/core": {
+ "optional": true
+ },
+ "@langchain/langgraph": {
+ "optional": true
+ },
+ "@langchain/mcp-adapters": {
+ "optional": true
+ }
+ },
"dependencies": {
"@databricks/lakebase": "workspace:*",
"@databricks/sdk-experimental": "^0.16.0",
@@ -71,6 +95,7 @@
"shared": "workspace:*",
"vite": "npm:rolldown-vite@7.1.14",
"ws": "^8.18.3",
+ "zod": "^4.1.13",
"zod-to-ts": "^2.0.0"
},
"devDependencies": {
diff --git a/packages/appkit/src/index.ts b/packages/appkit/src/index.ts
index 0d762fde..64201c04 100644
--- a/packages/appkit/src/index.ts
+++ b/packages/appkit/src/index.ts
@@ -48,7 +48,14 @@ export {
} from "./errors";
// Plugin authoring
export { Plugin, type ToPlugin, toPlugin } from "./plugin";
-export { analytics, genie, lakebase, server } from "./plugins";
+export { agent, analytics, genie, lakebase, server } from "./plugins";
+export type {
+ AgentInterface,
+ IAgentConfig,
+ InvokeParams,
+ ResponseStreamEvent,
+ StandardAgent,
+} from "./plugins/agent";
// Registry types and utilities for plugin manifests
export type {
ConfigSchema,
diff --git a/packages/appkit/src/plugins/agent/agent-interface.ts b/packages/appkit/src/plugins/agent/agent-interface.ts
new file mode 100644
index 00000000..2e8a65bc
--- /dev/null
+++ b/packages/appkit/src/plugins/agent/agent-interface.ts
@@ -0,0 +1,121 @@
+/**
+ * Agent interface types for the AppKit Agent Plugin.
+ *
+ * These types define the contract between the plugin framework and agent
+ * implementations. They mirror the OpenAI Responses API SSE format without
+ * requiring the `openai` package as a dependency.
+ */
+
+// ---------------------------------------------------------------------------
+// Invoke params
+// ---------------------------------------------------------------------------
+
+export interface InvokeParams {
+ input: string;
+ chat_history?: Array<{ role: string; content: string }>;
+}
+
+// ---------------------------------------------------------------------------
+// Responses API output types (minimal subset)
+// ---------------------------------------------------------------------------
+
+export interface ResponseOutputTextContent {
+ type: "output_text";
+ text: string;
+ annotations: unknown[];
+}
+
+export interface ResponseOutputMessage {
+ id: string;
+ type: "message";
+ role: "assistant";
+ status: "in_progress" | "completed";
+ content: ResponseOutputTextContent[];
+}
+
+export interface ResponseFunctionToolCall {
+ id: string;
+ type: "function_call";
+ call_id: string;
+ name: string;
+ arguments: string;
+ status: "completed";
+}
+
+export interface ResponseFunctionCallOutput {
+ id: string;
+ type: "function_call_output";
+ call_id: string;
+ output: string;
+}
+
+export type ResponseOutputItem =
+ | ResponseOutputMessage
+ | ResponseFunctionToolCall
+ | ResponseFunctionCallOutput;
+
+// ---------------------------------------------------------------------------
+// Responses API SSE event types
+// ---------------------------------------------------------------------------
+
+export interface ResponseOutputItemAddedEvent {
+ type: "response.output_item.added";
+ item: ResponseOutputItem;
+ output_index: number;
+ sequence_number: number;
+}
+
+export interface ResponseOutputItemDoneEvent {
+ type: "response.output_item.done";
+ item: ResponseOutputItem;
+ output_index: number;
+ sequence_number: number;
+}
+
+export interface ResponseTextDeltaEvent {
+ type: "response.output_text.delta";
+ item_id: string;
+ output_index: number;
+ content_index: number;
+ delta: string;
+ sequence_number: number;
+}
+
+export interface ResponseCompletedEvent {
+ type: "response.completed";
+ sequence_number: number;
+ response: Record;
+}
+
+export interface ResponseErrorEvent {
+ type: "error";
+ error: string;
+}
+
+export interface ResponseFailedEvent {
+ type: "response.failed";
+}
+
+export type ResponseStreamEvent =
+ | ResponseOutputItemAddedEvent
+ | ResponseOutputItemDoneEvent
+ | ResponseTextDeltaEvent
+ | ResponseCompletedEvent
+ | ResponseErrorEvent
+ | ResponseFailedEvent;
+
+// ---------------------------------------------------------------------------
+// Agent interface
+// ---------------------------------------------------------------------------
+
+/**
+ * Contract that agent implementations must fulfil.
+ *
+ * The plugin calls `invoke()` for non-streaming requests and `stream()` for
+ * SSE streaming. Implementations are responsible for translating their SDK's
+ * output into Responses API types.
+ */
+export interface AgentInterface {
+ invoke(params: InvokeParams): Promise;
+ stream(params: InvokeParams): AsyncGenerator;
+}
diff --git a/packages/appkit/src/plugins/agent/agent.ts b/packages/appkit/src/plugins/agent/agent.ts
new file mode 100644
index 00000000..750e64e9
--- /dev/null
+++ b/packages/appkit/src/plugins/agent/agent.ts
@@ -0,0 +1,278 @@
+/**
+ * AgentPlugin — first-class AppKit plugin for LangChain/LangGraph agents.
+ *
+ * Provides:
+ * - POST /api/agent (standard AppKit namespaced route)
+ *
+ * Supports two modes:
+ * 1. Bring-your-own agent via `config.agentInstance`
+ * 2. Auto-build a LangGraph ReAct agent from config (model, tools, MCP servers)
+ *
+ * When using config (not agentInstance), you can add tools and MCP servers
+ * after app creation via appkit.agent.addTools() and appkit.agent.addMcpServers().
+ */
+
+import type { DatabricksMCPServer } from "@databricks/langchainjs";
+import type { StructuredToolInterface } from "@langchain/core/tools";
+import type express from "express";
+import { createLogger } from "../../logging/logger";
+import { Plugin, toPlugin } from "../../plugin";
+import type { AgentInterface } from "./agent-interface";
+import { createInvokeHandler } from "./invoke-handler";
+import manifest from "./manifest.json";
+import { StandardAgent } from "./standard-agent";
+import type { IAgentConfig } from "./types";
+
+const logger = createLogger("agent");
+
+const DEFAULT_SYSTEM_PROMPT =
+ "You are a helpful AI assistant with access to various tools.";
+
+type ChatDatabricksInstance = InstanceType<
+ Awaited["ChatDatabricks"]
+>;
+
+export class AgentPlugin extends Plugin {
+ public name = "agent" as const;
+
+ static manifest = manifest;
+
+ protected declare config: IAgentConfig;
+
+ private agentImpl: AgentInterface | null = null;
+ private systemPrompt = DEFAULT_SYSTEM_PROMPT;
+ private mcpClient: {
+ getTools(): Promise;
+ close(): Promise;
+ } | null = null;
+
+ /** Only set when building from config (not agentInstance). Used when rebuilding after addTools/addMcpServers. */
+ private model: ChatDatabricksInstance | null = null;
+ /** Mutable list of tools (config + added). Only used when building from config. */
+ private toolsList: StructuredToolInterface[] = [];
+ /** Mutable list of MCP servers (config + added). Only used when building from config. */
+ private mcpServersList: DatabricksMCPServer[] = [];
+
+ async setup() {
+ this.systemPrompt = this.config.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
+
+ // If a pre-built agent is provided, use it directly
+ if (this.config.agentInstance) {
+ this.agentImpl = this.config.agentInstance;
+ logger.info("AgentPlugin initialized with provided agentInstance");
+ return;
+ }
+
+ // Otherwise build a LangGraph ReAct agent from config
+ const modelName = this.config.model ?? process.env.DATABRICKS_MODEL;
+
+ if (!modelName) {
+ throw new Error(
+ "AgentPlugin: model name is required. Set config.model or DATABRICKS_MODEL env var.",
+ );
+ }
+
+ const { ChatDatabricks } = await import("@databricks/langchainjs");
+
+ this.model = new ChatDatabricks({
+ model: modelName,
+ useResponsesApi: this.config.useResponsesApi ?? false,
+ temperature: this.config.temperature ?? 0.1,
+ maxTokens: this.config.maxTokens ?? 2000,
+ maxRetries: 3,
+ });
+
+ this.toolsList = [...(this.config.tools ?? [])];
+ this.mcpServersList = [...(this.config.mcpServers ?? [])];
+
+ await this.buildStandardAgent();
+
+ logger.info(
+ "AgentPlugin initialized: model=%s tools=%d mcpServers=%d",
+ modelName,
+ this.toolsList.length,
+ this.mcpServersList.length,
+ );
+ }
+
+ /**
+ * Builds or rebuilds the LangGraph ReAct agent from current model, toolsList, and mcpServersList.
+ * Call this after changing toolsList or mcpServersList (e.g. via addTools/addMcpServers).
+ */
+ private async buildStandardAgent(): Promise {
+ if (!this.model) return;
+
+ // Close existing MCP client before creating a new one
+ if (this.mcpClient) {
+ try {
+ await this.mcpClient.close();
+ } catch (err) {
+ logger.warn("Error closing MCP client during rebuild: %O", err);
+ }
+ this.mcpClient = null;
+ }
+
+ const tools: StructuredToolInterface[] = [];
+
+ if (this.mcpServersList.length > 0) {
+ try {
+ const { buildMCPServerConfig } = await import(
+ "@databricks/langchainjs"
+ );
+ const mcpServerConfigs = await buildMCPServerConfig(
+ this.mcpServersList,
+ );
+ const { MultiServerMCPClient } = await import(
+ "@langchain/mcp-adapters"
+ );
+ this.mcpClient = new MultiServerMCPClient({
+ mcpServers: mcpServerConfigs,
+ throwOnLoadError: false,
+ prefixToolNameWithServerName: true,
+ });
+ const mcpTools = await this.mcpClient.getTools();
+ tools.push(...mcpTools);
+ logger.info(
+ "Loaded %d MCP tools from %d server(s)",
+ mcpTools.length,
+ this.mcpServersList.length,
+ );
+ } catch (err) {
+ logger.warn(
+ "Failed to load MCP tools — continuing without them: %O",
+ err,
+ );
+ }
+ }
+
+ tools.push(...this.toolsList);
+
+ const { createReactAgent } = await import("@langchain/langgraph/prebuilt");
+ const langGraphAgent = createReactAgent({
+ llm: this.model,
+ tools,
+ });
+
+ this.agentImpl = new StandardAgent(
+ langGraphAgent as any,
+ this.systemPrompt,
+ );
+ }
+
+ /**
+ * Add tools to the agent after app creation. Only supported when the plugin
+ * was initialized from config (not when using agentInstance). Rebuilds the
+ * underlying LangGraph agent with the new tool set.
+ */
+ async addTools(tools: StructuredToolInterface[]): Promise {
+ if (this.config.agentInstance) {
+ throw new Error(
+ "addTools() is not supported when using a custom agentInstance",
+ );
+ }
+ if (!this.model) {
+ throw new Error("AgentPlugin not initialized — call setup() first");
+ }
+ this.toolsList.push(...tools);
+ await this.buildStandardAgent();
+ logger.info(
+ "Added %d tool(s); total tools=%d",
+ tools.length,
+ this.toolsList.length,
+ );
+ }
+
+ /**
+ * Add MCP servers to the agent after app creation. Only supported when the
+ * plugin was initialized from config (not when using agentInstance). Rebuilds
+ * the underlying LangGraph agent so new MCP tools are available.
+ */
+ async addMcpServers(servers: DatabricksMCPServer[]): Promise {
+ if (this.config.agentInstance) {
+ throw new Error(
+ "addMcpServers() is not supported when using a custom agentInstance",
+ );
+ }
+ if (!this.model) {
+ throw new Error("AgentPlugin not initialized — call setup() first");
+ }
+ this.mcpServersList.push(...servers);
+ await this.buildStandardAgent();
+ logger.info(
+ "Added %d MCP server(s); total servers=%d",
+ servers.length,
+ this.mcpServersList.length,
+ );
+ }
+
+ private getAgentImpl(): AgentInterface {
+ if (!this.agentImpl) {
+ throw new Error("AgentPlugin not initialized — call setup() first");
+ }
+ return this.agentImpl;
+ }
+
+ injectRoutes(router: express.Router) {
+ const handler = createInvokeHandler(() => this.getAgentImpl());
+ router.post("/", handler);
+ this.registerEndpoint("invoke", `/api/${this.name}`);
+ }
+
+ async abortActiveOperations() {
+ await super.abortActiveOperations();
+ if (this.mcpClient) {
+ try {
+ await this.mcpClient.close();
+ } catch (err) {
+ logger.warn("Error closing MCP client: %O", err);
+ }
+ }
+ }
+
+ exports() {
+ return {
+ invoke: async (
+ messages: { role: string; content: string }[],
+ ): Promise => {
+ if (!this.agentImpl) {
+ throw new Error("AgentPlugin not initialized");
+ }
+ const lastUser = [...messages].reverse().find((m) => m.role === "user");
+ const input = lastUser?.content ?? "";
+ const chatHistory = messages.slice(0, -1);
+ const items = await this.agentImpl.invoke({
+ input,
+ chat_history: chatHistory,
+ });
+ const msg = items.find((i) => i.type === "message") as any;
+ const text = msg?.content?.[0]?.text ?? "";
+ return text;
+ },
+
+ stream: async function* (
+ this: AgentPlugin,
+ messages: { role: string; content: string }[],
+ ) {
+ if (!this.agentImpl) {
+ throw new Error("AgentPlugin not initialized");
+ }
+ const lastUser = [...messages].reverse().find((m) => m.role === "user");
+ const input = lastUser?.content ?? "";
+ const chatHistory = messages.slice(0, -1);
+ yield* this.agentImpl.stream({
+ input,
+ chat_history: chatHistory,
+ });
+ }.bind(this),
+
+ addTools: (tools: StructuredToolInterface[]) => this.addTools(tools),
+ addMcpServers: (servers: DatabricksMCPServer[]) =>
+ this.addMcpServers(servers),
+ };
+ }
+}
+
+export const agent = toPlugin(
+ AgentPlugin,
+ "agent",
+);
diff --git a/packages/appkit/src/plugins/agent/index.ts b/packages/appkit/src/plugins/agent/index.ts
new file mode 100644
index 00000000..616e7f8c
--- /dev/null
+++ b/packages/appkit/src/plugins/agent/index.ts
@@ -0,0 +1,14 @@
+export { AgentPlugin, agent } from "./agent";
+export type {
+ AgentInterface,
+ InvokeParams,
+ ResponseFunctionCallOutput,
+ ResponseFunctionToolCall,
+ ResponseOutputItem,
+ ResponseOutputMessage,
+ ResponseStreamEvent,
+} from "./agent-interface";
+export { createInvokeHandler } from "./invoke-handler";
+export type { LangGraphAgent } from "./standard-agent";
+export { StandardAgent } from "./standard-agent";
+export type { IAgentConfig } from "./types";
diff --git a/packages/appkit/src/plugins/agent/invoke-handler.ts b/packages/appkit/src/plugins/agent/invoke-handler.ts
new file mode 100644
index 00000000..20af5798
--- /dev/null
+++ b/packages/appkit/src/plugins/agent/invoke-handler.ts
@@ -0,0 +1,160 @@
+/**
+ * Responses API invoke handler for the agent plugin.
+ *
+ * Accepts Responses API request format, parses it into InvokeParams, then
+ * delegates to AgentInterface.stream() / AgentInterface.invoke(). The handler
+ * is a pure pass-through — all SSE event shaping happens inside the agent.
+ */
+
+import type express from "express";
+import { z } from "zod";
+import type { AgentInterface } from "./agent-interface";
+
+const responsesRequestSchema = z.object({
+ input: z.union([
+ z.string(),
+ z.array(
+ z.union([
+ z.object({
+ role: z.enum(["user", "assistant", "system"]),
+ content: z.union([
+ z.string(),
+ z.array(
+ z.union([
+ z.object({ type: z.string(), text: z.string() }).passthrough(),
+ z.object({ type: z.string() }).passthrough(),
+ ]),
+ ),
+ ]),
+ }),
+ z.object({ type: z.string() }).passthrough(),
+ ]),
+ ),
+ ]),
+ stream: z.boolean().optional().default(true),
+ model: z.string().optional(),
+});
+
+/**
+ * Flatten a Responses API message to a plain `{ role, content }` object.
+ * Handles function_call / function_call_output items and array content.
+ */
+function flattenHistoryItem(item: any): { role: string; content: string } {
+ if (item.type === "function_call") {
+ return {
+ role: "assistant",
+ content: `[Tool Call: ${item.name}(${item.arguments})]`,
+ };
+ }
+ if (item.type === "function_call_output") {
+ return { role: "assistant", content: `[Tool Result: ${item.output}]` };
+ }
+
+ if (Array.isArray(item.content)) {
+ const textParts = item.content
+ .filter(
+ (p: any) =>
+ p.type === "input_text" ||
+ p.type === "output_text" ||
+ p.type === "text",
+ )
+ .map((p: any) => p.text);
+
+ const toolParts = item.content
+ .filter(
+ (p: any) =>
+ p.type === "function_call" || p.type === "function_call_output",
+ )
+ .map((p: any) =>
+ p.type === "function_call"
+ ? `[Tool Call: ${p.name}(${JSON.stringify(p.arguments)})]`
+ : `[Tool Result: ${p.output}]`,
+ );
+
+ const allParts = [...textParts, ...toolParts].filter((p) => p.length > 0);
+ return { ...item, content: allParts.join("\n") };
+ }
+
+ return { role: item.role ?? "user", content: item.content ?? "" };
+}
+
+/**
+ * Create an Express handler that invokes the agent via the AgentInterface
+ * and streams/returns the response in Responses API format.
+ */
+export function createInvokeHandler(
+ getAgent: () => AgentInterface,
+): express.RequestHandler {
+ return async (req: express.Request, res: express.Response) => {
+ try {
+ const parsed = responsesRequestSchema.safeParse(req.body);
+ if (!parsed.success) {
+ res.status(400).json({
+ error: "Invalid request format",
+ details: parsed.error.format(),
+ });
+ return;
+ }
+
+ const { stream } = parsed.data;
+
+ const input =
+ typeof parsed.data.input === "string"
+ ? [{ role: "user" as const, content: parsed.data.input }]
+ : parsed.data.input;
+
+ const userMessages = input.filter((msg: any) => msg.role === "user");
+ if (userMessages.length === 0) {
+ res.status(400).json({ error: "No user message found in input" });
+ return;
+ }
+
+ const lastUserMessage = userMessages[userMessages.length - 1];
+
+ let userInput: string;
+ if (Array.isArray(lastUserMessage.content)) {
+ userInput = lastUserMessage.content
+ .filter(
+ (part: any) => part.type === "input_text" || part.type === "text",
+ )
+ .map((part: any) => part.text)
+ .join("\n");
+ } else {
+ userInput = lastUserMessage.content as string;
+ }
+
+ const chatHistory = input.slice(0, -1).map(flattenHistoryItem);
+
+ const agentParams = { input: userInput, chat_history: chatHistory };
+ const agent = getAgent();
+
+ if (stream) {
+ res.setHeader("Content-Type", "text/event-stream");
+ res.setHeader("Cache-Control", "no-cache");
+ res.setHeader("Connection", "keep-alive");
+
+ try {
+ for await (const event of agent.stream(agentParams)) {
+ res.write(`data: ${JSON.stringify(event)}\n\n`);
+ }
+ res.write("data: [DONE]\n\n");
+ res.end();
+ } catch (err: unknown) {
+ const message = err instanceof Error ? err.message : String(err);
+ res.write(
+ `data: ${JSON.stringify({ type: "error", error: message })}\n\n`,
+ );
+ res.write(`data: ${JSON.stringify({ type: "response.failed" })}\n\n`);
+ res.write("data: [DONE]\n\n");
+ res.end();
+ }
+ } else {
+ const items = await agent.invoke(agentParams);
+ res.json({ output: items });
+ }
+ } catch (err: unknown) {
+ const message = err instanceof Error ? err.message : String(err);
+ res.status(500).json({ error: "Internal server error", message });
+ }
+ };
+}
diff --git a/packages/appkit/src/plugins/agent/manifest.json b/packages/appkit/src/plugins/agent/manifest.json
new file mode 100644
index 00000000..ee10116e
--- /dev/null
+++ b/packages/appkit/src/plugins/agent/manifest.json
@@ -0,0 +1,23 @@
+{
+ "name": "agent",
+ "displayName": "Agent Plugin",
+ "description": "LangChain/LangGraph AI agent with streaming Responses API and MCP tool support",
+ "resources": {
+ "required": [
+ {
+ "type": "serving_endpoint",
+ "alias": "Model Endpoint",
+ "resourceKey": "agent-model-endpoint",
+ "description": "Databricks model serving endpoint for the agent LLM",
+ "permission": "CAN_QUERY",
+ "fields": {
+ "name": {
+ "env": "DATABRICKS_MODEL",
+ "description": "Model serving endpoint name"
+ }
+ }
+ }
+ ],
+ "optional": []
+ }
+}
diff --git a/packages/appkit/src/plugins/agent/standard-agent.ts b/packages/appkit/src/plugins/agent/standard-agent.ts
new file mode 100644
index 00000000..39ad9c13
--- /dev/null
+++ b/packages/appkit/src/plugins/agent/standard-agent.ts
@@ -0,0 +1,223 @@
+/**
+ * StandardAgent — LangGraph wrapper implementing AgentInterface.
+ *
+ * Wraps a LangGraph `createReactAgent` instance and translates its stream
+ * events into Responses API SSE format. If you swap LangGraph for another
+ * SDK, provide your own AgentInterface implementation instead.
+ */
+
+import { randomUUID } from "node:crypto";
+import type { BaseMessage } from "@langchain/core/messages";
+import { HumanMessage, SystemMessage } from "@langchain/core/messages";
+import type {
+ AgentInterface,
+ InvokeParams,
+ ResponseFunctionToolCall,
+ ResponseOutputItem,
+ ResponseOutputMessage,
+ ResponseStreamEvent,
+} from "./agent-interface";
+
+/**
+ * Minimal interface for the LangGraph agent returned by createReactAgent.
+ */
+export interface LangGraphAgent {
+ invoke(input: {
+ messages: BaseMessage[];
+ }): Promise<{ messages: BaseMessage[] }>;
+ streamEvents(
+ input: { messages: BaseMessage[] },
+ options: { version: "v1" | "v2" },
+ ): AsyncIterable<{
+ event: string;
+ name: string;
+ run_id: string;
+ data?: any;
+ }>;
+}
+
+function convertToBaseMessages(messages: any[]): BaseMessage[] {
+ return messages.map((msg) => {
+ if (msg instanceof HumanMessage || msg instanceof SystemMessage) {
+ return msg;
+ }
+ const content = msg.content || "";
+ switch (msg.role) {
+ case "user":
+ return new HumanMessage(content);
+ case "system":
+ return new SystemMessage(content);
+ default:
+ return new HumanMessage(content);
+ }
+ });
+}
+
+export class StandardAgent implements AgentInterface {
+ constructor(
+ private agent: LangGraphAgent,
+ private systemPrompt: string,
+ ) {}
+
+ async invoke(params: InvokeParams): Promise {
+ const { input, chat_history = [] } = params;
+
+ const messages: BaseMessage[] = [
+ new SystemMessage(this.systemPrompt),
+ ...convertToBaseMessages(chat_history),
+ new HumanMessage(input),
+ ];
+
+ const result = await this.agent.invoke({ messages });
+ const finalMessages = result.messages || [];
+ const lastMessage = finalMessages[finalMessages.length - 1];
+ const text =
+ typeof lastMessage?.content === "string" ? lastMessage.content : "";
+
+ const outputMessage: ResponseOutputMessage = {
+ id: `msg_${randomUUID()}`,
+ type: "message",
+ role: "assistant",
+ status: "completed",
+ content: [{ type: "output_text", text, annotations: [] }],
+ };
+
+ return [outputMessage];
+ }
+
+ async *stream(params: InvokeParams): AsyncGenerator {
+ const { input, chat_history = [] } = params;
+
+ const messages: BaseMessage[] = [
+ new SystemMessage(this.systemPrompt),
+ ...convertToBaseMessages(chat_history),
+ new HumanMessage(input),
+ ];
+
+ const toolCallIds = new Map();
+ let seqNum = 0;
+ let outputIndex = 0;
+ const textItemId = `msg_${randomUUID()}`;
+ let textOutputIndex = -1;
+
+ const eventStream = this.agent.streamEvents(
+ { messages },
+ { version: "v2" },
+ );
+
+ for await (const event of eventStream) {
+ if (event.event === "on_tool_start") {
+ const callId = `call_${randomUUID()}`;
+ toolCallIds.set(`${event.name}_${event.run_id}`, callId);
+
+ const fcItem: ResponseFunctionToolCall = {
+ id: `fc_${randomUUID()}`,
+ call_id: callId,
+ name: event.name,
+ arguments: JSON.stringify(event.data?.input || {}),
+ type: "function_call",
+ status: "completed",
+ };
+
+ const currentIndex = outputIndex++;
+
+ yield {
+ type: "response.output_item.added",
+ item: fcItem,
+ output_index: currentIndex,
+ sequence_number: seqNum++,
+ };
+
+ yield {
+ type: "response.output_item.done",
+ item: fcItem,
+ output_index: currentIndex,
+ sequence_number: seqNum++,
+ };
+ }
+
+ if (event.event === "on_tool_end") {
+ const toolKey = `${event.name}_${event.run_id}`;
+ const callId = toolCallIds.get(toolKey) || `call_${randomUUID()}`;
+ toolCallIds.delete(toolKey);
+
+ const outputItem = {
+ id: `fco_${randomUUID()}`,
+ call_id: callId,
+ output: JSON.stringify(event.data?.output || ""),
+ type: "function_call_output" as const,
+ };
+
+ const currentIndex = outputIndex++;
+
+ yield {
+ type: "response.output_item.added",
+ item: outputItem,
+ output_index: currentIndex,
+ sequence_number: seqNum++,
+ };
+
+ yield {
+ type: "response.output_item.done",
+ item: outputItem,
+ output_index: currentIndex,
+ sequence_number: seqNum++,
+ };
+ }
+
+ if (event.event === "on_chat_model_stream") {
+ const content = event.data?.chunk?.content;
+ if (content && typeof content === "string") {
+ if (textOutputIndex === -1) {
+ textOutputIndex = outputIndex++;
+
+ const msgItem: ResponseOutputMessage = {
+ id: textItemId,
+ type: "message",
+ role: "assistant",
+ status: "in_progress",
+ content: [],
+ };
+ yield {
+ type: "response.output_item.added",
+ item: msgItem,
+ output_index: textOutputIndex,
+ sequence_number: seqNum++,
+ };
+ }
+
+ yield {
+ type: "response.output_text.delta",
+ item_id: textItemId,
+ output_index: textOutputIndex,
+ content_index: 0,
+ delta: content,
+ sequence_number: seqNum++,
+ };
+ }
+ }
+ }
+
+ if (textOutputIndex !== -1) {
+ const msgItem: ResponseOutputMessage = {
+ id: textItemId,
+ type: "message",
+ role: "assistant",
+ status: "completed",
+ content: [],
+ };
+ yield {
+ type: "response.output_item.done",
+ item: msgItem,
+ output_index: textOutputIndex,
+ sequence_number: seqNum++,
+ };
+ }
+
+ yield {
+ type: "response.completed",
+ sequence_number: seqNum++,
+ response: {},
+ };
+ }
+}
diff --git a/packages/appkit/src/plugins/agent/tests/agent.integration.test.ts b/packages/appkit/src/plugins/agent/tests/agent.integration.test.ts
new file mode 100644
index 00000000..d4c2fdb6
--- /dev/null
+++ b/packages/appkit/src/plugins/agent/tests/agent.integration.test.ts
@@ -0,0 +1,228 @@
+import type { Server } from "node:http";
+import { mockServiceContext, setupDatabricksEnv } from "@tools/test-helpers";
+import { afterAll, beforeAll, describe, expect, test } from "vitest";
+
+process.env.DATABRICKS_APP_PORT = "8000";
+process.env.FLASK_RUN_HOST = "0.0.0.0";
+process.env.DATABRICKS_MODEL = "test-model";
+
+import { ServiceContext } from "../../../context/service-context";
+import { createApp } from "../../../core";
+import { server as serverPlugin } from "../../server/index";
+import { agent } from "../agent";
+import { StubAgent } from "./stub-agent";
+
+function parseSSEStream(text: string) {
+ const events: any[] = [];
+ let fullOutput = "";
+ const lines = text.split("\n");
+ for (const line of lines) {
+ if (line.startsWith("data: ") && line !== "data: [DONE]") {
+ try {
+ const data = JSON.parse(line.slice(6));
+ events.push(data);
+ if (data.type === "response.output_text.delta") {
+ fullOutput += data.delta;
+ }
+ } catch {}
+ }
+ }
+ return { events, fullOutput };
+}
+
+describe("AgentPlugin Integration", () => {
+ let server: Server;
+ let baseUrl: string;
+ let serviceContextMock: Awaited>;
+ const TEST_PORT = 9885;
+
+ beforeAll(async () => {
+ setupDatabricksEnv();
+ ServiceContext.reset();
+ serviceContextMock = await mockServiceContext();
+
+ const app = await createApp({
+ plugins: [
+ agent({ agentInstance: new StubAgent() }),
+ serverPlugin({
+ port: TEST_PORT,
+ host: "127.0.0.1",
+ autoStart: false,
+ }),
+ ],
+ });
+
+ await app.server.start();
+ server = app.server.getServer();
+ baseUrl = `http://127.0.0.1:${TEST_PORT}`;
+
+ await new Promise((resolve) => setTimeout(resolve, 100));
+ });
+
+ afterAll(async () => {
+ serviceContextMock?.restore();
+ if (server) {
+ await new Promise((resolve, reject) => {
+ server.close((err) => {
+ if (err) reject(err);
+ else resolve();
+ });
+ });
+ }
+ });
+
+ describe("POST /api/agent (streaming)", () => {
+ test("streams SSE events and completes", async () => {
+ const response = await fetch(`${baseUrl}/api/agent`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ input: [{ role: "user", content: "Hello agent" }],
+ stream: true,
+ }),
+ });
+
+ expect(response.ok).toBe(true);
+ expect(response.headers.get("content-type")).toContain(
+ "text/event-stream",
+ );
+
+ const text = await response.text();
+ const { events, fullOutput } = parseSSEStream(text);
+
+ expect(fullOutput).toContain("Echo: Hello agent");
+
+ const hasCompleted = events.some((e) => e.type === "response.completed");
+ expect(hasCompleted).toBe(true);
+
+ expect(text).toContain("data: [DONE]");
+ });
+ });
+
+ describe("non-streaming mode", () => {
+ test("returns JSON response", async () => {
+ const response = await fetch(`${baseUrl}/api/agent`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ input: [{ role: "user", content: "No stream" }],
+ stream: false,
+ }),
+ });
+
+ expect(response.ok).toBe(true);
+ const data = (await response.json()) as {
+ output: { type: string; content: { text: string }[] }[];
+ };
+
+ expect(data.output).toBeDefined();
+ expect(data.output).toHaveLength(1);
+ expect(data.output[0].type).toBe("message");
+ expect(data.output[0].content[0].text).toContain("Echo: No stream");
+ });
+ });
+
+ describe("string input", () => {
+ test("accepts plain string as input", async () => {
+ const response = await fetch(`${baseUrl}/api/agent`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ input: "Plain string input",
+ stream: true,
+ }),
+ });
+
+ expect(response.ok).toBe(true);
+ const text = await response.text();
+ const { fullOutput } = parseSSEStream(text);
+ expect(fullOutput).toContain("Echo: Plain string input");
+ });
+ });
+
+ describe("multi-turn conversations", () => {
+ test("handles chat history", async () => {
+ const response = await fetch(`${baseUrl}/api/agent`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ input: [
+ { role: "user", content: "My name is Alice" },
+ {
+ role: "assistant",
+ content: "Nice to meet you, Alice",
+ },
+ {
+ role: "user",
+ content: "What is my name?",
+ },
+ ],
+ stream: true,
+ }),
+ });
+
+ expect(response.ok).toBe(true);
+ const text = await response.text();
+ const { fullOutput } = parseSSEStream(text);
+ expect(fullOutput).toContain("Echo: What is my name?");
+ });
+
+ test("handles function_call items in history", async () => {
+ const response = await fetch(`${baseUrl}/api/agent`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ input: [
+ { role: "user", content: "Look up the answer" },
+ {
+ type: "function_call",
+ name: "search",
+ arguments: '{"q":"test"}',
+ },
+ {
+ type: "function_call_output",
+ output: '"42"',
+ },
+ {
+ role: "user",
+ content: "What did you find?",
+ },
+ ],
+ stream: true,
+ }),
+ });
+
+ expect(response.ok).toBe(true);
+ const text = await response.text();
+ const { fullOutput } = parseSSEStream(text);
+ expect(fullOutput.length).toBeGreaterThan(0);
+ });
+ });
+
+ describe("error responses", () => {
+ test("returns 400 for malformed input", async () => {
+ const response = await fetch(`${baseUrl}/api/agent`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ stream: true }),
+ });
+
+ expect(response.ok).toBe(false);
+ expect(response.status).toBe(400);
+ });
+
+ test("returns 400 when no user message", async () => {
+ const response = await fetch(`${baseUrl}/api/agent`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ input: [{ role: "assistant", content: "Only assistant" }],
+ stream: true,
+ }),
+ });
+
+ expect(response.ok).toBe(false);
+ expect(response.status).toBe(400);
+ });
+ });
+});
diff --git a/packages/appkit/src/plugins/agent/tests/agent.test.ts b/packages/appkit/src/plugins/agent/tests/agent.test.ts
new file mode 100644
index 00000000..4816b0cb
--- /dev/null
+++ b/packages/appkit/src/plugins/agent/tests/agent.test.ts
@@ -0,0 +1,172 @@
+import {
+ createMockRouter,
+ mockServiceContext,
+ setupDatabricksEnv,
+} from "@tools/test-helpers";
+import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
+import { ServiceContext } from "../../../context/service-context";
+import { AgentPlugin, agent } from "../agent";
+import type { IAgentConfig } from "../types";
+import { StubAgent } from "./stub-agent";
+
+// Mock CacheManager singleton
+vi.mock("../../../cache", () => ({
+ CacheManager: {
+ getInstanceSync: vi.fn(() => ({
+ get: vi.fn(),
+ set: vi.fn(),
+ delete: vi.fn(),
+ getOrExecute: vi.fn(async (_key: unknown[], fn: () => Promise) =>
+ fn(),
+ ),
+ generateKey: vi.fn(() => "test-key"),
+ })),
+ },
+}));
+
+describe("AgentPlugin", () => {
+ let serviceContextMock: Awaited>;
+
+ beforeEach(async () => {
+ setupDatabricksEnv();
+ ServiceContext.reset();
+ serviceContextMock = await mockServiceContext();
+ });
+
+ afterEach(() => {
+ serviceContextMock?.restore();
+ });
+
+ test("agent factory produces correct plugin data", () => {
+ const pluginData = agent({ agentInstance: new StubAgent() });
+ expect(pluginData.name).toBe("agent");
+ });
+
+ test("plugin has correct manifest", () => {
+ expect(AgentPlugin.manifest).toBeDefined();
+ expect(AgentPlugin.manifest.name).toBe("agent");
+ expect(AgentPlugin.manifest.resources.required).toHaveLength(1);
+ expect(AgentPlugin.manifest.resources.required[0].type).toBe(
+ "serving_endpoint",
+ );
+ });
+
+ test("plugin instance has correct name", () => {
+ const config: IAgentConfig = { agentInstance: new StubAgent() };
+ const plugin = new AgentPlugin(config);
+ expect(plugin.name).toBe("agent");
+ });
+
+ describe("setup()", () => {
+ test("uses provided agentInstance", async () => {
+ const stub = new StubAgent();
+ const config: IAgentConfig = { agentInstance: stub };
+ const plugin = new AgentPlugin(config);
+
+ await plugin.setup();
+
+ const exported = plugin.exports();
+ const result = await exported.invoke([{ role: "user", content: "hi" }]);
+ expect(result).toContain("Echo: hi");
+ });
+
+ test("throws when no model and no agentInstance", async () => {
+ const config: IAgentConfig = {};
+ const plugin = new AgentPlugin(config);
+
+ await expect(plugin.setup()).rejects.toThrow("model name is required");
+ });
+
+ test("resolves model from env var when not in config", async () => {
+ process.env.DATABRICKS_MODEL = "test-model";
+
+ const config: IAgentConfig = {};
+ const plugin = new AgentPlugin(config);
+
+ // Will fail because ChatDatabricks isn't available, but it
+ // should get past the model name check
+ try {
+ await plugin.setup();
+ } catch (e: any) {
+ expect(e.message).not.toContain("model name is required");
+ }
+
+ delete process.env.DATABRICKS_MODEL;
+ });
+ });
+
+ describe("injectRoutes()", () => {
+ test("registers POST handler on router", () => {
+ const stub = new StubAgent();
+ const config: IAgentConfig = { agentInstance: stub };
+ const plugin = new AgentPlugin(config);
+
+ const { router } = createMockRouter();
+ plugin.injectRoutes(router as any);
+
+ expect(router.post).toHaveBeenCalledWith("/", expect.any(Function));
+ });
+ });
+
+ describe("exports()", () => {
+ test("returns invoke and stream methods", async () => {
+ const stub = new StubAgent();
+ const config: IAgentConfig = { agentInstance: stub };
+ const plugin = new AgentPlugin(config);
+ await plugin.setup();
+
+ const exported = plugin.exports();
+
+ expect(typeof exported.invoke).toBe("function");
+ expect(typeof exported.stream).toBe("function");
+ });
+
+ test("invoke returns text from agent response", async () => {
+ const stub = new StubAgent();
+ const config: IAgentConfig = { agentInstance: stub };
+ const plugin = new AgentPlugin(config);
+ await plugin.setup();
+
+ const result = await plugin
+ .exports()
+ .invoke([{ role: "user", content: "test message" }]);
+
+ expect(result).toBe("Echo: test message");
+ });
+
+ test("stream yields ResponseStreamEvents", async () => {
+ const stub = new StubAgent();
+ const config: IAgentConfig = { agentInstance: stub };
+ const plugin = new AgentPlugin(config);
+ await plugin.setup();
+
+ const events: any[] = [];
+ for await (const event of plugin
+ .exports()
+ .stream([{ role: "user", content: "hello" }])) {
+ events.push(event);
+ }
+
+ expect(events.length).toBeGreaterThan(0);
+ const deltaEvent = events.find(
+ (e) => e.type === "response.output_text.delta",
+ );
+ expect(deltaEvent).toBeDefined();
+ expect(deltaEvent.delta).toContain("Echo: hello");
+
+ const completedEvent = events.find(
+ (e) => e.type === "response.completed",
+ );
+ expect(completedEvent).toBeDefined();
+ });
+
+ test("throws when not initialized", async () => {
+ const config: IAgentConfig = { agentInstance: new StubAgent() };
+ const plugin = new AgentPlugin(config);
+
+ await expect(
+ plugin.exports().invoke([{ role: "user", content: "hi" }]),
+ ).rejects.toThrow("not initialized");
+ });
+ });
+});
diff --git a/packages/appkit/src/plugins/agent/tests/invoke-handler.test.ts b/packages/appkit/src/plugins/agent/tests/invoke-handler.test.ts
new file mode 100644
index 00000000..8bd1cec6
--- /dev/null
+++ b/packages/appkit/src/plugins/agent/tests/invoke-handler.test.ts
@@ -0,0 +1,325 @@
+import { createMockRequest, createMockResponse } from "@tools/test-helpers";
+import { describe, expect, test, vi } from "vitest";
+import { createInvokeHandler } from "../invoke-handler";
+import { StubAgent } from "./stub-agent";
+
+function makeReq(body: any) {
+ return createMockRequest({ body }) as any;
+}
+
+function makeRes() {
+ const res = createMockResponse() as any;
+ // Collect all writes for SSE assertions
+ const chunks: string[] = [];
+ res.write.mockImplementation((chunk: string) => {
+ chunks.push(chunk);
+ return true;
+ });
+ (res as any).__chunks = chunks;
+ return res;
+}
+
+function parseSSE(res: any): { events: any[]; fullOutput: string } {
+ const chunks: string[] = res.__chunks;
+ const events: any[] = [];
+ let fullOutput = "";
+
+ for (const chunk of chunks) {
+ const lines = chunk.split("\n");
+ for (const line of lines) {
+ if (line.startsWith("data: ") && line !== "data: [DONE]") {
+ try {
+ const data = JSON.parse(line.slice(6));
+ events.push(data);
+ if (data.type === "response.output_text.delta") {
+ fullOutput += data.delta;
+ }
+ } catch {}
+ }
+ }
+ }
+ return { events, fullOutput };
+}
+
+describe("createInvokeHandler", () => {
+ const stubAgent = new StubAgent();
+ const handler = createInvokeHandler(() => stubAgent);
+
+ describe("streaming mode", () => {
+ test("streams SSE events with correct format", async () => {
+ const req = makeReq({
+ input: [{ role: "user", content: "Hello" }],
+ stream: true,
+ });
+ const res = makeRes();
+
+ await handler(req, res, vi.fn());
+
+ expect(res.setHeader).toHaveBeenCalledWith(
+ "Content-Type",
+ "text/event-stream",
+ );
+
+ const { events, fullOutput } = parseSSE(res);
+
+ expect(fullOutput).toContain("Echo: Hello");
+
+ const hasCompleted = events.some((e) => e.type === "response.completed");
+ expect(hasCompleted).toBe(true);
+
+ // Last write should be [DONE]
+ const lastChunk = res.__chunks[res.__chunks.length - 1];
+ expect(lastChunk).toContain("[DONE]");
+
+ expect(res.end).toHaveBeenCalled();
+ });
+
+ test("emits output_item.added and output_item.done events", async () => {
+ const req = makeReq({
+ input: [{ role: "user", content: "Test" }],
+ stream: true,
+ });
+ const res = makeRes();
+
+ await handler(req, res, vi.fn());
+
+ const { events } = parseSSE(res);
+ const addedEvent = events.find(
+ (e) => e.type === "response.output_item.added",
+ );
+ const doneEvent = events.find(
+ (e) => e.type === "response.output_item.done",
+ );
+
+ expect(addedEvent).toBeDefined();
+ expect(addedEvent.item.type).toBe("message");
+ expect(doneEvent).toBeDefined();
+ });
+ });
+
+ describe("non-streaming mode", () => {
+ test("returns JSON with output items", async () => {
+ const req = makeReq({
+ input: [{ role: "user", content: "Hello" }],
+ stream: false,
+ });
+ const res = makeRes();
+
+ await handler(req, res, vi.fn());
+
+ expect(res.json).toHaveBeenCalledWith(
+ expect.objectContaining({
+ output: expect.arrayContaining([
+ expect.objectContaining({
+ type: "message",
+ content: expect.arrayContaining([
+ expect.objectContaining({
+ type: "output_text",
+ text: "Echo: Hello",
+ }),
+ ]),
+ }),
+ ]),
+ }),
+ );
+ });
+ });
+
+ describe("input parsing", () => {
+ test("accepts string input", async () => {
+ const req = makeReq({
+ input: "Hello string",
+ stream: true,
+ });
+ const res = makeRes();
+
+ await handler(req, res, vi.fn());
+
+ const { fullOutput } = parseSSE(res);
+ expect(fullOutput).toContain("Echo: Hello string");
+ });
+
+ test("accepts array input with multipart content", async () => {
+ const req = makeReq({
+ input: [
+ {
+ role: "user",
+ content: [
+ { type: "input_text", text: "Part one" },
+ { type: "input_text", text: "Part two" },
+ ],
+ },
+ ],
+ stream: true,
+ });
+ const res = makeRes();
+
+ await handler(req, res, vi.fn());
+
+ const { fullOutput } = parseSSE(res);
+ expect(fullOutput).toContain("Echo: Part one\nPart two");
+ });
+ });
+
+ describe("chat history", () => {
+ test("passes chat history to agent", async () => {
+ const spyAgent = {
+ invoke: vi.fn().mockResolvedValue([
+ {
+ id: "msg_1",
+ type: "message",
+ role: "assistant",
+ status: "completed",
+ content: [
+ { type: "output_text", text: "response", annotations: [] },
+ ],
+ },
+ ]),
+ stream: vi.fn(),
+ };
+ const historyHandler = createInvokeHandler(() => spyAgent as any);
+
+ const req = makeReq({
+ input: [
+ { role: "user", content: "First message" },
+ { role: "assistant", content: "First reply" },
+ { role: "user", content: "Second message" },
+ ],
+ stream: false,
+ });
+ const res = makeRes();
+
+ await historyHandler(req, res, vi.fn());
+
+ expect(spyAgent.invoke).toHaveBeenCalledWith(
+ expect.objectContaining({
+ input: "Second message",
+ chat_history: expect.arrayContaining([
+ expect.objectContaining({
+ role: "user",
+ content: "First message",
+ }),
+ expect.objectContaining({
+ role: "assistant",
+ content: "First reply",
+ }),
+ ]),
+ }),
+ );
+ });
+
+ test("handles function_call items in history", async () => {
+ const spyAgent = {
+ invoke: vi.fn().mockResolvedValue([
+ {
+ id: "msg_1",
+ type: "message",
+ role: "assistant",
+ status: "completed",
+ content: [{ type: "output_text", text: "done", annotations: [] }],
+ },
+ ]),
+ stream: vi.fn(),
+ };
+ const historyHandler = createInvokeHandler(() => spyAgent as any);
+
+ const req = makeReq({
+ input: [
+ { role: "user", content: "Look up the answer" },
+ {
+ type: "function_call",
+ name: "search",
+ arguments: '{"q":"test"}',
+ },
+ {
+ type: "function_call_output",
+ output: '"42"',
+ },
+ { role: "user", content: "What did you find?" },
+ ],
+ stream: false,
+ });
+ const res = makeRes();
+
+ await historyHandler(req, res, vi.fn());
+
+ const calledHistory = spyAgent.invoke.mock.calls[0][0].chat_history;
+ expect(calledHistory).toHaveLength(3);
+ expect(calledHistory[1].content).toContain("[Tool Call:");
+ expect(calledHistory[2].content).toContain("[Tool Result:");
+ });
+ });
+
+ describe("error handling", () => {
+ test("returns 400 for missing input", async () => {
+ const req = makeReq({ stream: true });
+ const res = makeRes();
+
+ await handler(req, res, vi.fn());
+
+ expect(res.status).toHaveBeenCalledWith(400);
+ expect(res.json).toHaveBeenCalledWith(
+ expect.objectContaining({ error: "Invalid request format" }),
+ );
+ });
+
+ test("returns 400 when no user message is present", async () => {
+ const req = makeReq({
+ input: [{ role: "assistant", content: "I am assistant" }],
+ stream: true,
+ });
+ const res = makeRes();
+
+ await handler(req, res, vi.fn());
+
+ expect(res.status).toHaveBeenCalledWith(400);
+ expect(res.json).toHaveBeenCalledWith(
+ expect.objectContaining({
+ error: "No user message found in input",
+ }),
+ );
+ });
+
+ test("handles agent errors gracefully in streaming mode", async () => {
+ const errorAgent = {
+ invoke: vi.fn(),
+ stream: (_params: any) => {
+ // Return an async iterable that throws on first next()
+ return {
+ async next() {
+ throw new Error("Agent exploded");
+ },
+ async return() {
+ return { done: true, value: undefined };
+ },
+ async throw(e: unknown) {
+ throw e;
+ },
+ [Symbol.asyncIterator]() {
+ return this;
+ },
+ [Symbol.asyncDispose]: undefined,
+ } as unknown as AsyncGenerator;
+ },
+ };
+ const errorHandler = createInvokeHandler(() => errorAgent as any);
+
+ const req = makeReq({
+ input: [{ role: "user", content: "boom" }],
+ stream: true,
+ });
+ const res = makeRes();
+
+ await errorHandler(req, res, vi.fn());
+
+ const { events } = parseSSE(res);
+ const errorEvent = events.find((e) => e.type === "error");
+ const failedEvent = events.find((e) => e.type === "response.failed");
+
+ expect(errorEvent).toBeDefined();
+ expect(errorEvent.error).toContain("Agent exploded");
+ expect(failedEvent).toBeDefined();
+ expect(res.end).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/packages/appkit/src/plugins/agent/tests/stub-agent.ts b/packages/appkit/src/plugins/agent/tests/stub-agent.ts
new file mode 100644
index 00000000..540a2fca
--- /dev/null
+++ b/packages/appkit/src/plugins/agent/tests/stub-agent.ts
@@ -0,0 +1,71 @@
+/**
+ * Deterministic stub AgentInterface for framework tests.
+ *
+ * Echoes user input as "Echo: {input}" — no LLM or network required.
+ */
+
+import { randomUUID } from "node:crypto";
+import type {
+ AgentInterface,
+ InvokeParams,
+ ResponseOutputItem,
+ ResponseOutputMessage,
+ ResponseStreamEvent,
+} from "../agent-interface";
+
+export class StubAgent implements AgentInterface {
+ async invoke(params: InvokeParams): Promise {
+ const text = `Echo: ${params.input}`;
+ const message: ResponseOutputMessage = {
+ id: `msg_${randomUUID()}`,
+ type: "message",
+ role: "assistant",
+ status: "completed",
+ content: [{ type: "output_text", text, annotations: [] }],
+ };
+ return [message];
+ }
+
+ async *stream(params: InvokeParams): AsyncGenerator {
+ const text = `Echo: ${params.input}`;
+ const itemId = `msg_${randomUUID()}`;
+ let seqNum = 0;
+
+ const msgItem: ResponseOutputMessage = {
+ id: itemId,
+ type: "message",
+ role: "assistant",
+ status: "in_progress",
+ content: [],
+ };
+
+ yield {
+ type: "response.output_item.added",
+ item: msgItem,
+ output_index: 0,
+ sequence_number: seqNum++,
+ };
+
+ yield {
+ type: "response.output_text.delta",
+ item_id: itemId,
+ output_index: 0,
+ content_index: 0,
+ delta: text,
+ sequence_number: seqNum++,
+ };
+
+ yield {
+ type: "response.output_item.done",
+ item: { ...msgItem, status: "completed" },
+ output_index: 0,
+ sequence_number: seqNum++,
+ };
+
+ yield {
+ type: "response.completed",
+ sequence_number: seqNum++,
+ response: {},
+ };
+ }
+}
diff --git a/packages/appkit/src/plugins/agent/types.ts b/packages/appkit/src/plugins/agent/types.ts
new file mode 100644
index 00000000..0f6fa02c
--- /dev/null
+++ b/packages/appkit/src/plugins/agent/types.ts
@@ -0,0 +1,43 @@
+import type { DatabricksMCPServer } from "@databricks/langchainjs";
+import type { StructuredTool } from "@langchain/core/tools";
+import type { BasePluginConfig } from "shared";
+import type { AgentInterface } from "./agent-interface";
+
+export interface IAgentConfig extends BasePluginConfig {
+ /**
+ * Pre-built agent implementing AgentInterface.
+ * When provided the plugin skips internal LangGraph setup and delegates
+ * directly to this instance. Use this to bring your own agent
+ * implementation or a different LangChain variant.
+ */
+ agentInstance?: AgentInterface;
+
+ /**
+ * Databricks model serving endpoint name (e.g. "databricks-claude-sonnet-4-5").
+ * Falls back to DATABRICKS_MODEL env var.
+ * Ignored when `agentInstance` is provided.
+ */
+ model?: string;
+
+ /**
+ * Whether ChatDatabricks calls the upstream model using the Responses API
+ * instead of the Chat Completions API. Default: false.
+ * Ignored when `agentInstance` is provided.
+ */
+ useResponsesApi?: boolean;
+
+ /** System prompt injected at the start of every conversation */
+ systemPrompt?: string;
+
+ /** Sampling temperature (0.0-1.0, default 0.1). Ignored when `agentInstance` is provided. */
+ temperature?: number;
+
+ /** Max tokens to generate (default 2000). Ignored when `agentInstance` is provided. */
+ maxTokens?: number;
+
+ /** MCP servers for Databricks tool integration. Ignored when `agentInstance` is provided. */
+ mcpServers?: DatabricksMCPServer[];
+
+ /** Additional LangChain tools to register alongside MCP tools. Ignored when `agentInstance` is provided. */
+ tools?: StructuredTool[];
+}
diff --git a/packages/appkit/src/plugins/index.ts b/packages/appkit/src/plugins/index.ts
index fafd11eb..23fc1cb5 100644
--- a/packages/appkit/src/plugins/index.ts
+++ b/packages/appkit/src/plugins/index.ts
@@ -1,3 +1,4 @@
+export * from "./agent";
export * from "./analytics";
export * from "./genie";
export * from "./lakebase";
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 05a67f18..99e1dcaa 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -248,12 +248,27 @@ importers:
packages/appkit:
dependencies:
+ '@arizeai/openinference-instrumentation-langchain':
+ specifier: '>=4.0.0'
+ version: 4.0.6(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))
'@databricks/lakebase':
specifier: workspace:*
version: link:../lakebase
+ '@databricks/langchainjs':
+ specifier: '>=0.1.0'
+ version: 0.1.0(@cfworker/json-schema@4.1.1)(@langchain/langgraph@1.2.1(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(zod-to-json-schema@3.25.1(zod@4.1.13))(zod@4.1.13))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))
'@databricks/sdk-experimental':
specifier: ^0.16.0
version: 0.16.0
+ '@langchain/core':
+ specifier: '>=1.0.0'
+ version: 1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))
+ '@langchain/langgraph':
+ specifier: '>=1.0.0'
+ version: 1.2.1(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(zod-to-json-schema@3.25.1(zod@4.1.13))(zod@4.1.13)
+ '@langchain/mcp-adapters':
+ specifier: '>=1.0.0'
+ version: 1.1.3(@cfworker/json-schema@4.1.1)(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(@langchain/langgraph@1.2.1(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(zod-to-json-schema@3.25.1(zod@4.1.13))(zod@4.1.13))
'@opentelemetry/api':
specifier: ^1.9.0
version: 1.9.0
@@ -326,6 +341,9 @@ importers:
ws:
specifier: ^8.18.3
version: 8.18.3(bufferutil@4.0.9)
+ zod:
+ specifier: ^4.1.13
+ version: 4.1.13
zod-to-ts:
specifier: ^2.0.0
version: 2.0.0(typescript@5.9.3)(zod@4.1.13)
@@ -576,16 +594,32 @@ packages:
peerDependencies:
zod: ^3.25.76 || ^4.1.8
+ '@ai-sdk/gateway@3.0.66':
+ resolution: {integrity: sha512-SIQ0YY0iMuv+07HLsZ+bB990zUJ6S4ujORAh+Jv1V2KGNn73qQKnGO0JBk+w+Res8YqOFSycwDoWcFlQrVxS4A==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ zod: ^3.25.76 || ^4.1.8
+
'@ai-sdk/provider-utils@3.0.19':
resolution: {integrity: sha512-W41Wc9/jbUVXVwCN/7bWa4IKe8MtxO3EyA0Hfhx6grnmiYlCvpI8neSYWFE0zScXJkgA/YK3BRybzgyiXuu6JA==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.25.76 || ^4.1.8
+ '@ai-sdk/provider-utils@4.0.19':
+ resolution: {integrity: sha512-3eG55CrSWCu2SXlqq2QCsFjo3+E7+Gmg7i/oRVoSZzIodTuDSfLb3MRje67xE9RFea73Zao7Lm4mADIfUETKGg==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ zod: ^3.25.76 || ^4.1.8
+
'@ai-sdk/provider@2.0.0':
resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==}
engines: {node: '>=18'}
+ '@ai-sdk/provider@3.0.8':
+ resolution: {integrity: sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==}
+ engines: {node: '>=18'}
+
'@ai-sdk/react@2.0.115':
resolution: {integrity: sha512-Etu7gWSEi2dmXss1PoR5CAZGwGShXsF9+Pon1eRO6EmatjYaBMhq1CfHPyYhGzWrint8jJIK2VaAhiMef29qZw==}
engines: {node: '>=18'}
@@ -676,6 +710,17 @@ packages:
'@antfu/install-pkg@1.1.0':
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
+ '@arizeai/openinference-core@2.0.5':
+ resolution: {integrity: sha512-BnufYaFqmG9twkz/9DHX9WTcOs7YvVAYaufau5tdjOT1c0Y8niJwmNWzV36phNPg3c7SmdD5OYLuzeAUN0T3pQ==}
+
+ '@arizeai/openinference-instrumentation-langchain@4.0.6':
+ resolution: {integrity: sha512-yvA7ObrNUjhUN8y37lO+Cr8Ef7Bq6NKKoChXPOaKG/IufwAAcXUowdEC40gipUelS3k3AOgxcIU2rfP+7f+YyQ==}
+ peerDependencies:
+ '@langchain/core': ^1.0.0 || ^0.3.0 || ^0.2.0
+
+ '@arizeai/openinference-semantic-conventions@2.1.7':
+ resolution: {integrity: sha512-KyBfwxkSusPvxHBaW/TJ0japEbXCNziW9o6/IRKiPu+gp5TMKIagV2NKvt47rWYa4Jc0Nl+SvAPm+yxkdJqVbg==}
+
'@asamuzakjp/css-color@4.0.5':
resolution: {integrity: sha512-lMrXidNhPGsDjytDy11Vwlb6OIGrT3CmLg3VWNFyWkLWtijKl7xjvForlh8vuj0SHGjgl4qZEQzUmYTeQA2JFQ==}
@@ -1431,6 +1476,9 @@ packages:
'@braintree/sanitize-url@7.1.1':
resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==}
+ '@cfworker/json-schema@4.1.1':
+ resolution: {integrity: sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==}
+
'@chevrotain/cst-dts-gen@11.0.3':
resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==}
@@ -1831,6 +1879,21 @@ packages:
peerDependencies:
postcss: ^8.4
+ '@databricks/ai-sdk-provider@0.3.0':
+ resolution: {integrity: sha512-KKSeF/vvTeN/YEIzbpPl0tC0uWqXbCU3bjzAlX90aIUdyLjhD+8PviEXuh2g7YYpsDsBdWClu33Z7K+ooudfCA==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ '@ai-sdk/provider': ^3.0.5
+ '@ai-sdk/provider-utils': ^4.0.10
+
+ '@databricks/langchainjs@0.1.0':
+ resolution: {integrity: sha512-pCAsmoqBxoBOrHP9pxAxWj+jNbqqaD2WfYtnk61xpBpCbgfak1NA5MOZrc56TokidT8kam/f2RNKlFHjsok9aA==}
+ engines: {node: '>=18.0.0'}
+
+ '@databricks/sdk-experimental@0.15.0':
+ resolution: {integrity: sha512-HkoMiF7dNDt6WRW0xhi7oPlBJQfxJ9suJhEZRFt08VwLMaWcw2PiF8monfHlkD4lkufEYV6CTxi5njQkciqiHA==}
+ engines: {node: '>=22.0', npm: '>=10.0.0'}
+
'@databricks/sdk-experimental@0.16.0':
resolution: {integrity: sha512-9c2RxWYoRDFupdt4ZnBc1IPE1XaXgN+/wyV4DVcEqOnIa31ep51OnwAD/3014BImfKdyXg32nmgrB9dwvB6+lg==}
engines: {node: '>=22.0', npm: '>=10.0.0'}
@@ -2303,6 +2366,12 @@ packages:
'@hapi/topo@5.1.0':
resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
+ '@hono/node-server@1.19.11':
+ resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==}
+ engines: {node: '>=18.14.1'}
+ peerDependencies:
+ hono: ^4
+
'@hookform/resolvers@5.2.2':
resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==}
peerDependencies:
@@ -2551,6 +2620,48 @@ packages:
peerDependencies:
tslib: '2'
+ '@langchain/core@1.1.31':
+ resolution: {integrity: sha512-FxsgIUONjKaRpjx59sISgmb0OMCbAetPGyhzjGa2kX0y1f8LZ5xm9VB2db7W9HYWyLvzRWcMA51Uu4OSTJmtZQ==}
+ engines: {node: '>=20'}
+
+ '@langchain/langgraph-checkpoint@1.0.0':
+ resolution: {integrity: sha512-xrclBGvNCXDmi0Nz28t3vjpxSH6UYx6w5XAXSiiB1WEdc2xD2iY/a913I3x3a31XpInUW/GGfXXfePfaghV54A==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@langchain/core': ^1.0.1
+
+ '@langchain/langgraph-sdk@1.6.5':
+ resolution: {integrity: sha512-JjprmbhgCnoNJ9DUKcvrEU+C9FfKsNGyT3ooqWxAY5Cx2qofhXmDJOpTCqqbxfDHPKG0RjTs5HgVK3WW5M6Big==}
+ peerDependencies:
+ '@langchain/core': ^1.1.16
+ react: ^18 || ^19
+ react-dom: ^18 || ^19
+ peerDependenciesMeta:
+ '@langchain/core':
+ optional: true
+ react:
+ optional: true
+ react-dom:
+ optional: true
+
+ '@langchain/langgraph@1.2.1':
+ resolution: {integrity: sha512-OeLMejye1DZeZBPnurus2bqvjRi+pyrqfAXX77hYdUqKeQ3hAG7pLG04xdrvMs0pl/F57ZtwywqoE2oVqcI6JA==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@langchain/core': ^1.1.16
+ zod: ^3.25.32 || ^4.2.0
+ zod-to-json-schema: ^3.x
+ peerDependenciesMeta:
+ zod-to-json-schema:
+ optional: true
+
+ '@langchain/mcp-adapters@1.1.3':
+ resolution: {integrity: sha512-OPHIQNkTUJjnRj1pr+cp2nguMBZeF3Q1pVT1hCbgU7BrHgV7lov99wbU8po8Cm4zZzmeRtVO/T9X1SrDD1ogtQ==}
+ engines: {node: '>=20.10.0'}
+ peerDependencies:
+ '@langchain/core': ^1.0.0
+ '@langchain/langgraph': ^1.0.0
+
'@leichtgewicht/ip-codec@2.0.5':
resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==}
@@ -2566,6 +2677,16 @@ packages:
'@mermaid-js/parser@0.6.3':
resolution: {integrity: sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==}
+ '@modelcontextprotocol/sdk@1.27.1':
+ resolution: {integrity: sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@cfworker/json-schema': ^4.1.1
+ zod: ^3.25 || ^4.0
+ peerDependenciesMeta:
+ '@cfworker/json-schema':
+ optional: true
+
'@napi-rs/wasm-runtime@1.0.7':
resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==}
@@ -2660,6 +2781,12 @@ packages:
peerDependencies:
'@opentelemetry/api': '>=1.0.0 <1.10.0'
+ '@opentelemetry/core@1.30.1':
+ resolution: {integrity: sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ '@opentelemetry/api': '>=1.0.0 <1.10.0'
+
'@opentelemetry/core@2.2.0':
resolution: {integrity: sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==}
engines: {node: ^18.19.0 || >=20.6.0}
@@ -2984,6 +3111,12 @@ packages:
peerDependencies:
'@opentelemetry/api': ^1.3.0
+ '@opentelemetry/instrumentation@0.46.0':
+ resolution: {integrity: sha512-a9TijXZZbk0vI5TGLZl+0kxyFfrXHhX6Svtz7Pp2/VBlCSKrazuULEyoJQrOknJyFWNMEmbbJgOciHCCpQcisw==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ '@opentelemetry/api': ^1.3.0
+
'@opentelemetry/otlp-exporter-base@0.208.0':
resolution: {integrity: sha512-gMd39gIfVb2OgxldxUtOwGJYSH8P1kVFFlJLuut32L6KgUC4gl1dMhn+YC2mGn0bDOiQYSk/uHOdSjuKp58vvA==}
engines: {node: ^18.19.0 || >=20.6.0}
@@ -3084,6 +3217,10 @@ packages:
peerDependencies:
'@opentelemetry/api': '>=1.0.0 <1.10.0'
+ '@opentelemetry/semantic-conventions@1.28.0':
+ resolution: {integrity: sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==}
+ engines: {node: '>=14'}
+
'@opentelemetry/semantic-conventions@1.38.0':
resolution: {integrity: sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg==}
engines: {node: '>=14'}
@@ -4820,6 +4957,9 @@ packages:
'@types/serve-static@1.15.9':
resolution: {integrity: sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA==}
+ '@types/shimmer@1.2.0':
+ resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==}
+
'@types/sockjs@0.3.36':
resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==}
@@ -4838,6 +4978,9 @@ packages:
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
+ '@types/uuid@10.0.0':
+ resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==}
+
'@types/validator@13.15.10':
resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==}
@@ -4916,6 +5059,10 @@ packages:
resolution: {integrity: sha512-fnYhv671l+eTTp48gB4zEsTW/YtRgRPnkI2nT7x6qw5rkI1Lq2hTmQIpHPgyThI0znLK+vX2n9XxKdXZ7BUbbw==}
engines: {node: '>= 20'}
+ '@vercel/oidc@3.1.0':
+ resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==}
+ engines: {node: '>= 20'}
+
'@vitejs/plugin-react@5.0.4':
resolution: {integrity: sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -5039,6 +5186,16 @@ packages:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
engines: {node: '>= 0.6'}
+ accepts@2.0.0:
+ resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
+ engines: {node: '>= 0.6'}
+
+ acorn-import-assertions@1.9.0:
+ resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==}
+ deprecated: package has been renamed to acorn-import-attributes
+ peerDependencies:
+ acorn: ^8
+
acorn-import-attributes@1.9.5:
resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==}
peerDependencies:
@@ -5082,6 +5239,12 @@ packages:
peerDependencies:
zod: ^3.25.76 || ^4.1.8
+ ai@6.0.116:
+ resolution: {integrity: sha512-7yM+cTmyRLeNIXwt4Vj+mrrJgVQ9RMIW5WO0ydoLoYkewIvsMcvUmqS4j2RJTUXaF1HphwmSKUMQ/HypNRGOmA==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ zod: ^3.25.76 || ^4.1.8
+
ajv-formats@2.1.1:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
@@ -5340,6 +5503,10 @@ packages:
resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ body-parser@2.2.2:
+ resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==}
+ engines: {node: '>=18'}
+
bonjour-service@1.3.0:
resolution: {integrity: sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==}
@@ -5727,6 +5894,9 @@ packages:
console-control-strings@1.1.0:
resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
+ console-table-printer@2.15.0:
+ resolution: {integrity: sha512-SrhBq4hYVjLCkBVOWaTzceJalvn5K1Zq5aQA6wXC/cYjI3frKWNPEMK3sZsJfNNQApvCQmgBcc13ZKmFj8qExw==}
+
content-disposition@0.5.2:
resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==}
engines: {node: '>= 0.6'}
@@ -5735,6 +5905,10 @@ packages:
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
engines: {node: '>= 0.6'}
+ content-disposition@1.0.1:
+ resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==}
+ engines: {node: '>=18'}
+
content-type@1.0.5:
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
engines: {node: '>= 0.6'}
@@ -5790,6 +5964,10 @@ packages:
cookie-signature@1.0.7:
resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==}
+ cookie-signature@1.2.2:
+ resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
+ engines: {node: '>=6.6.0'}
+
cookie@0.7.2:
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
engines: {node: '>= 0.6'}
@@ -5812,6 +5990,10 @@ packages:
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+ cors@2.8.6:
+ resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==}
+ engines: {node: '>= 0.10'}
+
cose-base@1.0.3:
resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==}
@@ -6188,6 +6370,10 @@ packages:
supports-color:
optional: true
+ decamelize@1.2.0:
+ resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
+ engines: {node: '>=0.10.0'}
+
decimal.js-light@2.5.1:
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
@@ -6822,6 +7008,10 @@ packages:
resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==}
engines: {node: '>=18.0.0'}
+ eventsource@3.0.7:
+ resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
+ engines: {node: '>=18.0.0'}
+
execa@5.1.1:
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
engines: {node: '>=10'}
@@ -6838,10 +7028,20 @@ packages:
resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==}
engines: {node: '>=12.0.0'}
+ express-rate-limit@8.3.0:
+ resolution: {integrity: sha512-KJzBawY6fB9FiZGdE/0aftepZ91YlaGIrV8vgblRM3J8X+dHx/aiowJWwkx6LIGyuqGiANsjSwwrbb8mifOJ4Q==}
+ engines: {node: '>= 16'}
+ peerDependencies:
+ express: '>= 4.11'
+
express@4.22.0:
resolution: {integrity: sha512-c2iPh3xp5vvCLgaHK03+mWLFPhox7j1LwyxcZwFVApEv5i0X+IjPpbT50SJJwwLpdBVfp45AkK/v+AFgv/XlfQ==}
engines: {node: '>= 0.10.0'}
+ express@5.2.1:
+ resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==}
+ engines: {node: '>= 18'}
+
exsolve@1.0.8:
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
@@ -6852,6 +7052,9 @@ packages:
extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
+ extended-eventsource@1.7.0:
+ resolution: {integrity: sha512-s8rtvZuYcKBpzytHb5g95cHbZ1J99WeMnV18oKc5wKoxkHzlzpPc/bNAm7Da2Db0BDw0CAu1z3LpH+7UsyzIpw==}
+
fast-content-type-parse@3.0.0:
resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==}
@@ -6932,6 +7135,10 @@ packages:
resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==}
engines: {node: '>= 0.8'}
+ finalhandler@2.1.1:
+ resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
+ engines: {node: '>= 18.0.0'}
+
find-cache-dir@4.0.0:
resolution: {integrity: sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==}
engines: {node: '>=14.16'}
@@ -7034,6 +7241,10 @@ packages:
resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
engines: {node: '>= 0.6'}
+ fresh@2.0.0:
+ resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
+ engines: {node: '>= 0.8'}
+
fs-extra@11.3.2:
resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==}
engines: {node: '>=14.14'}
@@ -7399,6 +7610,10 @@ packages:
resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==}
engines: {node: '>=0.10.0'}
+ hono@4.12.5:
+ resolution: {integrity: sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg==}
+ engines: {node: '>=16.9.0'}
+
hookable@6.0.1:
resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==}
@@ -7555,6 +7770,9 @@ packages:
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
engines: {node: '>=6'}
+ import-in-the-middle@1.7.1:
+ resolution: {integrity: sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg==}
+
import-in-the-middle@2.0.0:
resolution: {integrity: sha512-yNZhyQYqXpkT0AKq3F3KLasUSK4fHvebNH5hOsKQw2dhGSALvQ4U0BqUc5suziKvydO5u5hgN2hy1RJaho8U5A==}
@@ -7795,6 +8013,9 @@ packages:
is-potential-custom-element-name@1.0.1:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+ is-promise@4.0.0:
+ resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
+
is-regexp@1.0.0:
resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==}
engines: {node: '>=0.10.0'}
@@ -7930,6 +8151,12 @@ packages:
joi@17.13.3:
resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
+ jose@6.2.1:
+ resolution: {integrity: sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw==}
+
+ js-tiktoken@1.0.21:
+ resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -7977,6 +8204,9 @@ packages:
json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
+ json-schema-typed@8.0.2:
+ resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==}
+
json-schema@0.4.0:
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
@@ -8023,6 +8253,23 @@ packages:
resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==}
engines: {node: '>=16.0.0'}
+ langsmith@0.5.8:
+ resolution: {integrity: sha512-AsdwxazXXLwbEzVTXB5uo7Fva5MhGhSvIJ9FjBbkWOkgwqC28E9Gmah5SGbPM3CPjN0FdxB6nKzX5GRkkkXDjQ==}
+ peerDependencies:
+ '@opentelemetry/api': '*'
+ '@opentelemetry/exporter-trace-otlp-proto': '*'
+ '@opentelemetry/sdk-trace-base': '*'
+ openai: '*'
+ peerDependenciesMeta:
+ '@opentelemetry/api':
+ optional: true
+ '@opentelemetry/exporter-trace-otlp-proto':
+ optional: true
+ '@opentelemetry/sdk-trace-base':
+ optional: true
+ openai:
+ optional: true
+
latest-version@7.0.0:
resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==}
engines: {node: '>=14.16'}
@@ -8390,6 +8637,10 @@ packages:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'}
+ media-typer@1.1.0:
+ resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
+ engines: {node: '>= 0.8'}
+
memfs@4.51.1:
resolution: {integrity: sha512-Eyt3XrufitN2ZL9c/uIRMyDwXanLI88h/L3MoWqNY747ha3dMR9dWqp8cRT5ntjZ0U1TNuq4U91ZXK0sMBjYOQ==}
@@ -8404,6 +8655,10 @@ packages:
merge-descriptors@1.0.3:
resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==}
+ merge-descriptors@2.0.0:
+ resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
+ engines: {node: '>=18'}
+
merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
@@ -8661,6 +8916,10 @@ packages:
resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==}
hasBin: true
+ mustache@4.2.0:
+ resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
+ hasBin: true
+
mute-stream@1.0.0:
resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -8688,6 +8947,10 @@ packages:
resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==}
engines: {node: '>= 0.6'}
+ negotiator@1.0.0:
+ resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
+ engines: {node: '>= 0.6'}
+
neo-async@2.6.2:
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
@@ -8916,14 +9179,26 @@ packages:
resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==}
engines: {node: '>=8'}
+ p-queue@9.1.0:
+ resolution: {integrity: sha512-O/ZPaXuQV29uSLbxWBGGZO1mCQXV2BLIwUr59JUU9SoH76mnYvtms7aafH/isNSNGwuEfP6W/4xD0/TJXxrizw==}
+ engines: {node: '>=20'}
+
p-retry@6.2.1:
resolution: {integrity: sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==}
engines: {node: '>=16.17'}
+ p-retry@7.1.1:
+ resolution: {integrity: sha512-J5ApzjyRkkf601HpEeykoiCvzHQjWxPAHhyjFcEUP2SWq0+35NKh8TLhpLw+Dkq5TZBFvUM6UigdE9hIVYTl5w==}
+ engines: {node: '>=20'}
+
p-timeout@3.2.0:
resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==}
engines: {node: '>=8'}
+ p-timeout@7.0.1:
+ resolution: {integrity: sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==}
+ engines: {node: '>=20'}
+
pac-proxy-agent@7.2.0:
resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==}
engines: {node: '>= 14'}
@@ -9040,6 +9315,9 @@ packages:
path-to-regexp@3.3.0:
resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==}
+ path-to-regexp@8.3.0:
+ resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==}
+
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@@ -9107,6 +9385,10 @@ packages:
engines: {node: '>=0.10'}
hasBin: true
+ pkce-challenge@5.0.1:
+ resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==}
+ engines: {node: '>=16.20.0'}
+
pkg-dir@7.0.0:
resolution: {integrity: sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==}
engines: {node: '>=14.16'}
@@ -9642,6 +9924,10 @@ packages:
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
engines: {node: '>=0.6'}
+ qs@6.15.0:
+ resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==}
+ engines: {node: '>=0.6'}
+
quansync@1.0.0:
resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==}
@@ -9670,6 +9956,10 @@ packages:
resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==}
engines: {node: '>= 0.8'}
+ raw-body@3.0.2:
+ resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==}
+ engines: {node: '>= 0.10'}
+
rc9@2.1.2:
resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==}
@@ -9939,6 +10229,10 @@ packages:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
+ require-in-the-middle@7.5.2:
+ resolution: {integrity: sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==}
+ engines: {node: '>=8.6.0'}
+
require-in-the-middle@8.0.1:
resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==}
engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'}
@@ -10103,6 +10397,10 @@ packages:
roughjs@4.6.6:
resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==}
+ router@2.2.0:
+ resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
+ engines: {node: '>= 18'}
+
rrweb-cssom@0.8.0:
resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==}
@@ -10206,6 +10504,10 @@ packages:
resolution: {integrity: sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==}
engines: {node: '>= 0.8.0'}
+ send@1.2.1:
+ resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==}
+ engines: {node: '>= 18'}
+
sequelize-pool@7.1.0:
resolution: {integrity: sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==}
engines: {node: '>= 10.0.0'}
@@ -10257,6 +10559,10 @@ packages:
resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
engines: {node: '>= 0.8.0'}
+ serve-static@2.2.1:
+ resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
+ engines: {node: '>= 18'}
+
set-function-length@1.2.2:
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
engines: {node: '>= 0.4'}
@@ -10291,6 +10597,9 @@ packages:
resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==}
engines: {node: '>= 0.4'}
+ shimmer@1.2.1:
+ resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==}
+
side-channel-list@1.0.0:
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
engines: {node: '>= 0.4'}
@@ -10317,6 +10626,9 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
+ simple-wcswidth@1.1.2:
+ resolution: {integrity: sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==}
+
sirv@2.0.4:
resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==}
engines: {node: '>= 10'}
@@ -10857,6 +11169,10 @@ packages:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'}
+ type-is@2.0.1:
+ resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
+ engines: {node: '>= 0.6'}
+
typed-array-buffer@1.0.3:
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
engines: {node: '>= 0.4'}
@@ -11155,10 +11471,18 @@ packages:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
+ uuid@10.0.0:
+ resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
+ hasBin: true
+
uuid@11.1.0:
resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==}
hasBin: true
+ uuid@13.0.0:
+ resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==}
+ hasBin: true
+
uuid@8.3.2:
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
hasBin: true
@@ -11581,6 +11905,11 @@ packages:
resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==}
engines: {node: '>=18'}
+ zod-to-json-schema@3.25.1:
+ resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==}
+ peerDependencies:
+ zod: ^3.25 || ^4
+
zod-to-ts@2.0.0:
resolution: {integrity: sha512-aHsUgIl+CQutKAxtRNeZslLCLXoeuSq+j5HU7q3kvi/c2KIAo6q4YjT7/lwFfACxLB923ELHYMkHmlxiqFy4lw==}
peerDependencies:
@@ -11596,6 +11925,9 @@ packages:
zod@4.1.13:
resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==}
+ zod@4.3.6:
+ resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
+
zrender@6.0.0:
resolution: {integrity: sha512-41dFXEEXuJpNecuUQq6JlbybmnHaqqpGlbH1yxnA5V9MMP4SbohSVZsJIwz+zdjQXSSlR1Vc34EgH1zxyTDvhg==}
@@ -11614,6 +11946,13 @@ snapshots:
'@vercel/oidc': 3.0.5
zod: 4.1.13
+ '@ai-sdk/gateway@3.0.66(zod@4.3.6)':
+ dependencies:
+ '@ai-sdk/provider': 3.0.8
+ '@ai-sdk/provider-utils': 4.0.19(zod@4.3.6)
+ '@vercel/oidc': 3.1.0
+ zod: 4.3.6
+
'@ai-sdk/provider-utils@3.0.19(zod@4.1.13)':
dependencies:
'@ai-sdk/provider': 2.0.0
@@ -11621,10 +11960,21 @@ snapshots:
eventsource-parser: 3.0.6
zod: 4.1.13
+ '@ai-sdk/provider-utils@4.0.19(zod@4.3.6)':
+ dependencies:
+ '@ai-sdk/provider': 3.0.8
+ '@standard-schema/spec': 1.1.0
+ eventsource-parser: 3.0.6
+ zod: 4.3.6
+
'@ai-sdk/provider@2.0.0':
dependencies:
json-schema: 0.4.0
+ '@ai-sdk/provider@3.0.8':
+ dependencies:
+ json-schema: 0.4.0
+
'@ai-sdk/react@2.0.115(react@19.2.0)(zod@4.1.13)':
dependencies:
'@ai-sdk/provider-utils': 3.0.19(zod@4.1.13)
@@ -11750,6 +12100,25 @@ snapshots:
package-manager-detector: 1.6.0
tinyexec: 1.0.1
+ '@arizeai/openinference-core@2.0.5':
+ dependencies:
+ '@arizeai/openinference-semantic-conventions': 2.1.7
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0)
+
+ '@arizeai/openinference-instrumentation-langchain@4.0.6(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))':
+ dependencies:
+ '@arizeai/openinference-core': 2.0.5
+ '@arizeai/openinference-semantic-conventions': 2.1.7
+ '@langchain/core': 1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0)
+ '@opentelemetry/instrumentation': 0.46.0(@opentelemetry/api@1.9.0)
+ transitivePeerDependencies:
+ - supports-color
+
+ '@arizeai/openinference-semantic-conventions@2.1.7': {}
+
'@asamuzakjp/css-color@4.0.5':
dependencies:
'@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
@@ -12701,6 +13070,8 @@ snapshots:
'@braintree/sanitize-url@7.1.1': {}
+ '@cfworker/json-schema@4.1.1': {}
+
'@chevrotain/cst-dts-gen@11.0.3':
dependencies:
'@chevrotain/gast': 11.0.3
@@ -13153,6 +13524,40 @@ snapshots:
dependencies:
postcss: 8.5.6
+ '@databricks/ai-sdk-provider@0.3.0(@ai-sdk/provider-utils@4.0.19(zod@4.3.6))(@ai-sdk/provider@3.0.8)':
+ dependencies:
+ '@ai-sdk/provider': 3.0.8
+ '@ai-sdk/provider-utils': 4.0.19(zod@4.3.6)
+ zod: 4.3.6
+
+ '@databricks/langchainjs@0.1.0(@cfworker/json-schema@4.1.1)(@langchain/langgraph@1.2.1(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(zod-to-json-schema@3.25.1(zod@4.1.13))(zod@4.1.13))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))':
+ dependencies:
+ '@ai-sdk/provider': 3.0.8
+ '@ai-sdk/provider-utils': 4.0.19(zod@4.3.6)
+ '@databricks/ai-sdk-provider': 0.3.0(@ai-sdk/provider-utils@4.0.19(zod@4.3.6))(@ai-sdk/provider@3.0.8)
+ '@databricks/sdk-experimental': 0.15.0
+ '@langchain/core': 1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))
+ '@langchain/mcp-adapters': 1.1.3(@cfworker/json-schema@4.1.1)(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(@langchain/langgraph@1.2.1(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(zod-to-json-schema@3.25.1(zod@4.1.13))(zod@4.1.13))
+ ai: 6.0.116(zod@4.3.6)
+ zod: 4.3.6
+ transitivePeerDependencies:
+ - '@cfworker/json-schema'
+ - '@langchain/langgraph'
+ - '@opentelemetry/api'
+ - '@opentelemetry/exporter-trace-otlp-proto'
+ - '@opentelemetry/sdk-trace-base'
+ - openai
+ - supports-color
+
+ '@databricks/sdk-experimental@0.15.0':
+ dependencies:
+ google-auth-library: 10.5.0
+ ini: 6.0.0
+ reflect-metadata: 0.2.2
+ semver: 7.7.3
+ transitivePeerDependencies:
+ - supports-color
+
'@databricks/sdk-experimental@0.16.0':
dependencies:
google-auth-library: 10.5.0
@@ -14172,6 +14577,10 @@ snapshots:
dependencies:
'@hapi/hoek': 9.3.0
+ '@hono/node-server@1.19.11(hono@4.12.5)':
+ dependencies:
+ hono: 4.12.5
+
'@hookform/resolvers@5.2.2(react-hook-form@7.68.0(react@19.2.0))':
dependencies:
'@standard-schema/utils': 0.3.0
@@ -14416,6 +14825,68 @@ snapshots:
'@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1)
tslib: 2.8.1
+ '@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))':
+ dependencies:
+ '@cfworker/json-schema': 4.1.1
+ '@standard-schema/spec': 1.1.0
+ ansi-styles: 5.2.0
+ camelcase: 6.3.0
+ decamelize: 1.2.0
+ js-tiktoken: 1.0.21
+ langsmith: 0.5.8(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))
+ mustache: 4.2.0
+ p-queue: 6.6.2
+ uuid: 11.1.0
+ zod: 4.1.13
+ transitivePeerDependencies:
+ - '@opentelemetry/api'
+ - '@opentelemetry/exporter-trace-otlp-proto'
+ - '@opentelemetry/sdk-trace-base'
+ - openai
+
+ '@langchain/langgraph-checkpoint@1.0.0(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))':
+ dependencies:
+ '@langchain/core': 1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))
+ uuid: 10.0.0
+
+ '@langchain/langgraph-sdk@1.6.5(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@types/json-schema': 7.0.15
+ p-queue: 9.1.0
+ p-retry: 7.1.1
+ uuid: 13.0.0
+ optionalDependencies:
+ '@langchain/core': 1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@langchain/langgraph@1.2.1(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(zod-to-json-schema@3.25.1(zod@4.1.13))(zod@4.1.13)':
+ dependencies:
+ '@langchain/core': 1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))
+ '@langchain/langgraph-checkpoint': 1.0.0(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))
+ '@langchain/langgraph-sdk': 1.6.5(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@standard-schema/spec': 1.1.0
+ uuid: 10.0.0
+ zod: 4.1.13
+ optionalDependencies:
+ zod-to-json-schema: 3.25.1(zod@4.1.13)
+ transitivePeerDependencies:
+ - react
+ - react-dom
+
+ '@langchain/mcp-adapters@1.1.3(@cfworker/json-schema@4.1.1)(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(@langchain/langgraph@1.2.1(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(zod-to-json-schema@3.25.1(zod@4.1.13))(zod@4.1.13))':
+ dependencies:
+ '@langchain/core': 1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))
+ '@langchain/langgraph': 1.2.1(@langchain/core@1.1.31(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(zod-to-json-schema@3.25.1(zod@4.1.13))(zod@4.1.13)
+ '@modelcontextprotocol/sdk': 1.27.1(@cfworker/json-schema@4.1.1)(zod@4.1.13)
+ debug: 4.4.3
+ zod: 4.1.13
+ optionalDependencies:
+ extended-eventsource: 1.7.0
+ transitivePeerDependencies:
+ - '@cfworker/json-schema'
+ - supports-color
+
'@leichtgewicht/ip-codec@2.0.5': {}
'@mdx-js/mdx@3.1.1':
@@ -14458,6 +14929,30 @@ snapshots:
dependencies:
langium: 3.3.1
+ '@modelcontextprotocol/sdk@1.27.1(@cfworker/json-schema@4.1.1)(zod@4.1.13)':
+ dependencies:
+ '@hono/node-server': 1.19.11(hono@4.12.5)
+ ajv: 8.17.1
+ ajv-formats: 3.0.1(ajv@8.17.1)
+ content-type: 1.0.5
+ cors: 2.8.6
+ cross-spawn: 7.0.6
+ eventsource: 3.0.7
+ eventsource-parser: 3.0.6
+ express: 5.2.1
+ express-rate-limit: 8.3.0(express@5.2.1)
+ hono: 4.12.5
+ jose: 6.2.1
+ json-schema-typed: 8.0.2
+ pkce-challenge: 5.0.1
+ raw-body: 3.0.2
+ zod: 4.1.13
+ zod-to-json-schema: 3.25.1(zod@4.1.13)
+ optionalDependencies:
+ '@cfworker/json-schema': 4.1.1
+ transitivePeerDependencies:
+ - supports-color
+
'@napi-rs/wasm-runtime@1.0.7':
dependencies:
'@emnapi/core': 1.7.1
@@ -14617,6 +15112,11 @@ snapshots:
dependencies:
'@opentelemetry/api': 1.9.0
+ '@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0)':
+ dependencies:
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/semantic-conventions': 1.28.0
+
'@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0)':
dependencies:
'@opentelemetry/api': 1.9.0
@@ -15077,6 +15577,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@opentelemetry/instrumentation@0.46.0(@opentelemetry/api@1.9.0)':
+ dependencies:
+ '@opentelemetry/api': 1.9.0
+ '@types/shimmer': 1.2.0
+ import-in-the-middle: 1.7.1
+ require-in-the-middle: 7.5.2
+ semver: 7.7.3
+ shimmer: 1.2.1
+ transitivePeerDependencies:
+ - supports-color
+
'@opentelemetry/otlp-exporter-base@0.208.0(@opentelemetry/api@1.9.0)':
dependencies:
'@opentelemetry/api': 1.9.0
@@ -15211,6 +15722,8 @@ snapshots:
'@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/semantic-conventions@1.28.0': {}
+
'@opentelemetry/semantic-conventions@1.38.0': {}
'@opentelemetry/sql-common@0.41.2(@opentelemetry/api@1.9.0)':
@@ -16898,6 +17411,8 @@ snapshots:
'@types/node': 24.10.1
'@types/send': 0.17.5
+ '@types/shimmer@1.2.0': {}
+
'@types/sockjs@0.3.36':
dependencies:
'@types/node': 24.10.1
@@ -16917,6 +17432,8 @@ snapshots:
'@types/unist@3.0.3': {}
+ '@types/uuid@10.0.0': {}
+
'@types/validator@13.15.10': {}
'@types/ws@8.18.1':
@@ -17024,6 +17541,8 @@ snapshots:
'@vercel/oidc@3.0.5': {}
+ '@vercel/oidc@3.1.0': {}
+
'@vitejs/plugin-react@5.0.4(rolldown-vite@7.1.14(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))':
dependencies:
'@babel/core': 7.28.4
@@ -17254,6 +17773,15 @@ snapshots:
mime-types: 2.1.35
negotiator: 0.6.3
+ accepts@2.0.0:
+ dependencies:
+ mime-types: 3.0.2
+ negotiator: 1.0.0
+
+ acorn-import-assertions@1.9.0(acorn@8.15.0):
+ dependencies:
+ acorn: 8.15.0
+
acorn-import-attributes@1.9.5(acorn@8.15.0):
dependencies:
acorn: 8.15.0
@@ -17289,6 +17817,14 @@ snapshots:
'@opentelemetry/api': 1.9.0
zod: 4.1.13
+ ai@6.0.116(zod@4.3.6):
+ dependencies:
+ '@ai-sdk/gateway': 3.0.66(zod@4.3.6)
+ '@ai-sdk/provider': 3.0.8
+ '@ai-sdk/provider-utils': 4.0.19(zod@4.3.6)
+ '@opentelemetry/api': 1.9.0
+ zod: 4.3.6
+
ajv-formats@2.1.1(ajv@8.17.1):
optionalDependencies:
ajv: 8.17.1
@@ -17552,6 +18088,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ body-parser@2.2.2:
+ dependencies:
+ bytes: 3.1.2
+ content-type: 1.0.5
+ debug: 4.4.3
+ http-errors: 2.0.1
+ iconv-lite: 0.7.0
+ on-finished: 2.4.1
+ qs: 6.15.0
+ raw-body: 3.0.2
+ type-is: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
bonjour-service@1.3.0:
dependencies:
fast-deep-equal: 3.1.3
@@ -17975,12 +18525,18 @@ snapshots:
console-control-strings@1.1.0: {}
+ console-table-printer@2.15.0:
+ dependencies:
+ simple-wcswidth: 1.1.2
+
content-disposition@0.5.2: {}
content-disposition@0.5.4:
dependencies:
safe-buffer: 5.2.1
+ content-disposition@1.0.1: {}
+
content-type@1.0.5: {}
conventional-changelog-angular@7.0.0:
@@ -18042,6 +18598,8 @@ snapshots:
cookie-signature@1.0.7: {}
+ cookie-signature@1.2.2: {}
+
cookie@0.7.2: {}
copy-webpack-plugin@11.0.0(webpack@5.103.0):
@@ -18064,6 +18622,11 @@ snapshots:
core-util-is@1.0.3: {}
+ cors@2.8.6:
+ dependencies:
+ object-assign: 4.1.1
+ vary: 1.1.2
+
cose-base@1.0.3:
dependencies:
layout-base: 1.0.2
@@ -18476,6 +19039,8 @@ snapshots:
dependencies:
ms: 2.1.3
+ decamelize@1.2.0: {}
+
decimal.js-light@2.5.1: {}
decimal.js@10.6.0: {}
@@ -19052,6 +19617,10 @@ snapshots:
eventsource-parser@3.0.6: {}
+ eventsource@3.0.7:
+ dependencies:
+ eventsource-parser: 3.0.6
+
execa@5.1.1:
dependencies:
cross-spawn: 7.0.6
@@ -19082,6 +19651,11 @@ snapshots:
expect-type@1.2.2: {}
+ express-rate-limit@8.3.0(express@5.2.1):
+ dependencies:
+ express: 5.2.1
+ ip-address: 10.1.0
+
express@4.22.0:
dependencies:
accepts: 1.3.8
@@ -19118,6 +19692,39 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ express@5.2.1:
+ dependencies:
+ accepts: 2.0.0
+ body-parser: 2.2.2
+ content-disposition: 1.0.1
+ content-type: 1.0.5
+ cookie: 0.7.2
+ cookie-signature: 1.2.2
+ debug: 4.4.3
+ depd: 2.0.0
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ finalhandler: 2.1.1
+ fresh: 2.0.0
+ http-errors: 2.0.1
+ merge-descriptors: 2.0.0
+ mime-types: 3.0.2
+ on-finished: 2.4.1
+ once: 1.4.0
+ parseurl: 1.3.3
+ proxy-addr: 2.0.7
+ qs: 6.14.0
+ range-parser: 1.2.1
+ router: 2.2.0
+ send: 1.2.1
+ serve-static: 2.2.1
+ statuses: 2.0.2
+ type-is: 2.0.1
+ vary: 1.1.2
+ transitivePeerDependencies:
+ - supports-color
+
exsolve@1.0.8: {}
extend-shallow@2.0.1:
@@ -19126,6 +19733,9 @@ snapshots:
extend@3.0.2: {}
+ extended-eventsource@1.7.0:
+ optional: true
+
fast-content-type-parse@3.0.0: {}
fast-deep-equal@3.1.3: {}
@@ -19219,6 +19829,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ finalhandler@2.1.1:
+ dependencies:
+ debug: 4.4.3
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ statuses: 2.0.2
+ transitivePeerDependencies:
+ - supports-color
+
find-cache-dir@4.0.0:
dependencies:
common-path-prefix: 3.0.0
@@ -19303,6 +19924,8 @@ snapshots:
fresh@0.5.2: {}
+ fresh@2.0.0: {}
+
fs-extra@11.3.2:
dependencies:
graceful-fs: 4.2.11
@@ -19900,6 +20523,8 @@ snapshots:
dependencies:
parse-passwd: 1.0.0
+ hono@4.12.5: {}
+
hookable@6.0.1: {}
hosted-git-info@8.1.0:
@@ -20074,6 +20699,13 @@ snapshots:
parent-module: 1.0.1
resolve-from: 4.0.0
+ import-in-the-middle@1.7.1:
+ dependencies:
+ acorn: 8.15.0
+ acorn-import-assertions: 1.9.0(acorn@8.15.0)
+ cjs-module-lexer: 1.4.3
+ module-details-from-path: 1.0.4
+
import-in-the-middle@2.0.0:
dependencies:
acorn: 8.15.0
@@ -20257,6 +20889,8 @@ snapshots:
is-potential-custom-element-name@1.0.1: {}
+ is-promise@4.0.0: {}
+
is-regexp@1.0.0: {}
is-relative@1.0.0:
@@ -20396,6 +21030,12 @@ snapshots:
'@sideway/formula': 3.0.1
'@sideway/pinpoint': 2.0.0
+ jose@6.2.1: {}
+
+ js-tiktoken@1.0.21:
+ dependencies:
+ base64-js: 1.5.1
+
js-tokens@4.0.0: {}
js-tokens@9.0.1: {}
@@ -20453,6 +21093,8 @@ snapshots:
json-schema-traverse@1.0.0: {}
+ json-schema-typed@8.0.2: {}
+
json-schema@0.4.0: {}
json-stable-stringify-without-jsonify@1.0.1: {}
@@ -20500,6 +21142,19 @@ snapshots:
vscode-languageserver-textdocument: 1.0.12
vscode-uri: 3.0.8
+ langsmith@0.5.8(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)):
+ dependencies:
+ '@types/uuid': 10.0.0
+ chalk: 5.6.2
+ console-table-printer: 2.15.0
+ p-queue: 6.6.2
+ semver: 7.7.3
+ uuid: 10.0.0
+ optionalDependencies:
+ '@opentelemetry/api': 1.9.0
+ '@opentelemetry/exporter-trace-otlp-proto': 0.208.0(@opentelemetry/api@1.9.0)
+ '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0)
+
latest-version@7.0.0:
dependencies:
package-json: 8.1.1
@@ -20962,6 +21617,8 @@ snapshots:
media-typer@0.3.0: {}
+ media-typer@1.1.0: {}
+
memfs@4.51.1:
dependencies:
'@jsonjoy.com/json-pack': 1.21.0(tslib@2.8.1)
@@ -20977,6 +21634,8 @@ snapshots:
merge-descriptors@1.0.3: {}
+ merge-descriptors@2.0.0: {}
+
merge-stream@2.0.0: {}
merge2@1.4.1: {}
@@ -21398,6 +22057,8 @@ snapshots:
dns-packet: 5.6.1
thunky: 1.1.0
+ mustache@4.2.0: {}
+
mute-stream@1.0.0: {}
mute-stream@2.0.0: {}
@@ -21414,6 +22075,8 @@ snapshots:
negotiator@0.6.4: {}
+ negotiator@1.0.0: {}
+
neo-async@2.6.2: {}
netmask@2.0.2: {}
@@ -21661,16 +22324,27 @@ snapshots:
eventemitter3: 4.0.7
p-timeout: 3.2.0
+ p-queue@9.1.0:
+ dependencies:
+ eventemitter3: 5.0.1
+ p-timeout: 7.0.1
+
p-retry@6.2.1:
dependencies:
'@types/retry': 0.12.2
is-network-error: 1.3.0
retry: 0.13.1
+ p-retry@7.1.1:
+ dependencies:
+ is-network-error: 1.3.0
+
p-timeout@3.2.0:
dependencies:
p-finally: 1.0.0
+ p-timeout@7.0.1: {}
+
pac-proxy-agent@7.2.0:
dependencies:
'@tootallnate/quickjs-emscripten': 0.23.0
@@ -21798,6 +22472,8 @@ snapshots:
path-to-regexp@3.3.0: {}
+ path-to-regexp@8.3.0: {}
+
path-type@4.0.0: {}
pathe@2.0.3: {}
@@ -21851,6 +22527,8 @@ snapshots:
pidtree@0.6.0: {}
+ pkce-challenge@5.0.1: {}
+
pkg-dir@7.0.0:
dependencies:
find-up: 6.3.0
@@ -22473,6 +23151,10 @@ snapshots:
dependencies:
side-channel: 1.1.0
+ qs@6.15.0:
+ dependencies:
+ side-channel: 1.1.0
+
quansync@1.0.0: {}
queue-microtask@1.2.3: {}
@@ -22496,6 +23178,13 @@ snapshots:
iconv-lite: 0.4.24
unpipe: 1.0.0
+ raw-body@3.0.2:
+ dependencies:
+ bytes: 3.1.2
+ http-errors: 2.0.1
+ iconv-lite: 0.7.0
+ unpipe: 1.0.0
+
rc9@2.1.2:
dependencies:
defu: 6.1.4
@@ -22885,6 +23574,14 @@ snapshots:
require-from-string@2.0.2: {}
+ require-in-the-middle@7.5.2:
+ dependencies:
+ debug: 4.4.3
+ module-details-from-path: 1.0.4
+ resolve: 1.22.10
+ transitivePeerDependencies:
+ - supports-color
+
require-in-the-middle@8.0.1:
dependencies:
debug: 4.4.3
@@ -23101,6 +23798,16 @@ snapshots:
points-on-curve: 0.2.0
points-on-path: 0.2.1
+ router@2.2.0:
+ dependencies:
+ debug: 4.4.3
+ depd: 2.0.0
+ is-promise: 4.0.0
+ parseurl: 1.3.3
+ path-to-regexp: 8.3.0
+ transitivePeerDependencies:
+ - supports-color
+
rrweb-cssom@0.8.0: {}
rtlcss@4.3.0:
@@ -23222,6 +23929,22 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ send@1.2.1:
+ dependencies:
+ debug: 4.4.3
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ fresh: 2.0.0
+ http-errors: 2.0.1
+ mime-types: 3.0.2
+ ms: 2.1.3
+ on-finished: 2.4.1
+ range-parser: 1.2.1
+ statuses: 2.0.2
+ transitivePeerDependencies:
+ - supports-color
+
sequelize-pool@7.1.0: {}
sequelize@6.37.7(pg@8.18.0):
@@ -23282,6 +24005,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ serve-static@2.2.1:
+ dependencies:
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ parseurl: 1.3.3
+ send: 1.2.1
+ transitivePeerDependencies:
+ - supports-color
+
set-function-length@1.2.2:
dependencies:
define-data-property: 1.1.4
@@ -23315,6 +24047,8 @@ snapshots:
shell-quote@1.8.3: {}
+ shimmer@1.2.1: {}
+
side-channel-list@1.0.0:
dependencies:
es-errors: 1.3.0
@@ -23349,6 +24083,8 @@ snapshots:
signal-exit@4.1.0: {}
+ simple-wcswidth@1.1.2: {}
+
sirv@2.0.4:
dependencies:
'@polka/url': 1.0.0-next.29
@@ -23831,6 +24567,12 @@ snapshots:
media-typer: 0.3.0
mime-types: 2.1.35
+ type-is@2.0.1:
+ dependencies:
+ content-type: 1.0.5
+ media-typer: 1.1.0
+ mime-types: 3.0.2
+
typed-array-buffer@1.0.3:
dependencies:
call-bound: 1.0.4
@@ -24095,8 +24837,12 @@ snapshots:
utils-merge@1.0.1: {}
+ uuid@10.0.0: {}
+
uuid@11.1.0: {}
+ uuid@13.0.0: {}
+
uuid@8.3.2: {}
uuid@9.0.1: {}
@@ -24605,6 +25351,10 @@ snapshots:
yoctocolors@2.1.2: {}
+ zod-to-json-schema@3.25.1(zod@4.1.13):
+ dependencies:
+ zod: 4.1.13
+
zod-to-ts@2.0.0(typescript@5.9.3)(zod@4.1.13):
dependencies:
typescript: 5.9.3
@@ -24616,6 +25366,8 @@ snapshots:
zod@4.1.13: {}
+ zod@4.3.6: {}
+
zrender@6.0.0:
dependencies:
tslib: 2.3.0
diff --git a/template/appkit.plugins.json b/template/appkit.plugins.json
index 03bcabc2..d93fe2d3 100644
--- a/template/appkit.plugins.json
+++ b/template/appkit.plugins.json
@@ -2,6 +2,30 @@
"$schema": "https://databricks.github.io/appkit/schemas/template-plugins.schema.json",
"version": "1.0",
"plugins": {
+ "agent": {
+ "name": "agent",
+ "displayName": "Agent Plugin",
+ "description": "LangChain/LangGraph AI agent with streaming Responses API and MCP tool support",
+ "package": "@databricks/appkit",
+ "resources": {
+ "required": [
+ {
+ "type": "serving_endpoint",
+ "alias": "Model Endpoint",
+ "resourceKey": "agent-model-endpoint",
+ "description": "Databricks model serving endpoint for the agent LLM",
+ "permission": "CAN_QUERY",
+ "fields": {
+ "name": {
+ "env": "DATABRICKS_MODEL",
+ "description": "Model serving endpoint name"
+ }
+ }
+ }
+ ],
+ "optional": []
+ }
+ },
"analytics": {
"name": "analytics",
"displayName": "Analytics Plugin",