diff --git a/.gitignore b/.gitignore
index 7167d0b1..d12cb157 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,3 +46,5 @@ storybook-static
# Angular
.angular/
.playwright-mcp/
+
+.pnpm-store
diff --git a/apps/angular/demo-server/package.json b/apps/angular/demo-server/package.json
index 4aff6a1e..b47cc43f 100644
--- a/apps/angular/demo-server/package.json
+++ b/apps/angular/demo-server/package.json
@@ -8,7 +8,7 @@
"start": "node --env-file=.env --loader tsx src/index.ts"
},
"dependencies": {
- "@ag-ui/client": "0.0.40-alpha.3",
+ "@ag-ui/client": "0.0.40-alpha.6",
"@ag-ui/langgraph": "^0.0.11",
"@copilotkitnext/demo-agents": "workspace:^",
"@copilotkitnext/runtime": "workspace:^",
diff --git a/apps/angular/demo-server/src/index.ts b/apps/angular/demo-server/src/index.ts
index 5c105349..9f93ae6a 100644
--- a/apps/angular/demo-server/src/index.ts
+++ b/apps/angular/demo-server/src/index.ts
@@ -1,13 +1,20 @@
import { serve } from "@hono/node-server";
import { Hono } from "hono";
import { cors } from "hono/cors";
-import { CopilotRuntime, createCopilotEndpoint, InMemoryAgentRunner } from "@copilotkitnext/runtime";
-import { OpenAIAgent, SlowToolCallStreamingAgent } from "@copilotkitnext/demo-agents";
+import {
+ CopilotRuntime,
+ createCopilotEndpoint,
+ InMemoryAgentRunner,
+} from "@copilotkitnext/runtime";
+import {
+ OpenAIAgent,
+ SlowToolCallStreamingAgent,
+} from "@copilotkitnext/demo-agents";
const runtime = new CopilotRuntime({
agents: {
// @ts-ignore
- default: new OpenAIAgent(),
+ default: new SlowToolCallStreamingAgent(),
},
runner: new InMemoryAgentRunner(),
});
@@ -25,7 +32,7 @@ app.use(
exposeHeaders: ["Content-Type"],
credentials: true,
maxAge: 86400,
- }),
+ })
);
// Create the CopilotKit endpoint
@@ -39,4 +46,6 @@ app.route("/", copilotApp);
const port = Number(process.env.PORT || 3001);
serve({ fetch: app.fetch, port });
-console.log(`CopilotKit runtime listening at http://localhost:${port}/api/copilotkit`);
+console.log(
+ `CopilotKit runtime listening at http://localhost:${port}/api/copilotkit`
+);
diff --git a/apps/angular/demo/package.json b/apps/angular/demo/package.json
index ad81164b..a1a962af 100644
--- a/apps/angular/demo/package.json
+++ b/apps/angular/demo/package.json
@@ -22,7 +22,6 @@
"@copilotkitnext/angular": "workspace:*",
"rxjs": "^7.8.1",
"tslib": "^2.8.1",
- "zod": "^3.25.75",
"zone.js": "^0.14.0"
},
"devDependencies": {
diff --git a/apps/angular/demo/src/app/app.config.ts b/apps/angular/demo/src/app/app.config.ts
index 081f8f88..d2c2747d 100644
--- a/apps/angular/demo/src/app/app.config.ts
+++ b/apps/angular/demo/src/app/app.config.ts
@@ -1,8 +1,10 @@
import { ApplicationConfig, importProvidersFrom } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
-import { provideCopilotKit, provideCopilotChatLabels } from "@copilotkitnext/angular";
+import {
+ provideCopilotKit,
+ provideCopilotChatLabels,
+} from "@copilotkitnext/angular";
import { WildcardToolRenderComponent } from "./components/wildcard-tool-render.component";
-import { helloWorldToolConfig } from "./tools/hello-world";
export const appConfig: ApplicationConfig = {
providers: [
@@ -15,12 +17,13 @@ export const appConfig: ApplicationConfig = {
component: WildcardToolRenderComponent,
} as any,
],
- frontendTools: [helloWorldToolConfig],
+ frontendTools: [],
humanInTheLoop: [],
}),
provideCopilotChatLabels({
chatInputPlaceholder: "Ask me anything...",
- chatDisclaimerText: "CopilotKit Angular Demo - AI responses may need verification.",
+ chatDisclaimerText:
+ "CopilotKit Angular Demo - AI responses may need verification.",
}),
],
};
diff --git a/apps/angular/demo/src/app/tools/hello-world.ts b/apps/angular/demo/src/app/tools/hello-world.ts
deleted file mode 100644
index 6a989527..00000000
--- a/apps/angular/demo/src/app/tools/hello-world.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { Component, input } from "@angular/core";
-import { FrontendToolConfig, ToolRenderer } from "@copilotkitnext/angular";
-import { JsonPipe } from "@angular/common";
-import { AngularToolCall } from "@copilotkitnext/angular";
-import { z } from "zod";
-
-@Component({
- selector: "app-hello-world-tool",
- template: `
{{ toolCall() | json }} `,
- standalone: true,
- imports: [JsonPipe],
-})
-export class HelloWorldTool implements ToolRenderer {
- toolCall = input.required();
-}
-
-export const helloWorldToolConfig: FrontendToolConfig = {
- name: "hello_world",
- description: "Says hello to the world",
- args: z.object({
- name: z.string(),
- }),
- component: HelloWorldTool,
- handler: async (args) => {
- return `Hello ${args.name}!`;
- },
-};
diff --git a/apps/angular/storybook/package.json b/apps/angular/storybook/package.json
index d668c9f2..c53ccbac 100644
--- a/apps/angular/storybook/package.json
+++ b/apps/angular/storybook/package.json
@@ -9,7 +9,7 @@
"storybook:build": "ng run storybook-angular:build-storybook"
},
"dependencies": {
- "@ag-ui/client": "0.0.40-alpha.3",
+ "@ag-ui/client": "0.0.40-alpha.6",
"@angular/animations": "^18.2.0",
"@angular/common": "^18.2.0",
"@angular/compiler": "^18.2.0",
diff --git a/apps/react/demo/package.json b/apps/react/demo/package.json
index 7fe4923d..60652968 100644
--- a/apps/react/demo/package.json
+++ b/apps/react/demo/package.json
@@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
- "@ag-ui/client": "0.0.40-alpha.3",
+ "@ag-ui/client": "0.0.40-alpha.6",
"@copilotkitnext/agent": "workspace:*",
"@copilotkitnext/core": "workspace:*",
"@copilotkitnext/react": "workspace:*",
diff --git a/apps/react/demo/src/app/page.tsx b/apps/react/demo/src/app/page.tsx
index 983daba5..a6107430 100644
--- a/apps/react/demo/src/app/page.tsx
+++ b/apps/react/demo/src/app/page.tsx
@@ -1,14 +1,13 @@
"use client";
-import { HttpAgent } from "@ag-ui/client";
import {
CopilotChat,
CopilotKitProvider,
useFrontendTool,
defineToolCallRenderer,
useConfigureSuggestions,
- type ToolsMenuItem,
} from "@copilotkitnext/react";
+import type { ToolsMenuItem } from "@copilotkitnext/react";
import { z } from "zod";
import { useMemo } from "react";
@@ -76,7 +75,7 @@ function Chat() {
return `Hello ${name}`;
},
});
- const toolsMenu = useMemo<("-" | ToolsMenuItem)[]>(
+ const toolsMenu = useMemo<(ToolsMenuItem | "-")[]>(
() => [
{
label: "Say hi to CopilotKit",
@@ -108,5 +107,5 @@ function Chat() {
[],
);
- return ;
+ return ;
}
diff --git a/package.json b/package.json
index 180efc13..96d30e4e 100644
--- a/package.json
+++ b/package.json
@@ -2,11 +2,11 @@
"name": "CopilotKitNext",
"private": true,
"scripts": {
- "predev": "turbo run build --filter='@copilotkitnext/core' --filter='@copilotkitnext/shared' --filter='@copilotkitnext/web-inspector' --filter='@copilotkitnext/react' --filter='@copilotkitnext/angular' --filter='@copilotkitnext/agent'",
+ "predev": "turbo run build --filter='@copilotkitnext/core' --filter='@copilotkitnext/shared' --filter='@copilotkitnext/web-inspector' --filter='@copilotkitnext/react' --filter='@copilotkitnext/angular' --filter='@copilotkitnext/agent' --filter='@copilotkitnext/sqlite-runner'",
"build": "turbo run build",
"clean": "turbo run clean",
- "dev": "turbo run dev --filter='@copilotkitnext/core' --filter='@copilotkitnext/shared' --filter='@copilotkitnext/web-inspector' --filter='@copilotkitnext/runtime' --filter='@copilotkitnext/react' --filter='@copilotkitnext/angular' --filter='@copilotkitnext/agent' --concurrency=15",
- "dev:packages": "turbo run dev --filter='@copilotkitnext/core' --filter='@copilotkitnext/shared' --filter='@copilotkitnext/web-inspector' --filter='@copilotkitnext/runtime' --filter='@copilotkitnext/react' --filter='@copilotkitnext/angular' --filter='@copilotkitnext/agent'",
+ "dev": "turbo run dev --filter='@copilotkitnext/core' --filter='@copilotkitnext/shared' --filter='@copilotkitnext/web-inspector' --filter='@copilotkitnext/runtime' --filter='@copilotkitnext/sqlite-runner' --filter='@copilotkitnext/react' --filter='@copilotkitnext/angular' --filter='@copilotkitnext/agent' --concurrency=15",
+ "dev:packages": "turbo run dev --filter='@copilotkitnext/core' --filter='@copilotkitnext/shared' --filter='@copilotkitnext/web-inspector' --filter='@copilotkitnext/runtime' --filter='@copilotkitnext/sqlite-runner' --filter='@copilotkitnext/react' --filter='@copilotkitnext/angular' --filter='@copilotkitnext/agent'",
"demo:angular": "turbo run dev --filter='@copilotkitnext/angular-demo-server' --filter='@copilotkitnext/angular-demo'",
"storybook:angular": "pnpm -C apps/angular/storybook dev",
"demo:react": "pnpm -C apps/react/demo dev",
@@ -22,9 +22,9 @@
"storybook": "pnpm storybook:react",
"storybook:all": "echo 'Run storybooks in separate terminals: pnpm storybook:react | pnpm storybook:angular'",
"build-storybook": "turbo run build --filter=storybook --filter=storybook-angular",
- "bump:prerelease": "pnpm -r --filter='@copilotkitnext/agent' --filter='@copilotkitnext/angular' --filter='@copilotkitnext/core' --filter='@copilotkitnext/react' --filter='@copilotkitnext/runtime' --filter='@copilotkitnext/shared' --filter='@copilotkitnext/web-inspector' exec pnpm version prerelease --preid=alpha",
- "bump:release": "pnpm -r --filter='@copilotkitnext/agent' --filter='@copilotkitnext/angular' --filter='@copilotkitnext/core' --filter='@copilotkitnext/react' --filter='@copilotkitnext/runtime' --filter='@copilotkitnext/shared' --filter='@copilotkitnext/web-inspector' exec pnpm version patch",
- "publish:prerelease": "pnpm -r clean && pnpm install && turbo build && pnpm publish -r --no-git-checks --filter='@copilotkitnext/agent' --filter='@copilotkitnext/angular' --filter='@copilotkitnext/core' --filter='@copilotkitnext/react' --filter='@copilotkitnext/runtime' --filter='@copilotkitnext/shared' --filter='@copilotkitnext/web-inspector' --tag alpha",
+ "bump:prerelease": "pnpm -r --filter='@copilotkitnext/agent' --filter='@copilotkitnext/angular' --filter='@copilotkitnext/core' --filter='@copilotkitnext/react' --filter='@copilotkitnext/runtime' --filter='@copilotkitnext/sqlite-runner' --filter='@copilotkitnext/shared' --filter='@copilotkitnext/web-inspector' exec pnpm version prerelease --preid=alpha",
+ "bump:release": "pnpm -r --filter='@copilotkitnext/agent' --filter='@copilotkitnext/angular' --filter='@copilotkitnext/core' --filter='@copilotkitnext/react' --filter='@copilotkitnext/runtime' --filter='@copilotkitnext/sqlite-runner' --filter='@copilotkitnext/shared' --filter='@copilotkitnext/web-inspector' exec pnpm version patch",
+ "publish:prerelease": "pnpm -r clean && pnpm install && turbo build && pnpm publish -r --no-git-checks --filter='@copilotkitnext/agent' --filter='@copilotkitnext/angular' --filter='@copilotkitnext/core' --filter='@copilotkitnext/react' --filter='@copilotkitnext/runtime' --filter='@copilotkitnext/sqlite-runner' --filter='@copilotkitnext/shared' --filter='@copilotkitnext/web-inspector' --tag alpha",
"publish:release:dry": "pnpm -r --filter '@copilotkitnext/*' publish --access public --dry-run",
"publish:release": "pnpm -r --filter '@copilotkitnext/*' publish --access public"
},
diff --git a/packages/agent/package.json b/packages/agent/package.json
index 5a0d82e9..740dfee6 100644
--- a/packages/agent/package.json
+++ b/packages/agent/package.json
@@ -1,6 +1,6 @@
{
"name": "@copilotkitnext/agent",
- "version": "0.0.15",
+ "version": "0.0.14",
"description": "Basic Agent for CopilotKit",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -36,7 +36,7 @@
"vitest": "^3.0.5"
},
"dependencies": {
- "@ag-ui/client": "0.0.40-alpha.3",
+ "@ag-ui/client": "0.0.40-alpha.6",
"@ai-sdk/anthropic": "^2.0.22",
"@ai-sdk/google": "^2.0.17",
"@ai-sdk/openai": "^2.0.42",
diff --git a/packages/angular/package.json b/packages/angular/package.json
index d7e7e573..7320f831 100644
--- a/packages/angular/package.json
+++ b/packages/angular/package.json
@@ -1,6 +1,6 @@
{
"name": "@copilotkitnext/angular",
- "version": "0.0.15",
+ "version": "0.0.14",
"description": "Angular library for CopilotKit",
"main": "dist/fesm2022/copilotkitnext-angular.mjs",
"module": "dist/fesm2022/copilotkitnext-angular.mjs",
@@ -31,8 +31,8 @@
"test:watch": "vitest --watch"
},
"dependencies": {
- "@ag-ui/client": "0.0.40-alpha.3",
- "@ag-ui/core": "0.0.40-alpha.3",
+ "@ag-ui/client": "0.0.40-alpha.6",
+ "@ag-ui/core": "0.0.40-alpha.6",
"@copilotkitnext/core": "workspace:*",
"@copilotkitnext/shared": "workspace:*",
"clsx": "^2.1.1",
diff --git a/packages/angular/src/lib/agent.ts b/packages/angular/src/lib/agent.ts
index 5bf71f0a..02eedc89 100644
--- a/packages/angular/src/lib/agent.ts
+++ b/packages/angular/src/lib/agent.ts
@@ -1,4 +1,11 @@
-import { DestroyRef, Injectable, inject, signal, computed, Signal } from "@angular/core";
+import {
+ DestroyRef,
+ Injectable,
+ inject,
+ signal,
+ computed,
+ Signal,
+} from "@angular/core";
import { CopilotKit } from "./copilotkit";
import type { AbstractAgent } from "@ag-ui/client";
import type { Message } from "@ag-ui/client";
@@ -54,7 +61,10 @@ export class AgentStore {
export class CopilotkitAgentFactory {
readonly #copilotkit = inject(CopilotKit);
- createAgentStoreSignal(agentId: Signal, destroyRef: DestroyRef): Signal {
+ createAgentStoreSignal(
+ agentId: Signal,
+ destroyRef: DestroyRef
+ ): Signal {
let lastAgentStore: AgentStore | undefined;
return computed(() => {
@@ -65,7 +75,9 @@ export class CopilotkitAgentFactory {
lastAgentStore = undefined;
}
- const abstractAgent = this.#copilotkit.getAgent(agentId() || DEFAULT_AGENT_ID);
+ const abstractAgent = this.#copilotkit.getAgent(
+ agentId() || DEFAULT_AGENT_ID
+ );
if (!abstractAgent) return undefined;
lastAgentStore = new AgentStore(abstractAgent, destroyRef);
@@ -74,10 +86,13 @@ export class CopilotkitAgentFactory {
}
}
-export function injectAgentStore(agentId: string | Signal): Signal {
+export function injectAgentStore(
+ agentId: string | Signal
+): Signal {
const agentFactory = inject(CopilotkitAgentFactory);
const destroyRef = inject(DestroyRef);
- const agentIdSignal = typeof agentId === "function" ? agentId : computed(() => agentId);
+ const agentIdSignal =
+ typeof agentId === "function" ? agentId : computed(() => agentId);
return agentFactory.createAgentStoreSignal(agentIdSignal, destroyRef);
}
diff --git a/packages/angular/src/lib/copilotkit.ts b/packages/angular/src/lib/copilotkit.ts
index 1190ea0e..8df87fd3 100644
--- a/packages/angular/src/lib/copilotkit.ts
+++ b/packages/angular/src/lib/copilotkit.ts
@@ -1,7 +1,19 @@
import { AbstractAgent } from "@ag-ui/client";
import { FrontendTool, CopilotKitCore } from "@copilotkitnext/core";
-import { Injectable, Injector, Signal, WritableSignal, runInInjectionContext, signal, inject } from "@angular/core";
-import { FrontendToolConfig, HumanInTheLoopConfig, RenderToolCallConfig } from "./tools";
+import {
+ Injectable,
+ Injector,
+ Signal,
+ WritableSignal,
+ runInInjectionContext,
+ signal,
+ inject,
+} from "@angular/core";
+import {
+ FrontendToolConfig,
+ HumanInTheLoopConfig,
+ RenderToolCallConfig,
+} from "./tools";
import { injectCopilotKitConfig } from "./config";
import { HumanInTheLoop } from "./human-in-the-loop";
@@ -10,7 +22,9 @@ export class CopilotKit {
readonly #config = injectCopilotKitConfig();
readonly #hitl = inject(HumanInTheLoop);
readonly #rootInjector = inject(Injector);
- readonly #agents = signal>(this.#config.agents ?? {});
+ readonly #agents = signal>(
+ this.#config.agents ?? {}
+ );
readonly agents = this.#agents.asReadonly();
readonly core = new CopilotKitCore({
@@ -21,12 +35,18 @@ export class CopilotKit {
tools: this.#config.tools,
});
- readonly #toolCallRenderConfigs: WritableSignal = signal([]);
- readonly #clientToolCallRenderConfigs: WritableSignal = signal([]);
- readonly #humanInTheLoopToolRenderConfigs: WritableSignal = signal([]);
-
- readonly toolCallRenderConfigs: Signal = this.#toolCallRenderConfigs.asReadonly();
- readonly clientToolCallRenderConfigs: Signal = this.#clientToolCallRenderConfigs.asReadonly();
+ readonly #toolCallRenderConfigs: WritableSignal =
+ signal([]);
+ readonly #clientToolCallRenderConfigs: WritableSignal =
+ signal([]);
+ readonly #humanInTheLoopToolRenderConfigs: WritableSignal<
+ HumanInTheLoopConfig[]
+ > = signal([]);
+
+ readonly toolCallRenderConfigs: Signal =
+ this.#toolCallRenderConfigs.asReadonly();
+ readonly clientToolCallRenderConfigs: Signal =
+ this.#clientToolCallRenderConfigs.asReadonly();
readonly humanInTheLoopToolRenderConfigs: Signal =
this.#humanInTheLoopToolRenderConfigs.asReadonly();
@@ -64,36 +84,38 @@ export class CopilotKit {
#bindClientTool(
clientToolWithInjector: FrontendToolConfig & {
injector: Injector;
- },
+ }
): FrontendTool {
- const { injector, handler, args, description, name, agentId } = clientToolWithInjector;
+ const { injector, handler, ...frontendCandidate } = clientToolWithInjector;
return {
- description,
- name,
- agentId,
+ ...frontendCandidate,
handler: (args) => runInInjectionContext(injector, () => handler(args)),
- parameters: args,
};
}
addFrontendTool(
clientToolWithInjector: FrontendToolConfig & {
injector: Injector;
- },
+ }
): void {
const tool = this.#bindClientTool(clientToolWithInjector);
this.core.addTool(tool);
- this.#clientToolCallRenderConfigs.update((current) => [...current, clientToolWithInjector]);
+ this.#clientToolCallRenderConfigs.update((current) => [
+ ...current,
+ clientToolWithInjector,
+ ]);
}
addRenderToolCall(renderConfig: RenderToolCallConfig): void {
this.#toolCallRenderConfigs.update((current) => [...current, renderConfig]);
}
- #bindHumanInTheLoopTool(humanInTheLoopTool: HumanInTheLoopConfig): FrontendTool {
+ #bindHumanInTheLoopTool(
+ humanInTheLoopTool: HumanInTheLoopConfig
+ ): FrontendTool {
return {
...humanInTheLoopTool,
handler: (args, toolCall) => {
@@ -103,14 +125,20 @@ export class CopilotKit {
}
addHumanInTheLoop(humanInTheLoopTool: HumanInTheLoopConfig): void {
- this.#humanInTheLoopToolRenderConfigs.update((current) => [...current, humanInTheLoopTool]);
+ this.#humanInTheLoopToolRenderConfigs.update((current) => [
+ ...current,
+ humanInTheLoopTool,
+ ]);
const tool = this.#bindHumanInTheLoopTool(humanInTheLoopTool);
this.core.addTool(tool);
}
- #isSameAgentId(target: T, agentId?: string): boolean {
+ #isSameAgentId(
+ target: T,
+ agentId?: string
+ ): boolean {
if (agentId) {
return target.agentId === agentId;
}
@@ -121,13 +149,25 @@ export class CopilotKit {
removeTool(toolName: string, agentId?: string): void {
this.core.removeTool(toolName);
this.#clientToolCallRenderConfigs.update((current) =>
- current.filter((renderConfig) => renderConfig.name !== toolName && this.#isSameAgentId(renderConfig, agentId)),
+ current.filter(
+ (renderConfig) =>
+ renderConfig.name !== toolName &&
+ this.#isSameAgentId(renderConfig, agentId)
+ )
);
this.#humanInTheLoopToolRenderConfigs.update((current) =>
- current.filter((renderConfig) => renderConfig.name !== toolName && this.#isSameAgentId(renderConfig, agentId)),
+ current.filter(
+ (renderConfig) =>
+ renderConfig.name !== toolName &&
+ this.#isSameAgentId(renderConfig, agentId)
+ )
);
this.#toolCallRenderConfigs.update((current) =>
- current.filter((renderConfig) => renderConfig.name !== toolName && this.#isSameAgentId(renderConfig, agentId)),
+ current.filter(
+ (renderConfig) =>
+ renderConfig.name !== toolName &&
+ this.#isSameAgentId(renderConfig, agentId)
+ )
);
}
diff --git a/packages/core/package.json b/packages/core/package.json
index 4987b8e3..f372c3a3 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@copilotkitnext/core",
- "version": "0.0.15",
+ "version": "0.0.14",
"description": "Core web utilities for CopilotKit2",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -36,7 +36,7 @@
"vitest": "^3.2.4"
},
"dependencies": {
- "@ag-ui/client": "0.0.40-alpha.3",
+ "@ag-ui/client": "0.0.40-alpha.6",
"@copilotkitnext/shared": "workspace:*",
"rxjs": "7.8.1",
"zod": "^3.25.75",
diff --git a/packages/react/package.json b/packages/react/package.json
index 6ebd551e..95a46049 100644
--- a/packages/react/package.json
+++ b/packages/react/package.json
@@ -1,6 +1,6 @@
{
"name": "@copilotkitnext/react",
- "version": "0.0.15",
+ "version": "0.0.14",
"description": "React components for CopilotKit2",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -53,8 +53,8 @@
"vitest": "^3.2.4"
},
"dependencies": {
- "@ag-ui/client": "0.0.40-alpha.3",
- "@ag-ui/core": "0.0.40-alpha.3",
+ "@ag-ui/client": "0.0.40-alpha.6",
+ "@ag-ui/core": "0.0.40-alpha.6",
"@copilotkitnext/core": "workspace:*",
"@copilotkitnext/shared": "workspace:*",
"@copilotkitnext/web-inspector": "workspace:*",
diff --git a/packages/react/src/__tests__/setup.ts b/packages/react/src/__tests__/setup.ts
index 4a2184dc..bd80a7cc 100644
--- a/packages/react/src/__tests__/setup.ts
+++ b/packages/react/src/__tests__/setup.ts
@@ -16,6 +16,9 @@ global.ResizeObserver = class ResizeObserver {
disconnect() {}
};
+// Mock scrollIntoView which is not available in jsdom
+HTMLElement.prototype.scrollIntoView = vi.fn();
+
// Ensure we cleanup between tests to avoid lingering handles
afterEach(() => {
cleanup();
diff --git a/packages/react/src/components/chat/CopilotChatAssistantMessage.tsx b/packages/react/src/components/chat/CopilotChatAssistantMessage.tsx
index 1e54fcc9..393a77da 100644
--- a/packages/react/src/components/chat/CopilotChatAssistantMessage.tsx
+++ b/packages/react/src/components/chat/CopilotChatAssistantMessage.tsx
@@ -155,7 +155,9 @@ export function CopilotChatAssistantMessage({
// Don't show toolbar if message has no content (only tool calls)
const hasContent = !!(message.content && message.content.trim().length > 0);
- const shouldShowToolbar = toolbarVisible && hasContent;
+ const isLatestAssistantMessage =
+ message.role === "assistant" && messages?.[messages.length - 1]?.id === message.id;
+ const shouldShowToolbar = toolbarVisible && hasContent && !(isRunning && isLatestAssistantMessage);
if (children) {
return (
diff --git a/packages/runtime/package.json b/packages/runtime/package.json
index 59a81999..a8258e28 100644
--- a/packages/runtime/package.json
+++ b/packages/runtime/package.json
@@ -1,6 +1,6 @@
{
"name": "@copilotkitnext/runtime",
- "version": "0.0.15",
+ "version": "0.0.14",
"description": "Server-side runtime package for CopilotKit2",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -28,35 +28,25 @@
"devDependencies": {
"@copilotkitnext/eslint-config": "workspace:*",
"@copilotkitnext/typescript-config": "workspace:*",
- "@types/better-sqlite3": "^7.6.13",
"@types/node": "^22.15.3",
- "better-sqlite3": "^12.2.0",
"eslint": "^9.30.0",
- "ioredis-mock": "^8.9.0",
"openai": "^5.9.0",
"tsup": "^8.5.0",
"typescript": "5.8.2",
"vitest": "^3.0.5"
},
"dependencies": {
- "@ag-ui/client": "0.0.40-alpha.3",
- "@ag-ui/core": "0.0.40-alpha.3",
- "@ag-ui/encoder": "0.0.40-alpha.3",
+ "@ag-ui/client": "0.0.40-alpha.6",
+ "@ag-ui/core": "0.0.40-alpha.6",
+ "@ag-ui/encoder": "0.0.40-alpha.6",
"@copilotkitnext/shared": "workspace:*",
"hono": "^4.6.13",
- "ioredis": "^5.7.0",
- "kysely": "^0.28.5",
"rxjs": "7.8.1"
},
"peerDependencies": {
- "better-sqlite3": "^12.2.0",
"openai": "^5.9.0"
},
- "peerDependenciesMeta": {
- "better-sqlite3": {
- "optional": true
- }
- },
+ "peerDependenciesMeta": {},
"engines": {
"node": ">=18"
}
diff --git a/packages/runtime/src/__tests__/handle-run.test.ts b/packages/runtime/src/__tests__/handle-run.test.ts
index 5ee1a108..570c7fba 100644
--- a/packages/runtime/src/__tests__/handle-run.test.ts
+++ b/packages/runtime/src/__tests__/handle-run.test.ts
@@ -1,5 +1,5 @@
import { Observable } from "rxjs";
-import { describe, it, expect } from "vitest";
+import { describe, it, expect, vi } from "vitest";
import { AbstractAgent, BaseEvent, HttpAgent } from "@ag-ui/client";
import { handleRunAgent } from "../handlers/handle-run";
import { CopilotRuntime } from "../runtime";
@@ -53,20 +53,26 @@ describe("handleRunAgent", () => {
const request = createMockRequest();
const agentId = "test-agent";
- const response = await handleRunAgent({
- runtime,
- request,
- agentId,
- });
-
- expect(response.status).toBe(500);
- expect(response.headers.get("Content-Type")).toBe("application/json");
-
- const body = await response.json();
- expect(body).toEqual({
- error: "Failed to run agent",
- message: "Database connection failed",
- });
+ const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
+
+ try {
+ const response = await handleRunAgent({
+ runtime,
+ request,
+ agentId,
+ });
+
+ expect(response.status).toBe(500);
+ expect(response.headers.get("Content-Type")).toBe("application/json");
+
+ const body = await response.json();
+ expect(body).toEqual({
+ error: "Failed to run agent",
+ message: "Database connection failed",
+ });
+ } finally {
+ errorSpy.mockRestore();
+ }
});
it("forwards only authorization and custom x- headers to HttpAgent runs", async () => {
diff --git a/packages/runtime/src/__tests__/in-process-agent-runner-messages.test.ts b/packages/runtime/src/__tests__/in-process-agent-runner-messages.test.ts
index df1f67b0..073713d8 100644
--- a/packages/runtime/src/__tests__/in-process-agent-runner-messages.test.ts
+++ b/packages/runtime/src/__tests__/in-process-agent-runner-messages.test.ts
@@ -3,597 +3,202 @@ import { InMemoryAgentRunner } from "../runner/in-memory";
import {
AbstractAgent,
BaseEvent,
- RunAgentInput,
+ EventType,
Message,
+ RunAgentInput,
RunStartedEvent,
- EventType,
} from "@ag-ui/client";
-import { EMPTY, firstValueFrom, Observable } from "rxjs";
+import { EMPTY, Observable, firstValueFrom } from "rxjs";
import { toArray } from "rxjs/operators";
-// Type helpers for event filtering
-type EventWithType = BaseEvent & { type: string };
-type EventWithId = BaseEvent & { id: string };
-type EventWithMessageId = BaseEvent & { messageId: string };
-type EventWithMessageIdAndDelta = BaseEvent & {
- messageId: string;
- delta: string;
+type RunAgentCallbacks = {
+ onEvent: (event: { event: BaseEvent }) => void;
+ onNewMessage?: (args: { message: Message }) => void;
+ onRunStartedEvent?: (args: { event: BaseEvent }) => void;
};
-// Mock agent that can handle messages and callbacks
class MessageAwareAgent extends AbstractAgent {
- private events: BaseEvent[] = [];
- public receivedMessages: Message[] = [];
- public onNewMessageCalled = 0;
- public onRunStartedCalled = 0;
-
- constructor(events: BaseEvent[] = []) {
+ constructor(
+ private readonly events: BaseEvent[] = [],
+ private readonly emitDefaultRunStarted = true,
+ ) {
super();
- this.events = events;
}
- protected run(input: RunAgentInput): Observable {
+ protected run(_input: RunAgentInput): Observable {
return EMPTY;
}
async runAgent(
input: RunAgentInput,
- options: {
- onEvent: (event: { event: BaseEvent }) => void;
- onNewMessage?: (args: { message: Message }) => void;
- onRunStartedEvent?: (args: { event: BaseEvent }) => void;
- }
- // @ts-expect-error
- ): Promise {
- // Call onRunStartedEvent if provided
- if (options.onRunStartedEvent) {
- this.onRunStartedCalled++;
- const runStartedEvent = {
+ callbacks: RunAgentCallbacks,
+ ): Promise {
+ if (this.emitDefaultRunStarted) {
+ const runStarted: RunStartedEvent = {
type: EventType.RUN_STARTED,
threadId: input.threadId,
runId: input.runId,
- } as RunStartedEvent;
- options.onRunStartedEvent({ event: runStartedEvent });
+ };
+
+ callbacks.onEvent({ event: runStarted });
+ callbacks.onRunStartedEvent?.({ event: runStarted });
}
- // Emit the agent's own events
for (const event of this.events) {
- options.onEvent({ event });
+ callbacks.onEvent({ event });
}
-
- // Return a promise as expected
- return Promise.resolve();
}
}
-describe("InMemoryAgentRunner - Message Injection", () => {
+describe("InMemoryAgentRunner – run started inputs", () => {
let runner: InMemoryAgentRunner;
beforeEach(() => {
runner = new InMemoryAgentRunner();
});
- describe("Message Injection on Run", () => {
- it("should inject user messages as events when running an agent", async () => {
- const threadId = "test-thread-messages-1";
- const userMessage: Message = {
- id: "user-msg-1",
- role: "user",
- content: "Hello, agent!",
- };
-
- const agentEvents: BaseEvent[] = [
- {
- type: EventType.CUSTOM,
- id: "agent-response-1",
- timestamp: Date.now(),
- name: "agent-response",
- value: { text: "Hello, user!" },
- } as BaseEvent,
- ];
-
- const agent = new MessageAwareAgent(agentEvents);
- const input: RunAgentInput = {
- messages: [userMessage],
- state: {},
- threadId,
- runId: "run-1",
- tools: [],
- context: [],
- };
-
- // Run the agent
- const runObservable = runner.run({ threadId, agent, input });
- const runEvents = await firstValueFrom(runObservable.pipe(toArray()));
-
- // run() should only return agent events, not injected messages
- expect(runEvents).toHaveLength(1);
- expect((runEvents[0] as EventWithId).id).toBe("agent-response-1");
-
- // connect() should have all events including injected messages
- const connectObservable = runner.connect({ threadId });
- const allEvents = await firstValueFrom(connectObservable.pipe(toArray()));
-
- // Should have: user message events (Start, Content, End) + agent event = 4 events
- expect(allEvents.length).toBe(4);
-
- // Find the injected user message events
- const textStartEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_START
- );
- const textContentEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_CONTENT
- );
- const textEndEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_END
- );
-
- expect(textStartEvents).toHaveLength(1);
- expect(textStartEvents[0]).toMatchObject({
- type: EventType.TEXT_MESSAGE_START,
- messageId: "user-msg-1",
- });
-
- expect(textContentEvents).toHaveLength(1);
- expect(textContentEvents[0]).toMatchObject({
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: "user-msg-1",
- delta: "Hello, agent!",
- });
-
- expect(textEndEvents).toHaveLength(1);
- expect(textEndEvents[0]).toMatchObject({
- type: EventType.TEXT_MESSAGE_END,
- messageId: "user-msg-1",
- });
-
- // Verify the agent callbacks
- expect(agent.onNewMessageCalled).toBe(0); // onNewMessage is not called by the test agent
- expect(agent.onRunStartedCalled).toBe(1);
- });
-
- it("should inject assistant messages as proper TextMessage events", async () => {
- const threadId = "test-thread-messages-2";
- const assistantMessage: Message = {
- id: "assistant-msg-1",
- role: "assistant",
- content: "I can help you with that!",
- };
-
- const agent = new MessageAwareAgent([]);
- const input: RunAgentInput = {
- messages: [assistantMessage],
- state: {},
- threadId,
- runId: "run-2",
- tools: [],
- context: [],
- };
-
- // Run the agent
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Check events via connect
- const allEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Find the injected message events
- const textStartEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_START
- );
- const textContentEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_CONTENT
- );
- const textEndEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_END
- );
-
- expect(textStartEvents).toHaveLength(1);
- expect(textStartEvents[0]).toMatchObject({
- type: EventType.TEXT_MESSAGE_START,
- messageId: "assistant-msg-1",
- role: "assistant",
- });
-
- expect(textContentEvents).toHaveLength(1);
- expect(textContentEvents[0]).toMatchObject({
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: "assistant-msg-1",
- delta: "I can help you with that!",
- });
-
- expect(textEndEvents).toHaveLength(1);
- expect(textEndEvents[0]).toMatchObject({
- type: EventType.TEXT_MESSAGE_END,
- messageId: "assistant-msg-1",
- });
- });
-
- it("should inject tool call messages as proper ToolCall events", async () => {
- const threadId = "test-thread-messages-3";
- const toolCallMessage: Message = {
- id: "assistant-msg-2",
+ it("attaches every input message to the emitted RUN_STARTED event", async () => {
+ const threadId = "thread-all-messages";
+ const messages: Message[] = [
+ { id: "user-1", role: "user", content: "User message" },
+ { id: "assistant-1", role: "assistant", content: "Assistant message" },
+ { id: "developer-1", role: "developer", content: "Developer hint" },
+ { id: "system-1", role: "system", content: "System prompt" },
+ {
+ id: "tool-call-1",
role: "assistant",
content: "",
toolCalls: [
{
id: "tool-call-1",
type: "function",
- function: {
- name: "get_weather",
- arguments: '{"location": "New York"}',
- },
+ function: { name: "calculator", arguments: "{\"a\":1}" },
},
],
- };
-
- const agent = new MessageAwareAgent([]);
- const input: RunAgentInput = {
- messages: [toolCallMessage],
- state: {},
- threadId,
- runId: "run-3",
- tools: [],
- context: [],
- };
-
- // Run the agent
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Check events via connect
- const allEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Find the injected tool call events
- const toolStartEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TOOL_CALL_START
- );
- const toolArgsEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TOOL_CALL_ARGS
- );
- const toolEndEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TOOL_CALL_END
- );
-
- expect(toolStartEvents).toHaveLength(1);
- expect(toolStartEvents[0]).toMatchObject({
- type: EventType.TOOL_CALL_START,
- toolCallId: "tool-call-1",
- toolCallName: "get_weather",
- parentMessageId: "assistant-msg-2",
- });
-
- expect(toolArgsEvents).toHaveLength(1);
- expect(toolArgsEvents[0]).toMatchObject({
- type: EventType.TOOL_CALL_ARGS,
- toolCallId: "tool-call-1",
- delta: '{"location": "New York"}',
- });
-
- expect(toolEndEvents).toHaveLength(1);
- expect(toolEndEvents[0]).toMatchObject({
- type: EventType.TOOL_CALL_END,
- toolCallId: "tool-call-1",
- });
- });
-
- it("should inject developer and system messages as TextMessage events", async () => {
- const threadId = "test-thread-messages-dev-sys";
- const developerMessage: Message = {
- id: "dev-msg-1",
- role: "developer",
- content: "You are a helpful assistant.",
- };
- const systemMessage: Message = {
- id: "sys-msg-1",
- role: "system",
- content: "System prompt: Be concise.",
- };
-
- const agent = new MessageAwareAgent([]);
- const input: RunAgentInput = {
- messages: [developerMessage, systemMessage],
- state: {},
- threadId,
- runId: "run-dev-sys",
- tools: [],
- context: [],
- };
-
- // Run the agent
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Check events via connect
- const allEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Find the injected message events
- const textStartEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_START
- );
- const textContentEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_CONTENT
- );
- const textEndEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_END
- );
-
- // Should have 2 sets of text message events (one for each message)
- expect(textStartEvents).toHaveLength(2);
- expect(textContentEvents).toHaveLength(2);
- expect(textEndEvents).toHaveLength(2);
-
- // Verify developer message events
- expect(
- textStartEvents.some(
- (e) => (e as EventWithMessageId).messageId === "dev-msg-1"
- )
- ).toBe(true);
- expect(
- textContentEvents.some((e) => {
- const evt = e as EventWithMessageIdAndDelta;
- return (
- evt.messageId === "dev-msg-1" &&
- evt.delta === "You are a helpful assistant."
- );
- })
- ).toBe(true);
-
- // Verify system message events
- expect(
- textStartEvents.some(
- (e) => (e as EventWithMessageId).messageId === "sys-msg-1"
- )
- ).toBe(true);
- expect(
- textContentEvents.some((e) => {
- const evt = e as EventWithMessageIdAndDelta;
- return (
- evt.messageId === "sys-msg-1" &&
- evt.delta === "System prompt: Be concise."
- );
- })
- ).toBe(true);
- });
-
- it("should inject tool result messages as ToolCallResult events", async () => {
- const threadId = "test-thread-messages-4";
- const toolResultMessage: Message = {
+ },
+ {
id: "tool-result-1",
role: "tool",
- content: "72°F and sunny",
+ content: "result",
toolCallId: "tool-call-1",
- };
-
- const agent = new MessageAwareAgent([]);
- const input: RunAgentInput = {
- messages: [toolResultMessage],
- state: {},
- threadId,
- runId: "run-4",
- tools: [],
- context: [],
- };
+ },
+ ];
+
+ const agent = new MessageAwareAgent();
+ const input: RunAgentInput = {
+ threadId,
+ runId: "run-1",
+ state: {},
+ messages,
+ };
+
+ const runEvents = await firstValueFrom(
+ runner.run({ threadId, agent, input }).pipe(toArray()),
+ );
+
+ expect(runEvents).toHaveLength(1);
+ const runStarted = runEvents[0] as RunStartedEvent;
+ expect(runStarted.type).toBe(EventType.RUN_STARTED);
+ expect(runStarted.input?.messages).toEqual(messages);
+
+ const connectEvents = await firstValueFrom(
+ runner.connect({ threadId }).pipe(toArray()),
+ );
+
+ expect(connectEvents).toHaveLength(1);
+ const connectRunStarted = connectEvents[0] as RunStartedEvent;
+ expect(connectRunStarted.input?.messages).toEqual(messages);
+ });
- // Run the agent
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
+ it("only includes new messages on subsequent runs", async () => {
+ const threadId = "thread-new-messages";
+ const existing: Message = {
+ id: "existing-msg",
+ role: "user",
+ content: "Hi there",
+ };
+
+ await firstValueFrom(
+ runner
+ .run({
+ threadId,
+ agent: new MessageAwareAgent(),
+ input: { threadId, runId: "run-0", state: {}, messages: [existing] },
+ })
+ .pipe(toArray()),
+ );
+
+ const newMessage: Message = {
+ id: "new-msg",
+ role: "user",
+ content: "Second question",
+ };
+
+ const secondRunEvents = await firstValueFrom(
+ runner
+ .run({
+ threadId,
+ agent: new MessageAwareAgent(),
+ input: {
+ threadId,
+ runId: "run-1",
+ state: {},
+ messages: [existing, newMessage],
+ },
+ })
+ .pipe(toArray()),
+ );
- // Check events via connect
- const allEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
+ const runStarted = secondRunEvents[0] as RunStartedEvent;
+ expect(runStarted.input?.messages).toEqual([newMessage]);
- // Find the injected tool result events
- const toolResultEvents = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TOOL_CALL_RESULT
- );
+ const connectEvents = await firstValueFrom(
+ runner.connect({ threadId }).pipe(toArray()),
+ );
- expect(toolResultEvents).toHaveLength(1);
- expect(toolResultEvents[0]).toMatchObject({
- type: EventType.TOOL_CALL_RESULT,
- messageId: "tool-result-1",
- toolCallId: "tool-call-1",
- content: "72°F and sunny",
- role: "tool",
- });
- });
+ const latestRunStarted = connectEvents
+ .filter((event) => event.type === EventType.RUN_STARTED)
+ .pop() as RunStartedEvent;
+ expect(latestRunStarted.input?.messages).toEqual([newMessage]);
});
- describe("Consecutive Runs with Different Messages", () => {
- it("should accumulate messages across multiple runs", async () => {
- const threadId = "test-thread-consecutive-1";
-
- // First run with a user message
- const userMessage1: Message = {
- id: "user-msg-1",
- role: "user",
- content: "What's the weather?",
- };
-
- const agent1 = new MessageAwareAgent([
+ it("preserves agent-provided RUN_STARTED input", async () => {
+ const threadId = "thread-agent-input";
+ const providedInput: RunAgentInput = {
+ threadId,
+ runId: "run-preserve",
+ state: { injected: true },
+ messages: [],
+ };
+
+ const agent = new MessageAwareAgent(
+ [
{
- type: EventType.CUSTOM,
- id: "agent-1-response",
- timestamp: Date.now(),
- name: "agent-response",
- value: { text: "Let me check..." },
- } as BaseEvent,
- ]);
-
- const input1: RunAgentInput = {
- messages: [userMessage1],
- state: {},
- threadId,
- runId: "run-1",
- tools: [],
- context: [],
- };
-
- await firstValueFrom(
- runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray())
- );
-
- // Second run with assistant and tool messages
- const assistantMessage: Message = {
- id: "assistant-msg-1",
- role: "assistant",
- content: "",
- toolCalls: [
- {
- id: "tool-call-1",
- type: "function",
- function: {
- name: "get_weather",
- arguments: '{"location": "current"}',
- },
+ type: EventType.RUN_STARTED,
+ threadId,
+ runId: "run-preserve",
+ input: providedInput,
+ } as RunStartedEvent,
+ ],
+ false,
+ );
+
+ const runEvents = await firstValueFrom(
+ runner
+ .run({
+ threadId,
+ agent,
+ input: {
+ threadId,
+ runId: "run-preserve",
+ state: {},
+ messages: [{ id: "extra", role: "user", content: "Hello" }],
},
- ],
- };
-
- const toolResultMessage: Message = {
- id: "tool-result-1",
- role: "tool",
- content: "72°F and sunny in New York",
- toolCallId: "tool-call-1",
- };
-
- const agent2 = new MessageAwareAgent([
- {
- type: EventType.CUSTOM,
- id: "agent-2-response",
- timestamp: Date.now(),
- name: "agent-response",
- value: { text: "It's 72°F and sunny!" },
- } as BaseEvent,
- ]);
-
- const input2: RunAgentInput = {
- messages: [userMessage1, assistantMessage, toolResultMessage],
- state: {},
- threadId,
- runId: "run-2",
- tools: [],
- context: [],
- };
-
- await firstValueFrom(
- runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray())
- );
-
- // Connect should have all events from both runs
- const allEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Should have events from both runs plus injected message events
- expect(allEvents.length).toBeGreaterThan(4);
-
- // Verify we have both agent responses
- const agentResponses = allEvents.filter(
- (e) => e.type === EventType.CUSTOM
- );
- expect(
- agentResponses.some((e) => (e as EventWithId).id === "agent-1-response")
- ).toBe(true);
- expect(
- agentResponses.some((e) => (e as EventWithId).id === "agent-2-response")
- ).toBe(true);
-
- // Verify we have the tool call events
- const toolCallStarts = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TOOL_CALL_START
- );
- expect(toolCallStarts).toHaveLength(1);
-
- // Verify we have the tool result event
- const toolResults = allEvents.filter(
- (e) => (e as EventWithType).type === EventType.TOOL_CALL_RESULT
- );
- expect(toolResults).toHaveLength(1);
- });
-
- it("should track seen message IDs and not duplicate messages", async () => {
- const threadId = "test-thread-duplicate-1";
-
- const sharedMessage: Message = {
- id: "shared-msg-1",
- role: "assistant",
- content: "This message appears in both runs",
- };
-
- const newMessage: Message = {
- id: "new-msg-1",
- role: "assistant",
- content: "This is a new message",
- };
-
- // First run with shared message
- const agent1 = new MessageAwareAgent([]);
- const input1: RunAgentInput = {
- messages: [sharedMessage],
- state: {},
- threadId,
- runId: "run-1",
- tools: [],
- context: [],
- };
-
- await firstValueFrom(
- runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray())
- );
-
- // Second run with shared message and new message
- const agent2 = new MessageAwareAgent([]);
- const input2: RunAgentInput = {
- messages: [sharedMessage, newMessage],
- state: {},
- threadId,
- runId: "run-2",
- tools: [],
- context: [],
- };
-
- await firstValueFrom(
- runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray())
- );
-
- // Connect should have events without duplicates
- const allEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Count TextMessageStart events for our messages
- const textStartEvents = allEvents.filter((e) => {
- const evt = e as EventWithType & { messageId?: string };
- return (
- evt.type === EventType.TEXT_MESSAGE_START &&
- (evt.messageId === "shared-msg-1" || evt.messageId === "new-msg-1")
- );
- });
+ })
+ .pipe(toArray()),
+ );
- // Should have exactly 2 TextMessageStart events (one for each unique message)
- expect(textStartEvents).toHaveLength(2);
- expect(
- textStartEvents.some(
- (e) => (e as EventWithMessageId).messageId === "shared-msg-1"
- )
- ).toBe(true);
- expect(
- textStartEvents.some(
- (e) => (e as EventWithMessageId).messageId === "new-msg-1"
- )
- ).toBe(true);
- });
+ const runStarted = runEvents[0] as RunStartedEvent;
+ expect(runStarted.input).toBe(providedInput);
});
});
diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts
index e1fefbbd..f4cb5fa7 100644
--- a/packages/runtime/src/index.ts
+++ b/packages/runtime/src/index.ts
@@ -1,8 +1,6 @@
export * from "./runtime";
export * from "./endpoint";
-// Export agent runners
+// Export agent runners and base types
+export * from "./runner/agent-runner";
export { InMemoryAgentRunner } from "./runner/in-memory";
-export { SqliteAgentRunner } from "./runner/sqlite";
-export { EnterpriseAgentRunner } from "./runner/enterprise";
-export type { EnterpriseAgentRunnerOptions } from "./runner/enterprise";
diff --git a/packages/runtime/src/runner/__tests__/enterprise-runner.test.ts b/packages/runtime/src/runner/__tests__/enterprise-runner.test.ts
deleted file mode 100644
index ee82f303..00000000
--- a/packages/runtime/src/runner/__tests__/enterprise-runner.test.ts
+++ /dev/null
@@ -1,992 +0,0 @@
-import { describe, it, expect, beforeEach, afterEach } from 'vitest';
-import { Kysely, SqliteDialect } from 'kysely';
-import Database from 'better-sqlite3';
-import IORedisMock from 'ioredis-mock';
-import { EnterpriseAgentRunner } from '../enterprise';
-import { EventType } from '@ag-ui/client';
-import type { AbstractAgent, RunAgentInput, BaseEvent, Message } from '@ag-ui/client';
-import { firstValueFrom, toArray } from 'rxjs';
-
-// Mock agent that takes custom events
-class CustomEventAgent implements AbstractAgent {
- private events: BaseEvent[];
-
- constructor(events: BaseEvent[] = []) {
- this.events = events;
- }
-
- async runAgent(
- input: RunAgentInput,
- callbacks: {
- onEvent: (params: { event: any }) => void | Promise;
- onNewMessage?: (params: { message: any }) => void | Promise;
- onRunStartedEvent?: () => void | Promise;
- }
- ): Promise {
- if (callbacks.onRunStartedEvent) {
- await callbacks.onRunStartedEvent();
- }
-
- for (const event of this.events) {
- await callbacks.onEvent({ event });
- }
- }
-}
-
-// Mock agent for testing
-class MockAgent implements AbstractAgent {
- async runAgent(
- input: RunAgentInput,
- callbacks: {
- onEvent: (params: { event: any }) => void | Promise;
- onNewMessage?: (params: { message: any }) => void | Promise;
- onRunStartedEvent?: () => void | Promise;
- }
- ): Promise {
- // Emit run started
- if (callbacks.onRunStartedEvent) {
- await callbacks.onRunStartedEvent();
- }
-
- // Emit some events
- await callbacks.onEvent({
- event: {
- type: EventType.RUN_STARTED,
- threadId: input.threadId,
- runId: input.runId,
- }
- });
-
- // Emit a text message
- await callbacks.onEvent({
- event: {
- type: EventType.TEXT_MESSAGE_START,
- messageId: 'test-msg-1',
- role: 'assistant',
- }
- });
-
- await callbacks.onEvent({
- event: {
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: 'test-msg-1',
- delta: 'Hello from agent',
- }
- });
-
- await callbacks.onEvent({
- event: {
- type: EventType.TEXT_MESSAGE_END,
- messageId: 'test-msg-1',
- }
- });
-
- // Emit run finished
- await callbacks.onEvent({
- event: {
- type: EventType.RUN_FINISHED,
- threadId: input.threadId,
- runId: input.runId,
- }
- });
- }
-}
-
-// Error agent for testing
-class ErrorAgent implements AbstractAgent {
- async runAgent(
- input: RunAgentInput,
- callbacks: {
- onEvent: (params: { event: any }) => void | Promise;
- onNewMessage?: (params: { message: any }) => void | Promise;
- onRunStartedEvent?: () => void | Promise;
- }
- ): Promise {
- await callbacks.onEvent({
- event: {
- type: EventType.RUN_STARTED,
- threadId: input.threadId,
- runId: input.runId,
- }
- });
-
- await callbacks.onEvent({
- event: {
- type: EventType.RUN_ERROR,
- error: 'Test error',
- }
- });
- }
-}
-
-describe('EnterpriseAgentRunner', () => {
- let db: Kysely;
- let redis: any;
- let redisSub: any;
- let runner: EnterpriseAgentRunner;
-
- beforeEach(async () => {
- // In-memory SQLite for testing
- db = new Kysely({
- dialect: new SqliteDialect({
- database: new Database(':memory:')
- })
- });
-
- // Mock Redis for unit tests
- redis = new IORedisMock();
- redisSub = redis.duplicate();
-
- runner = new EnterpriseAgentRunner({
- kysely: db,
- redis,
- redisSub,
- streamRetentionMs: 60000, // 1 minute for tests
- streamActiveTTLMs: 10000, // 10 seconds for tests
- lockTTLMs: 30000 // 30 seconds for tests
- });
-
- // Allow schema to initialize
- await new Promise(resolve => setTimeout(resolve, 100));
- });
-
- afterEach(async () => {
- await runner.close();
- });
-
- it('should prevent concurrent runs on same thread', async () => {
- // Create a slow agent that takes time to complete
- const slowAgent: AbstractAgent = {
- async runAgent(input, callbacks) {
- if (callbacks.onRunStartedEvent) {
- await callbacks.onRunStartedEvent();
- }
-
- await callbacks.onEvent({
- event: {
- type: EventType.RUN_STARTED,
- threadId: input.threadId,
- runId: input.runId,
- }
- });
-
- // Simulate long running task
- await new Promise(resolve => setTimeout(resolve, 500));
-
- await callbacks.onEvent({
- event: {
- type: EventType.RUN_FINISHED,
- threadId: input.threadId,
- runId: input.runId,
- }
- });
- }
- };
-
- const threadId = 'test-thread-1';
- const input1: RunAgentInput = {
- runId: 'run-1',
- threadId,
- messages: [],
- };
- const input2: RunAgentInput = {
- runId: 'run-2',
- threadId,
- messages: [],
- };
-
- // Start first run
- const run1 = runner.run({ threadId, agent: slowAgent, input: input1 });
-
- // Wait a bit for first run to acquire lock
- await new Promise(resolve => setTimeout(resolve, 100));
-
- // Try to start second run on same thread - should error
- const run2 = runner.run({ threadId, agent: slowAgent, input: input2 });
-
- let errorReceived = false;
- let completedWithoutError = false;
-
- await new Promise((resolve) => {
- run2.subscribe({
- next: () => {},
- error: (err) => {
- errorReceived = true;
- expect(err.message).toBe('Thread already running');
- resolve();
- },
- complete: () => {
- completedWithoutError = true;
- resolve();
- }
- });
- });
-
- expect(errorReceived).toBe(true);
- expect(completedWithoutError).toBe(false);
-
- // Let first run complete
- const events1 = await firstValueFrom(run1.pipe(toArray()));
- expect(events1.length).toBeGreaterThan(0);
- });
-
- it('should handle RUN_FINISHED event correctly', async () => {
- const agent = new MockAgent();
- const threadId = 'test-thread-2';
- const input: RunAgentInput = {
- runId: 'run-finished',
- threadId,
- messages: [],
- };
-
- const events = await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Should contain RUN_FINISHED event
- const runFinishedEvent = events.find(e => e.type === EventType.RUN_FINISHED);
- expect(runFinishedEvent).toBeDefined();
-
- // Thread should not be running after completion
- const isRunning = await runner.isRunning({ threadId });
- expect(isRunning).toBe(false);
-
- // Stream should have retention TTL
- const streamKey = `stream:${threadId}:${input.runId}`;
- const ttl = await redis.pttl(streamKey);
- expect(ttl).toBeGreaterThan(0);
- expect(ttl).toBeLessThanOrEqual(60000); // retention period
- });
-
- it('should handle RUN_ERROR event correctly', async () => {
- const agent = new ErrorAgent();
- const threadId = 'test-thread-3';
- const input: RunAgentInput = {
- runId: 'run-error',
- threadId,
- messages: [],
- };
-
- const events = await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Should contain RUN_ERROR event
- const runErrorEvent = events.find(e => e.type === EventType.RUN_ERROR);
- expect(runErrorEvent).toBeDefined();
-
- // Thread should not be running after error
- const isRunning = await runner.isRunning({ threadId });
- expect(isRunning).toBe(false);
- });
-
- it('should allow late readers to catch up during retention period', async () => {
- const agent = new MockAgent();
- const threadId = 'test-thread-4';
- const input: RunAgentInput = {
- runId: 'run-retention',
- threadId,
- messages: [],
- };
-
- // Start and complete a run
- const runEvents = await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Wait a bit
- await new Promise(resolve => setTimeout(resolve, 100));
-
- // Connect should still get all events
- const connectEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Should get the same events (after compaction)
- expect(connectEvents.length).toBeGreaterThan(0);
-
- // Should include text message events
- const textStartEvents = connectEvents.filter(e => e.type === EventType.TEXT_MESSAGE_START);
- expect(textStartEvents.length).toBeGreaterThan(0);
- });
-
- it('should handle connect() with no active runs', async () => {
- const threadId = 'test-thread-5';
-
- // Connect to thread with no runs
- const events = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Should complete with empty array
- expect(events).toEqual([]);
- });
-
- it('should handle connect() during active run', async () => {
- const agent = new MockAgent();
- const threadId = 'test-thread-6';
- const input: RunAgentInput = {
- runId: 'run-active',
- threadId,
- messages: [],
- };
-
- // Start a run but don't wait for it
- runner.run({ threadId, agent, input });
-
- // Wait for run to start
- await new Promise(resolve => setTimeout(resolve, 50));
-
- // Connect while run is active
- const connectPromise = firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Should eventually complete when run finishes
- const events = await connectPromise;
- expect(events.length).toBeGreaterThan(0);
-
- // Should include RUN_FINISHED
- const finishedEvent = events.find(e => e.type === EventType.RUN_FINISHED);
- expect(finishedEvent).toBeDefined();
- });
-
- it('should handle stop() correctly', async () => {
- const agent = new MockAgent();
- const threadId = 'test-thread-7';
- const input: RunAgentInput = {
- runId: 'run-stop',
- threadId,
- messages: [],
- };
-
- // Mock a slow agent
- const slowAgent: AbstractAgent = {
- async runAgent(input, callbacks) {
- await callbacks.onEvent({
- event: {
- type: EventType.RUN_STARTED,
- threadId: input.threadId,
- runId: input.runId,
- }
- });
-
- // Simulate long running task
- await new Promise(resolve => setTimeout(resolve, 1000));
- }
- };
-
- // Start run
- runner.run({ threadId, agent: slowAgent, input });
-
- // Wait for run to start
- await new Promise(resolve => setTimeout(resolve, 50));
-
- // Stop the run
- const stopped = await runner.stop({ threadId });
- expect(stopped).toBe(true);
-
- // Should not be running
- const isRunning = await runner.isRunning({ threadId });
- expect(isRunning).toBe(false);
-
- // Stream should contain RUN_ERROR event
- const streamKey = `stream:${threadId}:${input.runId}`;
- const stream = await redis.xrange(streamKey, '-', '+');
- const errorEvent = stream.find((entry: any) => {
- const fields = entry[1];
- for (let i = 0; i < fields.length; i += 2) {
- if (fields[i] === 'type' && fields[i + 1] === EventType.RUN_ERROR) {
- return true;
- }
- }
- return false;
- });
- expect(errorEvent).toBeDefined();
- });
-
- it('should handle multiple sequential runs on same thread', async () => {
- const agent = new MockAgent();
- const threadId = 'test-thread-8';
-
- // First run
- const input1: RunAgentInput = {
- runId: 'run-seq-1',
- threadId,
- messages: [],
- };
-
- const events1 = await firstValueFrom(
- runner.run({ threadId, agent, input: input1 }).pipe(toArray())
- );
- expect(events1.length).toBeGreaterThan(0);
-
- // Second run
- const input2: RunAgentInput = {
- runId: 'run-seq-2',
- threadId,
- messages: [],
- };
-
- const events2 = await firstValueFrom(
- runner.run({ threadId, agent, input: input2 }).pipe(toArray())
- );
- expect(events2.length).toBeGreaterThan(0);
-
- // Connect should get both runs' events
- const allEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Should have events from both runs
- expect(allEvents.length).toBeGreaterThan(events1.length);
- });
-
- it('should handle input messages correctly', async () => {
- const agent = new MockAgent();
- const threadId = 'test-thread-9';
- const input: RunAgentInput = {
- runId: 'run-messages',
- threadId,
- messages: [
- {
- id: 'user-msg-1',
- role: 'user',
- content: 'Hello',
- }
- ],
- };
-
- const events = await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Run events should not include input messages
- const userMessages = events.filter((e: any) =>
- e.type === EventType.TEXT_MESSAGE_START && e.role === 'user'
- );
- expect(userMessages.length).toBe(0);
-
- // But connect should include them
- const connectEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- const userMessagesInConnect = connectEvents.filter((e: any) =>
- e.type === EventType.TEXT_MESSAGE_START && e.role === 'user'
- );
- expect(userMessagesInConnect.length).toBe(1);
- });
-
- // Additional comprehensive tests to match SQLite/InMemory coverage
-
- it('should persist events across runner instances', async () => {
- const threadId = 'test-thread-persistence';
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: 'msg1', role: 'assistant' },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: 'msg1', delta: 'Persisted' },
- { type: EventType.TEXT_MESSAGE_END, messageId: 'msg1' },
- { type: EventType.RUN_FINISHED, threadId, runId: 'run1' },
- ];
-
- const agent = new CustomEventAgent(events);
- const input: RunAgentInput = {
- threadId,
- runId: 'run1',
- messages: [],
- };
-
- // Run with first instance
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Don't close the first runner's DB connection since we share it
- // Just disconnect Redis
- runner.redis.disconnect();
- runner.redisSub.disconnect();
-
- // Create new runner instance with same DB but new Redis
- const newRunner = new EnterpriseAgentRunner({
- kysely: db, // Reuse same DB connection
- redis: new IORedisMock(),
- streamRetentionMs: 60000,
- streamActiveTTLMs: 10000,
- lockTTLMs: 30000
- });
-
- // Connect should get persisted events
- const persistedEvents = await firstValueFrom(
- newRunner.connect({ threadId }).pipe(toArray())
- );
-
- expect(persistedEvents.length).toBeGreaterThan(0);
- const textContent = persistedEvents.find(
- e => e.type === EventType.TEXT_MESSAGE_CONTENT
- ) as any;
- expect(textContent?.delta).toBe('Persisted');
-
- // Clean up new runner's Redis connections only
- newRunner.redis.disconnect();
- newRunner.redisSub.disconnect();
- });
-
- it('should handle concurrent connections', async () => {
- const threadId = 'test-thread-concurrent';
- const agent = new MockAgent();
- const input: RunAgentInput = {
- threadId,
- runId: 'run1',
- messages: [],
- };
-
- // Start a run
- const runPromise = firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Start multiple connections while run is active
- await new Promise(resolve => setTimeout(resolve, 50));
-
- const conn1Promise = firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
- const conn2Promise = firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
- const conn3Promise = firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Wait for all to complete
- const [runEvents, conn1Events, conn2Events, conn3Events] = await Promise.all([
- runPromise,
- conn1Promise,
- conn2Promise,
- conn3Promise,
- ]);
-
- // All connections should receive events
- expect(conn1Events.length).toBeGreaterThan(0);
- expect(conn2Events.length).toBeGreaterThan(0);
- expect(conn3Events.length).toBeGreaterThan(0);
- });
-
- it('should store compacted events in the database', async () => {
- const threadId = 'test-thread-compaction';
- const messageId = 'msg-compact';
-
- // Create events that will be compacted
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId, role: 'assistant' },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId, delta: 'Hello' },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId, delta: ' ' },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId, delta: 'World' },
- { type: EventType.TEXT_MESSAGE_END, messageId },
- { type: EventType.RUN_FINISHED, threadId, runId: 'run1' },
- ];
-
- const agent = new CustomEventAgent(events);
- const input: RunAgentInput = {
- threadId,
- runId: 'run1',
- messages: [],
- };
-
- // Run the agent
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Check database has compacted events
- const dbRuns = await db
- .selectFrom('agent_runs')
- .where('thread_id', '=', threadId)
- .selectAll()
- .execute();
-
- expect(dbRuns).toHaveLength(1);
- const storedEvents = JSON.parse(dbRuns[0].events);
-
- // Should have compacted content into single delta
- const contentEvents = storedEvents.filter(
- (e: any) => e.type === EventType.TEXT_MESSAGE_CONTENT
- );
- expect(contentEvents).toHaveLength(1);
- expect(contentEvents[0].delta).toBe('Hello World');
- });
-
- it('should not store duplicate message IDs across multiple runs', async () => {
- const threadId = 'test-thread-nodupe';
- const messageId = 'shared-msg';
-
- // First run with a message
- const input1: RunAgentInput = {
- threadId,
- runId: 'run1',
- messages: [{
- id: messageId,
- role: 'user',
- content: 'First message',
- }],
- };
-
- const agent = new CustomEventAgent([
- { type: EventType.RUN_FINISHED, threadId, runId: 'run1' },
- ]);
-
- await firstValueFrom(
- runner.run({ threadId, agent, input: input1 }).pipe(toArray())
- );
-
- // Second run with same message ID
- const input2: RunAgentInput = {
- threadId,
- runId: 'run2',
- messages: [{
- id: messageId,
- role: 'user',
- content: 'First message',
- }],
- };
-
- await firstValueFrom(
- runner.run({ threadId, agent, input: input2 }).pipe(toArray())
- );
-
- // Check database - message should only be stored in first run
- const dbRuns = await db
- .selectFrom('agent_runs')
- .where('thread_id', '=', threadId)
- .selectAll()
- .orderBy('created_at', 'asc')
- .execute();
-
- expect(dbRuns).toHaveLength(2);
-
- const run1Events = JSON.parse(dbRuns[0].events);
- const run2Events = JSON.parse(dbRuns[1].events);
-
- // First run should have the message events
- const run1MessageEvents = run1Events.filter(
- (e: any) => e.messageId === messageId
- );
- expect(run1MessageEvents.length).toBeGreaterThan(0);
-
- // Second run should NOT have the message events
- const run2MessageEvents = run2Events.filter(
- (e: any) => e.messageId === messageId
- );
- expect(run2MessageEvents.length).toBe(0);
- });
-
- it('should handle all message types (user, assistant, tool, system, developer)', async () => {
- const threadId = 'test-thread-alltypes';
- const messages: Message[] = [
- { id: 'user-1', role: 'user', content: 'User message' },
- { id: 'assistant-1', role: 'assistant', content: 'Assistant message' },
- { id: 'system-1', role: 'system', content: 'System message' },
- { id: 'developer-1', role: 'developer', content: 'Developer message' },
- {
- id: 'tool-1',
- role: 'tool',
- content: 'Tool result',
- toolCallId: 'call-1'
- },
- ];
-
- const input: RunAgentInput = {
- threadId,
- runId: 'run1',
- messages,
- };
-
- const agent = new CustomEventAgent([
- { type: EventType.RUN_FINISHED, threadId, runId: 'run1' },
- ]);
-
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Connect should get all message types
- const connectEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Check each message type is present
- const userEvents = connectEvents.filter(
- (e: any) => e.type === EventType.TEXT_MESSAGE_START && e.role === 'user'
- );
- expect(userEvents.length).toBe(1);
-
- const assistantEvents = connectEvents.filter(
- (e: any) => e.type === EventType.TEXT_MESSAGE_START && e.role === 'assistant'
- );
- expect(assistantEvents.length).toBe(1);
-
- const systemEvents = connectEvents.filter(
- (e: any) => e.type === EventType.TEXT_MESSAGE_START && e.role === 'system'
- );
- expect(systemEvents.length).toBe(1);
-
- const developerEvents = connectEvents.filter(
- (e: any) => e.type === EventType.TEXT_MESSAGE_START && e.role === 'developer'
- );
- expect(developerEvents.length).toBe(1);
-
- const toolEvents = connectEvents.filter(
- (e: any) => e.type === EventType.TOOL_CALL_RESULT
- );
- expect(toolEvents.length).toBe(1);
- });
-
- it('should handle tool calls correctly', async () => {
- const threadId = 'test-thread-tools';
- const messageId = 'assistant-msg';
- const toolCallId = 'tool-call-1';
-
- const messages: Message[] = [
- {
- id: messageId,
- role: 'assistant',
- content: 'Let me help',
- toolCalls: [{
- id: toolCallId,
- function: {
- name: 'calculator',
- arguments: '{"a": 1, "b": 2}'
- }
- }]
- },
- {
- id: 'tool-result-1',
- role: 'tool',
- content: '3',
- toolCallId: toolCallId
- }
- ];
-
- const input: RunAgentInput = {
- threadId,
- runId: 'run1',
- messages,
- };
-
- const agent = new CustomEventAgent([
- { type: EventType.RUN_FINISHED, threadId, runId: 'run1' },
- ]);
-
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- const connectEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Check tool call events
- const toolCallStart = connectEvents.find(
- (e: any) => e.type === EventType.TOOL_CALL_START && e.toolCallId === toolCallId
- ) as any;
- expect(toolCallStart).toBeDefined();
- expect(toolCallStart.toolCallName).toBe('calculator');
-
- const toolCallArgs = connectEvents.find(
- (e: any) => e.type === EventType.TOOL_CALL_ARGS && e.toolCallId === toolCallId
- ) as any;
- expect(toolCallArgs).toBeDefined();
- expect(toolCallArgs.delta).toBe('{"a": 1, "b": 2}');
-
- const toolCallEnd = connectEvents.find(
- (e: any) => e.type === EventType.TOOL_CALL_END && e.toolCallId === toolCallId
- );
- expect(toolCallEnd).toBeDefined();
-
- const toolResult = connectEvents.find(
- (e: any) => e.type === EventType.TOOL_CALL_RESULT && e.toolCallId === toolCallId
- ) as any;
- expect(toolResult).toBeDefined();
- expect(toolResult.content).toBe('3');
- });
-
- it('should track running state correctly', async () => {
- const threadId = 'test-thread-state';
-
- // Use a slow agent to ensure we can check running state
- const slowAgent: AbstractAgent = {
- async runAgent(input, callbacks) {
- if (callbacks.onRunStartedEvent) {
- await callbacks.onRunStartedEvent();
- }
-
- await callbacks.onEvent({
- event: {
- type: EventType.RUN_STARTED,
- threadId: input.threadId,
- runId: input.runId,
- }
- });
-
- // Delay to ensure we can check running state
- await new Promise(resolve => setTimeout(resolve, 200));
-
- await callbacks.onEvent({
- event: {
- type: EventType.RUN_FINISHED,
- threadId: input.threadId,
- runId: input.runId,
- }
- });
- }
- };
-
- const input: RunAgentInput = {
- threadId,
- runId: 'run1',
- messages: [],
- };
-
- // Check not running initially
- let isRunning = await runner.isRunning({ threadId });
- expect(isRunning).toBe(false);
-
- // Start run
- const runPromise = runner.run({ threadId, agent: slowAgent, input });
-
- // Check running state during execution
- await new Promise(resolve => setTimeout(resolve, 50));
- isRunning = await runner.isRunning({ threadId });
- expect(isRunning).toBe(true);
-
- // Wait for completion
- await firstValueFrom(runPromise.pipe(toArray()));
-
- // Check not running after completion
- isRunning = await runner.isRunning({ threadId });
- expect(isRunning).toBe(false);
- });
-
- it('should handle empty events arrays correctly', async () => {
- const threadId = 'test-thread-empty';
- const agent = new CustomEventAgent([]); // No events
- const input: RunAgentInput = {
- threadId,
- runId: 'run1',
- messages: [],
- };
-
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Check database - should still create a run record
- const dbRuns = await db
- .selectFrom('agent_runs')
- .where('thread_id', '=', threadId)
- .selectAll()
- .execute();
-
- expect(dbRuns).toHaveLength(1);
- const storedEvents = JSON.parse(dbRuns[0].events);
- expect(storedEvents).toEqual([]);
- });
-
- it('should handle parent-child run relationships', async () => {
- const threadId = 'test-thread-parent-child';
- const agent = new CustomEventAgent([
- { type: EventType.RUN_FINISHED, threadId, runId: 'run1' },
- ]);
-
- // First run (parent)
- await firstValueFrom(
- runner.run({
- threadId,
- agent,
- input: { threadId, runId: 'run1', messages: [] }
- }).pipe(toArray())
- );
-
- // Second run (child)
- await firstValueFrom(
- runner.run({
- threadId,
- agent,
- input: { threadId, runId: 'run2', messages: [] }
- }).pipe(toArray())
- );
-
- // Check parent-child relationship in database
- const dbRuns = await db
- .selectFrom('agent_runs')
- .where('thread_id', '=', threadId)
- .selectAll()
- .orderBy('created_at', 'asc')
- .execute();
-
- expect(dbRuns).toHaveLength(2);
- expect(dbRuns[0].parent_run_id).toBeNull();
- expect(dbRuns[1].parent_run_id).toBe('run1');
- });
-
- it('should handle database initialization correctly', async () => {
- // Check all tables exist
- const tables = await db
- .selectFrom('sqlite_master')
- .where('type', '=', 'table')
- .select('name')
- .execute();
-
- const tableNames = tables.map(t => t.name);
- expect(tableNames).toContain('agent_runs');
- expect(tableNames).toContain('run_state');
- expect(tableNames).toContain('schema_version');
-
- // Check schema version
- const schemaVersion = await db
- .selectFrom('schema_version')
- .selectAll()
- .executeTakeFirst();
-
- expect(schemaVersion).toBeDefined();
- expect(schemaVersion?.version).toBe(1);
- });
-
- it('should handle Redis stream expiry correctly', async () => {
- const threadId = 'test-thread-expiry';
- const agent = new MockAgent();
- const input: RunAgentInput = {
- threadId,
- runId: 'run1',
- messages: [],
- };
-
- // Run with short TTL
- const shortTTLRunner = new EnterpriseAgentRunner({
- kysely: db,
- redis,
- redisSub,
- streamRetentionMs: 100, // 100ms retention
- streamActiveTTLMs: 50, // 50ms active TTL
- lockTTLMs: 1000
- });
-
- await firstValueFrom(
- shortTTLRunner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Stream should exist immediately after run
- const streamKey = `stream:${threadId}:run1`;
- let exists = await redis.exists(streamKey);
- expect(exists).toBe(1);
-
- // Wait for retention period to expire
- await new Promise(resolve => setTimeout(resolve, 150));
-
- // Stream should be gone
- exists = await redis.exists(streamKey);
- expect(exists).toBe(0);
-
- await shortTTLRunner.close();
- });
-});
\ No newline at end of file
diff --git a/packages/runtime/src/runner/__tests__/event-compaction.test.ts b/packages/runtime/src/runner/__tests__/event-compaction.test.ts
deleted file mode 100644
index fe1e40af..00000000
--- a/packages/runtime/src/runner/__tests__/event-compaction.test.ts
+++ /dev/null
@@ -1,253 +0,0 @@
-import { describe, it, expect } from "vitest";
-import { compactEvents } from "../event-compaction";
-import { BaseEvent, EventType } from "@ag-ui/client";
-
-describe("Event Compaction", () => {
- describe("Text Message Compaction", () => {
- it("should compact multiple text message content events into one", () => {
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "user" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Hello" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: " " },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "world" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const compacted = compactEvents(events);
-
- expect(compacted).toHaveLength(3);
- expect(compacted[0].type).toBe(EventType.TEXT_MESSAGE_START);
- expect(compacted[1].type).toBe(EventType.TEXT_MESSAGE_CONTENT);
- expect((compacted[1] as any).delta).toBe("Hello world");
- expect(compacted[2].type).toBe(EventType.TEXT_MESSAGE_END);
- });
-
- it("should move interleaved events to after text message events", () => {
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Processing" },
- { type: EventType.CUSTOM, id: "custom1", name: "thinking" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "..." },
- { type: EventType.CUSTOM, id: "custom2", name: "done-thinking" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const compacted = compactEvents(events);
-
- expect(compacted).toHaveLength(5);
- // Text message events should come first
- expect(compacted[0].type).toBe(EventType.TEXT_MESSAGE_START);
- expect(compacted[1].type).toBe(EventType.TEXT_MESSAGE_CONTENT);
- expect((compacted[1] as any).delta).toBe("Processing...");
- expect(compacted[2].type).toBe(EventType.TEXT_MESSAGE_END);
- // Other events should come after
- expect(compacted[3].type).toBe(EventType.CUSTOM);
- expect((compacted[3] as any).id).toBe("custom1");
- expect(compacted[4].type).toBe(EventType.CUSTOM);
- expect((compacted[4] as any).id).toBe("custom2");
- });
-
- it("should handle multiple messages independently", () => {
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "user" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Hi" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg2", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "Hello" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: " there" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg2" },
- ];
-
- const compacted = compactEvents(events);
-
- expect(compacted).toHaveLength(6);
- // First message
- expect(compacted[0].type).toBe(EventType.TEXT_MESSAGE_START);
- expect((compacted[0] as any).messageId).toBe("msg1");
- expect(compacted[1].type).toBe(EventType.TEXT_MESSAGE_CONTENT);
- expect((compacted[1] as any).delta).toBe("Hi");
- expect(compacted[2].type).toBe(EventType.TEXT_MESSAGE_END);
- // Second message
- expect(compacted[3].type).toBe(EventType.TEXT_MESSAGE_START);
- expect((compacted[3] as any).messageId).toBe("msg2");
- expect(compacted[4].type).toBe(EventType.TEXT_MESSAGE_CONTENT);
- expect((compacted[4] as any).delta).toBe("Hello there");
- expect(compacted[5].type).toBe(EventType.TEXT_MESSAGE_END);
- });
-
- it("should handle incomplete messages", () => {
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "user" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Incomplete" },
- // No END event
- ];
-
- const compacted = compactEvents(events);
-
- expect(compacted).toHaveLength(2);
- expect(compacted[0].type).toBe(EventType.TEXT_MESSAGE_START);
- expect(compacted[1].type).toBe(EventType.TEXT_MESSAGE_CONTENT);
- expect((compacted[1] as any).delta).toBe("Incomplete");
- });
-
- it("should pass through non-text-message events unchanged", () => {
- const events: BaseEvent[] = [
- { type: EventType.CUSTOM, id: "custom1", name: "event1" },
- { type: EventType.TOOL_CALL_START, toolCallId: "tool1", toolCallName: "search" },
- { type: EventType.TOOL_CALL_END, toolCallId: "tool1" },
- ];
-
- const compacted = compactEvents(events);
-
- expect(compacted).toEqual(events);
- });
-
- it("should handle empty content deltas", () => {
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "user" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Hello" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const compacted = compactEvents(events);
-
- expect(compacted).toHaveLength(3);
- expect((compacted[1] as any).delta).toBe("Hello");
- });
- });
-
- describe("Tool Call Compaction", () => {
- it("should compact multiple tool call args events into one", () => {
- const events: BaseEvent[] = [
- { type: EventType.TOOL_CALL_START, toolCallId: "tool1", toolCallName: "search", parentMessageId: "msg1" },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: '{"query": "' },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: 'weather' },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: ' today"' },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: '}' },
- { type: EventType.TOOL_CALL_END, toolCallId: "tool1" },
- ];
-
- const compacted = compactEvents(events);
-
- expect(compacted).toHaveLength(3);
- expect(compacted[0].type).toBe(EventType.TOOL_CALL_START);
- expect(compacted[1].type).toBe(EventType.TOOL_CALL_ARGS);
- expect((compacted[1] as any).delta).toBe('{"query": "weather today"}');
- expect(compacted[2].type).toBe(EventType.TOOL_CALL_END);
- });
-
- it("should move interleaved events to after tool call events", () => {
- const events: BaseEvent[] = [
- { type: EventType.TOOL_CALL_START, toolCallId: "tool1", toolCallName: "calculate", parentMessageId: "msg1" },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: '{"a": ' },
- { type: EventType.CUSTOM, id: "custom1", name: "processing" },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: '10, "b": 20}' },
- { type: EventType.CUSTOM, id: "custom2", name: "calculating" },
- { type: EventType.TOOL_CALL_END, toolCallId: "tool1" },
- ];
-
- const compacted = compactEvents(events);
-
- expect(compacted).toHaveLength(5);
- // Tool call events should come first
- expect(compacted[0].type).toBe(EventType.TOOL_CALL_START);
- expect(compacted[1].type).toBe(EventType.TOOL_CALL_ARGS);
- expect((compacted[1] as any).delta).toBe('{"a": 10, "b": 20}');
- expect(compacted[2].type).toBe(EventType.TOOL_CALL_END);
- // Other events should come after
- expect(compacted[3].type).toBe(EventType.CUSTOM);
- expect((compacted[3] as any).id).toBe("custom1");
- expect(compacted[4].type).toBe(EventType.CUSTOM);
- expect((compacted[4] as any).id).toBe("custom2");
- });
-
- it("should handle multiple tool calls independently", () => {
- const events: BaseEvent[] = [
- { type: EventType.TOOL_CALL_START, toolCallId: "tool1", toolCallName: "search", parentMessageId: "msg1" },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: '{"query": "test"}' },
- { type: EventType.TOOL_CALL_END, toolCallId: "tool1" },
- { type: EventType.TOOL_CALL_START, toolCallId: "tool2", toolCallName: "calculate", parentMessageId: "msg1" },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool2", delta: '{"a": ' },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool2", delta: '5}' },
- { type: EventType.TOOL_CALL_END, toolCallId: "tool2" },
- ];
-
- const compacted = compactEvents(events);
-
- expect(compacted).toHaveLength(6);
- // First tool call
- expect(compacted[0].type).toBe(EventType.TOOL_CALL_START);
- expect((compacted[0] as any).toolCallId).toBe("tool1");
- expect(compacted[1].type).toBe(EventType.TOOL_CALL_ARGS);
- expect((compacted[1] as any).delta).toBe('{"query": "test"}');
- expect(compacted[2].type).toBe(EventType.TOOL_CALL_END);
- // Second tool call
- expect(compacted[3].type).toBe(EventType.TOOL_CALL_START);
- expect((compacted[3] as any).toolCallId).toBe("tool2");
- expect(compacted[4].type).toBe(EventType.TOOL_CALL_ARGS);
- expect((compacted[4] as any).delta).toBe('{"a": 5}');
- expect(compacted[5].type).toBe(EventType.TOOL_CALL_END);
- });
-
- it("should handle incomplete tool calls", () => {
- const events: BaseEvent[] = [
- { type: EventType.TOOL_CALL_START, toolCallId: "tool1", toolCallName: "search", parentMessageId: "msg1" },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: '{"incomplete": ' },
- // No END event
- ];
-
- const compacted = compactEvents(events);
-
- expect(compacted).toHaveLength(2);
- expect(compacted[0].type).toBe(EventType.TOOL_CALL_START);
- expect(compacted[1].type).toBe(EventType.TOOL_CALL_ARGS);
- expect((compacted[1] as any).delta).toBe('{"incomplete": ');
- });
-
- it("should handle empty args deltas", () => {
- const events: BaseEvent[] = [
- { type: EventType.TOOL_CALL_START, toolCallId: "tool1", toolCallName: "search", parentMessageId: "msg1" },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: "" },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: '{"test": true}' },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: "" },
- { type: EventType.TOOL_CALL_END, toolCallId: "tool1" },
- ];
-
- const compacted = compactEvents(events);
-
- expect(compacted).toHaveLength(3);
- expect((compacted[1] as any).delta).toBe('{"test": true}');
- });
- });
-
- describe("Mixed Compaction", () => {
- it("should handle text messages and tool calls together", () => {
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Let me " },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "search for that" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- { type: EventType.TOOL_CALL_START, toolCallId: "tool1", toolCallName: "search", parentMessageId: "msg1" },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: '{"q": "' },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool1", delta: 'test"}' },
- { type: EventType.TOOL_CALL_END, toolCallId: "tool1" },
- ];
-
- const compacted = compactEvents(events);
-
- expect(compacted).toHaveLength(6);
- // Text message
- expect(compacted[0].type).toBe(EventType.TEXT_MESSAGE_START);
- expect(compacted[1].type).toBe(EventType.TEXT_MESSAGE_CONTENT);
- expect((compacted[1] as any).delta).toBe("Let me search for that");
- expect(compacted[2].type).toBe(EventType.TEXT_MESSAGE_END);
- // Tool call
- expect(compacted[3].type).toBe(EventType.TOOL_CALL_START);
- expect(compacted[4].type).toBe(EventType.TOOL_CALL_ARGS);
- expect((compacted[4] as any).delta).toBe('{"q": "test"}');
- expect(compacted[5].type).toBe(EventType.TOOL_CALL_END);
- });
- });
-});
\ No newline at end of file
diff --git a/packages/runtime/src/runner/__tests__/in-memory-runner.e2e.test.ts b/packages/runtime/src/runner/__tests__/in-memory-runner.e2e.test.ts
new file mode 100644
index 00000000..bfd87a72
--- /dev/null
+++ b/packages/runtime/src/runner/__tests__/in-memory-runner.e2e.test.ts
@@ -0,0 +1,750 @@
+import { describe, it, expect } from "vitest";
+import { InMemoryAgentRunner } from "../in-memory";
+import {
+ AbstractAgent,
+ BaseEvent,
+ EventType,
+ Message,
+ RunAgentInput,
+ RunErrorEvent,
+ RunFinishedEvent,
+ RunStartedEvent,
+} from "@ag-ui/client";
+import { EMPTY, Subscription, firstValueFrom, from } from "rxjs";
+import { toArray } from "rxjs/operators";
+
+type RunCallbacks = {
+ onEvent: (event: { event: BaseEvent }) => void;
+ onNewMessage?: (args: { message: Message }) => void;
+ onRunStartedEvent?: () => void;
+};
+
+interface EmitAgentOptions {
+ events?: BaseEvent[];
+ emitDefaultRunStarted?: boolean;
+ includeRunFinished?: boolean;
+ runFinishedEvent?: RunFinishedEvent;
+ afterEvent?: (args: { event: BaseEvent; index: number }) => void | Promise;
+}
+
+class EmitAgent extends AbstractAgent {
+ constructor(private readonly options: EmitAgentOptions = {}) {
+ super();
+ }
+
+ async runAgent(input: RunAgentInput, callbacks: RunCallbacks): Promise {
+ const {
+ emitDefaultRunStarted = true,
+ includeRunFinished = true,
+ runFinishedEvent,
+ afterEvent,
+ } = this.options;
+ const scriptedEvents = this.options.events ?? [];
+
+ let index = 0;
+ const emit = async (event: BaseEvent) => {
+ callbacks.onEvent({ event });
+ if (event.type === EventType.RUN_STARTED) {
+ callbacks.onRunStartedEvent?.();
+ }
+ await afterEvent?.({ event, index });
+ index += 1;
+ };
+
+ if (emitDefaultRunStarted) {
+ const runStarted: RunStartedEvent = {
+ type: EventType.RUN_STARTED,
+ threadId: input.threadId,
+ runId: input.runId,
+ parentRunId: input.parentRunId,
+ };
+ await emit(runStarted);
+ }
+
+ for (const event of scriptedEvents) {
+ await emit(event);
+ }
+
+ const hasRunFinishedEvent =
+ scriptedEvents.some((event) => event.type === EventType.RUN_FINISHED) ||
+ runFinishedEvent?.type === EventType.RUN_FINISHED;
+
+ if (includeRunFinished && !hasRunFinishedEvent) {
+ const finishEvent: RunFinishedEvent =
+ runFinishedEvent ?? {
+ type: EventType.RUN_FINISHED,
+ threadId: input.threadId,
+ runId: input.runId,
+ };
+ await emit(finishEvent);
+ }
+ }
+
+ clone(): AbstractAgent {
+ return new EmitAgent({
+ ...this.options,
+ events: this.options.events ? [...this.options.events] : undefined,
+ });
+ }
+
+ protected run(): ReturnType {
+ return EMPTY;
+ }
+
+ protected connect(): ReturnType {
+ return EMPTY;
+ }
+}
+
+class ReplayAgent extends AbstractAgent {
+ constructor(private readonly replayEvents: BaseEvent[], threadId: string) {
+ super({ threadId });
+ }
+
+ async runAgent(): Promise {
+ throw new Error("not used");
+ }
+
+ protected run(): ReturnType {
+ return EMPTY;
+ }
+
+ protected connect(): ReturnType {
+ return from(this.replayEvents);
+ }
+}
+
+class RunnerConnectAgent extends AbstractAgent {
+ constructor(private readonly runner: InMemoryAgentRunner, threadId: string) {
+ super({ threadId });
+ }
+
+ async runAgent(): Promise {
+ throw new Error("not used");
+ }
+
+ protected run(): ReturnType {
+ return EMPTY;
+ }
+
+ protected connect(input: RunAgentInput): ReturnType {
+ return this.runner.connect({ threadId: input.threadId });
+ }
+}
+
+type Deferred = {
+ promise: Promise;
+ resolve: (value: T) => void;
+ reject: (reason?: unknown) => void;
+};
+
+function createDeferred(): Deferred {
+ let resolve!: (value: T) => void;
+ let reject!: (reason?: unknown) => void;
+ const promise = new Promise((res, rej) => {
+ resolve = res;
+ reject = rej;
+ });
+ return { promise, resolve, reject };
+}
+
+async function collectEvents(observable: ReturnType | ReturnType) {
+ return firstValueFrom(observable.pipe(toArray()));
+}
+
+function createRunInput({
+ threadId,
+ runId,
+ messages,
+ state,
+ parentRunId,
+}: {
+ threadId: string;
+ runId: string;
+ messages: Message[];
+ state?: Record;
+ parentRunId?: string | null;
+}): RunAgentInput {
+ return {
+ threadId,
+ runId,
+ parentRunId: parentRunId ?? undefined,
+ state: state ?? {},
+ messages,
+ tools: [],
+ context: [],
+ forwardedProps: undefined,
+ };
+}
+
+function expectRunStartedEvent(event: BaseEvent, expectedMessages: Message[]) {
+ expect(event.type).toBe(EventType.RUN_STARTED);
+ const runStarted = event as RunStartedEvent;
+ expect(runStarted.input?.messages).toEqual(expectedMessages);
+}
+
+function createTextMessageEvents({
+ messageId,
+ role = "assistant",
+ content,
+}: {
+ messageId: string;
+ role?: "assistant" | "developer" | "system" | "user";
+ content: string;
+}): BaseEvent[] {
+ return [
+ {
+ type: EventType.TEXT_MESSAGE_START,
+ messageId,
+ role,
+ },
+ {
+ type: EventType.TEXT_MESSAGE_CONTENT,
+ messageId,
+ delta: content,
+ },
+ {
+ type: EventType.TEXT_MESSAGE_END,
+ messageId,
+ },
+ ] as BaseEvent[];
+}
+
+function createToolCallEvents({
+ toolCallId,
+ parentMessageId,
+ toolName,
+ argsJson,
+ resultMessageId,
+ resultContent,
+}: {
+ toolCallId: string;
+ parentMessageId: string;
+ toolName: string;
+ argsJson: string;
+ resultMessageId: string;
+ resultContent: string;
+}): BaseEvent[] {
+ return [
+ {
+ type: EventType.TOOL_CALL_START,
+ toolCallId,
+ toolCallName: toolName,
+ parentMessageId,
+ },
+ {
+ type: EventType.TOOL_CALL_ARGS,
+ toolCallId,
+ delta: argsJson,
+ },
+ {
+ type: EventType.TOOL_CALL_END,
+ toolCallId,
+ },
+ {
+ type: EventType.TOOL_CALL_RESULT,
+ toolCallId,
+ messageId: resultMessageId,
+ content: resultContent,
+ role: "tool",
+ },
+ ] as BaseEvent[];
+}
+
+describe("InMemoryAgentRunner e2e", () => {
+ describe("Fresh Replay After Single Run", () => {
+ it("replays sanitized message history on connectAgent", async () => {
+ const runner = new InMemoryAgentRunner();
+ const threadId = "thread-fresh-replay";
+ const existingMessage: Message = {
+ id: "message-existing",
+ role: "user",
+ content: "Hello there",
+ };
+
+ const runEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent(),
+ input: createRunInput({
+ threadId,
+ runId: "run-0",
+ messages: [existingMessage],
+ }),
+ }),
+ );
+
+ expectRunStartedEvent(runEvents[0], [existingMessage]);
+ expect(runEvents.at(-1)?.type).toBe(EventType.RUN_FINISHED);
+
+ const replayEvents = await collectEvents(runner.connect({ threadId }));
+ const replayAgent = new ReplayAgent(replayEvents, threadId);
+ await replayAgent.connectAgent({ runId: "replay-run" });
+
+ expect(replayAgent.messages).toEqual([existingMessage]);
+ });
+ });
+
+ describe("New Messages on Subsequent Runs", () => {
+ it("merges new message IDs without duplicating history", async () => {
+ const runner = new InMemoryAgentRunner();
+ const threadId = "thread-subsequent-runs";
+ const existingMessage: Message = {
+ id: "msg-existing",
+ role: "user",
+ content: "First turn",
+ };
+
+ const initialRunEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent(),
+ input: createRunInput({
+ threadId,
+ runId: "run-0",
+ messages: [existingMessage],
+ }),
+ }),
+ );
+ expectRunStartedEvent(initialRunEvents[0], [existingMessage]);
+
+ const newMessage: Message = {
+ id: "msg-new",
+ role: "user",
+ content: "Second turn",
+ };
+
+ const secondRunEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent(),
+ input: createRunInput({
+ threadId,
+ runId: "run-1",
+ messages: [existingMessage, newMessage],
+ }),
+ }),
+ );
+
+ expectRunStartedEvent(secondRunEvents[0], [newMessage]);
+
+ const replayEvents = await collectEvents(runner.connect({ threadId }));
+ const replayAgent = new ReplayAgent(replayEvents, threadId);
+ await replayAgent.connectAgent({ runId: "replay-run" });
+
+ expect(replayAgent.messages).toEqual([existingMessage, newMessage]);
+ expect(new Set(replayAgent.messages.map((message) => message.id)).size).toBe(
+ replayAgent.messages.length,
+ );
+ });
+ });
+
+ describe("Fresh Agent Connection After Prior Runs", () => {
+ it("hydrates a brand-new agent via connect()", async () => {
+ const runner = new InMemoryAgentRunner();
+ const threadId = "thread-new-agent-connection";
+ const existingMessage: Message = {
+ id: "existing-connection",
+ role: "user",
+ content: "Persist me",
+ };
+
+ const runEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent(),
+ input: createRunInput({
+ threadId,
+ runId: "run-0",
+ messages: [existingMessage],
+ }),
+ }),
+ );
+ expectRunStartedEvent(runEvents[0], [existingMessage]);
+
+ const connectingAgent = new RunnerConnectAgent(runner, threadId);
+ await connectingAgent.connectAgent({ runId: "connect-run" });
+
+ expect(connectingAgent.messages).toEqual([existingMessage]);
+ });
+ });
+
+ describe("Mixed Roles and Tool Results", () => {
+ it("preserves agent-emitted tool events alongside heterogeneous inputs", async () => {
+ const runner = new InMemoryAgentRunner();
+ const threadId = "thread-mixed-roles";
+
+ const systemMessage: Message = {
+ id: "sys-1",
+ role: "system",
+ content: "Global directive",
+ };
+ const developerMessage: Message = {
+ id: "dev-1",
+ role: "developer",
+ content: "Internal guidance",
+ };
+ const userMessage: Message = {
+ id: "user-1",
+ role: "user",
+ content: "Need the weather",
+ };
+ const baseMessages = [systemMessage, developerMessage, userMessage];
+
+ const assistantMessageId = "assistant-1";
+ const toolCallId = "tool-call-1";
+ const toolMessageId = "tool-msg-1";
+
+ const agentEvents: BaseEvent[] = [
+ ...createTextMessageEvents({
+ messageId: assistantMessageId,
+ content: "Calling the weather tool",
+ }),
+ ...createToolCallEvents({
+ toolCallId,
+ parentMessageId: assistantMessageId,
+ toolName: "getWeather",
+ argsJson: '{"location":"NYC"}',
+ resultMessageId: toolMessageId,
+ resultContent: '{"temp":72}',
+ }),
+ ];
+
+ const runEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent({ events: agentEvents }),
+ input: createRunInput({
+ threadId,
+ runId: "run-0",
+ messages: baseMessages,
+ }),
+ }),
+ );
+
+ expectRunStartedEvent(runEvents[0], baseMessages);
+ expect(runEvents.filter((event) => event.type === EventType.TOOL_CALL_RESULT)).toHaveLength(1);
+
+ const replayEvents = await collectEvents(runner.connect({ threadId }));
+ const replayAgent = new ReplayAgent(replayEvents, threadId);
+ await replayAgent.connectAgent({ runId: "replay-run" });
+
+ expect(replayAgent.messages).toEqual([
+ systemMessage,
+ developerMessage,
+ userMessage,
+ {
+ id: assistantMessageId,
+ role: "assistant",
+ content: "Calling the weather tool",
+ toolCalls: [
+ {
+ id: toolCallId,
+ type: "function",
+ function: {
+ name: "getWeather",
+ arguments: '{"location":"NYC"}',
+ },
+ },
+ ],
+ },
+ {
+ id: toolMessageId,
+ role: "tool",
+ content: '{"temp":72}',
+ toolCallId,
+ },
+ ]);
+ expect(replayAgent.messages.filter((message) => message.role === "tool")).toHaveLength(1);
+ });
+ });
+
+ describe("Multiple Consecutive Runs with Agent Output", () => {
+ it("deduplicates input history while emitting each agent message once", async () => {
+ const runner = new InMemoryAgentRunner();
+ const threadId = "thread-multi-runs";
+ const systemMessage: Message = {
+ id: "system-shared",
+ role: "system",
+ content: "System context",
+ };
+ const userMessages: Message[] = [];
+
+ for (let index = 0; index < 3; index += 1) {
+ const userMessage: Message = {
+ id: `user-${index + 1}`,
+ role: "user",
+ content: `User message ${index + 1}`,
+ };
+ userMessages.push(userMessage);
+
+ const messagesForRun = [systemMessage, ...userMessages];
+ const assistantId = `assistant-${index + 1}`;
+ const toolCallId = `tool-call-${index + 1}`;
+ const toolMessageId = `tool-msg-${index + 1}`;
+
+ const events: BaseEvent[] = [
+ ...createTextMessageEvents({
+ messageId: assistantId,
+ content: `Assistant reply ${index + 1}`,
+ }),
+ ...createToolCallEvents({
+ toolCallId,
+ parentMessageId: assistantId,
+ toolName: `tool-${index + 1}`,
+ argsJson: `{"step":${index + 1}}`,
+ resultMessageId: toolMessageId,
+ resultContent: `{"ok":${index + 1}}`,
+ }),
+ ];
+
+ const runEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent({ events }),
+ input: createRunInput({
+ threadId,
+ runId: `run-${index}`,
+ messages: messagesForRun,
+ }),
+ }),
+ );
+
+ if (index === 0) {
+ expectRunStartedEvent(runEvents[0], messagesForRun);
+ } else {
+ expectRunStartedEvent(runEvents[0], [userMessage]);
+ }
+ expect(runEvents.at(-1)?.type).toBe(EventType.RUN_FINISHED);
+ }
+
+ const replayEvents = await collectEvents(runner.connect({ threadId }));
+ const replayAgent = new ReplayAgent(replayEvents, threadId);
+ await replayAgent.connectAgent({ runId: "replay-final" });
+
+ const finalMessages = replayAgent.messages;
+ expect(new Set(finalMessages.map((message) => message.id)).size).toBe(finalMessages.length);
+ const roleCounts = finalMessages.reduce>((counts, message) => {
+ counts[message.role] = (counts[message.role] ?? 0) + 1;
+ return counts;
+ }, {});
+ expect(roleCounts.system).toBe(1);
+ expect(roleCounts.user).toBe(3);
+ expect(roleCounts.assistant).toBe(3);
+ expect(roleCounts.tool).toBe(3);
+ });
+ });
+
+ describe("Agent-Provided RUN_STARTED input", () => {
+ it("forwards the agent-specified payload without sanitizing", async () => {
+ const runner = new InMemoryAgentRunner();
+ const threadId = "thread-custom-run-started";
+ const runId = "run-0";
+
+ const customMessages: Message[] = [
+ {
+ id: "custom-user",
+ role: "user",
+ content: "Pre-sent content",
+ },
+ ];
+ const customInput: RunAgentInput = {
+ threadId,
+ runId,
+ parentRunId: undefined,
+ state: { injected: true },
+ messages: customMessages,
+ tools: [],
+ context: [],
+ forwardedProps: { source: "agent" },
+ };
+ const customRunStarted: RunStartedEvent = {
+ type: EventType.RUN_STARTED,
+ threadId,
+ runId,
+ parentRunId: null,
+ input: customInput,
+ };
+
+ const agentEvents: BaseEvent[] = [
+ customRunStarted,
+ ...createTextMessageEvents({
+ messageId: "agent-message",
+ content: "Custom start acknowledged",
+ }),
+ ];
+
+ const runEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent({
+ events: agentEvents,
+ emitDefaultRunStarted: false,
+ }),
+ input: createRunInput({
+ threadId,
+ runId,
+ messages: [],
+ }),
+ }),
+ );
+
+ expect(runEvents[0]).toEqual(customRunStarted);
+ expect(runEvents.filter((event) => event.type === EventType.RUN_FINISHED)).toHaveLength(1);
+
+ const replayEvents = await collectEvents(runner.connect({ threadId }));
+ const replayAgent = new ReplayAgent(replayEvents, threadId);
+ await replayAgent.connectAgent({ runId: "replay-run" });
+ expect(replayAgent.messages.find((message) => message.id === "custom-user")).toEqual(
+ customMessages[0],
+ );
+ });
+ });
+
+ describe("Concurrent Connections During Run", () => {
+ it("streams in-flight events to live subscribers and persists final history", async () => {
+ const runner = new InMemoryAgentRunner();
+ const threadId = "thread-concurrency";
+ const runId = "run-live";
+ const initialMessage: Message = {
+ id: "initial-user",
+ role: "user",
+ content: "Start run",
+ };
+
+ const runStartedSignal = createDeferred();
+ const resumeSignal = createDeferred();
+
+ const agent = new EmitAgent({
+ events: [
+ ...createTextMessageEvents({
+ messageId: "assistant-live",
+ content: "Streaming content",
+ }),
+ ],
+ afterEvent: async ({ event }) => {
+ if (event.type === EventType.RUN_STARTED) {
+ runStartedSignal.resolve();
+ await resumeSignal.promise;
+ }
+ },
+ });
+
+ const runEvents: BaseEvent[] = [];
+ const run$ = runner.run({
+ threadId,
+ agent,
+ input: createRunInput({
+ threadId,
+ runId,
+ messages: [initialMessage],
+ }),
+ });
+
+ let runSubscription: Subscription;
+ const runCompletion = new Promise((resolve, reject) => {
+ runSubscription = run$.subscribe({
+ next: (event) => runEvents.push(event),
+ error: (error) => {
+ runSubscription.unsubscribe();
+ reject(error);
+ },
+ complete: () => {
+ runSubscription.unsubscribe();
+ resolve();
+ },
+ });
+ });
+
+ await runStartedSignal.promise;
+
+ const liveEvents: BaseEvent[] = [];
+ const connect$ = runner.connect({ threadId });
+ let connectSubscription: Subscription;
+ const connectCompletion = new Promise((resolve, reject) => {
+ connectSubscription = connect$.subscribe({
+ next: (event) => liveEvents.push(event),
+ error: (error) => {
+ connectSubscription.unsubscribe();
+ reject(error);
+ },
+ complete: () => {
+ connectSubscription.unsubscribe();
+ resolve();
+ },
+ });
+ });
+
+ resumeSignal.resolve();
+
+ await Promise.all([runCompletion, connectCompletion]);
+
+ expectRunStartedEvent(runEvents[0], [initialMessage]);
+ expect(runEvents.at(-1)?.type).toBe(EventType.RUN_FINISHED);
+ expect(liveEvents).toEqual(runEvents);
+
+ const persistedEvents = await collectEvents(runner.connect({ threadId }));
+ expect(persistedEvents).toEqual(runEvents);
+
+ const replayAgent = new ReplayAgent(persistedEvents, threadId);
+ await replayAgent.connectAgent({ runId: "replay-run" });
+ expect(replayAgent.messages.map((message) => message.id)).toEqual([
+ initialMessage.id,
+ "assistant-live",
+ ]);
+ });
+ });
+
+ describe("Error Handling", () => {
+ it("propagates RUN_ERROR while retaining input history", async () => {
+ const runner = new InMemoryAgentRunner();
+ const threadId = "thread-run-error";
+ const userMessage: Message = {
+ id: "error-user",
+ role: "user",
+ content: "Trigger error",
+ };
+
+ const runErrorEvent: RunErrorEvent = {
+ type: EventType.RUN_ERROR,
+ message: "Agent failure",
+ };
+
+ const runEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent({
+ events: [runErrorEvent],
+ includeRunFinished: false,
+ }),
+ input: createRunInput({
+ threadId,
+ runId: "run-error",
+ messages: [userMessage],
+ }),
+ }),
+ );
+
+ expectRunStartedEvent(runEvents[0], [userMessage]);
+ expect(runEvents.at(-1)).toEqual(runErrorEvent);
+
+ const replayEvents = await collectEvents(runner.connect({ threadId }));
+ const replayAgent = new ReplayAgent(replayEvents, threadId);
+ const capturedRunErrors: RunErrorEvent[] = [];
+ const result = await replayAgent.connectAgent(
+ { runId: "replay-run" },
+ {
+ onRunErrorEvent: ({ event }) => {
+ capturedRunErrors.push(event);
+ },
+ },
+ );
+
+ expect(runEvents.at(-1)?.type).toBe(EventType.RUN_ERROR);
+ expect(capturedRunErrors).toHaveLength(1);
+ expect(capturedRunErrors[0]).toMatchObject(runErrorEvent);
+ expect(result.newMessages).toEqual([userMessage]);
+ expect(replayAgent.messages).toEqual([userMessage]);
+ });
+ });
+});
diff --git a/packages/runtime/src/runner/__tests__/in-memory-runner.test.ts b/packages/runtime/src/runner/__tests__/in-memory-runner.test.ts
index cc6e6035..d63d302f 100644
--- a/packages/runtime/src/runner/__tests__/in-memory-runner.test.ts
+++ b/packages/runtime/src/runner/__tests__/in-memory-runner.test.ts
@@ -6,20 +6,21 @@ import {
EventType,
Message,
RunAgentInput,
+ RunStartedEvent,
TextMessageContentEvent,
TextMessageEndEvent,
TextMessageStartEvent,
ToolCallResultEvent,
} from "@ag-ui/client";
-import { firstValueFrom } from "rxjs";
+import { EMPTY, firstValueFrom } from "rxjs";
import { toArray } from "rxjs/operators";
class TestAgent extends AbstractAgent {
- private events: BaseEvent[] = [];
-
- constructor(events: BaseEvent[] = []) {
+ constructor(
+ private readonly events: BaseEvent[] = [],
+ private readonly emitDefaultRunStarted = true,
+ ) {
super();
- this.events = events;
}
async runAgent(
@@ -28,31 +29,33 @@ class TestAgent extends AbstractAgent {
onEvent: (event: { event: BaseEvent }) => void;
onNewMessage?: (args: { message: Message }) => void;
onRunStartedEvent?: () => void;
- }
+ },
): Promise {
- // Call onRunStartedEvent to trigger message injection
- if (options.onRunStartedEvent) {
- options.onRunStartedEvent();
+ if (this.emitDefaultRunStarted) {
+ const runStarted: RunStartedEvent = {
+ type: EventType.RUN_STARTED,
+ threadId: input.threadId,
+ runId: input.runId,
+ };
+ options.onEvent({ event: runStarted });
+ options.onRunStartedEvent?.();
}
- // Emit test events
for (const event of this.events) {
options.onEvent({ event });
}
-
- // Call onNewMessage for assistant messages we generate
- if (options.onNewMessage) {
- const assistantMessage: Message = {
- id: "assistant-msg-1",
- role: "assistant",
- content: "Test response",
- };
- options.onNewMessage({ message: assistantMessage });
- }
}
clone(): AbstractAgent {
- return new TestAgent(this.events);
+ return new TestAgent(this.events, this.emitDefaultRunStarted);
+ }
+
+ protected run(): ReturnType {
+ return EMPTY;
+ }
+
+ protected connect(): ReturnType {
+ return EMPTY;
}
}
@@ -63,35 +66,10 @@ describe("InMemoryAgentRunner", () => {
runner = new InMemoryAgentRunner();
});
- describe("Event Storage", () => {
- it("should not store empty events", async () => {
- const threadId = "test-thread-no-empty";
- const agent = new TestAgent([]);
-
- const input: RunAgentInput = {
- messages: [],
- state: {},
- threadId,
- runId: "run-1",
- };
-
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Connect and get stored events
- const storedEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // No events should be stored
- expect(storedEvents).toHaveLength(0);
- });
-
- it("should store and compact text message events", async () => {
- const threadId = "test-thread-compact";
-
- const events: BaseEvent[] = [
+ describe("RunStarted payload", () => {
+ it("emits RUN_STARTED before agent events", async () => {
+ const threadId = "in-memory-basic";
+ const agent = new TestAgent([
{
type: EventType.TEXT_MESSAGE_START,
messageId: "msg-1",
@@ -102,382 +80,185 @@ describe("InMemoryAgentRunner", () => {
messageId: "msg-1",
delta: "Hello",
} as TextMessageContentEvent,
- {
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: "msg-1",
- delta: " world",
- } as TextMessageContentEvent,
{
type: EventType.TEXT_MESSAGE_END,
messageId: "msg-1",
} as TextMessageEndEvent,
- ];
-
- const agent = new TestAgent(events);
- const input: RunAgentInput = {
- messages: [],
- state: {},
- threadId,
- runId: "run-1",
- };
-
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Connect and get stored events
- const storedEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Should have start, single content (compacted), and end events
- expect(storedEvents).toHaveLength(3);
- expect(storedEvents[0].type).toBe(EventType.TEXT_MESSAGE_START);
- expect(storedEvents[1].type).toBe(EventType.TEXT_MESSAGE_CONTENT);
- expect((storedEvents[1] as TextMessageContentEvent).delta).toBe("Hello world");
- expect(storedEvents[2].type).toBe(EventType.TEXT_MESSAGE_END);
- });
-
- it("should not store duplicate message IDs across multiple runs", async () => {
- const threadId = "test-thread-no-duplicates";
- const userMessage: Message = {
- id: "user-msg-1",
- role: "user",
- content: "Hello",
- };
-
- // First run
- const agent1 = new TestAgent([
- {
- type: EventType.TEXT_MESSAGE_START,
- messageId: "assistant-msg-1",
- role: "assistant",
- } as TextMessageStartEvent,
- {
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: "assistant-msg-1",
- delta: "Hi from run 1",
- } as TextMessageContentEvent,
- {
- type: EventType.TEXT_MESSAGE_END,
- messageId: "assistant-msg-1",
- } as TextMessageEndEvent,
]);
- const input1: RunAgentInput = {
- messages: [userMessage],
- state: {},
- threadId,
- runId: "run-1",
- };
-
- await firstValueFrom(
- runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray())
+ const events = await firstValueFrom(
+ runner
+ .run({
+ threadId,
+ agent,
+ input: { threadId, runId: "run-1", messages: [], state: {} },
+ })
+ .pipe(toArray()),
);
- // Second run with same user message plus new one
- const newUserMessage: Message = {
- id: "user-msg-2",
- role: "user",
- content: "How are you?",
- };
-
- const agent2 = new TestAgent([
- {
- type: EventType.TEXT_MESSAGE_START,
- messageId: "assistant-msg-2",
- role: "assistant",
- } as TextMessageStartEvent,
- {
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: "assistant-msg-2",
- delta: "Hi from run 2",
- } as TextMessageContentEvent,
- {
- type: EventType.TEXT_MESSAGE_END,
- messageId: "assistant-msg-2",
- } as TextMessageEndEvent,
- ]);
-
- const input2: RunAgentInput = {
- messages: [userMessage, newUserMessage],
- state: {},
- threadId,
- runId: "run-2",
- };
-
- await firstValueFrom(
- runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray())
- );
-
- // Connect and get all stored events
- const storedEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Count unique message IDs
- const messageIds = new Set();
- for (const event of storedEvents) {
- if ('messageId' in event && event.messageId) {
- messageIds.add(event.messageId);
- }
- }
-
- // Should have: user-msg-1, assistant-msg-1, user-msg-2, assistant-msg-2
- expect(messageIds.size).toBe(4);
- expect(messageIds.has("user-msg-1")).toBe(true);
- expect(messageIds.has("assistant-msg-1")).toBe(true);
- expect(messageIds.has("user-msg-2")).toBe(true);
- expect(messageIds.has("assistant-msg-2")).toBe(true);
-
- // Check that each message ID appears only once in start events
- const startEvents = storedEvents.filter(e => e.type === EventType.TEXT_MESSAGE_START);
- const startMessageIds = startEvents.map(e => (e as any).messageId);
- const uniqueStartIds = new Set(startMessageIds);
- expect(startMessageIds.length).toBe(uniqueStartIds.size);
- });
-
- it("should store all types of new messages (user, assistant, tool, system, developer)", async () => {
- const threadId = "test-thread-all-messages";
-
- const messages: Message[] = [
- { id: "user-1", role: "user", content: "User message" },
- { id: "system-1", role: "system", content: "System message" },
- { id: "developer-1", role: "developer", content: "Developer message" },
- { id: "tool-1", role: "tool", content: "Tool result", toolCallId: "tool-call-1" },
- ];
-
- const agent = new TestAgent([
- {
- type: EventType.TEXT_MESSAGE_START,
- messageId: "assistant-1",
- role: "assistant",
- } as TextMessageStartEvent,
- {
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: "assistant-1",
- delta: "Assistant response",
- } as TextMessageContentEvent,
- {
- type: EventType.TEXT_MESSAGE_END,
- messageId: "assistant-1",
- } as TextMessageEndEvent,
- ]);
-
- const input: RunAgentInput = {
- messages,
- state: {},
- threadId,
- runId: "run-1",
- };
-
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Connect and get stored events
- const storedEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Collect all message IDs
- const messageIds = new Set();
- for (const event of storedEvents) {
- if ('messageId' in event && event.messageId) {
- messageIds.add(event.messageId);
- }
- }
-
- // Should have all message types
- expect(messageIds.has("user-1")).toBe(true);
- expect(messageIds.has("system-1")).toBe(true);
- expect(messageIds.has("developer-1")).toBe(true);
- expect(messageIds.has("tool-1")).toBe(true);
- expect(messageIds.has("assistant-1")).toBe(true);
-
- // Check tool result event
- const toolEvents = storedEvents.filter(e => e.type === EventType.TOOL_CALL_RESULT);
- expect(toolEvents).toHaveLength(1);
- const toolEvent = toolEvents[0] as ToolCallResultEvent;
- expect(toolEvent.messageId).toBe("tool-1");
- expect(toolEvent.content).toBe("Tool result");
- expect(toolEvent.toolCallId).toBe("tool-call-1");
+ expect(events).toHaveLength(4);
+ expect(events[0].type).toBe(EventType.RUN_STARTED);
+ const compacted = events.slice(1);
+ expect(compacted[0].type).toBe(EventType.TEXT_MESSAGE_START);
+ expect(compacted[1].type).toBe(EventType.TEXT_MESSAGE_CONTENT);
+ expect((compacted[1] as TextMessageContentEvent).delta).toBe("Hello");
+ expect(compacted[2].type).toBe(EventType.TEXT_MESSAGE_END);
});
- it("should only store new messages for each run", async () => {
- const threadId = "test-thread-only-new";
-
- // First run
- const message1: Message = { id: "msg-1", role: "user", content: "First" };
- const agent1 = new TestAgent([]);
- const input1: RunAgentInput = {
- messages: [message1],
- state: {},
- threadId,
- runId: "run-1",
- };
+ it("attaches only new messages to the RUN_STARTED input", async () => {
+ const threadId = "in-memory-new-messages";
+ const existing: Message = { id: "existing-msg", role: "user", content: "Hi" };
await firstValueFrom(
- runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray())
+ runner
+ .run({
+ threadId,
+ agent: new TestAgent(),
+ input: { threadId, runId: "run-0", messages: [existing], state: {} },
+ })
+ .pipe(toArray()),
);
- // Second run with old message and new message
- const message2: Message = { id: "msg-2", role: "user", content: "Second" };
- const agent2 = new TestAgent([]);
- const input2: RunAgentInput = {
- messages: [message1, message2], // Include old message for context
- state: {},
- threadId,
- runId: "run-2",
- };
-
- await firstValueFrom(
- runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray())
+ const newMessage: Message = { id: "new-msg", role: "user", content: "Follow up" };
+
+ const secondRun = await firstValueFrom(
+ runner
+ .run({
+ threadId,
+ agent: new TestAgent(),
+ input: {
+ threadId,
+ runId: "run-1",
+ messages: [existing, newMessage],
+ state: { counter: 1 },
+ },
+ })
+ .pipe(toArray()),
);
- // Third run with all old messages and one new
- const message3: Message = { id: "msg-3", role: "user", content: "Third" };
- const agent3 = new TestAgent([]);
- const input3: RunAgentInput = {
- messages: [message1, message2, message3],
- state: {},
- threadId,
- runId: "run-3",
- };
+ const runStarted = secondRun[0] as RunStartedEvent;
+ expect(runStarted.input?.messages?.map((m) => m.id)).toEqual(["new-msg"]);
+ expect(runStarted.input?.state).toEqual({ counter: 1 });
- await firstValueFrom(
- runner.run({ threadId, agent: agent3, input: input3 }).pipe(toArray())
+ const connectEvents = await firstValueFrom(
+ runner.connect({ threadId }).pipe(toArray()),
);
-
- // Connect and verify each message appears only once
- const storedEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Count start events for each message
- const startEvents = storedEvents.filter(e => e.type === EventType.TEXT_MESSAGE_START);
- const messageIdCounts = new Map();
-
- for (const event of startEvents) {
- const messageId = (event as any).messageId;
- messageIdCounts.set(messageId, (messageIdCounts.get(messageId) || 0) + 1);
- }
-
- // Each message should appear exactly once
- expect(messageIdCounts.get("msg-1")).toBe(1);
- expect(messageIdCounts.get("msg-2")).toBe(1);
- expect(messageIdCounts.get("msg-3")).toBe(1);
+ const latestRunStarted = connectEvents
+ .filter((event): event is RunStartedEvent => event.type === EventType.RUN_STARTED)
+ .pop();
+ expect(latestRunStarted?.input?.messages?.map((m) => m.id)).toEqual(["new-msg"]);
});
- it("should handle tool messages correctly", async () => {
- const threadId = "test-thread-tool-messages";
-
- const toolMessage: Message = {
- id: "tool-msg-1",
- role: "tool",
- content: "Tool execution result",
- toolCallId: "tool-call-123",
- };
-
- const agent = new TestAgent([]);
- const input: RunAgentInput = {
- messages: [toolMessage],
- state: {},
+ it("preserves agent-provided RUN_STARTED input", async () => {
+ const threadId = "in-memory-agent-input";
+ const providedInput: RunAgentInput = {
threadId,
- runId: "run-1",
+ runId: "run-preserve",
+ messages: [],
+ state: { fromAgent: true },
};
- await firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
+ const agent = new TestAgent(
+ [
+ {
+ type: EventType.RUN_STARTED,
+ threadId,
+ runId: "run-preserve",
+ input: providedInput,
+ } as RunStartedEvent,
+ ],
+ false,
);
- // Connect and get stored events
- const storedEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
+ const events = await firstValueFrom(
+ runner
+ .run({
+ threadId,
+ agent,
+ input: {
+ threadId,
+ runId: "run-preserve",
+ messages: [{ id: "extra", role: "user", content: "hi" }],
+ state: {},
+ },
+ })
+ .pipe(toArray()),
);
- // Should have the tool result event
- const toolEvents = storedEvents.filter(e => e.type === EventType.TOOL_CALL_RESULT);
- expect(toolEvents).toHaveLength(1);
-
- const toolEvent = toolEvents[0] as ToolCallResultEvent;
- expect(toolEvent.messageId).toBe("tool-msg-1");
- expect(toolEvent.toolCallId).toBe("tool-call-123");
- expect(toolEvent.content).toBe("Tool execution result");
- expect(toolEvent.role).toBe("tool");
+ expect(events).toHaveLength(1);
+ const runStarted = events[0] as RunStartedEvent;
+ expect(runStarted.input).toBe(providedInput);
});
});
- describe("Run Isolation", () => {
- it("should store each run's events separately", async () => {
- const threadId = "test-thread-isolation";
-
- // First run
- const agent1 = new TestAgent([
+ describe("Event propagation", () => {
+ it("replays agent events for new connections", async () => {
+ const threadId = "in-memory-replay";
+ const agent = new TestAgent([
{
type: EventType.TEXT_MESSAGE_START,
- messageId: "run1-msg",
+ messageId: "msg-1",
role: "assistant",
} as TextMessageStartEvent,
{
type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: "run1-msg",
- delta: "From run 1",
+ messageId: "msg-1",
+ delta: "Hello",
} as TextMessageContentEvent,
{
type: EventType.TEXT_MESSAGE_END,
- messageId: "run1-msg",
+ messageId: "msg-1",
} as TextMessageEndEvent,
]);
await firstValueFrom(
- runner.run({
- threadId,
- agent: agent1,
- input: { messages: [], state: {}, threadId, runId: "run-1" },
- }).pipe(toArray())
+ runner
+ .run({
+ threadId,
+ agent,
+ input: { threadId, runId: "run-1", messages: [], state: {} },
+ })
+ .pipe(toArray()),
);
- // Second run
- const agent2 = new TestAgent([
- {
- type: EventType.TEXT_MESSAGE_START,
- messageId: "run2-msg",
- role: "assistant",
- } as TextMessageStartEvent,
- {
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: "run2-msg",
- delta: "From run 2",
- } as TextMessageContentEvent,
- {
- type: EventType.TEXT_MESSAGE_END,
- messageId: "run2-msg",
- } as TextMessageEndEvent,
+ const connectEvents = await firstValueFrom(
+ runner.connect({ threadId }).pipe(toArray()),
+ );
+
+ expect(connectEvents).toHaveLength(4);
+ expect(connectEvents[0].type).toBe(EventType.RUN_STARTED);
+ expect(connectEvents.slice(1).map((event) => event.type)).toEqual([
+ EventType.TEXT_MESSAGE_START,
+ EventType.TEXT_MESSAGE_CONTENT,
+ EventType.TEXT_MESSAGE_END,
]);
+ });
- await firstValueFrom(
- runner.run({
- threadId,
- agent: agent2,
- input: { messages: [], state: {}, threadId, runId: "run-2" },
- }).pipe(toArray())
- );
+ it("keeps agent-generated tool results", async () => {
+ const threadId = "in-memory-tool-results";
+ const agent = new TestAgent([
+ {
+ type: EventType.TOOL_CALL_RESULT,
+ messageId: "tool-msg",
+ toolCallId: "tool-call",
+ content: "42",
+ role: "tool",
+ } as ToolCallResultEvent,
+ ]);
- // Connect and verify both runs' events are present
- const storedEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
+ const events = await firstValueFrom(
+ runner
+ .run({
+ threadId,
+ agent,
+ input: { threadId, runId: "run-1", messages: [], state: {} },
+ })
+ .pipe(toArray()),
);
- const messageIds = new Set();
- for (const event of storedEvents) {
- if ('messageId' in event && event.messageId) {
- messageIds.add(event.messageId);
- }
- }
-
- expect(messageIds.has("run1-msg")).toBe(true);
- expect(messageIds.has("run2-msg")).toBe(true);
+ expect(events).toHaveLength(2);
+ const [, toolResult] = events;
+ expect(toolResult.type).toBe(EventType.TOOL_CALL_RESULT);
});
});
-});
\ No newline at end of file
+});
diff --git a/packages/runtime/src/runner/__tests__/sqlite-runner.test.ts b/packages/runtime/src/runner/__tests__/sqlite-runner.test.ts
deleted file mode 100644
index 46e2fd26..00000000
--- a/packages/runtime/src/runner/__tests__/sqlite-runner.test.ts
+++ /dev/null
@@ -1,975 +0,0 @@
-import { describe, it, expect, beforeEach, afterEach } from "vitest";
-import { SqliteAgentRunner } from "../sqlite";
-import { InMemoryAgentRunner } from "../in-memory";
-import { AbstractAgent, BaseEvent, RunAgentInput, EventType } from "@ag-ui/client";
-import { firstValueFrom } from "rxjs";
-import { toArray } from "rxjs/operators";
-import Database from "better-sqlite3";
-import * as fs from "fs";
-import * as path from "path";
-import * as os from "os";
-
-// Mock agent for testing
-class MockAgent extends AbstractAgent {
- private events: BaseEvent[];
-
- constructor(events: BaseEvent[] = []) {
- super();
- this.events = events;
- }
-
- async runAgent(
- input: RunAgentInput,
- options: {
- onEvent: (event: { event: BaseEvent }) => void;
- onNewMessage?: (args: { message: any }) => void;
- onRunStartedEvent?: () => void;
- }
- ): Promise {
- // Call onRunStartedEvent if provided
- if (options.onRunStartedEvent) {
- options.onRunStartedEvent();
- }
-
- // Emit all events
- for (const event of this.events) {
- options.onEvent({ event });
- }
- }
-
- clone(): AbstractAgent {
- return new MockAgent(this.events);
- }
-}
-
-describe("SqliteAgentRunner", () => {
- let tempDir: string;
- let dbPath: string;
- let runner: SqliteAgentRunner;
-
- beforeEach(() => {
- // Create a temporary directory for test database
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "sqlite-test-"));
- dbPath = path.join(tempDir, "test.db");
- runner = new SqliteAgentRunner({ dbPath });
- });
-
- afterEach(() => {
- // Clean up test database
- if (fs.existsSync(dbPath)) {
- fs.unlinkSync(dbPath);
- }
- if (fs.existsSync(tempDir)) {
- fs.rmdirSync(tempDir);
- }
- });
-
- describe("Basic functionality", () => {
- it("should run an agent and emit events", async () => {
- const threadId = "test-thread-1";
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Hello" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const agent = new MockAgent(events);
- const input: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- const runObservable = runner.run({ threadId, agent, input });
- const emittedEvents = await firstValueFrom(runObservable.pipe(toArray()));
-
- expect(emittedEvents).toHaveLength(3);
- expect(emittedEvents[0].type).toBe(EventType.TEXT_MESSAGE_START);
- });
-
- it("should persist events across runner instances", async () => {
- const threadId = "test-thread-persistence";
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Persisted" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const agent = new MockAgent(events);
- const input: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- // Run with first instance
- await firstValueFrom(runner.run({ threadId, agent, input }).pipe(toArray()));
-
- // Create new runner instance with same database
- const newRunner = new SqliteAgentRunner({ dbPath });
-
- // Connect should return persisted events
- const persistedEvents = await firstValueFrom(
- newRunner.connect({ threadId }).pipe(toArray())
- );
-
- expect(persistedEvents).toHaveLength(3);
- expect(persistedEvents[1].type).toBe(EventType.TEXT_MESSAGE_CONTENT);
- expect((persistedEvents[1] as any).delta).toBe("Persisted");
- });
-
- it("should handle concurrent connections", async () => {
- const threadId = "test-thread-concurrent";
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Test" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const agent = new MockAgent(events);
- const input: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- // Run the agent
- await firstValueFrom(runner.run({ threadId, agent, input }).pipe(toArray()));
-
- // Create multiple concurrent connections
- const connection1 = runner.connect({ threadId });
- const connection2 = runner.connect({ threadId });
- const connection3 = runner.connect({ threadId });
-
- const [events1, events2, events3] = await Promise.all([
- firstValueFrom(connection1.pipe(toArray())),
- firstValueFrom(connection2.pipe(toArray())),
- firstValueFrom(connection3.pipe(toArray())),
- ]);
-
- // All connections should receive the same events
- expect(events1).toHaveLength(3);
- expect(events2).toHaveLength(3);
- expect(events3).toHaveLength(3);
- expect(events1).toEqual(events2);
- expect(events2).toEqual(events3);
- });
-
- it("should track running state correctly", async () => {
- const threadId = "test-thread-running";
- const agent = new MockAgent([]);
- const input: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- // Initially not running
- expect(await runner.isRunning({ threadId })).toBe(false);
-
- // Start running
- const runPromise = firstValueFrom(
- runner.run({ threadId, agent, input }).pipe(toArray())
- );
-
- // Should be running now
- expect(await runner.isRunning({ threadId })).toBe(true);
-
- // Wait for completion
- await runPromise;
-
- // Should not be running after completion
- expect(await runner.isRunning({ threadId })).toBe(false);
- });
-
- it("should prevent concurrent runs on same thread", async () => {
- const threadId = "test-thread-no-concurrent";
- const agent = new MockAgent([]);
- const input: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- // Start first run (don't await)
- runner.run({ threadId, agent, input }).subscribe();
-
- // Try to start second run immediately
- expect(() => {
- runner.run({ threadId, agent, input: { ...input, runId: "run2" } });
- }).toThrow("Thread already running");
- });
- });
-
- describe("Event compaction", () => {
- it("should store compacted events in the database", async () => {
- const threadId = "test-thread-compaction";
-
- // Create events that should be compacted
- const events1: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Hello " },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "world" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const agent1 = new MockAgent(events1);
- const input1: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- // Run first agent
- await firstValueFrom(runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray()));
-
- // Add more events - each run stores only its own events
- const events2: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg2", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "Second " },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "message" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg2" },
- ];
-
- const agent2 = new MockAgent(events2);
- const input2: RunAgentInput = {
- threadId,
- runId: "run2",
- messages: [],
- };
-
- // Run second agent
- await firstValueFrom(runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray()));
-
- // Check database directly to verify compaction
- const db = new Database(dbPath);
- const rows = db.prepare("SELECT events FROM agent_runs WHERE thread_id = ?").all(threadId) as any[];
- db.close();
-
- // Parse events from both runs
- const run1Events = JSON.parse(rows[0].events);
- const run2Events = JSON.parse(rows[1].events);
-
- // First run should have only its own compacted events
- // We expect: START, single CONTENT with "Hello world", END
- expect(run1Events).toHaveLength(3);
- const contentEvents1 = run1Events.filter((e: any) => e.type === EventType.TEXT_MESSAGE_CONTENT);
- expect(contentEvents1).toHaveLength(1);
- expect(contentEvents1[0].delta).toBe("Hello world");
- expect(run1Events[0].messageId).toBe("msg1");
-
- // Second run should have only its own compacted events
- expect(run2Events).toHaveLength(3);
- const contentEvents2 = run2Events.filter((e: any) => e.type === EventType.TEXT_MESSAGE_CONTENT);
- expect(contentEvents2).toHaveLength(1);
- expect(contentEvents2[0].delta).toBe("Second message");
- expect(run2Events[0].messageId).toBe("msg2");
-
- // Verify runs have different message IDs (no cross-contamination)
- const run1MessageIds = new Set(run1Events.filter((e: any) => e.messageId).map((e: any) => e.messageId));
- const run2MessageIds = new Set(run2Events.filter((e: any) => e.messageId).map((e: any) => e.messageId));
-
- // Ensure no overlap between message IDs in different runs
- for (const id of run1MessageIds) {
- expect(run2MessageIds.has(id)).toBe(false);
- }
- });
-
- it("should never store empty events after text message compaction", async () => {
- const threadId = "test-thread-text-compaction-not-empty";
-
- // First run: multiple text content events that will be compacted
- const events1: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "user" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "H" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "e" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "l" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "l" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "o" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const agent1 = new MockAgent(events1);
- const input1: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray()));
-
- // Second run: more text content events
- const events2: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg2", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "W" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "o" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "r" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "l" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "d" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg2" },
- ];
-
- const agent2 = new MockAgent(events2);
- const input2: RunAgentInput = {
- threadId,
- runId: "run2",
- messages: [],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray()));
-
- // Check database directly
- const db = new Database(dbPath);
- const rows = db.prepare("SELECT run_id, events FROM agent_runs WHERE thread_id = ? ORDER BY created_at").all(threadId) as any[];
- db.close();
-
- expect(rows).toHaveLength(2);
-
- // Both runs should have non-empty compacted events
- const run1Events = JSON.parse(rows[0].events);
- const run2Events = JSON.parse(rows[1].events);
-
- // Verify run1 events are not empty and properly compacted
- expect(run1Events).not.toHaveLength(0);
- expect(run1Events).toHaveLength(3); // START, compacted CONTENT, END
- expect(run1Events[0].type).toBe(EventType.TEXT_MESSAGE_START);
- expect(run1Events[1].type).toBe(EventType.TEXT_MESSAGE_CONTENT);
- expect(run1Events[1].delta).toBe("Hello"); // All characters concatenated
- expect(run1Events[2].type).toBe(EventType.TEXT_MESSAGE_END);
-
- // Verify run2 events are not empty and properly compacted
- expect(run2Events).not.toHaveLength(0);
- expect(run2Events).toHaveLength(3); // START, compacted CONTENT, END
- expect(run2Events[0].type).toBe(EventType.TEXT_MESSAGE_START);
- expect(run2Events[1].type).toBe(EventType.TEXT_MESSAGE_CONTENT);
- expect(run2Events[1].delta).toBe("World"); // All characters concatenated
- expect(run2Events[2].type).toBe(EventType.TEXT_MESSAGE_END);
- });
-
- it("should handle complex compaction scenarios with multiple message types", async () => {
- const threadId = "test-thread-complex-compaction";
-
- // First run: Mix of events including text messages and other events
- const events1: BaseEvent[] = [
- { type: EventType.RUN_STARTED, runId: "run1" },
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "user" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Part " },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "1" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- { type: EventType.RUN_FINISHED, runId: "run1" },
- ];
-
- const agent1 = new MockAgent(events1);
- const input1: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray()));
-
- // Second run: Another message that could potentially compact to empty
- const events2: BaseEvent[] = [
- { type: EventType.RUN_STARTED, runId: "run2" },
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg2", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "Part " },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "2" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg2" },
- { type: EventType.RUN_FINISHED, runId: "run2" },
- ];
-
- const agent2 = new MockAgent(events2);
- const input2: RunAgentInput = {
- threadId,
- runId: "run2",
- messages: [],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray()));
-
- // Third run: Test with already compacted previous events
- const events3: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg3", role: "user" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg3", delta: "Part " },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg3", delta: "3" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg3" },
- ];
-
- const agent3 = new MockAgent(events3);
- const input3: RunAgentInput = {
- threadId,
- runId: "run3",
- messages: [],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent3, input: input3 }).pipe(toArray()));
-
- // Check database directly
- const db = new Database(dbPath);
- const rows = db.prepare("SELECT run_id, events FROM agent_runs WHERE thread_id = ? ORDER BY created_at").all(threadId) as any[];
- db.close();
-
- expect(rows).toHaveLength(3);
-
- // All runs should have non-empty events
- for (let i = 0; i < rows.length; i++) {
- const events = JSON.parse(rows[i].events);
- expect(events).not.toHaveLength(0);
- expect(events.length).toBeGreaterThan(0);
-
- // Verify text messages are properly compacted
- const textContentEvents = events.filter((e: any) => e.type === EventType.TEXT_MESSAGE_CONTENT);
- textContentEvents.forEach((event: any) => {
- expect(event.delta).toBeTruthy();
- expect(event.delta).not.toBe("");
- });
- }
- });
-
- it("should retrieve already-compacted events without re-compacting", async () => {
- const threadId = "test-thread-no-recompact";
-
- // Create events that would be compacted
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Part 1 " },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Part 2 " },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Part 3" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const agent = new MockAgent(events);
- const input: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- // Run and store compacted events
- await firstValueFrom(runner.run({ threadId, agent, input }).pipe(toArray()));
-
- // Connect and retrieve events
- const retrievedEvents = await firstValueFrom(
- runner.connect({ threadId }).pipe(toArray())
- );
-
- // Should have compacted format: START, single CONTENT, END
- expect(retrievedEvents).toHaveLength(3);
- expect(retrievedEvents[0].type).toBe(EventType.TEXT_MESSAGE_START);
- expect(retrievedEvents[1].type).toBe(EventType.TEXT_MESSAGE_CONTENT);
- expect((retrievedEvents[1] as any).delta).toBe("Part 1 Part 2 Part 3");
- expect(retrievedEvents[2].type).toBe(EventType.TEXT_MESSAGE_END);
- });
-
- it("should handle edge case where new events are identical to compacted previous events", async () => {
- const threadId = "test-thread-identical-after-compaction";
-
- // First run: send a compacted-looking message
- const events1: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "user" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Hello World" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const agent1 = new MockAgent(events1);
- const input1: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray()));
-
- // Second run: send events that would compact to the same thing
- const events2: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg2", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "Hello " },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "World" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg2" },
- ];
-
- const agent2 = new MockAgent(events2);
- const input2: RunAgentInput = {
- threadId,
- runId: "run2",
- messages: [],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray()));
-
- // Check database directly
- const db = new Database(dbPath);
- const rows = db.prepare("SELECT run_id, events FROM agent_runs WHERE thread_id = ? ORDER BY created_at").all(threadId) as any[];
- db.close();
-
- expect(rows).toHaveLength(2);
-
- // Both runs should have events stored
- const run1Events = JSON.parse(rows[0].events);
- const run2Events = JSON.parse(rows[1].events);
-
- // Both should be non-empty
- expect(run1Events).not.toHaveLength(0);
- expect(run2Events).not.toHaveLength(0);
-
- // Both should have proper structure
- expect(run1Events).toHaveLength(3);
- expect(run2Events).toHaveLength(3);
-
- // Verify the content is correct
- expect(run1Events[1].delta).toBe("Hello World");
- expect(run2Events[1].delta).toBe("Hello World");
-
- // Messages should have different IDs
- expect(run1Events[0].messageId).toBe("msg1");
- expect(run2Events[0].messageId).toBe("msg2");
- });
- });
-
- describe("Comparison with InMemoryAgentRunner", () => {
- it("should behave identically to InMemoryAgentRunner for basic operations", async () => {
- const threadId = "test-thread-comparison";
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "user" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Test message" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const agent = new MockAgent(events);
- const input: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- // Run with SQLite runner
- const sqliteRunner = new SqliteAgentRunner({ dbPath });
- const sqliteRunEvents = await firstValueFrom(
- sqliteRunner.run({ threadId, agent: agent.clone(), input }).pipe(toArray())
- );
- const sqliteConnectEvents = await firstValueFrom(
- sqliteRunner.connect({ threadId }).pipe(toArray())
- );
-
- // Run with InMemory runner
- const memoryRunner = new InMemoryAgentRunner();
- const memoryRunEvents = await firstValueFrom(
- memoryRunner.run({ threadId, agent: agent.clone(), input }).pipe(toArray())
- );
- const memoryConnectEvents = await firstValueFrom(
- memoryRunner.connect({ threadId }).pipe(toArray())
- );
-
- // Both should emit the same events
- expect(sqliteRunEvents).toEqual(memoryRunEvents);
- expect(sqliteConnectEvents).toEqual(memoryConnectEvents);
- });
- });
-
- describe("Input message handling", () => {
- it("should store NEW input messages but NOT old ones", async () => {
- const threadId = "test-thread-input-storage";
-
- // First run: create some messages
- const events1: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "first-run-msg", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "first-run-msg", delta: "First run message" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "first-run-msg" },
- ];
-
- const agent1 = new MockAgent(events1);
- const input1: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray()));
-
- // Second run: pass OLD message and a NEW message as input
- const events2: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "second-run-msg", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "second-run-msg", delta: "Second run message" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "second-run-msg" },
- ];
-
- const agent2 = new MockAgent(events2);
- const input2: RunAgentInput = {
- threadId,
- runId: "run2",
- messages: [
- {
- id: "first-run-msg", // This is OLD - from run1, should NOT be stored again
- role: "assistant",
- content: "First run message"
- },
- {
- id: "new-user-msg", // This is NEW - should be stored in run2
- role: "user",
- content: "This is a NEW user message that SHOULD be stored in run2"
- }
- ],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray()));
-
- // Check database directly
- const db = new Database(dbPath);
- const rows = db.prepare("SELECT run_id, events FROM agent_runs WHERE thread_id = ? ORDER BY created_at").all(threadId) as any[];
- db.close();
-
- expect(rows).toHaveLength(2);
-
- // First run should only have its own message
- const run1Events = JSON.parse(rows[0].events);
- const run1MessageIds = run1Events.filter((e: any) => e.messageId).map((e: any) => e.messageId);
- expect(run1MessageIds).toContain("first-run-msg");
- expect(run1MessageIds).not.toContain("new-user-msg");
- expect(run1MessageIds).not.toContain("second-run-msg");
-
- // Second run should have the NEW user message and agent response, but NOT the old message
- const run2Events = JSON.parse(rows[1].events);
- const run2MessageIds = run2Events.filter((e: any) => e.messageId).map((e: any) => e.messageId);
- expect(run2MessageIds).toContain("second-run-msg"); // Agent's response
- expect(run2MessageIds).toContain("new-user-msg"); // NEW user message - SHOULD be stored
- expect(run2MessageIds).not.toContain("first-run-msg"); // OLD message - should NOT be stored again
-
- // Verify the second run has the right messages
- const uniqueRun2MessageIds = [...new Set(run2MessageIds)];
- expect(uniqueRun2MessageIds).toHaveLength(2); // Should have exactly 2 message IDs
- expect(uniqueRun2MessageIds).toContain("new-user-msg");
- expect(uniqueRun2MessageIds).toContain("second-run-msg");
- });
- });
-
- describe("Complete conversation flow", () => {
- it("should store ALL types of NEW messages including tool results", async () => {
- const threadId = "test-thread-all-message-types";
-
- // Run 1: User message with tool call and result
- const agent1 = new MockAgent([
- { type: EventType.TOOL_CALL_START, toolCallId: "tool-1", toolName: "calculator" },
- { type: EventType.TOOL_CALL_ARGS, toolCallId: "tool-1", delta: '{"a": 1, "b": 2}' },
- { type: EventType.TOOL_CALL_END, toolCallId: "tool-1" },
- ]);
-
- const input1: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [
- { id: "user-1", role: "user", content: "Calculate 1+2" },
- { id: "assistant-1", role: "assistant", content: "Let me calculate that", toolCalls: [
- { id: "tool-1", type: "function", function: { name: "calculator", arguments: JSON.stringify({ a: 1, b: 2 }) } }
- ]},
- { id: "tool-result-1", role: "tool", toolCallId: "tool-1", content: "3" }
- ],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray()));
-
- // Run 2: Add more messages including system and developer
- const agent2 = new MockAgent([
- { type: EventType.TEXT_MESSAGE_START, messageId: "assistant-2", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "assistant-2", delta: "The answer is 3" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "assistant-2" },
- ]);
-
- const input2: RunAgentInput = {
- threadId,
- runId: "run2",
- messages: [
- // Old messages from run 1
- { id: "user-1", role: "user", content: "Calculate 1+2" },
- { id: "assistant-1", role: "assistant", content: "Let me calculate that", toolCalls: [
- { id: "tool-1", type: "function", function: { name: "calculator", arguments: JSON.stringify({ a: 1, b: 2 }) } }
- ]},
- { id: "tool-result-1", role: "tool", toolCallId: "tool-1", content: "3" },
- // New messages for run 2
- { id: "system-1", role: "system", content: "Be concise" },
- { id: "developer-1", role: "developer", content: "Use simple language" },
- { id: "user-2", role: "user", content: "What was the result?" }
- ],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray()));
-
- // Check database
- const db = new Database(dbPath);
- const rows = db.prepare("SELECT run_id, events FROM agent_runs WHERE thread_id = ? ORDER BY created_at").all(threadId) as any[];
- db.close();
-
- expect(rows).toHaveLength(2);
-
- // Run 1 should have all the initial messages
- const run1Events = JSON.parse(rows[0].events);
- const run1MessageIds = [...new Set(run1Events.filter((e: any) => e.messageId).map((e: any) => e.messageId))];
- const run1ToolIds = [...new Set(run1Events.filter((e: any) => e.toolCallId).map((e: any) => e.toolCallId))];
-
- expect(run1MessageIds).toContain("user-1");
- expect(run1MessageIds).toContain("assistant-1");
- expect(run1ToolIds).toContain("tool-1"); // Tool events from both input and agent
-
- // Verify tool result event is stored
- const toolResultEvents = run1Events.filter((e: any) => e.type === EventType.TOOL_CALL_RESULT);
- expect(toolResultEvents).toHaveLength(1);
- expect(toolResultEvents[0].toolCallId).toBe("tool-1");
- expect(toolResultEvents[0].content).toBe("3");
-
- // Run 2 should have ONLY the new messages
- const run2Events = JSON.parse(rows[1].events);
- const run2MessageIds = [...new Set(run2Events.filter((e: any) => e.messageId).map((e: any) => e.messageId))];
-
- expect(run2MessageIds).toContain("system-1"); // NEW system message
- expect(run2MessageIds).toContain("developer-1"); // NEW developer message
- expect(run2MessageIds).toContain("user-2"); // NEW user message
- expect(run2MessageIds).toContain("assistant-2"); // NEW assistant response
-
- // Should NOT contain old messages
- expect(run2MessageIds).not.toContain("user-1");
- expect(run2MessageIds).not.toContain("assistant-1");
-
- // Should NOT contain old tool results
- const run2ToolResults = run2Events.filter((e: any) => e.type === EventType.TOOL_CALL_RESULT);
- expect(run2ToolResults.filter((e: any) => e.toolCallId === "tool-1")).toHaveLength(0);
-
- // Verify we captured all 4 new message types in run 2
- const run2EventTypes = new Set(run2Events.map((e: any) => e.type));
- expect(run2EventTypes.has(EventType.TEXT_MESSAGE_START)).toBe(true);
- expect(run2EventTypes.has(EventType.TEXT_MESSAGE_CONTENT)).toBe(true);
- expect(run2EventTypes.has(EventType.TEXT_MESSAGE_END)).toBe(true);
- });
-
- it("should correctly store a multi-turn conversation", async () => {
- const threadId = "test-thread-conversation";
-
- // Run 1: Initial user message and agent response
- const agent1 = new MockAgent([
- { type: EventType.TEXT_MESSAGE_START, messageId: "agent-1", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "agent-1", delta: "Hello! How can I help?" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "agent-1" },
- ]);
-
- const input1: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [
- { id: "user-1", role: "user", content: "Hi!" }
- ],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray()));
-
- // Run 2: Second user message and agent response
- const agent2 = new MockAgent([
- { type: EventType.TEXT_MESSAGE_START, messageId: "agent-2", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "agent-2", delta: "The weather is nice today!" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "agent-2" },
- ]);
-
- const input2: RunAgentInput = {
- threadId,
- runId: "run2",
- messages: [
- { id: "user-1", role: "user", content: "Hi!" },
- { id: "agent-1", role: "assistant", content: "Hello! How can I help?" },
- { id: "user-2", role: "user", content: "What's the weather?" }
- ],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray()));
-
- // Check database
- const db = new Database(dbPath);
- const rows = db.prepare("SELECT run_id, events FROM agent_runs WHERE thread_id = ? ORDER BY created_at").all(threadId) as any[];
- db.close();
-
- expect(rows).toHaveLength(2);
-
- // Run 1 should have user-1 and agent-1
- const run1Events = JSON.parse(rows[0].events);
- const run1MessageIds = [...new Set(run1Events.filter((e: any) => e.messageId).map((e: any) => e.messageId))];
- expect(run1MessageIds).toHaveLength(2);
- expect(run1MessageIds).toContain("user-1");
- expect(run1MessageIds).toContain("agent-1");
-
- // Run 2 should have ONLY user-2 and agent-2 (not the old messages)
- const run2Events = JSON.parse(rows[1].events);
- const run2MessageIds = [...new Set(run2Events.filter((e: any) => e.messageId).map((e: any) => e.messageId))];
- expect(run2MessageIds).toHaveLength(2);
- expect(run2MessageIds).toContain("user-2");
- expect(run2MessageIds).toContain("agent-2");
- expect(run2MessageIds).not.toContain("user-1");
- expect(run2MessageIds).not.toContain("agent-1");
- });
- });
-
- describe("Database integrity", () => {
- it("should create all required tables", () => {
- const db = new Database(dbPath);
-
- // Check agent_runs table exists
- const agentRunsTable = db.prepare(
- "SELECT name FROM sqlite_master WHERE type='table' AND name='agent_runs'"
- ).get();
- expect(agentRunsTable).toBeDefined();
-
- // Check run_state table exists
- const runStateTable = db.prepare(
- "SELECT name FROM sqlite_master WHERE type='table' AND name='run_state'"
- ).get();
- expect(runStateTable).toBeDefined();
-
- // Check schema_version table exists
- const schemaVersionTable = db.prepare(
- "SELECT name FROM sqlite_master WHERE type='table' AND name='schema_version'"
- ).get();
- expect(schemaVersionTable).toBeDefined();
-
- db.close();
- });
-
- it("should handle database file creation", () => {
- // Database file should be created
- expect(fs.existsSync(dbPath)).toBe(true);
- });
-
- it("should never store empty events array", async () => {
- const threadId = "test-thread-no-empty";
-
- // Test with events that should be stored
- const events: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Test" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const agent = new MockAgent(events);
- const input: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- // Run the agent
- await firstValueFrom(runner.run({ threadId, agent, input }).pipe(toArray()));
-
- // Check database directly
- const db = new Database(dbPath);
- const rows = db.prepare("SELECT events FROM agent_runs WHERE thread_id = ?").all(threadId) as any[];
- db.close();
-
- // Should have one run
- expect(rows).toHaveLength(1);
-
- // Parse and check events are not empty
- const storedEvents = JSON.parse(rows[0].events);
- expect(storedEvents).not.toHaveLength(0);
- expect(storedEvents.length).toBeGreaterThan(0);
- expect(storedEvents).toEqual(expect.arrayContaining([
- expect.objectContaining({ type: EventType.TEXT_MESSAGE_START }),
- expect.objectContaining({ type: EventType.TEXT_MESSAGE_CONTENT }),
- expect.objectContaining({ type: EventType.TEXT_MESSAGE_END }),
- ]));
- });
-
- it("should store correct events after compaction on subsequent runs", async () => {
- const threadId = "test-thread-subsequent-runs";
-
- // First run with initial events
- const events1: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg1", role: "user" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg1", delta: "Hello" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg1" },
- ];
-
- const agent1 = new MockAgent(events1);
- const input1: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray()));
-
- // Second run with new events
- const events2: BaseEvent[] = [
- { type: EventType.TEXT_MESSAGE_START, messageId: "msg2", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg2", delta: "World" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "msg2" },
- ];
-
- const agent2 = new MockAgent(events2);
- const input2: RunAgentInput = {
- threadId,
- runId: "run2",
- messages: [],
- };
-
- await firstValueFrom(runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray()));
-
- // Check database directly
- const db = new Database(dbPath);
- const rows = db.prepare("SELECT run_id, events FROM agent_runs WHERE thread_id = ? ORDER BY created_at").all(threadId) as any[];
- db.close();
-
- // Should have two runs
- expect(rows).toHaveLength(2);
-
- // Both runs should have non-empty events
- const run1Events = JSON.parse(rows[0].events);
- const run2Events = JSON.parse(rows[1].events);
-
- expect(run1Events).not.toHaveLength(0);
- expect(run2Events).not.toHaveLength(0);
-
- // First run should have ONLY the first message events
- expect(run1Events).toEqual(expect.arrayContaining([
- expect.objectContaining({ messageId: "msg1" }),
- ]));
- expect(run1Events.every((e: any) => !e.messageId || e.messageId === "msg1")).toBe(true);
-
- // Second run should have ONLY the second message events
- expect(run2Events).toEqual(expect.arrayContaining([
- expect.objectContaining({ messageId: "msg2" }),
- ]));
- expect(run2Events.every((e: any) => !e.messageId || e.messageId === "msg2")).toBe(true);
-
- // Verify no message duplication across runs
- const run1MessageIds = new Set(run1Events.filter((e: any) => e.messageId).map((e: any) => e.messageId));
- const run2MessageIds = new Set(run2Events.filter((e: any) => e.messageId).map((e: any) => e.messageId));
- const intersection = [...run1MessageIds].filter(id => run2MessageIds.has(id));
- expect(intersection).toHaveLength(0);
- });
-
- it("should handle edge case with no new events after compaction", async () => {
- const threadId = "test-thread-edge-case";
-
- // Run with duplicate events that might compact to nothing new
- const events: BaseEvent[] = [
- { type: EventType.RUN_STARTED, runId: "run1" },
- { type: EventType.RUN_FINISHED, runId: "run1" },
- ];
-
- const agent = new MockAgent(events);
- const input: RunAgentInput = {
- threadId,
- runId: "run1",
- messages: [],
- };
-
- await firstValueFrom(runner.run({ threadId, agent, input }).pipe(toArray()));
-
- // Check database
- const db = new Database(dbPath);
- const rows = db.prepare("SELECT events FROM agent_runs WHERE thread_id = ?").all(threadId) as any[];
- db.close();
-
- // Should have stored the run
- expect(rows).toHaveLength(1);
-
- // Events should be stored (even if they are minimal after compaction)
- const storedEvents = JSON.parse(rows[0].events);
- expect(Array.isArray(storedEvents)).toBe(true);
- });
- });
-});
\ No newline at end of file
diff --git a/packages/runtime/src/runner/enterprise.ts b/packages/runtime/src/runner/enterprise.ts
deleted file mode 100644
index b5b29b6d..00000000
--- a/packages/runtime/src/runner/enterprise.ts
+++ /dev/null
@@ -1,653 +0,0 @@
-import {
- AgentRunner,
- AgentRunnerConnectRequest,
- AgentRunnerIsRunningRequest,
- AgentRunnerRunRequest,
- type AgentRunnerStopRequest,
-} from "./agent-runner";
-import { Observable, ReplaySubject } from "rxjs";
-import {
- BaseEvent,
- RunAgentInput,
- Message,
- EventType,
- TextMessageStartEvent,
- TextMessageContentEvent,
- TextMessageEndEvent,
- ToolCallStartEvent,
- ToolCallArgsEvent,
- ToolCallEndEvent,
- ToolCallResultEvent,
-} from "@ag-ui/client";
-import { compactEvents } from "./event-compaction";
-import { Kysely, Generated } from "kysely";
-import { Redis } from "ioredis";
-
-const SCHEMA_VERSION = 1;
-
-interface AgentDatabase {
- agent_runs: {
- id: Generated;
- thread_id: string;
- run_id: string;
- parent_run_id: string | null;
- events: string;
- input: string;
- created_at: number;
- version: number;
- };
-
- run_state: {
- thread_id: string;
- is_running: number;
- current_run_id: string | null;
- server_id: string | null;
- updated_at: number;
- };
-
- schema_version: {
- version: number;
- applied_at: number;
- };
-}
-
-interface AgentRunRecord {
- id: number;
- thread_id: string;
- run_id: string;
- parent_run_id: string | null;
- events: string;
- input: string;
- created_at: number;
- version: number;
-}
-
-const redisKeys = {
- stream: (threadId: string, runId: string) => `stream:${threadId}:${runId}`,
- active: (threadId: string) => `active:${threadId}`,
- lock: (threadId: string) => `lock:${threadId}`,
-};
-
-export interface EnterpriseAgentRunnerOptions {
- kysely: Kysely;
- redis: Redis;
- redisSub?: Redis;
- streamRetentionMs?: number;
- streamActiveTTLMs?: number;
- lockTTLMs?: number;
- serverId?: string;
-}
-
-export class EnterpriseAgentRunner extends AgentRunner {
- private db: Kysely;
- public redis: Redis;
- public redisSub: Redis;
- private serverId: string;
- private streamRetentionMs: number;
- private streamActiveTTLMs: number;
- private lockTTLMs: number;
-
- constructor(options: EnterpriseAgentRunnerOptions) {
- super();
- this.db = options.kysely;
- this.redis = options.redis;
- this.redisSub = options.redisSub || options.redis.duplicate();
- this.serverId = options.serverId || this.generateServerId();
- this.streamRetentionMs = options.streamRetentionMs ?? 3600000; // 1 hour
- this.streamActiveTTLMs = options.streamActiveTTLMs ?? 300000; // 5 minutes
- this.lockTTLMs = options.lockTTLMs ?? 300000; // 5 minutes
-
- this.initializeSchema();
- }
-
- run(request: AgentRunnerRunRequest): Observable {
- const runSubject = new ReplaySubject(Infinity);
-
- const executeRun = async () => {
- const { threadId, input, agent } = request;
- const runId = input.runId;
- const streamKey = redisKeys.stream(threadId, runId);
-
- // Check if thread already running (do this check synchronously for consistency with SQLite)
- // For now we'll just check after, but in production you might want a sync check
- const activeRunId = await this.redis.get(redisKeys.active(threadId));
- if (activeRunId) {
- throw new Error("Thread already running");
- }
-
- // Acquire distributed lock
- const lockAcquired = await this.redis.set(
- redisKeys.lock(threadId),
- this.serverId,
- 'PX', this.lockTTLMs,
- 'NX'
- );
-
- if (!lockAcquired) {
- throw new Error("Thread already running");
- }
-
- // Mark as active
- await this.redis.setex(
- redisKeys.active(threadId),
- Math.floor(this.lockTTLMs / 1000),
- runId
- );
-
- // Update database state
- await this.setRunState(threadId, true, runId);
-
- // Track events and message IDs
- const currentRunEvents: BaseEvent[] = [];
- const seenMessageIds = new Set();
-
- // Get historic message IDs
- const historicRuns = await this.getHistoricRuns(threadId);
- const historicMessageIds = new Set();
- for (const run of historicRuns) {
- const events = JSON.parse(run.events) as BaseEvent[];
- for (const event of events) {
- if ('messageId' in event && typeof event.messageId === 'string') {
- historicMessageIds.add(event.messageId);
- }
- }
- }
-
- const parentRunId = historicRuns[historicRuns.length - 1]?.run_id ?? null;
-
- try {
- await agent.runAgent(input, {
- onEvent: async ({ event }) => {
- // Emit to run() caller
- runSubject.next(event);
-
- // Collect for database
- currentRunEvents.push(event);
-
- // Stream to Redis for connect() subscribers
- await this.redis.xadd(
- streamKey,
- 'MAXLEN', '~', '10000',
- '*',
- 'type', event.type,
- 'data', JSON.stringify(event)
- );
-
- // Refresh TTL with sliding window during active writes
- await this.redis.pexpire(streamKey, this.streamActiveTTLMs);
-
- // Check for completion events
- if (event.type === EventType.RUN_FINISHED ||
- event.type === EventType.RUN_ERROR) {
- // Switch to retention TTL for late readers
- await this.redis.pexpire(streamKey, this.streamRetentionMs);
- }
- },
-
- onNewMessage: ({ message }) => {
- if (!seenMessageIds.has(message.id)) {
- seenMessageIds.add(message.id);
- }
- },
-
- onRunStartedEvent: async () => {
- // Process input messages
- if (input.messages) {
- for (const message of input.messages) {
- if (!seenMessageIds.has(message.id)) {
- seenMessageIds.add(message.id);
- const events = this.convertMessageToEvents(message);
- const isNewMessage = !historicMessageIds.has(message.id);
-
- for (const event of events) {
- // Stream to Redis for context
- await this.redis.xadd(
- streamKey,
- 'MAXLEN', '~', '10000',
- '*',
- 'type', event.type,
- 'data', JSON.stringify(event)
- );
-
- if (isNewMessage) {
- currentRunEvents.push(event);
- }
- }
- }
- }
- }
-
- // Refresh TTL
- await this.redis.pexpire(streamKey, this.streamActiveTTLMs);
- },
- });
-
- // Store to database
- const compactedEvents = compactEvents(currentRunEvents);
- await this.storeRun(threadId, runId, compactedEvents, input, parentRunId);
-
- } finally {
- // Clean up (even on error)
- await this.setRunState(threadId, false);
- await this.redis.del(redisKeys.active(threadId));
- await this.redis.del(redisKeys.lock(threadId));
-
- // Ensure stream has retention TTL for late readers
- const exists = await this.redis.exists(streamKey);
- if (exists) {
- await this.redis.pexpire(streamKey, this.streamRetentionMs);
- }
-
- runSubject.complete();
- }
- };
-
- executeRun().catch((error) => {
- runSubject.error(error);
- });
-
- return runSubject.asObservable();
- }
-
- connect(request: AgentRunnerConnectRequest): Observable {
- const connectionSubject = new ReplaySubject(Infinity);
-
- const streamConnection = async () => {
- const { threadId } = request;
-
- // Load and emit historic runs from database
- const historicRuns = await this.getHistoricRuns(threadId);
- const allHistoricEvents: BaseEvent[] = [];
-
- for (const run of historicRuns) {
- const events = JSON.parse(run.events) as BaseEvent[];
- allHistoricEvents.push(...events);
- }
-
- // Compact and emit historic events
- const compactedEvents = compactEvents(allHistoricEvents);
- const emittedMessageIds = new Set();
-
- for (const event of compactedEvents) {
- connectionSubject.next(event);
- if ('messageId' in event && typeof event.messageId === 'string') {
- emittedMessageIds.add(event.messageId);
- }
- }
-
- // Check for active run
- const activeRunId = await this.redis.get(redisKeys.active(threadId));
-
- if (activeRunId) {
- // Tail the run-specific Redis stream
- const streamKey = redisKeys.stream(threadId, activeRunId);
- let lastId = '0-0';
- let consecutiveEmptyReads = 0;
-
- while (true) {
- try {
- // Read with blocking using call method for better compatibility
- const result = await this.redis.call(
- 'XREAD',
- 'BLOCK', '5000',
- 'COUNT', '100',
- 'STREAMS', streamKey, lastId
- ) as [string, [string, string[]][]][] | null;
-
- if (!result || result.length === 0) {
- consecutiveEmptyReads++;
-
- // Check if stream still exists
- const exists = await this.redis.exists(streamKey);
- if (!exists) {
- // Stream expired, we're done
- break;
- }
-
- // Check if thread still active
- const stillActive = await this.redis.get(redisKeys.active(threadId));
- if (stillActive !== activeRunId) {
- // Different run started or thread stopped
- break;
- }
-
- // After multiple empty reads, assume completion
- if (consecutiveEmptyReads > 3) {
- break;
- }
-
- continue;
- }
-
- consecutiveEmptyReads = 0;
- const [, messages] = result[0] || [null, []];
-
- for (const [id, fields] of messages || []) {
- lastId = id;
-
- // Extract event data (fields is array: [key, value, key, value, ...])
- let eventData: string | null = null;
- let eventType: string | null = null;
-
- for (let i = 0; i < fields.length; i += 2) {
- if (fields[i] === 'data') {
- eventData = fields[i + 1] ?? null;
- } else if (fields[i] === 'type') {
- eventType = fields[i + 1] ?? null;
- }
- }
-
- if (eventData) {
- const event = JSON.parse(eventData) as BaseEvent;
-
- // Skip already emitted messages
- if ('messageId' in event &&
- typeof event.messageId === 'string' &&
- emittedMessageIds.has(event.messageId)) {
- continue;
- }
-
- connectionSubject.next(event);
-
- // Check for completion events
- if (eventType === EventType.RUN_FINISHED ||
- eventType === EventType.RUN_ERROR) {
- connectionSubject.complete();
- return;
- }
- }
- }
- } catch {
- // Redis error, complete the stream
- break;
- }
- }
- }
-
- connectionSubject.complete();
- };
-
- streamConnection().catch(() => connectionSubject.complete());
- return connectionSubject.asObservable();
- }
-
- async isRunning(request: AgentRunnerIsRunningRequest): Promise {
- const { threadId } = request;
-
- // Check Redis first for speed
- const activeRunId = await this.redis.get(redisKeys.active(threadId));
- if (activeRunId) return true;
-
- // Check lock
- const lockExists = await this.redis.exists(redisKeys.lock(threadId));
- if (lockExists) return true;
-
- // Fallback to database
- const state = await this.db
- .selectFrom('run_state')
- .where('thread_id', '=', threadId)
- .selectAll()
- .executeTakeFirst();
-
- return state?.is_running === 1;
- }
-
- async stop(request: AgentRunnerStopRequest): Promise {
- const { threadId } = request;
-
- // Get active run ID
- const activeRunId = await this.redis.get(redisKeys.active(threadId));
- if (!activeRunId) {
- return false;
- }
-
- // Add RUN_ERROR event to stream
- const streamKey = redisKeys.stream(threadId, activeRunId);
- await this.redis.xadd(
- streamKey,
- '*',
- 'type', EventType.RUN_ERROR,
- 'data', JSON.stringify({
- type: EventType.RUN_ERROR,
- error: 'Run stopped by user'
- })
- );
-
- // Set retention TTL
- await this.redis.pexpire(streamKey, this.streamRetentionMs);
-
- // Clean up
- await this.setRunState(threadId, false);
- await this.redis.del(redisKeys.active(threadId));
- await this.redis.del(redisKeys.lock(threadId));
-
- return true;
- }
-
- // Helper methods
- private convertMessageToEvents(message: Message): BaseEvent[] {
- const events: BaseEvent[] = [];
-
- if (
- (message.role === "assistant" ||
- message.role === "user" ||
- message.role === "developer" ||
- message.role === "system") &&
- message.content
- ) {
- const textStartEvent: TextMessageStartEvent = {
- type: EventType.TEXT_MESSAGE_START,
- messageId: message.id,
- role: message.role,
- };
- events.push(textStartEvent);
-
- const textContentEvent: TextMessageContentEvent = {
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: message.id,
- delta: message.content,
- };
- events.push(textContentEvent);
-
- const textEndEvent: TextMessageEndEvent = {
- type: EventType.TEXT_MESSAGE_END,
- messageId: message.id,
- };
- events.push(textEndEvent);
- }
-
- if (message.role === "assistant" && message.toolCalls) {
- for (const toolCall of message.toolCalls) {
- const toolStartEvent: ToolCallStartEvent = {
- type: EventType.TOOL_CALL_START,
- toolCallId: toolCall.id,
- toolCallName: toolCall.function.name,
- parentMessageId: message.id,
- };
- events.push(toolStartEvent);
-
- const toolArgsEvent: ToolCallArgsEvent = {
- type: EventType.TOOL_CALL_ARGS,
- toolCallId: toolCall.id,
- delta: toolCall.function.arguments,
- };
- events.push(toolArgsEvent);
-
- const toolEndEvent: ToolCallEndEvent = {
- type: EventType.TOOL_CALL_END,
- toolCallId: toolCall.id,
- };
- events.push(toolEndEvent);
- }
- }
-
- if (message.role === "tool" && message.toolCallId) {
- const toolResultEvent: ToolCallResultEvent = {
- type: EventType.TOOL_CALL_RESULT,
- messageId: message.id,
- toolCallId: message.toolCallId,
- content: message.content,
- role: "tool",
- };
- events.push(toolResultEvent);
- }
-
- return events;
- }
-
- private async initializeSchema(): Promise {
- try {
- // Create agent_runs table
- await this.db.schema
- .createTable('agent_runs')
- .ifNotExists()
- .addColumn('id', 'integer', (col) => col.primaryKey().autoIncrement())
- .addColumn('thread_id', 'text', (col) => col.notNull())
- .addColumn('run_id', 'text', (col) => col.notNull().unique())
- .addColumn('parent_run_id', 'text')
- .addColumn('events', 'text', (col) => col.notNull())
- .addColumn('input', 'text', (col) => col.notNull())
- .addColumn('created_at', 'integer', (col) => col.notNull())
- .addColumn('version', 'integer', (col) => col.notNull())
- .execute()
- .catch(() => {}); // Ignore if already exists
-
- // Create run_state table
- await this.db.schema
- .createTable('run_state')
- .ifNotExists()
- .addColumn('thread_id', 'text', (col) => col.primaryKey())
- .addColumn('is_running', 'integer', (col) => col.defaultTo(0))
- .addColumn('current_run_id', 'text')
- .addColumn('server_id', 'text')
- .addColumn('updated_at', 'integer', (col) => col.notNull())
- .execute()
- .catch(() => {}); // Ignore if already exists
-
- // Create schema_version table
- await this.db.schema
- .createTable('schema_version')
- .ifNotExists()
- .addColumn('version', 'integer', (col) => col.primaryKey())
- .addColumn('applied_at', 'integer', (col) => col.notNull())
- .execute()
- .catch(() => {}); // Ignore if already exists
-
- // Create indexes
- await this.db.schema
- .createIndex('idx_thread_id')
- .ifNotExists()
- .on('agent_runs')
- .column('thread_id')
- .execute()
- .catch(() => {});
-
- await this.db.schema
- .createIndex('idx_parent_run_id')
- .ifNotExists()
- .on('agent_runs')
- .column('parent_run_id')
- .execute()
- .catch(() => {});
-
- // Check and set schema version
- const currentVersion = await this.db
- .selectFrom('schema_version')
- .orderBy('version', 'desc')
- .limit(1)
- .selectAll()
- .executeTakeFirst();
-
- if (!currentVersion || currentVersion.version < SCHEMA_VERSION) {
- await this.db
- .insertInto('schema_version')
- .values({
- version: SCHEMA_VERSION,
- applied_at: Date.now()
- })
- .onConflict((oc) => oc
- .column('version')
- .doUpdateSet({ applied_at: Date.now() })
- )
- .execute();
- }
- } catch {
- // Schema initialization might fail if DB is closed, ignore
- }
- }
-
- private async storeRun(
- threadId: string,
- runId: string,
- events: BaseEvent[],
- input: RunAgentInput,
- parentRunId: string | null
- ): Promise {
- await this.db.insertInto('agent_runs')
- .values({
- thread_id: threadId,
- run_id: runId,
- parent_run_id: parentRunId,
- events: JSON.stringify(events),
- input: JSON.stringify(input),
- created_at: Date.now(),
- version: SCHEMA_VERSION
- })
- .execute();
- }
-
- private async getHistoricRuns(threadId: string): Promise {
- const rows = await this.db
- .selectFrom('agent_runs')
- .where('thread_id', '=', threadId)
- .orderBy('created_at', 'asc')
- .selectAll()
- .execute();
-
- return rows.map(row => ({
- id: Number(row.id),
- thread_id: row.thread_id,
- run_id: row.run_id,
- parent_run_id: row.parent_run_id,
- events: row.events,
- input: row.input,
- created_at: row.created_at,
- version: row.version
- }));
- }
-
- private async setRunState(
- threadId: string,
- isRunning: boolean,
- runId?: string
- ): Promise {
- await this.db.insertInto('run_state')
- .values({
- thread_id: threadId,
- is_running: isRunning ? 1 : 0,
- current_run_id: runId ?? null,
- server_id: this.serverId,
- updated_at: Date.now()
- })
- .onConflict((oc) => oc
- .column('thread_id')
- .doUpdateSet({
- is_running: isRunning ? 1 : 0,
- current_run_id: runId ?? null,
- server_id: this.serverId,
- updated_at: Date.now()
- })
- )
- .execute();
- }
-
- async close(): Promise {
- await this.db.destroy();
- this.redis.disconnect();
- this.redisSub.disconnect();
- }
-
- private generateServerId(): string {
- return `server-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
- }
-}
\ No newline at end of file
diff --git a/packages/runtime/src/runner/event-compaction.ts b/packages/runtime/src/runner/event-compaction.ts
deleted file mode 100644
index 082a293e..00000000
--- a/packages/runtime/src/runner/event-compaction.ts
+++ /dev/null
@@ -1,250 +0,0 @@
-import {
- BaseEvent,
- EventType,
- TextMessageStartEvent,
- TextMessageContentEvent,
- TextMessageEndEvent,
- ToolCallStartEvent,
- ToolCallArgsEvent,
- ToolCallEndEvent,
-} from "@ag-ui/client";
-
-/**
- * Compacts streaming events by consolidating multiple deltas into single events.
- * For text messages: multiple content deltas become one concatenated delta.
- * For tool calls: multiple args deltas become one concatenated delta.
- * Events between related streaming events are reordered to keep streaming events together.
- *
- * @param events - Array of events to compact
- * @returns Compacted array of events
- */
-export function compactEvents(events: BaseEvent[]): BaseEvent[] {
- const compacted: BaseEvent[] = [];
- const pendingTextMessages = new Map();
- const pendingToolCalls = new Map();
-
- for (const event of events) {
- // Handle text message streaming events
- if (event.type === EventType.TEXT_MESSAGE_START) {
- const startEvent = event as TextMessageStartEvent;
- const messageId = startEvent.messageId;
-
- if (!pendingTextMessages.has(messageId)) {
- pendingTextMessages.set(messageId, {
- contents: [],
- otherEvents: []
- });
- }
-
- const pending = pendingTextMessages.get(messageId)!;
- pending.start = startEvent;
- } else if (event.type === EventType.TEXT_MESSAGE_CONTENT) {
- const contentEvent = event as TextMessageContentEvent;
- const messageId = contentEvent.messageId;
-
- if (!pendingTextMessages.has(messageId)) {
- pendingTextMessages.set(messageId, {
- contents: [],
- otherEvents: []
- });
- }
-
- const pending = pendingTextMessages.get(messageId)!;
- pending.contents.push(contentEvent);
- } else if (event.type === EventType.TEXT_MESSAGE_END) {
- const endEvent = event as TextMessageEndEvent;
- const messageId = endEvent.messageId;
-
- if (!pendingTextMessages.has(messageId)) {
- pendingTextMessages.set(messageId, {
- contents: [],
- otherEvents: []
- });
- }
-
- const pending = pendingTextMessages.get(messageId)!;
- pending.end = endEvent;
-
- // Flush this message's events
- flushTextMessage(messageId, pending, compacted);
- pendingTextMessages.delete(messageId);
- } else if (event.type === EventType.TOOL_CALL_START) {
- const startEvent = event as ToolCallStartEvent;
- const toolCallId = startEvent.toolCallId;
-
- if (!pendingToolCalls.has(toolCallId)) {
- pendingToolCalls.set(toolCallId, {
- args: [],
- otherEvents: []
- });
- }
-
- const pending = pendingToolCalls.get(toolCallId)!;
- pending.start = startEvent;
- } else if (event.type === EventType.TOOL_CALL_ARGS) {
- const argsEvent = event as ToolCallArgsEvent;
- const toolCallId = argsEvent.toolCallId;
-
- if (!pendingToolCalls.has(toolCallId)) {
- pendingToolCalls.set(toolCallId, {
- args: [],
- otherEvents: []
- });
- }
-
- const pending = pendingToolCalls.get(toolCallId)!;
- pending.args.push(argsEvent);
- } else if (event.type === EventType.TOOL_CALL_END) {
- const endEvent = event as ToolCallEndEvent;
- const toolCallId = endEvent.toolCallId;
-
- if (!pendingToolCalls.has(toolCallId)) {
- pendingToolCalls.set(toolCallId, {
- args: [],
- otherEvents: []
- });
- }
-
- const pending = pendingToolCalls.get(toolCallId)!;
- pending.end = endEvent;
-
- // Flush this tool call's events
- flushToolCall(toolCallId, pending, compacted);
- pendingToolCalls.delete(toolCallId);
- } else {
- // For non-streaming events, check if we're in the middle of any streaming sequences
- let addedToBuffer = false;
-
- // Check text messages
- for (const [messageId, pending] of pendingTextMessages) {
- // If we have a start but no end yet, this event is "in between"
- if (pending.start && !pending.end) {
- pending.otherEvents.push(event);
- addedToBuffer = true;
- break;
- }
- }
-
- // Check tool calls if not already buffered
- if (!addedToBuffer) {
- for (const [toolCallId, pending] of pendingToolCalls) {
- // If we have a start but no end yet, this event is "in between"
- if (pending.start && !pending.end) {
- pending.otherEvents.push(event);
- addedToBuffer = true;
- break;
- }
- }
- }
-
- // If not in the middle of any streaming sequence, add directly to compacted
- if (!addedToBuffer) {
- compacted.push(event);
- }
- }
- }
-
- // Flush any remaining incomplete messages
- for (const [messageId, pending] of pendingTextMessages) {
- flushTextMessage(messageId, pending, compacted);
- }
-
- // Flush any remaining incomplete tool calls
- for (const [toolCallId, pending] of pendingToolCalls) {
- flushToolCall(toolCallId, pending, compacted);
- }
-
- return compacted;
-}
-
-function flushTextMessage(
- messageId: string,
- pending: {
- start?: TextMessageStartEvent;
- contents: TextMessageContentEvent[];
- end?: TextMessageEndEvent;
- otherEvents: BaseEvent[];
- },
- compacted: BaseEvent[]
-): void {
- // Add start event if present
- if (pending.start) {
- compacted.push(pending.start);
- }
-
- // Compact all content events into one
- if (pending.contents.length > 0) {
- const concatenatedDelta = pending.contents
- .map(c => c.delta)
- .join('');
-
- const compactedContent: TextMessageContentEvent = {
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: messageId,
- delta: concatenatedDelta,
- };
-
- compacted.push(compactedContent);
- }
-
- // Add end event if present
- if (pending.end) {
- compacted.push(pending.end);
- }
-
- // Add any events that were in between
- for (const otherEvent of pending.otherEvents) {
- compacted.push(otherEvent);
- }
-}
-
-function flushToolCall(
- toolCallId: string,
- pending: {
- start?: ToolCallStartEvent;
- args: ToolCallArgsEvent[];
- end?: ToolCallEndEvent;
- otherEvents: BaseEvent[];
- },
- compacted: BaseEvent[]
-): void {
- // Add start event if present
- if (pending.start) {
- compacted.push(pending.start);
- }
-
- // Compact all args events into one
- if (pending.args.length > 0) {
- const concatenatedArgs = pending.args
- .map(a => a.delta)
- .join('');
-
- const compactedArgs: ToolCallArgsEvent = {
- type: EventType.TOOL_CALL_ARGS,
- toolCallId: toolCallId,
- delta: concatenatedArgs,
- };
-
- compacted.push(compactedArgs);
- }
-
- // Add end event if present
- if (pending.end) {
- compacted.push(pending.end);
- }
-
- // Add any events that were in between
- for (const otherEvent of pending.otherEvents) {
- compacted.push(otherEvent);
- }
-}
\ No newline at end of file
diff --git a/packages/runtime/src/runner/in-memory.ts b/packages/runtime/src/runner/in-memory.ts
index a57baca5..6625bc1a 100644
--- a/packages/runtime/src/runner/in-memory.ts
+++ b/packages/runtime/src/runner/in-memory.ts
@@ -8,18 +8,11 @@ import {
import { Observable, ReplaySubject } from "rxjs";
import {
BaseEvent,
- Message,
EventType,
- TextMessageStartEvent,
- TextMessageContentEvent,
- TextMessageEndEvent,
- ToolCallStartEvent,
- ToolCallArgsEvent,
- ToolCallEndEvent,
- ToolCallResultEvent,
MessagesSnapshotEvent,
+ RunStartedEvent,
+ compactEvents,
} from "@ag-ui/client";
-import { compactEvents } from "./event-compaction";
interface HistoricRun {
threadId: string;
@@ -51,76 +44,6 @@ class InMemoryEventStore {
const GLOBAL_STORE = new Map();
export class InMemoryAgentRunner extends AgentRunner {
- private convertMessageToEvents(message: Message): BaseEvent[] {
- const events: BaseEvent[] = [];
-
- if (
- (message.role === "assistant" ||
- message.role === "user" ||
- message.role === "developer" ||
- message.role === "system") &&
- message.content
- ) {
- const textStartEvent: TextMessageStartEvent = {
- type: EventType.TEXT_MESSAGE_START,
- messageId: message.id,
- role: message.role,
- };
- events.push(textStartEvent);
-
- const textContentEvent: TextMessageContentEvent = {
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: message.id,
- delta: message.content,
- };
- events.push(textContentEvent);
-
- const textEndEvent: TextMessageEndEvent = {
- type: EventType.TEXT_MESSAGE_END,
- messageId: message.id,
- };
- events.push(textEndEvent);
- }
-
- if (message.role === "assistant" && message.toolCalls) {
- for (const toolCall of message.toolCalls) {
- const toolStartEvent: ToolCallStartEvent = {
- type: EventType.TOOL_CALL_START,
- toolCallId: toolCall.id,
- toolCallName: toolCall.function.name,
- parentMessageId: message.id,
- };
- events.push(toolStartEvent);
-
- const toolArgsEvent: ToolCallArgsEvent = {
- type: EventType.TOOL_CALL_ARGS,
- toolCallId: toolCall.id,
- delta: toolCall.function.arguments,
- };
- events.push(toolArgsEvent);
-
- const toolEndEvent: ToolCallEndEvent = {
- type: EventType.TOOL_CALL_END,
- toolCallId: toolCall.id,
- };
- events.push(toolEndEvent);
- }
- }
-
- if (message.role === "tool" && message.toolCallId) {
- const toolResultEvent: ToolCallResultEvent = {
- type: EventType.TOOL_CALL_RESULT,
- messageId: message.id,
- toolCallId: message.toolCallId,
- content: message.content,
- role: "tool",
- };
- events.push(toolResultEvent);
- }
-
- return events;
- }
-
run(request: AgentRunnerRunRequest): Observable {
let existingStore = GLOBAL_STORE.get(request.threadId);
if (!existingStore) {
@@ -146,6 +69,13 @@ export class InMemoryAgentRunner extends AgentRunner {
if ("messageId" in event && typeof event.messageId === "string") {
historicMessageIds.add(event.messageId);
}
+ if (event.type === EventType.RUN_STARTED) {
+ const runStarted = event as RunStartedEvent;
+ const messages = runStarted.input?.messages ?? [];
+ for (const message of messages) {
+ historicMessageIds.add(message.id);
+ }
+ }
}
}
@@ -168,9 +98,31 @@ export class InMemoryAgentRunner extends AgentRunner {
try {
await request.agent.runAgent(request.input, {
onEvent: ({ event }) => {
- runSubject.next(event); // For run() return - only agent events
- nextSubject.next(event); // For connect() / store - all events
- currentRunEvents.push(event); // Accumulate for storage
+ let processedEvent: BaseEvent = event;
+ if (event.type === EventType.RUN_STARTED) {
+ const runStartedEvent = event as RunStartedEvent;
+ if (!runStartedEvent.input) {
+ const sanitizedMessages = request.input.messages
+ ? request.input.messages.filter(
+ (message) => !historicMessageIds.has(message.id),
+ )
+ : undefined;
+ const updatedInput = {
+ ...request.input,
+ ...(sanitizedMessages !== undefined
+ ? { messages: sanitizedMessages }
+ : {}),
+ };
+ processedEvent = {
+ ...runStartedEvent,
+ input: updatedInput,
+ } as RunStartedEvent;
+ }
+ }
+
+ runSubject.next(processedEvent); // For run() return - only agent events
+ nextSubject.next(processedEvent); // For connect() / store - all events
+ currentRunEvents.push(processedEvent); // Accumulate for storage
},
onNewMessage: ({ message }) => {
// Called for each new message
@@ -179,25 +131,11 @@ export class InMemoryAgentRunner extends AgentRunner {
}
},
onRunStartedEvent: () => {
- // Process input messages (same logic as SQLite)
+ // Mark any messages from the input as seen so they aren't emitted twice
if (request.input.messages) {
for (const message of request.input.messages) {
if (!seenMessageIds.has(message.id)) {
seenMessageIds.add(message.id);
- const events = this.convertMessageToEvents(message);
-
- // Check if this message is NEW (not in historic runs)
- const isNewMessage = !historicMessageIds.has(message.id);
-
- for (const event of events) {
- // Always emit to stream for context
- nextSubject.next(event);
-
- // Store if this is a NEW message for this run
- if (isNewMessage) {
- currentRunEvents.push(event);
- }
- }
}
}
}
diff --git a/packages/shared/package.json b/packages/shared/package.json
index d9dec245..c08c6c02 100644
--- a/packages/shared/package.json
+++ b/packages/shared/package.json
@@ -1,6 +1,6 @@
{
"name": "@copilotkitnext/shared",
- "version": "0.0.15",
+ "version": "0.0.14",
"description": "Shared utilities and types for CopilotKit2",
"main": "dist/index.js",
"types": "dist/index.d.ts",
diff --git a/packages/sqlite-runner/eslint.config.mjs b/packages/sqlite-runner/eslint.config.mjs
new file mode 100644
index 00000000..daa75ba7
--- /dev/null
+++ b/packages/sqlite-runner/eslint.config.mjs
@@ -0,0 +1,3 @@
+import { config as baseConfig } from "@copilotkitnext/eslint-config/base";
+
+export default [...baseConfig];
diff --git a/packages/sqlite-runner/package.json b/packages/sqlite-runner/package.json
new file mode 100644
index 00000000..3898ad9e
--- /dev/null
+++ b/packages/sqlite-runner/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "@copilotkitnext/sqlite-runner",
+ "version": "0.0.14",
+ "description": "SQLite-backed agent runner for CopilotKit2",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "import": "./dist/index.mjs",
+ "require": "./dist/index.js"
+ }
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "scripts": {
+ "build": "tsup",
+ "prepublishOnly": "pnpm run build",
+ "dev": "tsup --watch",
+ "lint": "eslint . --max-warnings 0",
+ "check-types": "tsc --noEmit",
+ "clean": "rm -rf dist",
+ "test": "vitest run",
+ "test:watch": "vitest",
+ "test:coverage": "vitest run --coverage"
+ },
+ "devDependencies": {
+ "@copilotkitnext/eslint-config": "workspace:*",
+ "@copilotkitnext/typescript-config": "workspace:*",
+ "@types/better-sqlite3": "^7.6.13",
+ "@types/node": "^22.15.3",
+ "better-sqlite3": "^12.2.0",
+ "eslint": "^9.30.0",
+ "tsup": "^8.5.0",
+ "typescript": "5.8.2",
+ "vitest": "^3.0.5"
+ },
+ "dependencies": {
+ "@ag-ui/client": "0.0.40-alpha.6",
+ "@copilotkitnext/runtime": "workspace:*",
+ "rxjs": "7.8.1"
+ },
+ "peerDependencies": {
+ "better-sqlite3": "^12.2.0"
+ },
+ "peerDependenciesMeta": {
+ "better-sqlite3": {
+ "optional": true
+ }
+ },
+ "engines": {
+ "node": ">=18"
+ }
+}
diff --git a/packages/sqlite-runner/src/__tests__/sqlite-runner.e2e.test.ts b/packages/sqlite-runner/src/__tests__/sqlite-runner.e2e.test.ts
new file mode 100644
index 00000000..e968eef0
--- /dev/null
+++ b/packages/sqlite-runner/src/__tests__/sqlite-runner.e2e.test.ts
@@ -0,0 +1,765 @@
+import { describe, it, expect, afterEach } from "vitest";
+import { SqliteAgentRunner } from "..";
+import {
+ AbstractAgent,
+ BaseEvent,
+ EventType,
+ Message,
+ RunAgentInput,
+ RunErrorEvent,
+ RunFinishedEvent,
+ RunStartedEvent,
+} from "@ag-ui/client";
+import { EMPTY, Subscription, firstValueFrom, from } from "rxjs";
+import { toArray } from "rxjs/operators";
+
+type RunCallbacks = {
+ onEvent: (event: { event: BaseEvent }) => void;
+ onNewMessage?: (args: { message: Message }) => void;
+ onRunStartedEvent?: () => void;
+};
+
+const createdRunners: SqliteAgentRunner[] = [];
+
+afterEach(() => {
+ while (createdRunners.length > 0) {
+ const runner = createdRunners.pop();
+ runner?.close();
+ }
+});
+
+function createRunner(): SqliteAgentRunner {
+ const runner = new SqliteAgentRunner();
+ createdRunners.push(runner);
+ return runner;
+}
+
+interface EmitAgentOptions {
+ events?: BaseEvent[];
+ emitDefaultRunStarted?: boolean;
+ includeRunFinished?: boolean;
+ runFinishedEvent?: RunFinishedEvent;
+ afterEvent?: (args: { event: BaseEvent; index: number }) => void | Promise;
+}
+
+class EmitAgent extends AbstractAgent {
+ constructor(private readonly options: EmitAgentOptions = {}) {
+ super();
+ }
+
+ async runAgent(input: RunAgentInput, callbacks: RunCallbacks): Promise {
+ const {
+ emitDefaultRunStarted = true,
+ includeRunFinished = true,
+ runFinishedEvent,
+ afterEvent,
+ } = this.options;
+ const scriptedEvents = this.options.events ?? [];
+
+ let index = 0;
+ const emit = async (event: BaseEvent) => {
+ callbacks.onEvent({ event });
+ if (event.type === EventType.RUN_STARTED) {
+ callbacks.onRunStartedEvent?.();
+ }
+ await afterEvent?.({ event, index });
+ index += 1;
+ };
+
+ if (emitDefaultRunStarted) {
+ const runStarted: RunStartedEvent = {
+ type: EventType.RUN_STARTED,
+ threadId: input.threadId,
+ runId: input.runId,
+ parentRunId: input.parentRunId,
+ };
+ await emit(runStarted);
+ }
+
+ for (const event of scriptedEvents) {
+ await emit(event);
+ }
+
+ const hasRunFinishedEvent =
+ scriptedEvents.some((event) => event.type === EventType.RUN_FINISHED) ||
+ runFinishedEvent?.type === EventType.RUN_FINISHED;
+
+ if (includeRunFinished && !hasRunFinishedEvent) {
+ const finishEvent: RunFinishedEvent =
+ runFinishedEvent ?? {
+ type: EventType.RUN_FINISHED,
+ threadId: input.threadId,
+ runId: input.runId,
+ };
+ await emit(finishEvent);
+ }
+ }
+
+ clone(): AbstractAgent {
+ return new EmitAgent({
+ ...this.options,
+ events: this.options.events ? [...this.options.events] : undefined,
+ });
+ }
+
+ protected run(): ReturnType {
+ return EMPTY;
+ }
+
+ protected connect(): ReturnType {
+ return EMPTY;
+ }
+}
+
+class ReplayAgent extends AbstractAgent {
+ constructor(private readonly replayEvents: BaseEvent[], threadId: string) {
+ super({ threadId });
+ }
+
+ async runAgent(): Promise {
+ throw new Error("not used");
+ }
+
+ protected run(): ReturnType {
+ return EMPTY;
+ }
+
+ protected connect(): ReturnType {
+ return from(this.replayEvents);
+ }
+}
+
+class RunnerConnectAgent extends AbstractAgent {
+ constructor(private readonly runner: SqliteAgentRunner, threadId: string) {
+ super({ threadId });
+ }
+
+ async runAgent(): Promise {
+ throw new Error("not used");
+ }
+
+ protected run(): ReturnType {
+ return EMPTY;
+ }
+
+ protected connect(input: RunAgentInput): ReturnType {
+ return this.runner.connect({ threadId: input.threadId });
+ }
+}
+
+type Deferred = {
+ promise: Promise;
+ resolve: (value: T) => void;
+ reject: (reason?: unknown) => void;
+};
+
+function createDeferred(): Deferred {
+ let resolve!: (value: T) => void;
+ let reject!: (reason?: unknown) => void;
+ const promise = new Promise((res, rej) => {
+ resolve = res;
+ reject = rej;
+ });
+ return { promise, resolve, reject };
+}
+
+async function collectEvents(observable: ReturnType | ReturnType) {
+ return firstValueFrom(observable.pipe(toArray()));
+}
+
+function createRunInput({
+ threadId,
+ runId,
+ messages,
+ state,
+ parentRunId,
+}: {
+ threadId: string;
+ runId: string;
+ messages: Message[];
+ state?: Record;
+ parentRunId?: string | null;
+}): RunAgentInput {
+ return {
+ threadId,
+ runId,
+ parentRunId: parentRunId ?? undefined,
+ state: state ?? {},
+ messages,
+ tools: [],
+ context: [],
+ forwardedProps: undefined,
+ };
+}
+
+function expectRunStartedEvent(event: BaseEvent, expectedMessages: Message[]) {
+ expect(event.type).toBe(EventType.RUN_STARTED);
+ const runStarted = event as RunStartedEvent;
+ expect(runStarted.input?.messages).toEqual(expectedMessages);
+}
+
+function createTextMessageEvents({
+ messageId,
+ role = "assistant",
+ content,
+}: {
+ messageId: string;
+ role?: "assistant" | "developer" | "system" | "user";
+ content: string;
+}): BaseEvent[] {
+ return [
+ {
+ type: EventType.TEXT_MESSAGE_START,
+ messageId,
+ role,
+ },
+ {
+ type: EventType.TEXT_MESSAGE_CONTENT,
+ messageId,
+ delta: content,
+ },
+ {
+ type: EventType.TEXT_MESSAGE_END,
+ messageId,
+ },
+ ] as BaseEvent[];
+}
+
+function createToolCallEvents({
+ toolCallId,
+ parentMessageId,
+ toolName,
+ argsJson,
+ resultMessageId,
+ resultContent,
+}: {
+ toolCallId: string;
+ parentMessageId: string;
+ toolName: string;
+ argsJson: string;
+ resultMessageId: string;
+ resultContent: string;
+}): BaseEvent[] {
+ return [
+ {
+ type: EventType.TOOL_CALL_START,
+ toolCallId,
+ toolCallName: toolName,
+ parentMessageId,
+ },
+ {
+ type: EventType.TOOL_CALL_ARGS,
+ toolCallId,
+ delta: argsJson,
+ },
+ {
+ type: EventType.TOOL_CALL_END,
+ toolCallId,
+ },
+ {
+ type: EventType.TOOL_CALL_RESULT,
+ toolCallId,
+ messageId: resultMessageId,
+ content: resultContent,
+ role: "tool",
+ },
+ ] as BaseEvent[];
+}
+
+describe("SqliteAgentRunner e2e", () => {
+ describe("Fresh Replay After Single Run", () => {
+ it("replays sanitized message history on connectAgent", async () => {
+ const runner = createRunner();
+ const threadId = "thread-fresh-replay";
+ const existingMessage: Message = {
+ id: "message-existing",
+ role: "user",
+ content: "Hello there",
+ };
+
+ const runEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent(),
+ input: createRunInput({
+ threadId,
+ runId: "run-0",
+ messages: [existingMessage],
+ }),
+ }),
+ );
+
+ expectRunStartedEvent(runEvents[0], [existingMessage]);
+ expect(runEvents.at(-1)?.type).toBe(EventType.RUN_FINISHED);
+
+ const replayEvents = await collectEvents(runner.connect({ threadId }));
+ const replayAgent = new ReplayAgent(replayEvents, threadId);
+ await replayAgent.connectAgent({ runId: "replay-run" });
+
+ expect(replayAgent.messages).toEqual([existingMessage]);
+ });
+ });
+
+ describe("New Messages on Subsequent Runs", () => {
+ it("merges new message IDs without duplicating history", async () => {
+ const runner = createRunner();
+ const threadId = "thread-subsequent-runs";
+ const existingMessage: Message = {
+ id: "msg-existing",
+ role: "user",
+ content: "First turn",
+ };
+
+ const initialRunEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent(),
+ input: createRunInput({
+ threadId,
+ runId: "run-0",
+ messages: [existingMessage],
+ }),
+ }),
+ );
+ expectRunStartedEvent(initialRunEvents[0], [existingMessage]);
+
+ const newMessage: Message = {
+ id: "msg-new",
+ role: "user",
+ content: "Second turn",
+ };
+
+ const secondRunEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent(),
+ input: createRunInput({
+ threadId,
+ runId: "run-1",
+ messages: [existingMessage, newMessage],
+ }),
+ }),
+ );
+
+ expectRunStartedEvent(secondRunEvents[0], [newMessage]);
+
+ const replayEvents = await collectEvents(runner.connect({ threadId }));
+ const replayAgent = new ReplayAgent(replayEvents, threadId);
+ await replayAgent.connectAgent({ runId: "replay-run" });
+
+ expect(replayAgent.messages).toEqual([existingMessage, newMessage]);
+ expect(new Set(replayAgent.messages.map((message) => message.id)).size).toBe(
+ replayAgent.messages.length,
+ );
+ });
+ });
+
+ describe("Fresh Agent Connection After Prior Runs", () => {
+ it("hydrates a brand-new agent via connect()", async () => {
+ const runner = createRunner();
+ const threadId = "thread-new-agent-connection";
+ const existingMessage: Message = {
+ id: "existing-connection",
+ role: "user",
+ content: "Persist me",
+ };
+
+ const runEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent(),
+ input: createRunInput({
+ threadId,
+ runId: "run-0",
+ messages: [existingMessage],
+ }),
+ }),
+ );
+ expectRunStartedEvent(runEvents[0], [existingMessage]);
+
+ const connectingAgent = new RunnerConnectAgent(runner, threadId);
+ await connectingAgent.connectAgent({ runId: "connect-run" });
+
+ expect(connectingAgent.messages).toEqual([existingMessage]);
+ });
+ });
+
+ describe("Mixed Roles and Tool Results", () => {
+ it("preserves agent-emitted tool events alongside heterogeneous inputs", async () => {
+ const runner = createRunner();
+ const threadId = "thread-mixed-roles";
+
+ const systemMessage: Message = {
+ id: "sys-1",
+ role: "system",
+ content: "Global directive",
+ };
+ const developerMessage: Message = {
+ id: "dev-1",
+ role: "developer",
+ content: "Internal guidance",
+ };
+ const userMessage: Message = {
+ id: "user-1",
+ role: "user",
+ content: "Need the weather",
+ };
+ const baseMessages = [systemMessage, developerMessage, userMessage];
+
+ const assistantMessageId = "assistant-1";
+ const toolCallId = "tool-call-1";
+ const toolMessageId = "tool-msg-1";
+
+ const agentEvents: BaseEvent[] = [
+ ...createTextMessageEvents({
+ messageId: assistantMessageId,
+ content: "Calling the weather tool",
+ }),
+ ...createToolCallEvents({
+ toolCallId,
+ parentMessageId: assistantMessageId,
+ toolName: "getWeather",
+ argsJson: '{"location":"NYC"}',
+ resultMessageId: toolMessageId,
+ resultContent: '{"temp":72}',
+ }),
+ ];
+
+ const runEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent({ events: agentEvents }),
+ input: createRunInput({
+ threadId,
+ runId: "run-0",
+ messages: baseMessages,
+ }),
+ }),
+ );
+
+ expectRunStartedEvent(runEvents[0], baseMessages);
+ expect(runEvents.filter((event) => event.type === EventType.TOOL_CALL_RESULT)).toHaveLength(1);
+
+ const replayEvents = await collectEvents(runner.connect({ threadId }));
+ const replayAgent = new ReplayAgent(replayEvents, threadId);
+ await replayAgent.connectAgent({ runId: "replay-run" });
+
+ expect(replayAgent.messages).toEqual([
+ systemMessage,
+ developerMessage,
+ userMessage,
+ {
+ id: assistantMessageId,
+ role: "assistant",
+ content: "Calling the weather tool",
+ toolCalls: [
+ {
+ id: toolCallId,
+ type: "function",
+ function: {
+ name: "getWeather",
+ arguments: '{"location":"NYC"}',
+ },
+ },
+ ],
+ },
+ {
+ id: toolMessageId,
+ role: "tool",
+ content: '{"temp":72}',
+ toolCallId,
+ },
+ ]);
+ expect(replayAgent.messages.filter((message) => message.role === "tool")).toHaveLength(1);
+ });
+ });
+
+ describe("Multiple Consecutive Runs with Agent Output", () => {
+ it("deduplicates input history while emitting each agent message once", async () => {
+ const runner = createRunner();
+ const threadId = "thread-multi-runs";
+ const systemMessage: Message = {
+ id: "system-shared",
+ role: "system",
+ content: "System context",
+ };
+ const userMessages: Message[] = [];
+
+ for (let index = 0; index < 3; index += 1) {
+ const userMessage: Message = {
+ id: `user-${index + 1}`,
+ role: "user",
+ content: `User message ${index + 1}`,
+ };
+ userMessages.push(userMessage);
+
+ const messagesForRun = [systemMessage, ...userMessages];
+ const assistantId = `assistant-${index + 1}`;
+ const toolCallId = `tool-call-${index + 1}`;
+ const toolMessageId = `tool-msg-${index + 1}`;
+
+ const events: BaseEvent[] = [
+ ...createTextMessageEvents({
+ messageId: assistantId,
+ content: `Assistant reply ${index + 1}`,
+ }),
+ ...createToolCallEvents({
+ toolCallId,
+ parentMessageId: assistantId,
+ toolName: `tool-${index + 1}`,
+ argsJson: `{"step":${index + 1}}`,
+ resultMessageId: toolMessageId,
+ resultContent: `{"ok":${index + 1}}`,
+ }),
+ ];
+
+ const runEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent({ events }),
+ input: createRunInput({
+ threadId,
+ runId: `run-${index}`,
+ messages: messagesForRun,
+ }),
+ }),
+ );
+
+ if (index === 0) {
+ expectRunStartedEvent(runEvents[0], messagesForRun);
+ } else {
+ expectRunStartedEvent(runEvents[0], [userMessage]);
+ }
+ expect(runEvents.at(-1)?.type).toBe(EventType.RUN_FINISHED);
+ }
+
+ const replayEvents = await collectEvents(runner.connect({ threadId }));
+ const replayAgent = new ReplayAgent(replayEvents, threadId);
+ await replayAgent.connectAgent({ runId: "replay-final" });
+
+ const finalMessages = replayAgent.messages;
+ expect(new Set(finalMessages.map((message) => message.id)).size).toBe(finalMessages.length);
+ const roleCounts = finalMessages.reduce>((counts, message) => {
+ counts[message.role] = (counts[message.role] ?? 0) + 1;
+ return counts;
+ }, {});
+ expect(roleCounts.system).toBe(1);
+ expect(roleCounts.user).toBe(3);
+ expect(roleCounts.assistant).toBe(3);
+ expect(roleCounts.tool).toBe(3);
+ });
+ });
+
+ describe("Agent-Provided RUN_STARTED input", () => {
+ it("forwards the agent-specified payload without sanitizing", async () => {
+ const runner = createRunner();
+ const threadId = "thread-custom-run-started";
+ const runId = "run-0";
+
+ const customMessages: Message[] = [
+ {
+ id: "custom-user",
+ role: "user",
+ content: "Pre-sent content",
+ },
+ ];
+ const customInput: RunAgentInput = {
+ threadId,
+ runId,
+ parentRunId: undefined,
+ state: { injected: true },
+ messages: customMessages,
+ tools: [],
+ context: [],
+ forwardedProps: { source: "agent" },
+ };
+ const customRunStarted: RunStartedEvent = {
+ type: EventType.RUN_STARTED,
+ threadId,
+ runId,
+ parentRunId: null,
+ input: customInput,
+ };
+
+ const agentEvents: BaseEvent[] = [
+ customRunStarted,
+ ...createTextMessageEvents({
+ messageId: "agent-message",
+ content: "Custom start acknowledged",
+ }),
+ ];
+
+ const runEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent({
+ events: agentEvents,
+ emitDefaultRunStarted: false,
+ }),
+ input: createRunInput({
+ threadId,
+ runId,
+ messages: [],
+ }),
+ }),
+ );
+
+ expect(runEvents[0]).toEqual(customRunStarted);
+ expect(runEvents.filter((event) => event.type === EventType.RUN_FINISHED)).toHaveLength(1);
+
+ const replayEvents = await collectEvents(runner.connect({ threadId }));
+ const replayAgent = new ReplayAgent(replayEvents, threadId);
+ await replayAgent.connectAgent({ runId: "replay-run" });
+ expect(replayAgent.messages.find((message) => message.id === "custom-user")).toEqual(
+ customMessages[0],
+ );
+ });
+ });
+
+ describe("Concurrent Connections During Run", () => {
+ it("streams in-flight events to live subscribers and persists final history", async () => {
+ const runner = createRunner();
+ const threadId = "thread-concurrency";
+ const runId = "run-live";
+ const initialMessage: Message = {
+ id: "initial-user",
+ role: "user",
+ content: "Start run",
+ };
+
+ const runStartedSignal = createDeferred();
+ const resumeSignal = createDeferred();
+
+ const agent = new EmitAgent({
+ events: [
+ ...createTextMessageEvents({
+ messageId: "assistant-live",
+ content: "Streaming content",
+ }),
+ ],
+ afterEvent: async ({ event }) => {
+ if (event.type === EventType.RUN_STARTED) {
+ runStartedSignal.resolve();
+ await resumeSignal.promise;
+ }
+ },
+ });
+
+ const runEvents: BaseEvent[] = [];
+ const run$ = runner.run({
+ threadId,
+ agent,
+ input: createRunInput({
+ threadId,
+ runId,
+ messages: [initialMessage],
+ }),
+ });
+
+ let runSubscription: Subscription;
+ const runCompletion = new Promise((resolve, reject) => {
+ runSubscription = run$.subscribe({
+ next: (event) => runEvents.push(event),
+ error: (error) => {
+ runSubscription.unsubscribe();
+ reject(error);
+ },
+ complete: () => {
+ runSubscription.unsubscribe();
+ resolve();
+ },
+ });
+ });
+
+ await runStartedSignal.promise;
+
+ const liveEvents: BaseEvent[] = [];
+ const connect$ = runner.connect({ threadId });
+ let connectSubscription: Subscription;
+ const connectCompletion = new Promise((resolve, reject) => {
+ connectSubscription = connect$.subscribe({
+ next: (event) => liveEvents.push(event),
+ error: (error) => {
+ connectSubscription.unsubscribe();
+ reject(error);
+ },
+ complete: () => {
+ connectSubscription.unsubscribe();
+ resolve();
+ },
+ });
+ });
+
+ resumeSignal.resolve();
+
+ await Promise.all([runCompletion, connectCompletion]);
+
+ expectRunStartedEvent(runEvents[0], [initialMessage]);
+ expect(runEvents.at(-1)?.type).toBe(EventType.RUN_FINISHED);
+ expect(liveEvents).toEqual(runEvents);
+
+ const persistedEvents = await collectEvents(runner.connect({ threadId }));
+ expect(persistedEvents).toEqual(runEvents);
+
+ const replayAgent = new ReplayAgent(persistedEvents, threadId);
+ await replayAgent.connectAgent({ runId: "replay-run" });
+ expect(replayAgent.messages.map((message) => message.id)).toEqual([
+ initialMessage.id,
+ "assistant-live",
+ ]);
+ });
+ });
+
+ describe("Error Handling", () => {
+ it("propagates RUN_ERROR while retaining input history", async () => {
+ const runner = createRunner();
+ const threadId = "thread-run-error";
+ const userMessage: Message = {
+ id: "error-user",
+ role: "user",
+ content: "Trigger error",
+ };
+
+ const runErrorEvent: RunErrorEvent = {
+ type: EventType.RUN_ERROR,
+ message: "Agent failure",
+ };
+
+ const runEvents = await collectEvents(
+ runner.run({
+ threadId,
+ agent: new EmitAgent({
+ events: [runErrorEvent],
+ includeRunFinished: false,
+ }),
+ input: createRunInput({
+ threadId,
+ runId: "run-error",
+ messages: [userMessage],
+ }),
+ }),
+ );
+
+ expectRunStartedEvent(runEvents[0], [userMessage]);
+ expect(runEvents.at(-1)).toEqual(runErrorEvent);
+
+ const replayEvents = await collectEvents(runner.connect({ threadId }));
+ const replayAgent = new ReplayAgent(replayEvents, threadId);
+ const capturedRunErrors: RunErrorEvent[] = [];
+ const result = await replayAgent.connectAgent(
+ { runId: "replay-run" },
+ {
+ onRunErrorEvent: ({ event }) => {
+ capturedRunErrors.push(event);
+ },
+ },
+ );
+
+ expect(runEvents.at(-1)?.type).toBe(EventType.RUN_ERROR);
+ expect(capturedRunErrors).toHaveLength(1);
+ expect(capturedRunErrors[0]).toMatchObject(runErrorEvent);
+ expect(result.newMessages).toEqual([userMessage]);
+ expect(replayAgent.messages).toEqual([userMessage]);
+ });
+ });
+});
diff --git a/packages/sqlite-runner/src/__tests__/sqlite-runner.test.ts b/packages/sqlite-runner/src/__tests__/sqlite-runner.test.ts
new file mode 100644
index 00000000..dd2f60d6
--- /dev/null
+++ b/packages/sqlite-runner/src/__tests__/sqlite-runner.test.ts
@@ -0,0 +1,226 @@
+import { describe, it, expect, beforeEach, afterEach } from "vitest";
+import { SqliteAgentRunner } from "..";
+import {
+ AbstractAgent,
+ BaseEvent,
+ EventType,
+ Message,
+ RunAgentInput,
+ RunStartedEvent,
+ TextMessageContentEvent,
+ TextMessageEndEvent,
+ TextMessageStartEvent,
+} from "@ag-ui/client";
+import { EMPTY, firstValueFrom } from "rxjs";
+import { toArray } from "rxjs/operators";
+import Database from "better-sqlite3";
+import fs from "fs";
+import os from "os";
+import path from "path";
+
+type RunCallbacks = {
+ onEvent: (event: { event: BaseEvent }) => void | Promise;
+ onNewMessage?: (args: { message: Message }) => void | Promise;
+ onRunStartedEvent?: () => void | Promise;
+};
+
+class MockAgent extends AbstractAgent {
+ constructor(
+ private readonly events: BaseEvent[] = [],
+ private readonly emitDefaultRunStarted = true,
+ ) {
+ super();
+ }
+
+ async runAgent(input: RunAgentInput, callbacks: RunCallbacks): Promise {
+ if (this.emitDefaultRunStarted) {
+ const runStarted: RunStartedEvent = {
+ type: EventType.RUN_STARTED,
+ threadId: input.threadId,
+ runId: input.runId,
+ };
+ await callbacks.onEvent({ event: runStarted });
+ await callbacks.onRunStartedEvent?.();
+ }
+
+ for (const event of this.events) {
+ await callbacks.onEvent({ event });
+ }
+ }
+
+ protected run(): ReturnType {
+ return EMPTY;
+ }
+
+ protected connect(): ReturnType {
+ return EMPTY;
+ }
+
+ clone(): AbstractAgent {
+ return new MockAgent(this.events, this.emitDefaultRunStarted);
+ }
+}
+
+describe("SqliteAgentRunner", () => {
+ let tempDir: string;
+ let dbPath: string;
+ let runner: SqliteAgentRunner;
+
+ beforeEach(() => {
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "sqlite-runner-test-"));
+ dbPath = path.join(tempDir, "test.db");
+ runner = new SqliteAgentRunner({ dbPath });
+ });
+
+ afterEach(() => {
+ if (fs.existsSync(dbPath)) fs.unlinkSync(dbPath);
+ if (fs.existsSync(tempDir)) fs.rmdirSync(tempDir);
+ });
+
+ it("emits RUN_STARTED and agent events", async () => {
+ const threadId = "sqlite-basic";
+ const agent = new MockAgent([
+ { type: EventType.TEXT_MESSAGE_START, messageId: "msg-1", role: "assistant" } as TextMessageStartEvent,
+ { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg-1", delta: "Hello" } as TextMessageContentEvent,
+ { type: EventType.TEXT_MESSAGE_END, messageId: "msg-1" } as TextMessageEndEvent,
+ ]);
+
+ const events = await firstValueFrom(
+ runner
+ .run({
+ threadId,
+ agent,
+ input: { threadId, runId: "run-1", messages: [], state: {} },
+ })
+ .pipe(toArray()),
+ );
+
+ expect(events.map((event) => event.type)).toEqual([
+ EventType.RUN_STARTED,
+ EventType.TEXT_MESSAGE_START,
+ EventType.TEXT_MESSAGE_CONTENT,
+ EventType.TEXT_MESSAGE_END,
+ ]);
+ });
+
+ it("attaches only new messages on subsequent runs", async () => {
+ const threadId = "sqlite-new-messages";
+ const existing: Message = { id: "existing", role: "user", content: "hi" };
+
+ await firstValueFrom(
+ runner
+ .run({
+ threadId,
+ agent: new MockAgent(),
+ input: { threadId, runId: "run-0", messages: [existing], state: {} },
+ })
+ .pipe(toArray()),
+ );
+
+ const newMessage: Message = { id: "new", role: "user", content: "follow up" };
+
+ const secondRun = await firstValueFrom(
+ runner
+ .run({
+ threadId,
+ agent: new MockAgent(),
+ input: {
+ threadId,
+ runId: "run-1",
+ messages: [existing, newMessage],
+ state: { counter: 1 },
+ },
+ })
+ .pipe(toArray()),
+ );
+
+ const runStarted = secondRun[0] as RunStartedEvent;
+ expect(runStarted.input?.messages?.map((m) => m.id)).toEqual(["new"]);
+
+ const db = new Database(dbPath);
+ const rows = db
+ .prepare("SELECT events FROM agent_runs WHERE thread_id = ? ORDER BY created_at")
+ .all(threadId) as { events: string }[];
+ db.close();
+
+ expect(rows).toHaveLength(2);
+ const run1Stored = JSON.parse(rows[0].events) as BaseEvent[];
+ const run2Stored = JSON.parse(rows[1].events) as BaseEvent[];
+
+ const run1Started = run1Stored.find((event) => event.type === EventType.RUN_STARTED) as RunStartedEvent;
+ expect(run1Started.input?.messages?.map((m) => m.id)).toEqual(["existing"]);
+
+ const run2Started = run2Stored.find((event) => event.type === EventType.RUN_STARTED) as RunStartedEvent;
+ expect(run2Started.input?.messages?.map((m) => m.id)).toEqual(["new"]);
+ });
+
+ it("preserves agent-provided input", async () => {
+ const threadId = "sqlite-agent-input";
+ const providedInput: RunAgentInput = {
+ threadId,
+ runId: "run-keep",
+ messages: [],
+ state: { fromAgent: true },
+ };
+
+ const agent = new MockAgent(
+ [
+ {
+ type: EventType.RUN_STARTED,
+ threadId,
+ runId: "run-keep",
+ input: providedInput,
+ } as RunStartedEvent,
+ ],
+ false,
+ );
+
+ const events = await firstValueFrom(
+ runner
+ .run({
+ threadId,
+ agent,
+ input: {
+ threadId,
+ runId: "run-keep",
+ messages: [{ id: "ignored", role: "user", content: "hi" }],
+ state: {},
+ },
+ })
+ .pipe(toArray()),
+ );
+
+ expect(events).toHaveLength(1);
+ const runStarted = events[0] as RunStartedEvent;
+ expect(runStarted.input).toBe(providedInput);
+ });
+
+ it("persists events across runner instances", async () => {
+ const threadId = "sqlite-persist";
+ const agent = new MockAgent([
+ { type: EventType.TEXT_MESSAGE_START, messageId: "msg", role: "assistant" } as TextMessageStartEvent,
+ { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "msg", delta: "hi" } as TextMessageContentEvent,
+ { type: EventType.TEXT_MESSAGE_END, messageId: "msg" } as TextMessageEndEvent,
+ ]);
+
+ await firstValueFrom(
+ runner
+ .run({
+ threadId,
+ agent,
+ input: { threadId, runId: "run-1", messages: [], state: {} },
+ })
+ .pipe(toArray()),
+ );
+
+ const newRunner = new SqliteAgentRunner({ dbPath });
+ const replayed = await firstValueFrom(newRunner.connect({ threadId }).pipe(toArray()));
+
+ expect(replayed[0].type).toBe(EventType.RUN_STARTED);
+ expect(replayed.slice(1).map((event) => event.type)).toEqual([
+ EventType.TEXT_MESSAGE_START,
+ EventType.TEXT_MESSAGE_CONTENT,
+ EventType.TEXT_MESSAGE_END,
+ ]);
+ });
+});
diff --git a/packages/sqlite-runner/src/index.ts b/packages/sqlite-runner/src/index.ts
new file mode 100644
index 00000000..9c2b44b8
--- /dev/null
+++ b/packages/sqlite-runner/src/index.ts
@@ -0,0 +1 @@
+export * from "./sqlite-runner";
diff --git a/packages/runtime/src/runner/sqlite.ts b/packages/sqlite-runner/src/sqlite-runner.ts
similarity index 78%
rename from packages/runtime/src/runner/sqlite.ts
rename to packages/sqlite-runner/src/sqlite-runner.ts
index 895835ed..2ba165ad 100644
--- a/packages/runtime/src/runner/sqlite.ts
+++ b/packages/sqlite-runner/src/sqlite-runner.ts
@@ -1,25 +1,18 @@
import {
AgentRunner,
- AgentRunnerConnectRequest,
- AgentRunnerIsRunningRequest,
- AgentRunnerRunRequest,
+ type AgentRunnerConnectRequest,
+ type AgentRunnerIsRunningRequest,
+ type AgentRunnerRunRequest,
type AgentRunnerStopRequest,
-} from "./agent-runner";
+} from "@copilotkitnext/runtime";
import { Observable, ReplaySubject } from "rxjs";
import {
BaseEvent,
RunAgentInput,
- Message,
EventType,
- TextMessageStartEvent,
- TextMessageContentEvent,
- TextMessageEndEvent,
- ToolCallStartEvent,
- ToolCallArgsEvent,
- ToolCallEndEvent,
- ToolCallResultEvent,
+ RunStartedEvent,
+ compactEvents,
} from "@ag-ui/client";
-import { compactEvents } from "./event-compaction";
import Database from "better-sqlite3";
const SCHEMA_VERSION = 1;
@@ -67,76 +60,6 @@ export class SqliteAgentRunner extends AgentRunner {
this.initializeSchema();
}
- private convertMessageToEvents(message: Message): BaseEvent[] {
- const events: BaseEvent[] = [];
-
- if (
- (message.role === "assistant" ||
- message.role === "user" ||
- message.role === "developer" ||
- message.role === "system") &&
- message.content
- ) {
- const textStartEvent: TextMessageStartEvent = {
- type: EventType.TEXT_MESSAGE_START,
- messageId: message.id,
- role: message.role,
- };
- events.push(textStartEvent);
-
- const textContentEvent: TextMessageContentEvent = {
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: message.id,
- delta: message.content,
- };
- events.push(textContentEvent);
-
- const textEndEvent: TextMessageEndEvent = {
- type: EventType.TEXT_MESSAGE_END,
- messageId: message.id,
- };
- events.push(textEndEvent);
- }
-
- if (message.role === "assistant" && message.toolCalls) {
- for (const toolCall of message.toolCalls) {
- const toolStartEvent: ToolCallStartEvent = {
- type: EventType.TOOL_CALL_START,
- toolCallId: toolCall.id,
- toolCallName: toolCall.function.name,
- parentMessageId: message.id,
- };
- events.push(toolStartEvent);
-
- const toolArgsEvent: ToolCallArgsEvent = {
- type: EventType.TOOL_CALL_ARGS,
- toolCallId: toolCall.id,
- delta: toolCall.function.arguments,
- };
- events.push(toolArgsEvent);
-
- const toolEndEvent: ToolCallEndEvent = {
- type: EventType.TOOL_CALL_END,
- toolCallId: toolCall.id,
- };
- events.push(toolEndEvent);
- }
- }
-
- if (message.role === "tool" && message.toolCallId) {
- const toolResultEvent: ToolCallResultEvent = {
- type: EventType.TOOL_CALL_RESULT,
- messageId: message.id,
- toolCallId: message.toolCallId,
- content: message.content,
- role: "tool",
- };
- events.push(toolResultEvent);
- }
-
- return events;
- }
-
private initializeSchema(): void {
// Create the agent_runs table
this.db.exec(`
@@ -300,6 +223,13 @@ export class SqliteAgentRunner extends AgentRunner {
if ('messageId' in event && typeof event.messageId === 'string') {
historicMessageIds.add(event.messageId);
}
+ if (event.type === EventType.RUN_STARTED) {
+ const runStarted = event as RunStartedEvent;
+ const messages = runStarted.input?.messages ?? [];
+ for (const message of messages) {
+ historicMessageIds.add(message.id);
+ }
+ }
}
}
@@ -321,9 +251,31 @@ export class SqliteAgentRunner extends AgentRunner {
try {
await request.agent.runAgent(request.input, {
onEvent: ({ event }) => {
- runSubject.next(event); // For run() return - only agent events
- nextSubject.next(event); // For connect() / store - all events
- currentRunEvents.push(event); // Accumulate for database storage
+ let processedEvent: BaseEvent = event;
+ if (event.type === EventType.RUN_STARTED) {
+ const runStartedEvent = event as RunStartedEvent;
+ if (!runStartedEvent.input) {
+ const sanitizedMessages = request.input.messages
+ ? request.input.messages.filter(
+ (message) => !historicMessageIds.has(message.id),
+ )
+ : undefined;
+ const updatedInput = {
+ ...request.input,
+ ...(sanitizedMessages !== undefined
+ ? { messages: sanitizedMessages }
+ : {}),
+ };
+ processedEvent = {
+ ...runStartedEvent,
+ input: updatedInput,
+ } as RunStartedEvent;
+ }
+ }
+
+ runSubject.next(processedEvent); // For run() return - only agent events
+ nextSubject.next(processedEvent); // For connect() / store - all events
+ currentRunEvents.push(processedEvent); // Accumulate for database storage
},
onNewMessage: ({ message }) => {
// Called for each new message
@@ -332,25 +284,11 @@ export class SqliteAgentRunner extends AgentRunner {
}
},
onRunStartedEvent: () => {
- // Process input messages
+ // Mark input messages as seen without emitting duplicates
if (request.input.messages) {
for (const message of request.input.messages) {
if (!seenMessageIds.has(message.id)) {
seenMessageIds.add(message.id);
- const events = this.convertMessageToEvents(message);
-
- // Check if this message is NEW (not in historic runs)
- const isNewMessage = !historicMessageIds.has(message.id);
-
- for (const event of events) {
- // Always emit to stream for context
- nextSubject.next(event);
-
- // Store if this is a NEW message for this run
- if (isNewMessage) {
- currentRunEvents.push(event);
- }
- }
}
}
}
@@ -478,4 +416,4 @@ export class SqliteAgentRunner extends AgentRunner {
this.db.close();
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/sqlite-runner/tsconfig.json b/packages/sqlite-runner/tsconfig.json
new file mode 100644
index 00000000..806f1abd
--- /dev/null
+++ b/packages/sqlite-runner/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "extends": "@copilotkitnext/typescript-config/base.json",
+ "compilerOptions": {
+ "outDir": "dist",
+ "rootDir": "src",
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "types": ["vitest/globals"]
+ },
+ "include": ["src/**/*"],
+ "exclude": ["dist", "node_modules", "src/**/__tests__/**", "src/**/*.test.ts"]
+}
diff --git a/packages/sqlite-runner/tsup.config.ts b/packages/sqlite-runner/tsup.config.ts
new file mode 100644
index 00000000..3cc0459b
--- /dev/null
+++ b/packages/sqlite-runner/tsup.config.ts
@@ -0,0 +1,11 @@
+import { defineConfig } from 'tsup';
+
+export default defineConfig({
+ entry: ['src/index.ts'],
+ format: ['cjs', 'esm'],
+ dts: true,
+ sourcemap: true,
+ clean: true,
+ target: 'es2022',
+ outDir: 'dist',
+});
diff --git a/packages/sqlite-runner/vitest.config.mjs b/packages/sqlite-runner/vitest.config.mjs
new file mode 100644
index 00000000..a0886b47
--- /dev/null
+++ b/packages/sqlite-runner/vitest.config.mjs
@@ -0,0 +1,15 @@
+import { defineConfig } from "vitest/config";
+
+export default defineConfig({
+ test: {
+ environment: "node",
+ globals: true,
+ include: ["src/**/__tests__/**/*.{test,spec}.ts"],
+ coverage: {
+ reporter: ["text", "lcov", "html"],
+ include: ["src/**/*.ts"],
+ exclude: ["src/**/*.d.ts", "src/**/index.ts"],
+ },
+ setupFiles: [],
+ },
+});
diff --git a/packages/web-inspector/package.json b/packages/web-inspector/package.json
index b0894759..feb29bde 100644
--- a/packages/web-inspector/package.json
+++ b/packages/web-inspector/package.json
@@ -1,6 +1,6 @@
{
"name": "@copilotkitnext/web-inspector",
- "version": "0.0.15",
+ "version": "0.0.14",
"description": "Lit-based web component for the CopilotKit web inspector",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -25,7 +25,7 @@
"clean": "rm -rf dist src/styles/generated.css"
},
"dependencies": {
- "@ag-ui/client": "0.0.40-alpha.3",
+ "@ag-ui/client": "0.0.40-alpha.6",
"@copilotkitnext/core": "workspace:*",
"lit": "^3.2.0",
"lucide": "^0.525.0"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e08fa9c9..75b45e76 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -13,10 +13,10 @@ importers:
version: 8.6.14(@types/react@19.1.0)(storybook@8.6.14(prettier@3.6.0))
'@storybook/addon-webpack5-compiler-swc':
specifier: ^1.0.5
- version: 1.0.6(@swc/helpers@0.5.15)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ version: 1.0.6(webpack@5.100.0(@swc/core@1.12.11))
'@storybook/react-webpack5':
specifier: ^8
- version: 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
+ version: 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(@swc/core@1.12.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
prettier:
specifier: ^3.6.0
version: 3.6.0
@@ -65,19 +65,16 @@ importers:
tslib:
specifier: ^2.8.1
version: 2.8.1
- zod:
- specifier: ^3.25.75
- version: 3.25.75
zone.js:
specifier: ^0.14.0
version: 0.14.10
devDependencies:
'@angular-devkit/build-angular':
specifier: ^18.2.0
- version: 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(chokidar@4.0.3)(html-webpack-plugin@5.6.3(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.12)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.12)(typescript@5.4.5)
+ version: 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11)(@types/node@22.15.3)(chokidar@3.6.0)(html-webpack-plugin@5.6.3(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@3.4.17)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@3.4.17)(typescript@5.4.5)
'@angular/cli':
specifier: ^18.2.0
- version: 18.2.20(chokidar@4.0.3)
+ version: 18.2.20(chokidar@3.6.0)
'@angular/compiler-cli':
specifier: ^18.2.0
version: 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5)
@@ -94,11 +91,11 @@ importers:
apps/angular/demo-server:
dependencies:
'@ag-ui/client':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@ag-ui/langgraph':
specifier: ^0.0.11
- version: 0.0.11(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.75))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 0.0.11(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.75))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@copilotkitnext/demo-agents':
specifier: workspace:^
version: link:../../../packages/demo-agents
@@ -131,8 +128,8 @@ importers:
apps/angular/storybook:
dependencies:
'@ag-ui/client':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@angular/animations':
specifier: ^18.2.0
version: 18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))
@@ -172,10 +169,10 @@ importers:
devDependencies:
'@angular-devkit/build-angular':
specifier: ^18.2.0
- version: 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(chokidar@4.0.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5)
+ version: 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11)(@types/node@22.15.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5)
'@angular/cli':
specifier: ^18.2.0
- version: 18.2.20(chokidar@4.0.3)
+ version: 18.2.20
'@angular/compiler-cli':
specifier: ^18.2.0
version: 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5)
@@ -196,7 +193,7 @@ importers:
version: 8.6.14(storybook@8.6.14(prettier@3.6.0))
'@storybook/angular':
specifier: ^8
- version: 8.6.14(@angular-devkit/architect@0.1902.15(chokidar@4.0.3))(@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(chokidar@4.0.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5))(@angular-devkit/core@19.2.15(chokidar@4.0.3))(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/cli@18.2.20(chokidar@4.0.3))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(@angular/forms@18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(rxjs@7.8.1))(@angular/platform-browser-dynamic@18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(rxjs@7.8.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.4.5)(zone.js@0.14.10)
+ version: 8.6.14(yd4v6lxii4rfhetgylkhgsqlgq)
'@storybook/test':
specifier: ^8
version: 8.6.14(storybook@8.6.14(prettier@3.6.0))
@@ -211,19 +208,19 @@ importers:
version: 10.4.21(postcss@8.5.6)
css-loader:
specifier: ^7.1.2
- version: 7.1.2(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ version: 7.1.2(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6))
postcss:
specifier: ^8.4.31
version: 8.5.6
postcss-loader:
specifier: ^8.1.1
- version: 8.1.1(postcss@8.5.6)(typescript@5.4.5)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ version: 8.1.1(postcss@8.5.6)(typescript@5.4.5)(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6))
storybook:
specifier: ^8
version: 8.6.14(prettier@3.6.0)
style-loader:
specifier: ^4.0.0
- version: 4.0.0(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ version: 4.0.0(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6))
tailwindcss:
specifier: ^4.1.11
version: 4.1.11
@@ -269,8 +266,8 @@ importers:
apps/react/demo:
dependencies:
'@ag-ui/client':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@copilotkitnext/agent':
specifier: workspace:*
version: link:../../../packages/agent
@@ -294,7 +291,7 @@ importers:
version: 4.8.10
next:
specifier: 15.4.4
- version: 15.4.4(@babel/core@7.28.0)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.90.0)
+ version: 15.4.4(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.90.0)
openai:
specifier: ^5.9.0
version: 5.9.0(ws@8.18.3)(zod@3.25.75)
@@ -352,7 +349,7 @@ importers:
version: 8.6.14(storybook@8.6.14(prettier@3.6.0))
'@storybook/nextjs':
specifier: ^8
- version: 8.6.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(next@15.4.4(@babel/core@7.28.0)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.90.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.90.0)(storybook@8.6.14(prettier@3.6.0))(type-fest@4.41.0)(typescript@5.8.2)(webpack-dev-server@5.2.2(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(webpack-hot-middleware@2.26.1)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ version: 8.6.14(@swc/core@1.12.11)(next@15.4.4(@babel/core@7.28.0)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.90.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.90.0)(storybook@8.6.14(prettier@3.6.0))(type-fest@4.41.0)(typescript@5.8.2)(webpack-dev-server@5.2.2(webpack@5.100.0(@swc/core@1.12.11)))(webpack-hot-middleware@2.26.1)(webpack@5.100.0(@swc/core@1.12.11))
'@storybook/react':
specifier: ^8
version: 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
@@ -406,8 +403,8 @@ importers:
packages/agent:
dependencies:
'@ag-ui/client':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@ai-sdk/anthropic':
specifier: ^2.0.22
version: 2.0.23(zod@3.25.75)
@@ -447,7 +444,7 @@ importers:
version: 9.30.0(jiti@2.5.1)
tsup:
specifier: ^8.5.0
- version: 8.5.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
+ version: 8.5.0(@swc/core@1.12.11)(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
typescript:
specifier: 5.8.2
version: 5.8.2
@@ -458,11 +455,11 @@ importers:
packages/angular:
dependencies:
'@ag-ui/client':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@ag-ui/core':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@copilotkitnext/core':
specifier: workspace:*
version: link:../core
@@ -496,10 +493,10 @@ importers:
devDependencies:
'@analogjs/vite-plugin-angular':
specifier: ^1.20.2
- version: 1.20.2(@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5))(@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5))
+ version: 1.20.2(@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11)(@types/node@22.15.3)(chokidar@4.0.3)(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5))(@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5))
'@analogjs/vitest-angular':
specifier: ^1.20.2
- version: 1.20.2(@analogjs/vite-plugin-angular@1.20.2(@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5))(@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5)))(@angular-devkit/architect@0.1902.15)(vitest@2.1.9(@types/node@22.15.3)(@vitest/ui@2.1.9)(jsdom@24.1.3)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1))
+ version: 1.20.2(@analogjs/vite-plugin-angular@1.20.2(@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11)(@types/node@22.15.3)(chokidar@4.0.3)(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5))(@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5)))(@angular-devkit/architect@0.1902.15(chokidar@4.0.3))(vitest@2.1.9(@types/node@22.15.3)(@vitest/ui@2.1.9)(jsdom@24.1.3)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1))
'@angular/cdk':
specifier: ^18.0.0
version: 18.2.14(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1)
@@ -600,8 +597,8 @@ importers:
packages/core:
dependencies:
'@ag-ui/client':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@copilotkitnext/shared':
specifier: workspace:*
version: link:../shared
@@ -632,7 +629,7 @@ importers:
version: 9.30.0(jiti@2.5.1)
tsup:
specifier: ^8.5.0
- version: 8.5.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
+ version: 8.5.0(@swc/core@1.12.11)(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
typescript:
specifier: 5.8.2
version: 5.8.2
@@ -666,13 +663,13 @@ importers:
version: 9.30.0(jiti@2.5.1)
tsup:
specifier: ^8.0.1
- version: 8.5.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
+ version: 8.5.0(@swc/core@1.12.11)(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
typescript:
specifier: ^5.8.2
version: 5.8.2
vitest:
specifier: ^2.1.8
- version: 2.1.9(@types/node@22.15.3)(@vitest/ui@3.2.4)(jsdom@26.1.0)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1)
+ version: 2.1.9(@types/node@22.15.3)(@vitest/ui@2.1.9)(jsdom@26.1.0)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1)
packages/eslint-config:
devDependencies:
@@ -713,11 +710,11 @@ importers:
packages/react:
dependencies:
'@ag-ui/client':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@ag-ui/core':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@copilotkitnext/core':
specifier: workspace:*
version: link:../core
@@ -832,7 +829,7 @@ importers:
version: 4.1.11
tsup:
specifier: ^8.5.0
- version: 8.5.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
+ version: 8.5.0(@swc/core@1.12.11)(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
typescript:
specifier: 5.8.2
version: 5.8.2
@@ -843,26 +840,20 @@ importers:
packages/runtime:
dependencies:
'@ag-ui/client':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@ag-ui/core':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@ag-ui/encoder':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@copilotkitnext/shared':
specifier: workspace:*
version: link:../shared
hono:
specifier: ^4.6.13
version: 4.8.10
- ioredis:
- specifier: ^5.7.0
- version: 5.7.0
- kysely:
- specifier: ^0.28.5
- version: 0.28.5
rxjs:
specifier: 7.8.1
version: 7.8.1
@@ -873,27 +864,18 @@ importers:
'@copilotkitnext/typescript-config':
specifier: workspace:*
version: link:../typescript-config
- '@types/better-sqlite3':
- specifier: ^7.6.13
- version: 7.6.13
'@types/node':
specifier: ^22.15.3
version: 22.15.3
- better-sqlite3:
- specifier: ^12.2.0
- version: 12.2.0
eslint:
specifier: ^9.30.0
version: 9.30.0(jiti@2.5.1)
- ioredis-mock:
- specifier: ^8.9.0
- version: 8.9.0(@types/ioredis-mock@8.2.6(ioredis@5.7.0))(ioredis@5.7.0)
openai:
specifier: ^5.9.0
version: 5.9.0(ws@8.18.3)(zod@3.25.75)
tsup:
specifier: ^8.5.0
- version: 8.5.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
+ version: 8.5.0(@swc/core@1.12.11)(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
typescript:
specifier: 5.8.2
version: 5.8.2
@@ -924,18 +906,58 @@ importers:
version: 9.30.0(jiti@2.5.1)
tsup:
specifier: ^8.5.0
- version: 8.5.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
+ version: 8.5.0(@swc/core@1.12.11)(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
+ typescript:
+ specifier: 5.8.2
+ version: 5.8.2
+
+ packages/sqlite-runner:
+ dependencies:
+ '@ag-ui/client':
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
+ '@copilotkitnext/runtime':
+ specifier: workspace:*
+ version: link:../runtime
+ rxjs:
+ specifier: 7.8.1
+ version: 7.8.1
+ devDependencies:
+ '@copilotkitnext/eslint-config':
+ specifier: workspace:*
+ version: link:../eslint-config
+ '@copilotkitnext/typescript-config':
+ specifier: workspace:*
+ version: link:../typescript-config
+ '@types/better-sqlite3':
+ specifier: ^7.6.13
+ version: 7.6.13
+ '@types/node':
+ specifier: ^22.15.3
+ version: 22.15.3
+ better-sqlite3:
+ specifier: ^12.2.0
+ version: 12.2.0
+ eslint:
+ specifier: ^9.30.0
+ version: 9.30.0(jiti@2.5.1)
+ tsup:
+ specifier: ^8.5.0
+ version: 8.5.0(@swc/core@1.12.11)(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
typescript:
specifier: 5.8.2
version: 5.8.2
+ vitest:
+ specifier: ^3.0.5
+ version: 3.2.4(@types/debug@4.1.12)(@types/node@22.15.3)(@vitest/ui@3.2.4)(jiti@2.5.1)(jsdom@26.1.0)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.0)
packages/typescript-config: {}
packages/web-inspector:
dependencies:
'@ag-ui/client':
- specifier: 0.0.40-alpha.3
- version: 0.0.40-alpha.3
+ specifier: 0.0.40-alpha.6
+ version: 0.0.40-alpha.6
'@copilotkitnext/core':
specifier: workspace:*
version: link:../core
@@ -969,7 +991,7 @@ importers:
version: 4.1.12
tsup:
specifier: ^8.5.0
- version: 8.5.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
+ version: 8.5.0(@swc/core@1.12.11)(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0)
typescript:
specifier: 5.8.2
version: 5.8.2
@@ -982,20 +1004,20 @@ packages:
'@ag-ui/client@0.0.36':
resolution: {integrity: sha512-1Ey2KqK9KQpRJcnJvKPfVyLiTK4+CLBQZ085oJvr6T1nznw224j0KyzXNJ7cRjXeEGnuafmXTgpU+xEbN3xuYQ==}
- '@ag-ui/client@0.0.40-alpha.3':
- resolution: {integrity: sha512-Za1j4r/9MZoic1DCmPGiRFIjSkGgr5sqnadYjQV6v/qvbv+cx4+8GX8K3snBcRX6H3EceOtQ9eY2BSZcR+Nc1g==}
+ '@ag-ui/client@0.0.40-alpha.6':
+ resolution: {integrity: sha512-QIgOY8nJvv3mrDz9OXyaoxwj3Js28YPYXz+myRQ2idR1ghoKq0V9MEZrXoHOE4O6Z7PnUSw5z7zZIemh7YK/5w==}
'@ag-ui/core@0.0.36':
resolution: {integrity: sha512-uYUrzw6uxuw4qVQ61mdSeiG0mFh2n/VAWmWsWzwETDuhqJZT7rFmd07IajcFWcyItMr1wjqxFDdlklucAyEYNA==}
- '@ag-ui/core@0.0.40-alpha.3':
- resolution: {integrity: sha512-35ctuwk4/799c7uCSYfwHLmy5tUFg35VONqdmv6n1xl3kbH7qYA4L6xaGeCaI/YtTAVDs1KuUb/alSifrfPSAA==}
+ '@ag-ui/core@0.0.40-alpha.6':
+ resolution: {integrity: sha512-XkZAnmtewucr0yayWxK2GEcOoxaHZ6cSZZKkVFKAEOPJuUwFCFstqS3vh0Z5rUy2ZE8eh8WJylBHidiCRW4yuA==}
'@ag-ui/encoder@0.0.36':
resolution: {integrity: sha512-p8UNh6a77G/oe/4EZmwkTeYCN/5SnqSY2Cz8f8psZpk4LKzzrPkRNykrUAIBsi1wMp50/VQiM27oTRaade/Qkw==}
- '@ag-ui/encoder@0.0.40-alpha.3':
- resolution: {integrity: sha512-hFCkR9x409ZzU9a0u9WTAnaWWAIRTpos4X9GfDXlrNXzmkHr1zwpzmJsvTbmnpAtg/stpLQuWebej4dk/8QBzg==}
+ '@ag-ui/encoder@0.0.40-alpha.6':
+ resolution: {integrity: sha512-q+bpJGp4fMjQplHowmbNaOQrICHzmk1J394jZXmTv/RjysNHtcDrWHythXBiPAnNRutYeqsG6bQJ5PASbQYiqg==}
'@ag-ui/langgraph@0.0.11':
resolution: {integrity: sha512-3xUkaOelnpQ5tbsbuoOTin71tTgWEN0GDZBjGs/7xAwly2Dn4fahbBAoscXullO/pH9kTGGgbuJ0rWDUgo6fKQ==}
@@ -1003,8 +1025,8 @@ packages:
'@ag-ui/proto@0.0.36':
resolution: {integrity: sha512-yaWLwJQmBaCtFstSoZEALztVckCYv+RD8guU91kL5AvywRXvZPP5mjiN+bEwvtw8VU3idXoee1ZbJGpSlSAQ8A==}
- '@ag-ui/proto@0.0.40-alpha.3':
- resolution: {integrity: sha512-VS9R2SGMJ+fbNq4hRT3jKe/FKeqRRev+DtKd1JIkwYiR+CaXF2h+gxi5xypCMiSyHzrH7QtftXI5nWU871HxAA==}
+ '@ag-ui/proto@0.0.40-alpha.6':
+ resolution: {integrity: sha512-xFw9igIC7OGdq/t1biUXRMinaC0sPLkavjj2oz820KaJe1uZOTSRfAK1qEgswoHJU1N4vRg0RQDEhd1wN8+GGg==}
'@ai-sdk/anthropic@2.0.23':
resolution: {integrity: sha512-ZEBiiv1UhjGjBwUU63pFhLK5LCSlNDb1idY9K1oZHm5/Fda1cuTojf32tOp0opH0RPbPAN/F8fyyNjbU33n9Kw==}
@@ -3160,12 +3182,6 @@ packages:
'@types/node':
optional: true
- '@ioredis/as-callback@3.0.0':
- resolution: {integrity: sha512-Kqv1rZ3WbgOrS+hgzJ5xG5WQuhvzzSTRYvNeyPMLOAM78MHSnuKI20JeJGbpuAt//LCuP0vsexZcorqW7kWhJg==}
-
- '@ioredis/commands@1.3.0':
- resolution: {integrity: sha512-M/T6Zewn7sDaBQEqIZ8Rb+i9y8qfGmq+5SDFSf9sA2lUZTmdDLVdOiQaeDp+Q4wElZ9HG1GAX5KhDaidp6LQsQ==}
-
'@isaacs/balanced-match@4.0.1':
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
engines: {node: 20 || >=22}
@@ -5295,11 +5311,6 @@ packages:
'@types/http-proxy@1.17.16':
resolution: {integrity: sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==}
- '@types/ioredis-mock@8.2.6':
- resolution: {integrity: sha512-5heqtZMvQ4nXARY0o8rc8cjkJjct2ScM12yCJ/h731S9He93a2cv+kAhwPCNwTKDfNH9gjRfLG4VpAEYJU0/gQ==}
- peerDependencies:
- ioredis: '>=5'
-
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@@ -6426,10 +6437,6 @@ packages:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
- cluster-key-slot@1.1.2:
- resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
- engines: {node: '>=0.10.0'}
-
code-block-writer@12.0.0:
resolution: {integrity: sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==}
@@ -6989,10 +6996,6 @@ packages:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
- denque@2.1.0:
- resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
- engines: {node: '>=0.10'}
-
depd@1.1.2:
resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==}
engines: {node: '>= 0.6'}
@@ -7631,14 +7634,6 @@ packages:
picomatch:
optional: true
- fengari-interop@0.1.3:
- resolution: {integrity: sha512-EtZ+oTu3kEwVJnoymFPBVLIbQcCoy9uWCVnMA6h3M/RqHkUBsLYp29+RRHf9rKr6GwjubWREU1O7RretFIXjHw==}
- peerDependencies:
- fengari: ^0.1.0
-
- fengari@0.1.4:
- resolution: {integrity: sha512-6ujqUuiIYmcgkGz8MGAdERU57EIluGGPSUgGPTsco657EHa+srq0S3/YUl/r9kx1+D+d4rGfYObd+m8K22gB1g==}
-
fetch-blob@3.2.0:
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
engines: {node: ^12.20 || >= 14.13}
@@ -8299,17 +8294,6 @@ packages:
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
engines: {node: '>=12'}
- ioredis-mock@8.9.0:
- resolution: {integrity: sha512-yIglcCkI1lvhwJVoMsR51fotZVsPsSk07ecTCgRTRlicG0Vq3lke6aAaHklyjmRNRsdYAgswqC2A0bPtQK4LSw==}
- engines: {node: '>=12.22'}
- peerDependencies:
- '@types/ioredis-mock': ^8
- ioredis: ^5
-
- ioredis@5.7.0:
- resolution: {integrity: sha512-NUcA93i1lukyXU+riqEyPtSEkyFq8tX90uL659J+qpCZ3rEdViB/APC58oAhIh3+bJln2hzdlZbBZsGNrlsR8g==}
- engines: {node: '>=12.22.0'}
-
ip-address@9.0.5:
resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==}
engines: {node: '>= 12'}
@@ -8762,10 +8746,6 @@ packages:
kolorist@1.8.0:
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
- kysely@0.28.5:
- resolution: {integrity: sha512-rlB0I/c6FBDWPcQoDtkxi9zIvpmnV5xoIalfCMSMCa7nuA6VGA3F54TW9mEgX4DVf10sXAWCF5fDbamI/5ZpKA==}
- engines: {node: '>=20.0.0'}
-
langium@3.3.1:
resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==}
engines: {node: '>=16.0.0'}
@@ -8978,12 +8958,6 @@ packages:
lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
- lodash.defaults@4.2.0:
- resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
-
- lodash.isarguments@3.1.0:
- resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
-
lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
@@ -10526,10 +10500,6 @@ packages:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
- readline-sync@1.4.10:
- resolution: {integrity: sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==}
- engines: {node: '>= 0.8.0'}
-
recast@0.23.11:
resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==}
engines: {node: '>= 4'}
@@ -10550,14 +10520,6 @@ packages:
resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
engines: {node: '>=8'}
- redis-errors@1.2.0:
- resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
- engines: {node: '>=4'}
-
- redis-parser@3.0.0:
- resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
- engines: {node: '>=4'}
-
reflect-metadata@0.2.2:
resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
@@ -11184,9 +11146,6 @@ packages:
stackframe@1.3.4:
resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==}
- standard-as-callback@2.1.0:
- resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
-
statuses@1.5.0:
resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
engines: {node: '>= 0.6'}
@@ -12544,11 +12503,11 @@ snapshots:
uuid: 11.1.0
zod: 3.25.75
- '@ag-ui/client@0.0.40-alpha.3':
+ '@ag-ui/client@0.0.40-alpha.6':
dependencies:
- '@ag-ui/core': 0.0.40-alpha.3
- '@ag-ui/encoder': 0.0.40-alpha.3
- '@ag-ui/proto': 0.0.40-alpha.3
+ '@ag-ui/core': 0.0.40-alpha.6
+ '@ag-ui/encoder': 0.0.40-alpha.6
+ '@ag-ui/proto': 0.0.40-alpha.6
'@types/uuid': 10.0.0
fast-json-patch: 3.1.1
rxjs: 7.8.1
@@ -12561,7 +12520,7 @@ snapshots:
rxjs: 7.8.1
zod: 3.25.75
- '@ag-ui/core@0.0.40-alpha.3':
+ '@ag-ui/core@0.0.40-alpha.6':
dependencies:
rxjs: 7.8.1
zod: 3.25.75
@@ -12571,16 +12530,16 @@ snapshots:
'@ag-ui/core': 0.0.36
'@ag-ui/proto': 0.0.36
- '@ag-ui/encoder@0.0.40-alpha.3':
+ '@ag-ui/encoder@0.0.40-alpha.6':
dependencies:
- '@ag-ui/core': 0.0.40-alpha.3
- '@ag-ui/proto': 0.0.40-alpha.3
+ '@ag-ui/core': 0.0.40-alpha.6
+ '@ag-ui/proto': 0.0.40-alpha.6
- '@ag-ui/langgraph@0.0.11(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.75))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@ag-ui/langgraph@0.0.11(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.75))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@ag-ui/client': 0.0.36
'@langchain/core': 0.3.73(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.75))
- '@langchain/langgraph-sdk': 0.0.105(@langchain/core@0.3.73(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.75)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@langchain/langgraph-sdk': 0.0.105(@langchain/core@0.3.73(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.75)))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
partial-json: 0.1.7
rxjs: 7.8.1
transitivePeerDependencies:
@@ -12597,9 +12556,9 @@ snapshots:
'@bufbuild/protobuf': 2.6.0
'@protobuf-ts/protoc': 2.11.1
- '@ag-ui/proto@0.0.40-alpha.3':
+ '@ag-ui/proto@0.0.40-alpha.6':
dependencies:
- '@ag-ui/core': 0.0.40-alpha.3
+ '@ag-ui/core': 0.0.40-alpha.6
'@bufbuild/protobuf': 2.6.0
'@protobuf-ts/protoc': 2.11.1
@@ -12650,20 +12609,27 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.12
'@jridgewell/trace-mapping': 0.3.30
- '@analogjs/vite-plugin-angular@1.20.2(@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5))(@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5))':
+ '@analogjs/vite-plugin-angular@1.20.2(@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11)(@types/node@22.15.3)(chokidar@4.0.3)(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5))(@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5))':
dependencies:
ts-morph: 21.0.1
vfile: 6.0.3
optionalDependencies:
- '@angular-devkit/build-angular': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5)
- '@angular/build': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5)
+ '@angular-devkit/build-angular': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11)(@types/node@22.15.3)(chokidar@4.0.3)(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5)
+ '@angular/build': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5)
- ? '@analogjs/vitest-angular@1.20.2(@analogjs/vite-plugin-angular@1.20.2(@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5))(@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5)))(@angular-devkit/architect@0.1902.15)(vitest@2.1.9(@types/node@22.15.3)(@vitest/ui@2.1.9)(jsdom@24.1.3)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1))'
- : dependencies:
- '@analogjs/vite-plugin-angular': 1.20.2(@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5))(@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5))
+ '@analogjs/vitest-angular@1.20.2(@analogjs/vite-plugin-angular@1.20.2(@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11)(@types/node@22.15.3)(chokidar@4.0.3)(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5))(@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5)))(@angular-devkit/architect@0.1902.15(chokidar@4.0.3))(vitest@2.1.9(@types/node@22.15.3)(@vitest/ui@2.1.9)(jsdom@24.1.3)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1))':
+ dependencies:
+ '@analogjs/vite-plugin-angular': 1.20.2(@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11)(@types/node@22.15.3)(chokidar@4.0.3)(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5))(@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5))
'@angular-devkit/architect': 0.1902.15(chokidar@4.0.3)
vitest: 2.1.9(@types/node@22.15.3)(@vitest/ui@2.1.9)(jsdom@24.1.3)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1)
+ '@angular-devkit/architect@0.1802.20(chokidar@3.6.0)':
+ dependencies:
+ '@angular-devkit/core': 18.2.20(chokidar@3.6.0)
+ rxjs: 7.8.1
+ transitivePeerDependencies:
+ - chokidar
+
'@angular-devkit/architect@0.1802.20(chokidar@4.0.3)':
dependencies:
'@angular-devkit/core': 18.2.20(chokidar@4.0.3)
@@ -12678,13 +12644,13 @@ snapshots:
transitivePeerDependencies:
- chokidar
- '@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(chokidar@4.0.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5)':
+ '@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11)(@types/node@22.15.3)(chokidar@3.6.0)(html-webpack-plugin@5.6.3(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@3.4.17)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@3.4.17)(typescript@5.4.5)':
dependencies:
'@ampproject/remapping': 2.3.0
- '@angular-devkit/architect': 0.1802.20(chokidar@4.0.3)
- '@angular-devkit/build-webpack': 0.1802.20(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
- '@angular-devkit/core': 18.2.20(chokidar@4.0.3)
- '@angular/build': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.2.0)(lightningcss@1.30.1)(postcss@8.4.41)(tailwindcss@4.1.11)(terser@5.31.6)(typescript@5.4.5)
+ '@angular-devkit/architect': 0.1802.20(chokidar@3.6.0)
+ '@angular-devkit/build-webpack': 0.1802.20(chokidar@3.6.0)(webpack-dev-server@5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
+ '@angular-devkit/core': 18.2.20(chokidar@3.6.0)
+ '@angular/build': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@3.6.0)(less@4.2.0)(lightningcss@1.30.1)(postcss@8.4.41)(tailwindcss@3.4.17)(terser@5.31.6)(typescript@5.4.5)
'@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5)
'@babel/core': 7.26.10
'@babel/generator': 7.26.10
@@ -12696,14 +12662,14 @@ snapshots:
'@babel/preset-env': 7.26.9(@babel/core@7.26.10)
'@babel/runtime': 7.26.10
'@discoveryjs/json-ext': 0.6.1
- '@ngtools/webpack': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ '@ngtools/webpack': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
ansi-colors: 4.1.3
autoprefixer: 10.4.20(postcss@8.4.41)
- babel-loader: 9.1.3(@babel/core@7.26.10)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ babel-loader: 9.1.3(@babel/core@7.26.10)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
browserslist: 4.25.1
- copy-webpack-plugin: 12.0.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ copy-webpack-plugin: 12.0.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
critters: 0.0.24
- css-loader: 7.1.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ css-loader: 7.1.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
esbuild-wasm: 0.23.0
fast-glob: 3.3.2
http-proxy-middleware: 3.0.5
@@ -12712,11 +12678,11 @@ snapshots:
jsonc-parser: 3.3.1
karma-source-map-support: 1.4.0
less: 4.2.0
- less-loader: 12.2.0(less@4.2.0)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
- license-webpack-plugin: 4.0.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ less-loader: 12.2.0(less@4.2.0)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
+ license-webpack-plugin: 4.0.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
loader-utils: 3.3.1
magic-string: 0.30.11
- mini-css-extract-plugin: 2.9.0(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ mini-css-extract-plugin: 2.9.0(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
mrmime: 2.0.0
open: 10.1.0
ora: 5.4.1
@@ -12724,28 +12690,28 @@ snapshots:
picomatch: 4.0.2
piscina: 4.6.1
postcss: 8.4.41
- postcss-loader: 8.1.1(postcss@8.4.41)(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ postcss-loader: 8.1.1(postcss@8.4.41)(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
resolve-url-loader: 5.0.0
rxjs: 7.8.1
sass: 1.77.6
- sass-loader: 16.0.0(sass@1.77.6)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ sass-loader: 16.0.0(sass@1.77.6)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
semver: 7.6.3
- source-map-loader: 5.0.0(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ source-map-loader: 5.0.0(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
source-map-support: 0.5.21
terser: 5.31.6
tree-kill: 1.2.2
tslib: 2.6.3
typescript: 5.4.5
watchpack: 2.4.1
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
- webpack-dev-middleware: 7.4.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
- webpack-dev-server: 5.2.2(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
+ webpack-dev-middleware: 7.4.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
+ webpack-dev-server: 5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
webpack-merge: 6.0.1
- webpack-subresource-integrity: 5.1.0(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ webpack-subresource-integrity: 5.1.0(html-webpack-plugin@5.6.3(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
optionalDependencies:
esbuild: 0.23.0
- ng-packagr: 18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5)
- tailwindcss: 4.1.11
+ ng-packagr: 18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@3.4.17)(tslib@2.8.1)(typescript@5.4.5)
+ tailwindcss: 3.4.17
transitivePeerDependencies:
- '@rspack/core'
- '@swc/core'
@@ -12764,13 +12730,13 @@ snapshots:
- utf-8-validate
- webpack-cli
- '@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(chokidar@4.0.3)(html-webpack-plugin@5.6.3(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.12)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.12)(typescript@5.4.5)':
+ '@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11)(@types/node@22.15.3)(chokidar@4.0.3)(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5)':
dependencies:
'@ampproject/remapping': 2.3.0
'@angular-devkit/architect': 0.1802.20(chokidar@4.0.3)
- '@angular-devkit/build-webpack': 0.1802.20(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ '@angular-devkit/build-webpack': 0.1802.20(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
'@angular-devkit/core': 18.2.20(chokidar@4.0.3)
- '@angular/build': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.2.0)(lightningcss@1.30.1)(postcss@8.4.41)(tailwindcss@4.1.12)(terser@5.31.6)(typescript@5.4.5)
+ '@angular/build': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.2.0)(lightningcss@1.30.1)(postcss@8.4.41)(tailwindcss@4.1.11)(terser@5.31.6)(typescript@5.4.5)
'@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5)
'@babel/core': 7.26.10
'@babel/generator': 7.26.10
@@ -12782,14 +12748,14 @@ snapshots:
'@babel/preset-env': 7.26.9(@babel/core@7.26.10)
'@babel/runtime': 7.26.10
'@discoveryjs/json-ext': 0.6.1
- '@ngtools/webpack': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ '@ngtools/webpack': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
ansi-colors: 4.1.3
autoprefixer: 10.4.20(postcss@8.4.41)
- babel-loader: 9.1.3(@babel/core@7.26.10)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ babel-loader: 9.1.3(@babel/core@7.26.10)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
browserslist: 4.25.1
- copy-webpack-plugin: 12.0.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ copy-webpack-plugin: 12.0.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
critters: 0.0.24
- css-loader: 7.1.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ css-loader: 7.1.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
esbuild-wasm: 0.23.0
fast-glob: 3.3.2
http-proxy-middleware: 3.0.5
@@ -12798,11 +12764,11 @@ snapshots:
jsonc-parser: 3.3.1
karma-source-map-support: 1.4.0
less: 4.2.0
- less-loader: 12.2.0(less@4.2.0)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
- license-webpack-plugin: 4.0.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ less-loader: 12.2.0(less@4.2.0)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
+ license-webpack-plugin: 4.0.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
loader-utils: 3.3.1
magic-string: 0.30.11
- mini-css-extract-plugin: 2.9.0(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ mini-css-extract-plugin: 2.9.0(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
mrmime: 2.0.0
open: 10.1.0
ora: 5.4.1
@@ -12810,28 +12776,28 @@ snapshots:
picomatch: 4.0.2
piscina: 4.6.1
postcss: 8.4.41
- postcss-loader: 8.1.1(postcss@8.4.41)(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ postcss-loader: 8.1.1(postcss@8.4.41)(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
resolve-url-loader: 5.0.0
rxjs: 7.8.1
sass: 1.77.6
- sass-loader: 16.0.0(sass@1.77.6)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ sass-loader: 16.0.0(sass@1.77.6)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
semver: 7.6.3
- source-map-loader: 5.0.0(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ source-map-loader: 5.0.0(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
source-map-support: 0.5.21
terser: 5.31.6
tree-kill: 1.2.2
tslib: 2.6.3
typescript: 5.4.5
watchpack: 2.4.1
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
- webpack-dev-middleware: 7.4.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
- webpack-dev-server: 5.2.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
+ webpack-dev-middleware: 7.4.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
+ webpack-dev-server: 5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
webpack-merge: 6.0.1
- webpack-subresource-integrity: 5.1.0(html-webpack-plugin@5.6.3(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ webpack-subresource-integrity: 5.1.0(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)))(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
optionalDependencies:
esbuild: 0.23.0
- ng-packagr: 18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.12)(tslib@2.8.1)(typescript@5.4.5)
- tailwindcss: 4.1.12
+ ng-packagr: 18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5)
+ tailwindcss: 4.1.11
transitivePeerDependencies:
- '@rspack/core'
- '@swc/core'
@@ -12849,14 +12815,15 @@ snapshots:
- uglify-js
- utf-8-validate
- webpack-cli
+ optional: true
- '@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5)':
+ '@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11)(@types/node@22.15.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5)':
dependencies:
'@ampproject/remapping': 2.3.0
'@angular-devkit/architect': 0.1802.20(chokidar@4.0.3)
- '@angular-devkit/build-webpack': 0.1802.20(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ '@angular-devkit/build-webpack': 0.1802.20(webpack-dev-server@5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
'@angular-devkit/core': 18.2.20(chokidar@4.0.3)
- '@angular/build': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.2.0)(lightningcss@1.30.1)(postcss@8.4.41)(tailwindcss@4.1.11)(terser@5.31.6)(typescript@5.4.5)
+ '@angular/build': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(less@4.2.0)(lightningcss@1.30.1)(postcss@8.4.41)(tailwindcss@4.1.11)(terser@5.31.6)(typescript@5.4.5)
'@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5)
'@babel/core': 7.26.10
'@babel/generator': 7.26.10
@@ -12868,14 +12835,14 @@ snapshots:
'@babel/preset-env': 7.26.9(@babel/core@7.26.10)
'@babel/runtime': 7.26.10
'@discoveryjs/json-ext': 0.6.1
- '@ngtools/webpack': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ '@ngtools/webpack': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
ansi-colors: 4.1.3
autoprefixer: 10.4.20(postcss@8.4.41)
- babel-loader: 9.1.3(@babel/core@7.26.10)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ babel-loader: 9.1.3(@babel/core@7.26.10)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
browserslist: 4.25.1
- copy-webpack-plugin: 12.0.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ copy-webpack-plugin: 12.0.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
critters: 0.0.24
- css-loader: 7.1.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ css-loader: 7.1.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
esbuild-wasm: 0.23.0
fast-glob: 3.3.2
http-proxy-middleware: 3.0.5
@@ -12884,11 +12851,11 @@ snapshots:
jsonc-parser: 3.3.1
karma-source-map-support: 1.4.0
less: 4.2.0
- less-loader: 12.2.0(less@4.2.0)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
- license-webpack-plugin: 4.0.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ less-loader: 12.2.0(less@4.2.0)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
+ license-webpack-plugin: 4.0.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
loader-utils: 3.3.1
magic-string: 0.30.11
- mini-css-extract-plugin: 2.9.0(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ mini-css-extract-plugin: 2.9.0(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
mrmime: 2.0.0
open: 10.1.0
ora: 5.4.1
@@ -12896,24 +12863,24 @@ snapshots:
picomatch: 4.0.2
piscina: 4.6.1
postcss: 8.4.41
- postcss-loader: 8.1.1(postcss@8.4.41)(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ postcss-loader: 8.1.1(postcss@8.4.41)(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
resolve-url-loader: 5.0.0
rxjs: 7.8.1
sass: 1.77.6
- sass-loader: 16.0.0(sass@1.77.6)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ sass-loader: 16.0.0(sass@1.77.6)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
semver: 7.6.3
- source-map-loader: 5.0.0(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ source-map-loader: 5.0.0(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
source-map-support: 0.5.21
terser: 5.31.6
tree-kill: 1.2.2
tslib: 2.6.3
typescript: 5.4.5
watchpack: 2.4.1
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
- webpack-dev-middleware: 7.4.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
- webpack-dev-server: 5.2.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
+ webpack-dev-middleware: 7.4.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
+ webpack-dev-server: 5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
webpack-merge: 6.0.1
- webpack-subresource-integrity: 5.1.0(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ webpack-subresource-integrity: 5.1.0(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)))(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
optionalDependencies:
esbuild: 0.23.0
ng-packagr: 18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5)
@@ -12935,17 +12902,46 @@ snapshots:
- uglify-js
- utf-8-validate
- webpack-cli
+
+ '@angular-devkit/build-webpack@0.1802.20(chokidar@3.6.0)(webpack-dev-server@5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))':
+ dependencies:
+ '@angular-devkit/architect': 0.1802.20(chokidar@3.6.0)
+ rxjs: 7.8.1
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
+ webpack-dev-server: 5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
+ transitivePeerDependencies:
+ - chokidar
+
+ '@angular-devkit/build-webpack@0.1802.20(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))':
+ dependencies:
+ '@angular-devkit/architect': 0.1802.20(chokidar@4.0.3)
+ rxjs: 7.8.1
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
+ webpack-dev-server: 5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
+ transitivePeerDependencies:
+ - chokidar
optional: true
- '@angular-devkit/build-webpack@0.1802.20(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))':
+ '@angular-devkit/build-webpack@0.1802.20(webpack-dev-server@5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))':
dependencies:
'@angular-devkit/architect': 0.1802.20(chokidar@4.0.3)
rxjs: 7.8.1
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
- webpack-dev-server: 5.2.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
+ webpack-dev-server: 5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
transitivePeerDependencies:
- chokidar
+ '@angular-devkit/core@18.2.20(chokidar@3.6.0)':
+ dependencies:
+ ajv: 8.17.1
+ ajv-formats: 3.0.1(ajv@8.17.1)
+ jsonc-parser: 3.3.1
+ picomatch: 4.0.2
+ rxjs: 7.8.1
+ source-map: 0.7.4
+ optionalDependencies:
+ chokidar: 3.6.0
+
'@angular-devkit/core@18.2.20(chokidar@4.0.3)':
dependencies:
ajv: 8.17.1
@@ -12968,7 +12964,7 @@ snapshots:
optionalDependencies:
chokidar: 4.0.3
- '@angular-devkit/schematics@18.2.20(chokidar@4.0.3)':
+ '@angular-devkit/schematics@18.2.20':
dependencies:
'@angular-devkit/core': 18.2.20(chokidar@4.0.3)
jsonc-parser: 3.3.1
@@ -12978,15 +12974,25 @@ snapshots:
transitivePeerDependencies:
- chokidar
+ '@angular-devkit/schematics@18.2.20(chokidar@3.6.0)':
+ dependencies:
+ '@angular-devkit/core': 18.2.20(chokidar@3.6.0)
+ jsonc-parser: 3.3.1
+ magic-string: 0.30.11
+ ora: 5.4.1
+ rxjs: 7.8.1
+ transitivePeerDependencies:
+ - chokidar
+
'@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))':
dependencies:
'@angular/core': 18.2.13(rxjs@7.8.1)(zone.js@0.14.10)
tslib: 2.8.1
- '@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.2.0)(lightningcss@1.30.1)(postcss@8.4.41)(tailwindcss@4.1.11)(terser@5.31.6)(typescript@5.4.5)':
+ '@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@3.6.0)(less@4.2.0)(lightningcss@1.30.1)(postcss@8.4.41)(tailwindcss@3.4.17)(terser@5.31.6)(typescript@5.4.5)':
dependencies:
'@ampproject/remapping': 2.3.0
- '@angular-devkit/architect': 0.1802.20(chokidar@4.0.3)
+ '@angular-devkit/architect': 0.1802.20(chokidar@3.6.0)
'@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5)
'@babel/core': 7.25.2
'@babel/helper-annotate-as-pure': 7.24.7
@@ -13015,7 +13021,7 @@ snapshots:
optionalDependencies:
less: 4.2.0
postcss: 8.4.41
- tailwindcss: 4.1.11
+ tailwindcss: 3.4.17
transitivePeerDependencies:
- '@types/node'
- chokidar
@@ -13026,7 +13032,7 @@ snapshots:
- supports-color
- terser
- '@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.2.0)(lightningcss@1.30.1)(postcss@8.4.41)(tailwindcss@4.1.12)(terser@5.31.6)(typescript@5.4.5)':
+ '@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.2.0)(lightningcss@1.30.1)(postcss@8.4.41)(tailwindcss@4.1.11)(terser@5.31.6)(typescript@5.4.5)':
dependencies:
'@ampproject/remapping': 2.3.0
'@angular-devkit/architect': 0.1802.20(chokidar@4.0.3)
@@ -13058,7 +13064,7 @@ snapshots:
optionalDependencies:
less: 4.2.0
postcss: 8.4.41
- tailwindcss: 4.1.12
+ tailwindcss: 4.1.11
transitivePeerDependencies:
- '@types/node'
- chokidar
@@ -13068,8 +13074,9 @@ snapshots:
- sugarss
- supports-color
- terser
+ optional: true
- '@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5)':
+ '@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(chokidar@4.0.3)(less@4.4.1)(lightningcss@1.30.1)(postcss@8.5.6)(tailwindcss@4.1.11)(terser@5.43.1)(typescript@5.4.5)':
dependencies:
'@ampproject/remapping': 2.3.0
'@angular-devkit/architect': 0.1802.20(chokidar@4.0.3)
@@ -13113,6 +13120,49 @@ snapshots:
- terser
optional: true
+ '@angular/build@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@types/node@22.15.3)(less@4.2.0)(lightningcss@1.30.1)(postcss@8.4.41)(tailwindcss@4.1.11)(terser@5.31.6)(typescript@5.4.5)':
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@angular-devkit/architect': 0.1802.20(chokidar@4.0.3)
+ '@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5)
+ '@babel/core': 7.25.2
+ '@babel/helper-annotate-as-pure': 7.24.7
+ '@babel/helper-split-export-declaration': 7.24.7
+ '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.25.2)
+ '@inquirer/confirm': 3.1.22
+ '@vitejs/plugin-basic-ssl': 1.1.0(vite@5.4.19(@types/node@22.15.3)(less@4.2.0)(lightningcss@1.30.1)(sass@1.77.6)(terser@5.31.6))
+ browserslist: 4.25.1
+ critters: 0.0.24
+ esbuild: 0.23.0
+ fast-glob: 3.3.2
+ https-proxy-agent: 7.0.5
+ listr2: 8.2.4
+ lmdb: 3.0.13
+ magic-string: 0.30.11
+ mrmime: 2.0.0
+ parse5-html-rewriting-stream: 7.0.0
+ picomatch: 4.0.2
+ piscina: 4.6.1
+ rollup: 4.22.4
+ sass: 1.77.6
+ semver: 7.6.3
+ typescript: 5.4.5
+ vite: 5.4.19(@types/node@22.15.3)(less@4.2.0)(lightningcss@1.30.1)(sass@1.77.6)(terser@5.31.6)
+ watchpack: 2.4.1
+ optionalDependencies:
+ less: 4.2.0
+ postcss: 8.4.41
+ tailwindcss: 4.1.11
+ transitivePeerDependencies:
+ - '@types/node'
+ - chokidar
+ - lightningcss
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+
'@angular/cdk@18.2.14(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1)':
dependencies:
'@angular/common': 18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1)
@@ -13122,14 +13172,38 @@ snapshots:
optionalDependencies:
parse5: 7.3.0
- '@angular/cli@18.2.20(chokidar@4.0.3)':
+ '@angular/cli@18.2.20':
dependencies:
'@angular-devkit/architect': 0.1802.20(chokidar@4.0.3)
'@angular-devkit/core': 18.2.20(chokidar@4.0.3)
- '@angular-devkit/schematics': 18.2.20(chokidar@4.0.3)
+ '@angular-devkit/schematics': 18.2.20
+ '@inquirer/prompts': 5.3.8
+ '@listr2/prompt-adapter-inquirer': 2.0.15(@inquirer/prompts@5.3.8)
+ '@schematics/angular': 18.2.20
+ '@yarnpkg/lockfile': 1.1.0
+ ini: 4.1.3
+ jsonc-parser: 3.3.1
+ listr2: 8.2.4
+ npm-package-arg: 11.0.3
+ npm-pick-manifest: 9.1.0
+ pacote: 18.0.6
+ resolve: 1.22.8
+ semver: 7.6.3
+ symbol-observable: 4.0.0
+ yargs: 17.7.2
+ transitivePeerDependencies:
+ - bluebird
+ - chokidar
+ - supports-color
+
+ '@angular/cli@18.2.20(chokidar@3.6.0)':
+ dependencies:
+ '@angular-devkit/architect': 0.1802.20(chokidar@3.6.0)
+ '@angular-devkit/core': 18.2.20(chokidar@3.6.0)
+ '@angular-devkit/schematics': 18.2.20(chokidar@3.6.0)
'@inquirer/prompts': 5.3.8
'@listr2/prompt-adapter-inquirer': 2.0.15(@inquirer/prompts@5.3.8)
- '@schematics/angular': 18.2.20(chokidar@4.0.3)
+ '@schematics/angular': 18.2.20(chokidar@3.6.0)
'@yarnpkg/lockfile': 1.1.0
ini: 4.1.3
jsonc-parser: 3.3.1
@@ -15541,10 +15615,6 @@ snapshots:
optionalDependencies:
'@types/node': 22.15.3
- '@ioredis/as-callback@3.0.0': {}
-
- '@ioredis/commands@1.3.0': {}
-
'@isaacs/balanced-match@4.0.1': {}
'@isaacs/brace-expansion@5.0.0':
@@ -15661,7 +15731,7 @@ snapshots:
- '@opentelemetry/sdk-trace-base'
- openai
- '@langchain/langgraph-sdk@0.0.105(@langchain/core@0.3.73(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.75)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@langchain/langgraph-sdk@0.0.105(@langchain/core@0.3.73(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.75)))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@types/json-schema': 7.0.15
p-queue: 6.6.2
@@ -15669,8 +15739,8 @@ snapshots:
uuid: 9.0.1
optionalDependencies:
'@langchain/core': 0.3.73(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.75))
- react: 18.3.1
- react-dom: 18.3.1(react@18.3.1)
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
'@leichtgewicht/ip-codec@2.0.5': {}
@@ -16186,11 +16256,11 @@ snapshots:
'@next/swc-win32-x64-msvc@15.4.4':
optional: true
- '@ngtools/webpack@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))':
+ '@ngtools/webpack@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))':
dependencies:
'@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5)
typescript: 5.4.5
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
'@nodelib/fs.scandir@2.1.5':
dependencies:
@@ -16364,7 +16434,7 @@ snapshots:
'@pkgjs/parseargs@0.11.0':
optional: true
- '@pmmmwh/react-refresh-webpack-plugin@0.5.17(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-dev-server@5.2.2(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(webpack-hot-middleware@2.26.1)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))':
+ '@pmmmwh/react-refresh-webpack-plugin@0.5.17(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-dev-server@5.2.2(webpack@5.100.0(@swc/core@1.12.11)))(webpack-hot-middleware@2.26.1)(webpack@5.100.0(@swc/core@1.12.11))':
dependencies:
ansi-html: 0.0.9
core-js-pure: 3.44.0
@@ -16374,10 +16444,10 @@ snapshots:
react-refresh: 0.14.2
schema-utils: 4.3.2
source-map: 0.7.4
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
optionalDependencies:
type-fest: 4.41.0
- webpack-dev-server: 5.2.2(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ webpack-dev-server: 5.2.2(webpack@5.100.0(@swc/core@1.12.11))
webpack-hot-middleware: 2.26.1
'@polka/url@1.0.0-next.29': {}
@@ -16881,10 +16951,18 @@ snapshots:
'@rushstack/eslint-patch@1.12.0': {}
- '@schematics/angular@18.2.20(chokidar@4.0.3)':
+ '@schematics/angular@18.2.20':
dependencies:
'@angular-devkit/core': 18.2.20(chokidar@4.0.3)
- '@angular-devkit/schematics': 18.2.20(chokidar@4.0.3)
+ '@angular-devkit/schematics': 18.2.20
+ jsonc-parser: 3.3.1
+ transitivePeerDependencies:
+ - chokidar
+
+ '@schematics/angular@18.2.20(chokidar@3.6.0)':
+ dependencies:
+ '@angular-devkit/core': 18.2.20(chokidar@3.6.0)
+ '@angular-devkit/schematics': 18.2.20(chokidar@3.6.0)
jsonc-parser: 3.3.1
transitivePeerDependencies:
- chokidar
@@ -17249,18 +17327,18 @@ snapshots:
memoizerific: 1.11.3
storybook: 8.6.14(prettier@3.6.0)
- '@storybook/addon-webpack5-compiler-swc@1.0.6(@swc/helpers@0.5.15)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))':
+ '@storybook/addon-webpack5-compiler-swc@1.0.6(webpack@5.100.0(@swc/core@1.12.11))':
dependencies:
- '@swc/core': 1.12.11(@swc/helpers@0.5.15)
- swc-loader: 0.2.6(@swc/core@1.12.11(@swc/helpers@0.5.15))(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ '@swc/core': 1.12.11
+ swc-loader: 0.2.6(@swc/core@1.12.11)(webpack@5.100.0(@swc/core@1.12.11))
transitivePeerDependencies:
- '@swc/helpers'
- webpack
- ? '@storybook/angular@8.6.14(@angular-devkit/architect@0.1902.15(chokidar@4.0.3))(@angular-devkit/build-angular@18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(chokidar@4.0.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5))(@angular-devkit/core@19.2.15(chokidar@4.0.3))(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/cli@18.2.20(chokidar@4.0.3))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(@angular/forms@18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(rxjs@7.8.1))(@angular/platform-browser-dynamic@18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(rxjs@7.8.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.4.5)(zone.js@0.14.10)'
- : dependencies:
+ '@storybook/angular@8.6.14(yd4v6lxii4rfhetgylkhgsqlgq)':
+ dependencies:
'@angular-devkit/architect': 0.1902.15(chokidar@4.0.3)
- '@angular-devkit/build-angular': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11(@swc/helpers@0.5.15))(@types/node@22.15.3)(chokidar@4.0.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5)
+ '@angular-devkit/build-angular': 18.2.20(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(@swc/core@1.12.11)(@types/node@22.15.3)(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)))(lightningcss@1.30.1)(ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5))(tailwindcss@4.1.11)(typescript@5.4.5)
'@angular-devkit/core': 19.2.15(chokidar@4.0.3)
'@angular/common': 18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1)
'@angular/compiler': 18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))
@@ -17269,7 +17347,7 @@ snapshots:
'@angular/forms': 18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(rxjs@7.8.1)
'@angular/platform-browser': 18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))
'@angular/platform-browser-dynamic': 18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))
- '@storybook/builder-webpack5': 8.6.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(storybook@8.6.14(prettier@3.6.0))(typescript@5.4.5)
+ '@storybook/builder-webpack5': 8.6.14(@swc/core@1.12.11)(esbuild@0.25.6)(storybook@8.6.14(prettier@3.6.0))(typescript@5.4.5)
'@storybook/components': 8.6.14(storybook@8.6.14(prettier@3.6.0))
'@storybook/core-webpack': 8.6.14(storybook@8.6.14(prettier@3.6.0))
'@storybook/global': 5.0.0
@@ -17290,10 +17368,10 @@ snapshots:
tsconfig-paths-webpack-plugin: 4.2.0
typescript: 5.4.5
util-deprecate: 1.0.2
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)
optionalDependencies:
'@angular/animations': 18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10))
- '@angular/cli': 18.2.20(chokidar@4.0.3)
+ '@angular/cli': 18.2.20
zone.js: 0.14.10
transitivePeerDependencies:
- '@rspack/core'
@@ -17311,7 +17389,7 @@ snapshots:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- '@storybook/builder-webpack5@8.6.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(storybook@8.6.14(prettier@3.6.0))(typescript@5.4.5)':
+ '@storybook/builder-webpack5@8.6.14(@swc/core@1.12.11)(esbuild@0.25.6)(storybook@8.6.14(prettier@3.6.0))(typescript@5.4.5)':
dependencies:
'@storybook/core-webpack': 8.6.14(storybook@8.6.14(prettier@3.6.0))
'@types/semver': 7.7.0
@@ -17319,23 +17397,23 @@ snapshots:
case-sensitive-paths-webpack-plugin: 2.4.0
cjs-module-lexer: 1.4.3
constants-browserify: 1.0.0
- css-loader: 6.11.0(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ css-loader: 6.11.0(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6))
es-module-lexer: 1.7.0
- fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.4.5)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
- html-webpack-plugin: 5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.4.5)(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6))
+ html-webpack-plugin: 5.6.3(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6))
magic-string: 0.30.17
path-browserify: 1.0.1
process: 0.11.10
semver: 7.7.2
storybook: 8.6.14(prettier@3.6.0)
- style-loader: 3.3.4(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
- terser-webpack-plugin: 5.3.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ style-loader: 3.3.4(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6))
+ terser-webpack-plugin: 5.3.14(@swc/core@1.12.11)(esbuild@0.25.6)(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6))
ts-dedent: 2.2.0
url: 0.11.4
util: 0.12.5
util-deprecate: 1.0.2
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
- webpack-dev-middleware: 6.1.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ webpack: 5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)
+ webpack-dev-middleware: 6.1.3(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6))
webpack-hot-middleware: 2.26.1
webpack-virtual-modules: 0.6.2
optionalDependencies:
@@ -17347,7 +17425,7 @@ snapshots:
- uglify-js
- webpack-cli
- '@storybook/builder-webpack5@8.6.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)':
+ '@storybook/builder-webpack5@8.6.14(@swc/core@1.12.11)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)':
dependencies:
'@storybook/core-webpack': 8.6.14(storybook@8.6.14(prettier@3.6.0))
'@types/semver': 7.7.0
@@ -17355,23 +17433,23 @@ snapshots:
case-sensitive-paths-webpack-plugin: 2.4.0
cjs-module-lexer: 1.4.3
constants-browserify: 1.0.0
- css-loader: 6.11.0(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ css-loader: 6.11.0(webpack@5.100.0(@swc/core@1.12.11))
es-module-lexer: 1.7.0
- fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.2)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
- html-webpack-plugin: 5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.2)(webpack@5.100.0(@swc/core@1.12.11))
+ html-webpack-plugin: 5.6.3(webpack@5.100.0(@swc/core@1.12.11))
magic-string: 0.30.17
path-browserify: 1.0.1
process: 0.11.10
semver: 7.7.2
storybook: 8.6.14(prettier@3.6.0)
- style-loader: 3.3.4(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
- terser-webpack-plugin: 5.3.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ style-loader: 3.3.4(webpack@5.100.0(@swc/core@1.12.11))
+ terser-webpack-plugin: 5.3.14(@swc/core@1.12.11)(webpack@5.100.0(@swc/core@1.12.11))
ts-dedent: 2.2.0
url: 0.11.4
util: 0.12.5
util-deprecate: 1.0.2
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
- webpack-dev-middleware: 6.1.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ webpack: 5.100.0(@swc/core@1.12.11)
+ webpack-dev-middleware: 6.1.3(webpack@5.100.0(@swc/core@1.12.11))
webpack-hot-middleware: 2.26.1
webpack-virtual-modules: 0.6.2
optionalDependencies:
@@ -17435,7 +17513,7 @@ snapshots:
dependencies:
storybook: 8.6.14(prettier@3.6.0)
- '@storybook/nextjs@8.6.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(next@15.4.4(@babel/core@7.28.0)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.90.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.90.0)(storybook@8.6.14(prettier@3.6.0))(type-fest@4.41.0)(typescript@5.8.2)(webpack-dev-server@5.2.2(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(webpack-hot-middleware@2.26.1)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))':
+ '@storybook/nextjs@8.6.14(@swc/core@1.12.11)(next@15.4.4(@babel/core@7.28.0)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.90.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.90.0)(storybook@8.6.14(prettier@3.6.0))(type-fest@4.41.0)(typescript@5.8.2)(webpack-dev-server@5.2.2(webpack@5.100.0(@swc/core@1.12.11)))(webpack-hot-middleware@2.26.1)(webpack@5.100.0(@swc/core@1.12.11))':
dependencies:
'@babel/core': 7.28.0
'@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.0)
@@ -17450,30 +17528,30 @@ snapshots:
'@babel/preset-react': 7.27.1(@babel/core@7.28.0)
'@babel/preset-typescript': 7.27.1(@babel/core@7.28.0)
'@babel/runtime': 7.27.6
- '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-dev-server@5.2.2(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(webpack-hot-middleware@2.26.1)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
- '@storybook/builder-webpack5': 8.6.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
- '@storybook/preset-react-webpack': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
+ '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-dev-server@5.2.2(webpack@5.100.0(@swc/core@1.12.11)))(webpack-hot-middleware@2.26.1)(webpack@5.100.0(@swc/core@1.12.11))
+ '@storybook/builder-webpack5': 8.6.14(@swc/core@1.12.11)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
+ '@storybook/preset-react-webpack': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(@swc/core@1.12.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
'@storybook/react': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
'@storybook/test': 8.6.14(storybook@8.6.14(prettier@3.6.0))
'@types/semver': 7.7.0
- babel-loader: 9.2.1(@babel/core@7.28.0)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
- css-loader: 6.11.0(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ babel-loader: 9.2.1(@babel/core@7.28.0)(webpack@5.100.0(@swc/core@1.12.11))
+ css-loader: 6.11.0(webpack@5.100.0(@swc/core@1.12.11))
find-up: 5.0.0
image-size: 1.2.1
loader-utils: 3.3.1
next: 15.4.4(@babel/core@7.28.0)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.90.0)
- node-polyfill-webpack-plugin: 2.0.1(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ node-polyfill-webpack-plugin: 2.0.1(webpack@5.100.0(@swc/core@1.12.11))
pnp-webpack-plugin: 1.7.0(typescript@5.8.2)
postcss: 8.5.6
- postcss-loader: 8.1.1(postcss@8.5.6)(typescript@5.8.2)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ postcss-loader: 8.1.1(postcss@8.5.6)(typescript@5.8.2)(webpack@5.100.0(@swc/core@1.12.11))
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-refresh: 0.14.2
resolve-url-loader: 5.0.0
- sass-loader: 14.2.1(sass@1.90.0)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ sass-loader: 14.2.1(sass@1.90.0)(webpack@5.100.0(@swc/core@1.12.11))
semver: 7.7.2
storybook: 8.6.14(prettier@3.6.0)
- style-loader: 3.3.4(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ style-loader: 3.3.4(webpack@5.100.0(@swc/core@1.12.11))
styled-jsx: 5.1.7(@babel/core@7.28.0)(react@18.3.1)
ts-dedent: 2.2.0
tsconfig-paths: 4.2.0
@@ -17481,7 +17559,7 @@ snapshots:
optionalDependencies:
sharp: 0.33.5
typescript: 5.8.2
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
transitivePeerDependencies:
- '@rspack/core'
- '@swc/core'
@@ -17500,11 +17578,11 @@ snapshots:
- webpack-hot-middleware
- webpack-plugin-serve
- '@storybook/preset-react-webpack@8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)':
+ '@storybook/preset-react-webpack@8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(@swc/core@1.12.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)':
dependencies:
'@storybook/core-webpack': 8.6.14(storybook@8.6.14(prettier@3.6.0))
'@storybook/react': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
- '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.2)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.2)(webpack@5.100.0(@swc/core@1.12.11))
'@types/semver': 7.7.0
find-up: 5.0.0
magic-string: 0.30.17
@@ -17515,7 +17593,7 @@ snapshots:
semver: 7.7.2
storybook: 8.6.14(prettier@3.6.0)
tsconfig-paths: 4.2.0
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
optionalDependencies:
typescript: 5.8.2
transitivePeerDependencies:
@@ -17530,7 +17608,7 @@ snapshots:
dependencies:
storybook: 8.6.14(prettier@3.6.0)
- '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.2)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))':
+ '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.2)(webpack@5.100.0(@swc/core@1.12.11))':
dependencies:
debug: 4.4.1(supports-color@5.5.0)
endent: 2.1.0
@@ -17540,7 +17618,7 @@ snapshots:
react-docgen-typescript: 2.4.0(typescript@5.8.2)
tslib: 2.8.1
typescript: 5.8.2
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
transitivePeerDependencies:
- supports-color
@@ -17550,10 +17628,10 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
storybook: 8.6.14(prettier@3.6.0)
- '@storybook/react-webpack5@8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)':
+ '@storybook/react-webpack5@8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(@swc/core@1.12.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)':
dependencies:
- '@storybook/builder-webpack5': 8.6.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
- '@storybook/preset-react-webpack': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
+ '@storybook/builder-webpack5': 8.6.14(@swc/core@1.12.11)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
+ '@storybook/preset-react-webpack': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(@swc/core@1.12.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
'@storybook/react': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.6.0)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.14(prettier@3.6.0))(typescript@5.8.2)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
@@ -17629,7 +17707,7 @@ snapshots:
'@swc/core-win32-x64-msvc@1.12.11':
optional: true
- '@swc/core@1.12.11(@swc/helpers@0.5.15)':
+ '@swc/core@1.12.11':
dependencies:
'@swc/counter': 0.1.3
'@swc/types': 0.1.23
@@ -17644,7 +17722,6 @@ snapshots:
'@swc/core-win32-arm64-msvc': 1.12.11
'@swc/core-win32-ia32-msvc': 1.12.11
'@swc/core-win32-x64-msvc': 1.12.11
- '@swc/helpers': 0.5.15
'@swc/counter@0.1.3': {}
@@ -18124,10 +18201,6 @@ snapshots:
dependencies:
'@types/node': 22.15.3
- '@types/ioredis-mock@8.2.6(ioredis@5.7.0)':
- dependencies:
- ioredis: 5.7.0
-
'@types/json-schema@7.0.15': {}
'@types/json5@0.0.29': {}
@@ -18616,18 +18689,6 @@ snapshots:
tinyrainbow: 1.2.0
vitest: 2.1.9(@types/node@22.15.3)(@vitest/ui@2.1.9)(jsdom@24.1.3)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1)
- '@vitest/ui@3.2.4(vitest@2.1.9)':
- dependencies:
- '@vitest/utils': 3.2.4
- fflate: 0.8.2
- flatted: 3.3.3
- pathe: 2.0.3
- sirv: 3.0.1
- tinyglobby: 0.2.14
- tinyrainbow: 2.0.0
- vitest: 2.1.9(@types/node@22.15.3)(@vitest/ui@3.2.4)(jsdom@26.1.0)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1)
- optional: true
-
'@vitest/ui@3.2.4(vitest@3.2.4)':
dependencies:
'@vitest/utils': 3.2.4
@@ -19047,19 +19108,19 @@ snapshots:
b4a@1.6.7: {}
- babel-loader@9.1.3(@babel/core@7.26.10)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ babel-loader@9.1.3(@babel/core@7.26.10)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
'@babel/core': 7.26.10
find-cache-dir: 4.0.0
schema-utils: 4.3.2
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
- babel-loader@9.2.1(@babel/core@7.28.0)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ babel-loader@9.2.1(@babel/core@7.28.0)(webpack@5.100.0(@swc/core@1.12.11)):
dependencies:
'@babel/core': 7.28.0
find-cache-dir: 4.0.0
schema-utils: 4.3.2
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.26.10):
dependencies:
@@ -19511,8 +19572,6 @@ snapshots:
clsx@2.1.1: {}
- cluster-key-slot@1.1.2: {}
-
code-block-writer@12.0.0: {}
code-excerpt@4.0.0:
@@ -19631,7 +19690,7 @@ snapshots:
dependencies:
is-what: 3.14.1
- copy-webpack-plugin@12.0.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ copy-webpack-plugin@12.0.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
fast-glob: 3.3.3
glob-parent: 6.0.2
@@ -19639,7 +19698,7 @@ snapshots:
normalize-path: 3.0.0
schema-utils: 4.3.2
serialize-javascript: 6.0.2
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
core-js-compat@3.44.0:
dependencies:
@@ -19748,7 +19807,20 @@ snapshots:
randombytes: 2.1.0
randomfill: 1.0.4
- css-loader@6.11.0(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ css-loader@6.11.0(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)):
+ dependencies:
+ icss-utils: 5.1.0(postcss@8.5.6)
+ postcss: 8.5.6
+ postcss-modules-extract-imports: 3.1.0(postcss@8.5.6)
+ postcss-modules-local-by-default: 4.2.0(postcss@8.5.6)
+ postcss-modules-scope: 3.2.1(postcss@8.5.6)
+ postcss-modules-values: 4.0.0(postcss@8.5.6)
+ postcss-value-parser: 4.2.0
+ semver: 7.7.2
+ optionalDependencies:
+ webpack: 5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)
+
+ css-loader@6.11.0(webpack@5.100.0(@swc/core@1.12.11)):
dependencies:
icss-utils: 5.1.0(postcss@8.5.6)
postcss: 8.5.6
@@ -19759,9 +19831,9 @@ snapshots:
postcss-value-parser: 4.2.0
semver: 7.7.2
optionalDependencies:
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
- css-loader@7.1.2(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ css-loader@7.1.2(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)):
dependencies:
icss-utils: 5.1.0(postcss@8.5.6)
postcss: 8.5.6
@@ -19772,9 +19844,9 @@ snapshots:
postcss-value-parser: 4.2.0
semver: 7.7.2
optionalDependencies:
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)
- css-loader@7.1.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ css-loader@7.1.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
icss-utils: 5.1.0(postcss@8.5.6)
postcss: 8.5.6
@@ -19785,7 +19857,7 @@ snapshots:
postcss-value-parser: 4.2.0
semver: 7.7.2
optionalDependencies:
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
css-select@4.3.0:
dependencies:
@@ -20131,8 +20203,6 @@ snapshots:
delayed-stream@1.0.0: {}
- denque@2.1.0: {}
-
depd@1.1.2: {}
depd@2.0.0: {}
@@ -21072,16 +21142,6 @@ snapshots:
optionalDependencies:
picomatch: 4.0.3
- fengari-interop@0.1.3(fengari@0.1.4):
- dependencies:
- fengari: 0.1.4
-
- fengari@0.1.4:
- dependencies:
- readline-sync: 1.4.10
- sprintf-js: 1.1.3
- tmp: 0.0.33
-
fetch-blob@3.2.0:
dependencies:
node-domexception: 1.0.0
@@ -21184,7 +21244,7 @@ snapshots:
cross-spawn: 7.0.6
signal-exit: 4.1.0
- fork-ts-checker-webpack-plugin@8.0.0(typescript@5.4.5)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ fork-ts-checker-webpack-plugin@8.0.0(typescript@5.4.5)(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)):
dependencies:
'@babel/code-frame': 7.27.1
chalk: 4.1.2
@@ -21199,9 +21259,9 @@ snapshots:
semver: 7.7.2
tapable: 2.2.2
typescript: 5.4.5
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)
- fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.2)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.2)(webpack@5.100.0(@swc/core@1.12.11)):
dependencies:
'@babel/code-frame': 7.27.1
chalk: 4.1.2
@@ -21216,7 +21276,7 @@ snapshots:
semver: 7.7.2
tapable: 2.2.2
typescript: 5.8.2
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
form-data-encoder@1.7.2: {}
@@ -21735,7 +21795,17 @@ snapshots:
html-void-elements@3.0.0: {}
- html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)):
+ dependencies:
+ '@types/html-minifier-terser': 6.1.0
+ html-minifier-terser: 6.1.0
+ lodash: 4.17.21
+ pretty-error: 4.0.0
+ tapable: 2.2.2
+ optionalDependencies:
+ webpack: 5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)
+
+ html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11)):
dependencies:
'@types/html-minifier-terser': 6.1.0
html-minifier-terser: 6.1.0
@@ -21743,9 +21813,9 @@ snapshots:
pretty-error: 4.0.0
tapable: 2.2.2
optionalDependencies:
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
- html-webpack-plugin@5.6.3(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ html-webpack-plugin@5.6.3(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
'@types/html-minifier-terser': 6.1.0
html-minifier-terser: 6.1.0
@@ -21753,7 +21823,7 @@ snapshots:
pretty-error: 4.0.0
tapable: 2.2.2
optionalDependencies:
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
optional: true
htmlparser2@6.1.0:
@@ -21988,30 +22058,6 @@ snapshots:
internmap@2.0.3: {}
- ioredis-mock@8.9.0(@types/ioredis-mock@8.2.6(ioredis@5.7.0))(ioredis@5.7.0):
- dependencies:
- '@ioredis/as-callback': 3.0.0
- '@ioredis/commands': 1.3.0
- '@types/ioredis-mock': 8.2.6(ioredis@5.7.0)
- fengari: 0.1.4
- fengari-interop: 0.1.3(fengari@0.1.4)
- ioredis: 5.7.0
- semver: 7.7.2
-
- ioredis@5.7.0:
- dependencies:
- '@ioredis/commands': 1.3.0
- cluster-key-slot: 1.1.2
- debug: 4.4.1(supports-color@5.5.0)
- denque: 2.1.0
- lodash.defaults: 4.2.0
- lodash.isarguments: 3.1.0
- redis-errors: 1.2.0
- redis-parser: 3.0.0
- standard-as-callback: 2.1.0
- transitivePeerDependencies:
- - supports-color
-
ip-address@9.0.5:
dependencies:
jsbn: 1.1.0
@@ -22455,8 +22501,6 @@ snapshots:
kolorist@1.8.0: {}
- kysely@0.28.5: {}
-
langium@3.3.1:
dependencies:
chevrotain: 11.0.3
@@ -22497,11 +22541,11 @@ snapshots:
dependencies:
gcd: 0.0.1
- less-loader@12.2.0(less@4.2.0)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ less-loader@12.2.0(less@4.2.0)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
less: 4.2.0
optionalDependencies:
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
less@4.2.0:
dependencies:
@@ -22540,11 +22584,11 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
- license-webpack-plugin@4.0.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ license-webpack-plugin@4.0.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
webpack-sources: 3.3.3
optionalDependencies:
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
lightningcss-darwin-arm64@1.30.1:
optional: true
@@ -22671,10 +22715,6 @@ snapshots:
lodash.debounce@4.0.8: {}
- lodash.defaults@4.2.0: {}
-
- lodash.isarguments@3.1.0: {}
-
lodash.isplainobject@4.0.6: {}
lodash.merge@4.6.2: {}
@@ -23369,11 +23409,11 @@ snapshots:
min-indent@1.0.1: {}
- mini-css-extract-plugin@2.9.0(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ mini-css-extract-plugin@2.9.0(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
schema-utils: 4.3.2
tapable: 2.2.2
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
minimalistic-assert@1.0.1: {}
@@ -23578,7 +23618,7 @@ snapshots:
- '@babel/core'
- babel-plugin-macros
- next@15.4.4(@babel/core@7.28.0)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.90.0):
+ next@15.4.4(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.90.0):
dependencies:
'@next/env': 15.4.4
'@swc/helpers': 0.5.15
@@ -23586,7 +23626,7 @@ snapshots:
postcss: 8.4.31
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
- styled-jsx: 5.1.6(@babel/core@7.28.0)(react@19.1.0)
+ styled-jsx: 5.1.6(react@19.1.0)
optionalDependencies:
'@next/swc-darwin-arm64': 15.4.4
'@next/swc-darwin-x64': 15.4.4
@@ -23603,7 +23643,7 @@ snapshots:
- '@babel/core'
- babel-plugin-macros
- ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5):
+ ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@3.4.17)(tslib@2.8.1)(typescript@5.4.5):
dependencies:
'@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5)
'@rollup/plugin-json': 6.1.0(rollup@4.45.1)
@@ -23632,9 +23672,10 @@ snapshots:
typescript: 5.4.5
optionalDependencies:
rollup: 4.45.1
- tailwindcss: 4.1.11
+ tailwindcss: 3.4.17
+ optional: true
- ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.12)(tslib@2.8.1)(typescript@5.4.5):
+ ng-packagr@18.2.1(@angular/compiler-cli@18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(tailwindcss@4.1.11)(tslib@2.8.1)(typescript@5.4.5):
dependencies:
'@angular/compiler-cli': 18.2.13(@angular/compiler@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5)
'@rollup/plugin-json': 6.1.0(rollup@4.45.1)
@@ -23663,8 +23704,7 @@ snapshots:
typescript: 5.4.5
optionalDependencies:
rollup: 4.45.1
- tailwindcss: 4.1.12
- optional: true
+ tailwindcss: 4.1.11
nice-napi@1.0.2:
dependencies:
@@ -23748,7 +23788,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- node-polyfill-webpack-plugin@2.0.1(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ node-polyfill-webpack-plugin@2.0.1(webpack@5.100.0(@swc/core@1.12.11)):
dependencies:
assert: 2.1.0
browserify-zlib: 0.2.0
@@ -23775,7 +23815,7 @@ snapshots:
url: 0.11.4
util: 0.12.5
vm-browserify: 1.1.2
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
node-releases@2.0.19: {}
@@ -24347,36 +24387,36 @@ snapshots:
tsx: 4.20.5
yaml: 2.8.0
- postcss-loader@8.1.1(postcss@8.4.41)(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ postcss-loader@8.1.1(postcss@8.4.41)(typescript@5.4.5)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
cosmiconfig: 9.0.0(typescript@5.4.5)
jiti: 1.21.7
postcss: 8.4.41
semver: 7.7.2
optionalDependencies:
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
transitivePeerDependencies:
- typescript
- postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.4.5)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.4.5)(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)):
dependencies:
cosmiconfig: 9.0.0(typescript@5.4.5)
jiti: 1.21.7
postcss: 8.5.6
semver: 7.7.2
optionalDependencies:
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)
transitivePeerDependencies:
- typescript
- postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.8.2)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.8.2)(webpack@5.100.0(@swc/core@1.12.11)):
dependencies:
cosmiconfig: 9.0.0(typescript@5.8.2)
jiti: 1.21.7
postcss: 8.5.6
semver: 7.7.2
optionalDependencies:
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
transitivePeerDependencies:
- typescript
@@ -24759,8 +24799,6 @@ snapshots:
readdirp@4.1.2: {}
- readline-sync@1.4.10: {}
-
recast@0.23.11:
dependencies:
ast-types: 0.16.1
@@ -24804,12 +24842,6 @@ snapshots:
indent-string: 4.0.0
strip-indent: 3.0.0
- redis-errors@1.2.0: {}
-
- redis-parser@3.0.0:
- dependencies:
- redis-errors: 1.2.0
-
reflect-metadata@0.2.2: {}
reflect.getprototypeof@1.0.10:
@@ -25230,19 +25262,19 @@ snapshots:
safer-buffer@2.1.2: {}
- sass-loader@14.2.1(sass@1.90.0)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ sass-loader@14.2.1(sass@1.90.0)(webpack@5.100.0(@swc/core@1.12.11)):
dependencies:
neo-async: 2.6.2
optionalDependencies:
sass: 1.90.0
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
- sass-loader@16.0.0(sass@1.77.6)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ sass-loader@16.0.0(sass@1.77.6)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
neo-async: 2.6.2
optionalDependencies:
sass: 1.77.6
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
sass@1.77.6:
dependencies:
@@ -25655,11 +25687,11 @@ snapshots:
source-map-js@1.2.1: {}
- source-map-loader@5.0.0(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ source-map-loader@5.0.0(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
iconv-lite: 0.6.3
source-map-js: 1.2.1
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
source-map-support@0.5.21:
dependencies:
@@ -25729,8 +25761,6 @@ snapshots:
stackframe@1.3.4: {}
- standard-as-callback@2.1.0: {}
-
statuses@1.5.0: {}
statuses@2.0.1: {}
@@ -25900,13 +25930,17 @@ snapshots:
dependencies:
js-tokens: 9.0.1
- style-loader@3.3.4(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ style-loader@3.3.4(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)):
dependencies:
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)
- style-loader@4.0.0(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ style-loader@3.3.4(webpack@5.100.0(@swc/core@1.12.11)):
dependencies:
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
+
+ style-loader@4.0.0(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)):
+ dependencies:
+ webpack: 5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)
style-to-js@1.1.17:
dependencies:
@@ -25923,12 +25957,10 @@ snapshots:
optionalDependencies:
'@babel/core': 7.28.0
- styled-jsx@5.1.6(@babel/core@7.28.0)(react@19.1.0):
+ styled-jsx@5.1.6(react@19.1.0):
dependencies:
client-only: 0.0.1
react: 19.1.0
- optionalDependencies:
- '@babel/core': 7.28.0
styled-jsx@5.1.7(@babel/core@7.28.0)(react@18.3.1):
dependencies:
@@ -25978,11 +26010,11 @@ snapshots:
deep-rename-keys: 0.2.1
xml-reader: 2.4.3
- swc-loader@0.2.6(@swc/core@1.12.11(@swc/helpers@0.5.15))(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ swc-loader@0.2.6(@swc/core@1.12.11)(webpack@5.100.0(@swc/core@1.12.11)):
dependencies:
- '@swc/core': 1.12.11(@swc/helpers@0.5.15)
+ '@swc/core': 1.12.11
'@swc/counter': 0.1.3
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
symbol-observable@4.0.0: {}
@@ -26078,30 +26110,41 @@ snapshots:
dependencies:
memoizerific: 1.11.3
- terser-webpack-plugin@5.3.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ terser-webpack-plugin@5.3.14(@swc/core@1.12.11)(esbuild@0.23.0)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
'@jridgewell/trace-mapping': 0.3.29
jest-worker: 27.5.1
schema-utils: 4.3.2
serialize-javascript: 6.0.2
terser: 5.43.1
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
optionalDependencies:
- '@swc/core': 1.12.11(@swc/helpers@0.5.15)
- esbuild: 0.25.6
+ '@swc/core': 1.12.11
+ esbuild: 0.23.0
- terser-webpack-plugin@5.3.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ terser-webpack-plugin@5.3.14(@swc/core@1.12.11)(esbuild@0.25.6)(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)):
dependencies:
'@jridgewell/trace-mapping': 0.3.29
jest-worker: 27.5.1
schema-utils: 4.3.2
serialize-javascript: 6.0.2
terser: 5.43.1
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)
optionalDependencies:
- '@swc/core': 1.12.11(@swc/helpers@0.5.15)
+ '@swc/core': 1.12.11
esbuild: 0.25.6
+ terser-webpack-plugin@5.3.14(@swc/core@1.12.11)(webpack@5.100.0(@swc/core@1.12.11)):
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.29
+ jest-worker: 27.5.1
+ schema-utils: 4.3.2
+ serialize-javascript: 6.0.2
+ terser: 5.43.1
+ webpack: 5.100.0(@swc/core@1.12.11)
+ optionalDependencies:
+ '@swc/core': 1.12.11
+
terser@5.31.6:
dependencies:
'@jridgewell/source-map': 0.3.10
@@ -26277,7 +26320,7 @@ snapshots:
tslib@2.8.1: {}
- tsup@8.5.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0):
+ tsup@8.5.0(@swc/core@1.12.11)(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.8.2)(yaml@2.8.0):
dependencies:
bundle-require: 5.1.0(esbuild@0.25.6)
cac: 6.7.14
@@ -26297,7 +26340,7 @@ snapshots:
tinyglobby: 0.2.14
tree-kill: 1.2.2
optionalDependencies:
- '@swc/core': 1.12.11(@swc/helpers@0.5.15)
+ '@swc/core': 1.12.11
postcss: 8.5.6
typescript: 5.8.2
transitivePeerDependencies:
@@ -26859,7 +26902,7 @@ snapshots:
- supports-color
- terser
- vitest@2.1.9(@types/node@22.15.3)(@vitest/ui@3.2.4)(jsdom@26.1.0)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1):
+ vitest@2.1.9(@types/node@22.15.3)(@vitest/ui@2.1.9)(jsdom@26.1.0)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1):
dependencies:
'@vitest/expect': 2.1.9
'@vitest/mocker': 2.1.9(vite@5.4.19(@types/node@22.15.3)(less@4.4.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.43.1))
@@ -26883,7 +26926,7 @@ snapshots:
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 22.15.3
- '@vitest/ui': 3.2.4(vitest@2.1.9)
+ '@vitest/ui': 2.1.9(vitest@2.1.9)
jsdom: 26.1.0
transitivePeerDependencies:
- less
@@ -26997,7 +27040,7 @@ snapshots:
webidl-conversions@7.0.0: {}
- webpack-dev-middleware@6.1.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ webpack-dev-middleware@6.1.3(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)):
dependencies:
colorette: 2.0.20
memfs: 3.5.3
@@ -27005,9 +27048,19 @@ snapshots:
range-parser: 1.2.1
schema-utils: 4.3.2
optionalDependencies:
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)
- webpack-dev-middleware@7.4.2(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ webpack-dev-middleware@6.1.3(webpack@5.100.0(@swc/core@1.12.11)):
+ dependencies:
+ colorette: 2.0.20
+ memfs: 3.5.3
+ mime-types: 2.1.35
+ range-parser: 1.2.1
+ schema-utils: 4.3.2
+ optionalDependencies:
+ webpack: 5.100.0(@swc/core@1.12.11)
+
+ webpack-dev-middleware@7.4.2(webpack@5.100.0(@swc/core@1.12.11)):
dependencies:
colorette: 2.0.20
memfs: 4.36.3
@@ -27016,9 +27069,10 @@ snapshots:
range-parser: 1.2.1
schema-utils: 4.3.2
optionalDependencies:
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
+ optional: true
- webpack-dev-middleware@7.4.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ webpack-dev-middleware@7.4.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
colorette: 2.0.20
memfs: 4.36.3
@@ -27027,9 +27081,9 @@ snapshots:
range-parser: 1.2.1
schema-utils: 4.3.2
optionalDependencies:
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
- webpack-dev-server@5.2.2(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)):
+ webpack-dev-server@5.2.2(webpack@5.100.0(@swc/core@1.12.11)):
dependencies:
'@types/bonjour': 3.5.13
'@types/connect-history-api-fallback': 1.5.4
@@ -27057,17 +27111,18 @@ snapshots:
serve-index: 1.9.1
sockjs: 0.3.24
spdy: 4.0.2
- webpack-dev-middleware: 7.4.2(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ webpack-dev-middleware: 7.4.2(webpack@5.100.0(@swc/core@1.12.11))
ws: 8.18.3
optionalDependencies:
- webpack: 5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.100.0(@swc/core@1.12.11)
transitivePeerDependencies:
- bufferutil
- debug
- supports-color
- utf-8-validate
+ optional: true
- webpack-dev-server@5.2.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ webpack-dev-server@5.2.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
'@types/bonjour': 3.5.13
'@types/connect-history-api-fallback': 1.5.4
@@ -27095,10 +27150,10 @@ snapshots:
serve-index: 1.9.1
sockjs: 0.3.24
spdy: 4.0.2
- webpack-dev-middleware: 7.4.2(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ webpack-dev-middleware: 7.4.2(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
ws: 8.18.3
optionalDependencies:
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
transitivePeerDependencies:
- bufferutil
- debug
@@ -27119,23 +27174,55 @@ snapshots:
webpack-sources@3.3.3: {}
- webpack-subresource-integrity@5.1.0(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)))(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ webpack-subresource-integrity@5.1.0(html-webpack-plugin@5.6.3(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6)))(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
typed-assert: 1.0.9
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
optionalDependencies:
- html-webpack-plugin: 5.6.3(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ html-webpack-plugin: 5.6.3(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6))
- webpack-subresource-integrity@5.1.0(html-webpack-plugin@5.6.3(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0)):
+ webpack-subresource-integrity@5.1.0(html-webpack-plugin@5.6.3(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)))(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)):
dependencies:
typed-assert: 1.0.9
- webpack: 5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)
+ webpack: 5.94.0(@swc/core@1.12.11)(esbuild@0.23.0)
optionalDependencies:
- html-webpack-plugin: 5.6.3(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ html-webpack-plugin: 5.6.3(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
webpack-virtual-modules@0.6.2: {}
- webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6):
+ webpack@5.100.0(@swc/core@1.12.11):
+ dependencies:
+ '@types/eslint-scope': 3.7.7
+ '@types/estree': 1.0.8
+ '@types/json-schema': 7.0.15
+ '@webassemblyjs/ast': 1.14.1
+ '@webassemblyjs/wasm-edit': 1.14.1
+ '@webassemblyjs/wasm-parser': 1.14.1
+ acorn: 8.15.0
+ acorn-import-phases: 1.0.3(acorn@8.15.0)
+ browserslist: 4.25.1
+ chrome-trace-event: 1.0.4
+ enhanced-resolve: 5.18.2
+ es-module-lexer: 1.7.0
+ eslint-scope: 5.1.1
+ events: 3.3.0
+ glob-to-regexp: 0.4.1
+ graceful-fs: 4.2.11
+ json-parse-even-better-errors: 2.3.1
+ loader-runner: 4.3.0
+ mime-types: 2.1.35
+ neo-async: 2.6.2
+ schema-utils: 4.3.2
+ tapable: 2.2.2
+ terser-webpack-plugin: 5.3.14(@swc/core@1.12.11)(webpack@5.100.0(@swc/core@1.12.11))
+ watchpack: 2.4.4
+ webpack-sources: 3.3.3
+ transitivePeerDependencies:
+ - '@swc/core'
+ - esbuild
+ - uglify-js
+
+ webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6):
dependencies:
'@types/eslint-scope': 3.7.7
'@types/estree': 1.0.8
@@ -27159,7 +27246,7 @@ snapshots:
neo-async: 2.6.2
schema-utils: 4.3.2
tapable: 2.2.2
- terser-webpack-plugin: 5.3.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(webpack@5.100.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6))
+ terser-webpack-plugin: 5.3.14(@swc/core@1.12.11)(esbuild@0.25.6)(webpack@5.100.0(@swc/core@1.12.11)(esbuild@0.25.6))
watchpack: 2.4.4
webpack-sources: 3.3.3
transitivePeerDependencies:
@@ -27167,7 +27254,7 @@ snapshots:
- esbuild
- uglify-js
- webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6):
+ webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0):
dependencies:
'@types/estree': 1.0.8
'@webassemblyjs/ast': 1.14.1
@@ -27189,7 +27276,7 @@ snapshots:
neo-async: 2.6.2
schema-utils: 3.3.0
tapable: 2.2.2
- terser-webpack-plugin: 5.3.14(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.25.6)(webpack@5.94.0(@swc/core@1.12.11(@swc/helpers@0.5.15))(esbuild@0.23.0))
+ terser-webpack-plugin: 5.3.14(@swc/core@1.12.11)(esbuild@0.23.0)(webpack@5.94.0(@swc/core@1.12.11)(esbuild@0.23.0))
watchpack: 2.4.4
webpack-sources: 3.3.3
transitivePeerDependencies: