@copilotkit/runtime 1.70.3 → 1.71.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/agent/index.cjs +5 -1
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.d.cts +1 -1
  4. package/dist/agent/index.d.cts.map +1 -1
  5. package/dist/agent/index.d.mts +1 -1
  6. package/dist/agent/index.d.mts.map +1 -1
  7. package/dist/agent/index.mjs +5 -1
  8. package/dist/agent/index.mjs.map +1 -1
  9. package/dist/package.cjs +3 -3
  10. package/dist/package.mjs +3 -3
  11. package/package.json +5 -6
  12. package/skills/runtime/SKILL.md +0 -98
  13. package/skills/runtime/references/agent-runners-custom.md +0 -161
  14. package/skills/runtime/references/agent-runners-in-memory.md +0 -79
  15. package/skills/runtime/references/agent-runners-sqlite.md +0 -90
  16. package/skills/runtime/references/agent-runners.md +0 -336
  17. package/skills/runtime/references/built-in-agent-factory-modes.md +0 -232
  18. package/skills/runtime/references/built-in-agent-helper-utilities.md +0 -123
  19. package/skills/runtime/references/built-in-agent-model-identifiers.md +0 -58
  20. package/skills/runtime/references/built-in-agent.md +0 -523
  21. package/skills/runtime/references/intelligence-mode.md +0 -364
  22. package/skills/runtime/references/middleware.md +0 -376
  23. package/skills/runtime/references/server-side-tools.md +0 -414
  24. package/skills/runtime/references/setup-endpoint.md +0 -503
  25. package/skills/runtime/references/transcription.md +0 -287
  26. package/skills/runtime/references/wiring-a2a.md +0 -40
  27. package/skills/runtime/references/wiring-adk.md +0 -45
  28. package/skills/runtime/references/wiring-ag2.md +0 -41
  29. package/skills/runtime/references/wiring-agno.md +0 -40
  30. package/skills/runtime/references/wiring-aws-strands.md +0 -59
  31. package/skills/runtime/references/wiring-crewai-crews.md +0 -51
  32. package/skills/runtime/references/wiring-crewai-flows.md +0 -45
  33. package/skills/runtime/references/wiring-external-agents.md +0 -348
  34. package/skills/runtime/references/wiring-langgraph.md +0 -49
  35. package/skills/runtime/references/wiring-llamaindex.md +0 -39
  36. package/skills/runtime/references/wiring-mastra.md +0 -70
  37. package/skills/runtime/references/wiring-mcp-apps-middleware.md +0 -73
  38. package/skills/runtime/references/wiring-ms-agent-framework.md +0 -41
  39. package/skills/runtime/references/wiring-pydantic-ai.md +0 -45
@@ -1,98 +0,0 @@
1
- ---
2
- name: runtime
3
- description: >
4
- @copilotkit/runtime — mount a fetch-native CopilotRuntime on any JS server, wire
5
- middleware, pick an AgentRunner, instantiate BuiltInAgent (Factory Mode with TanStack AI
6
- is the preferred default) or plug in any of 12 external agent frameworks (Mastra,
7
- LangGraph, CrewAI Crews/Flows, PydanticAI, ADK, LlamaIndex, Agno, AWS Strands, MS Agent
8
- Framework, AG2, A2A), enable Intelligence mode for durable threads + websocket,
9
- register server-side tools via defineTool, and wire voice transcription. Uses the
10
- fetch-based createCopilotRuntimeHandler primitive — the Express/Hono adapters are
11
- discouraged. Load the reference under references/ that matches your task.
12
- type: core
13
- library: copilotkit
14
- library_version: "1.70.3"
15
- requires: []
16
- sources:
17
- - "CopilotKit/CopilotKit:packages/runtime/src/v2/runtime/core/fetch-handler.ts"
18
- - "CopilotKit/CopilotKit:packages/runtime/src/v2/runtime/core/runtime.ts"
19
- - "CopilotKit/CopilotKit:packages/runtime/src/v2/runtime/core/hooks.ts"
20
- - "CopilotKit/CopilotKit:packages/runtime/src/v2/runtime/core/middleware.ts"
21
- - "CopilotKit/CopilotKit:packages/runtime/src/v2/runtime/runner/agent-runner.ts"
22
- - "CopilotKit/CopilotKit:packages/runtime/src/v2/runtime/runner/in-memory.ts"
23
- - "CopilotKit/CopilotKit:packages/runtime/src/v2/runtime/runner/intelligence.ts"
24
- - "CopilotKit/CopilotKit:packages/runtime/src/v2/runtime/intelligence-platform/client.ts"
25
- - "CopilotKit/CopilotKit:packages/runtime/src/v2/runtime/transcription-service/transcription-service.ts"
26
- - "CopilotKit/CopilotKit:packages/runtime/src/v2/runtime/handlers/handle-transcribe.ts"
27
- - "CopilotKit/CopilotKit:packages/runtime/src/agent/index.ts"
28
- - "CopilotKit/CopilotKit:packages/runtime/src/agent/converters/tanstack.ts"
29
- - "CopilotKit/CopilotKit:packages/sqlite-runner/src/sqlite-runner.ts"
30
- - "CopilotKit/CopilotKit:packages/shared/src/transcription-errors.ts"
31
- ---
32
-
33
- # CopilotKit Runtime
34
-
35
- `@copilotkit/runtime` is the server half of CopilotKit: it accepts AG-UI protocol
36
- requests, dispatches them to an `AbstractAgent` (built-in or external), runs the
37
- stream through an `AgentRunner`, and responds as Server-Sent Events.
38
-
39
- This SKILL.md is the **index**. Read the reference under `references/` that matches
40
- your task — do not try to absorb the whole package from this file.
41
-
42
- ## Mental Model — the three dictionaries you hand to `CopilotRuntime`
43
-
44
- ```ts
45
- new CopilotRuntime({
46
- agents, // Record<string, AbstractAgent> — see wiring-external-agents or built-in-agent
47
- runner, // AgentRunner (optional) — see agent-runners
48
- intelligence, // CopilotKitIntelligence (optional) — see intelligence-mode (auto-wires runner)
49
- mcpApps, // McpAppsConfig (optional) — see wiring-mcp-apps-middleware
50
- a2ui, // A2UIConfig (optional) — see packages/a2ui-renderer skill
51
- hooks, // { onRequest, onBeforeHandler } — see middleware
52
- beforeRequestMiddleware,
53
- afterRequestMiddleware, // legacy — see middleware
54
- transcription, // TranscriptionService (optional) — see transcription
55
- });
56
- ```
57
-
58
- You then mount it:
59
-
60
- ```ts
61
- import { createCopilotRuntimeHandler } from "@copilotkit/runtime/v2";
62
- const handler = createCopilotRuntimeHandler({
63
- runtime,
64
- basePath: "/api/copilotkit",
65
- });
66
- export default { fetch: handler };
67
- ```
68
-
69
- ## When to load which reference
70
-
71
- | Task | Reference |
72
- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
73
- | Mounting on any fetch-native server (Cloudflare Workers, Bun, Deno, Vercel Edge, Next.js App Router, React Router v7, TanStack Start) or delegating from Express/Node | `references/setup-endpoint.md` |
74
- | Auth / logging / rate-limit / request-scoped guards via `hooks.onRequest` / `hooks.onBeforeHandler` (preferred) or legacy `beforeRequestMiddleware` / `afterRequestMiddleware` | `references/middleware.md` |
75
- | Choosing between `InMemoryAgentRunner`, `SqliteAgentRunner`, or a custom subclass — including thread-locking semantics and the runner/Intelligence mutual exclusion | `references/agent-runners.md` (+ `-in-memory.md`, `-sqlite.md`, `-custom.md` for backend-specific detail) |
76
- | Enabling durable threads + realtime websocket via CopilotKit Intelligence (a **managed service**, not self-hostable) | `references/intelligence-mode.md` |
77
- | Voice transcription — implementing a `TranscriptionService` subclass for the `/transcribe` endpoint | `references/transcription.md` |
78
- | Instantiating `BuiltInAgent` — Simple Mode (classic) or Factory Mode with TanStack AI (preferred AG-UI-compliant default), AI SDK, or custom factory | `references/built-in-agent.md` (+ `-factory-modes.md`, `-helper-utilities.md`, `-model-identifiers.md`) |
79
- | Defining server-side tools via `defineTool` for `BuiltInAgent.config.tools` (Simple Mode only) | `references/server-side-tools.md` |
80
- | Wiring an external agent framework into `CopilotRuntime({ agents })` | `references/wiring-external-agents.md` (index) + per-framework refs (`wiring-mastra.md`, `wiring-langgraph.md`, `wiring-crewai-crews.md`, `wiring-crewai-flows.md`, `wiring-pydantic-ai.md`, `wiring-adk.md`, `wiring-llamaindex.md`, `wiring-agno.md`, `wiring-aws-strands.md`, `wiring-ms-agent-framework.md`, `wiring-ag2.md`, `wiring-a2a.md`) |
81
- | Wiring MCP Apps (runtime-level middleware, not an agent) | `references/wiring-mcp-apps-middleware.md` |
82
-
83
- ## Invariants and gotchas (load-once, before any reference)
84
-
85
- - `createCopilotRuntimeHandler` is the canonical primitive. `createCopilotExpressHandler` / `createCopilotHonoHandler` exist but are **avoid at all costs** — delegate from Express/Hono routes to the fetch primitive instead.
86
- - `publicLicenseKey` is the canonical provider-side field. `publicApiKey` is a **deprecated alias** — expect to see it in legacy code, emit the canonical name in new code.
87
- - Intelligence mode auto-wires `IntelligenceAgentRunner`. Passing both `runner` and `intelligence` to `CopilotRuntime` is rejected at construction.
88
- - Intelligence mode targets the managed CopilotKit Intelligence service (`api.cloud.copilotkit.ai`) and is **not self-hostable**.
89
- - `hooks.onRequest` runs **before** `beforeRequestMiddleware` (hook-based middleware wins for Response short-circuits). `beforeRequestMiddleware` runs **after** `hooks.onRequest` (see `fetch-handler.ts:136-147`).
90
- - `identifyUser` (Intelligence) does **not** forward thrown `Response` objects — convert to 500. Gate auth rejection in `hooks.onRequest`, which does forward Responses.
91
- - `agents__unsafe_dev_only` and `selfManagedAgents` are dev-only aliases of each other; do not reach for them in production. Either signals that the SPA is in dev mode.
92
-
93
- ## Reading order for a first-time reader
94
-
95
- 1. `setup-endpoint` — the primitive.
96
- 2. `built-in-agent` **or** pick one from `wiring-external-agents` — the agent.
97
- 3. `agent-runners` — production persistence choice.
98
- 4. Optional: `middleware`, `intelligence-mode`, `server-side-tools`, `transcription`.
@@ -1,161 +0,0 @@
1
- Custom AgentRunner — subclass the abstract `AgentRunner` to back thread state with Redis,
2
- Postgres, Durable Objects, or anything else you own.
3
-
4
- ## The abstract contract
5
-
6
- ```typescript
7
- // packages/runtime/src/v2/runtime/runner/agent-runner.ts
8
- import {
9
- AbstractAgent,
10
- BaseEvent,
11
- Message,
12
- RunAgentInput,
13
- } from "@ag-ui/client";
14
- import { Observable } from "rxjs";
15
-
16
- export interface AgentRunnerRunRequest {
17
- threadId: string;
18
- agent: AbstractAgent;
19
- input: RunAgentInput;
20
- joinCode?: string;
21
- persistedInputMessages?: Message[];
22
- }
23
- export interface AgentRunnerConnectRequest {
24
- threadId: string;
25
- headers?: Record<string, string>;
26
- joinCode?: string;
27
- }
28
- export interface AgentRunnerIsRunningRequest {
29
- threadId: string;
30
- }
31
- export interface AgentRunnerStopRequest {
32
- threadId: string;
33
- }
34
-
35
- export abstract class AgentRunner {
36
- abstract run(request: AgentRunnerRunRequest): Observable<BaseEvent>;
37
- abstract connect(request: AgentRunnerConnectRequest): Observable<BaseEvent>;
38
- abstract isRunning(request: AgentRunnerIsRunningRequest): Promise<boolean>;
39
- abstract stop(request: AgentRunnerStopRequest): Promise<boolean | undefined>;
40
- }
41
- ```
42
-
43
- ## Redis-backed skeleton (for reference)
44
-
45
- ```typescript
46
- import { AgentRunner } from "@copilotkit/runtime/v2";
47
- import type {
48
- AgentRunnerRunRequest,
49
- AgentRunnerConnectRequest,
50
- AgentRunnerIsRunningRequest,
51
- AgentRunnerStopRequest,
52
- } from "@copilotkit/runtime/v2";
53
- import { Observable, ReplaySubject } from "rxjs";
54
- import type { BaseEvent } from "@ag-ui/client";
55
- import { Redis } from "ioredis";
56
-
57
- const RUNNING_KEY = (t: string) => `copilotkit:running:${t}`;
58
- const STREAM_KEY = (t: string) => `copilotkit:stream:${t}`;
59
-
60
- export class RedisAgentRunner extends AgentRunner {
61
- constructor(private redis: Redis) {
62
- super();
63
- }
64
-
65
- run(request: AgentRunnerRunRequest): Observable<BaseEvent> {
66
- const { threadId, agent, input } = request;
67
- const subject = new ReplaySubject<BaseEvent>();
68
-
69
- (async () => {
70
- // NX guard — return 409-equivalent if another instance is running this thread
71
- const acquired = await this.redis.set(
72
- RUNNING_KEY(threadId),
73
- "1",
74
- "EX",
75
- 600,
76
- "NX",
77
- );
78
- if (!acquired) {
79
- subject.error(new Error("Thread already running"));
80
- return;
81
- }
82
-
83
- const sub = agent.run(input).subscribe({
84
- next: async (event) => {
85
- subject.next(event);
86
- await this.redis.xadd(
87
- STREAM_KEY(threadId),
88
- "*",
89
- "event",
90
- JSON.stringify(event),
91
- );
92
- },
93
- error: async (err) => {
94
- subject.error(err);
95
- await this.redis.del(RUNNING_KEY(threadId));
96
- },
97
- complete: async () => {
98
- subject.complete();
99
- await this.redis.del(RUNNING_KEY(threadId));
100
- },
101
- });
102
-
103
- // stop hook
104
- this.stopHandlers.set(threadId, () => sub.unsubscribe());
105
- })();
106
-
107
- return subject.asObservable();
108
- }
109
-
110
- connect(request: AgentRunnerConnectRequest): Observable<BaseEvent> {
111
- const subject = new ReplaySubject<BaseEvent>();
112
- (async () => {
113
- const entries = await this.redis.xrange(
114
- STREAM_KEY(request.threadId),
115
- "-",
116
- "+",
117
- );
118
- for (const [, fields] of entries) {
119
- const eventStr = fields[1];
120
- if (eventStr) subject.next(JSON.parse(eventStr));
121
- }
122
- subject.complete();
123
- })();
124
- return subject.asObservable();
125
- }
126
-
127
- async isRunning(request: AgentRunnerIsRunningRequest): Promise<boolean> {
128
- return (await this.redis.exists(RUNNING_KEY(request.threadId))) === 1;
129
- }
130
-
131
- async stop(request: AgentRunnerStopRequest): Promise<boolean | undefined> {
132
- const stop = this.stopHandlers.get(request.threadId);
133
- if (stop) {
134
- stop();
135
- this.stopHandlers.delete(request.threadId);
136
- }
137
- await this.redis.del(RUNNING_KEY(request.threadId));
138
- return true;
139
- }
140
-
141
- private stopHandlers = new Map<string, () => void>();
142
- }
143
- ```
144
-
145
- ## Contract gotchas
146
-
147
- - `run()` must throw `Error("Thread already running")` (or let a distributed lock return a
148
- non-acquired state) when a run is already active. Intelligence mode surfaces the 409 to
149
- the client as the typed `agent_thread_locked` error code; SSE mode (direct runner use)
150
- only emits a generic 500 response with the error message — so clients cannot depend on
151
- the typed code there, and should additionally guard with a busy flag on submit.
152
- - `connect()` must replay historic events so late clients can catch up on an active run.
153
- - `stop()` is optional to implement in the sense that returning `undefined` is allowed, but
154
- surface cancellations through `abortController.abort()` to the underlying agent if you can.
155
- - The runner does not persist user messages on its own — that is CopilotKit Intelligence's
156
- job. A custom runner that persists only its own event stream is still a drop-in replacement
157
- for `InMemoryAgentRunner` / `SqliteAgentRunner`.
158
-
159
- Source: `packages/runtime/src/v2/runtime/runner/agent-runner.ts`,
160
- `packages/runtime/src/v2/runtime/runner/in-memory.ts`,
161
- `packages/sqlite-runner/src/sqlite-runner.ts`.
@@ -1,79 +0,0 @@
1
- InMemoryAgentRunner — default ephemeral runner. Thread state lives in a bounded, process-global store shared by every runner instance in the process.
2
-
3
- ## Store layout
4
-
5
- ```typescript
6
- // packages/runtime/src/v2/runtime/runner/in-memory.ts
7
- export const ɵGLOBAL_STORE = new ɵBoundedThreadStore(ɵINMEMORY_DEFAULTS);
8
- ```
9
-
10
- `ɵBoundedThreadStore` owns the `Map<threadId, InMemoryEventStore>`, LRU ordering, byte accounting, and eviction. The runner keeps all streaming logic and delegates storage to the store. The `ɵ` prefix marks internal API — exported for tests, not part of the public surface.
11
-
12
- One `InMemoryEventStore` per `threadId`. Each store tracks:
13
-
14
- - `subject: ReplaySubject<BaseEvent> | null` — current consumers; released on run completion
15
- - `isRunning: boolean` — gate for the `"Thread already running"` throw
16
- - `currentRunId: string | null`
17
- - `historicRuns: HistoricRun[]` — completed runs (events only; see snapshot note below)
18
- - `messagesSnapshot: Message[]` — the thread's latest non-empty message snapshot, held at the THREAD level so run-cap eviction can never drop it
19
- - `agent: AbstractAgent | null` — the instance that owns the active run
20
- - `runSubject`, `currentEvents`, `stopRequested`
21
-
22
- ## Bounds
23
-
24
- Three limits, whichever trips first. Defaults in `ɵINMEMORY_DEFAULTS`:
25
-
26
- | Option | Default | Enforcement |
27
- | ------------------ | ------- | -------------------------------------------------------------- |
28
- | `maxThreads` | `1000` | LRU eviction of the least-recently-used thread |
29
- | `maxRunsPerThread` | `100` | FIFO drop of oldest runs; `Infinity` or `0` disables |
30
- | `maxBytes` | 512 MiB | Approximate total across all threads; evicts OTHER LRU threads |
31
-
32
- ```typescript
33
- new InMemoryAgentRunner({
34
- maxThreads: 200,
35
- maxRunsPerThread: 50,
36
- maxBytes: 128 * 1024 ** 2,
37
- });
38
- ```
39
-
40
- Invariants worth knowing before touching this code:
41
-
42
- - A thread is never evicted while `isRunning` **or** `stopRequested` is set. `stop()` flips `isRunning` false immediately but the run finalizes asynchronously; evicting in that window would make the pending `appendRun` silently drop history.
43
- - `maxBytes` only bounds **committed** history. A single in-flight run's buffered events are not counted until the run completes, so it does not bound one runaway run mid-stream.
44
- - `maxBytes` evicts other threads and never self-evicts the just-appended thread — it is a cross-thread ceiling, not a per-thread cap. A single dominant thread is bounded by `maxRunsPerThread`.
45
- - Byte accounting is a `JSON.stringify().length` estimate, not exact heap bytes.
46
- - Two eviction forms, both steering heavy users to an Intelligence backend via one shared warn-once latch. Whole-thread eviction (`maxThreads` count or `maxBytes` ceiling) drops the entire LRU thread — it stops appearing in `GET /threads`. Per-thread `maxRunsPerThread` trimming drops only a thread's oldest runs' events, keeping the thread visible with its original `createdAt` and its thread-level `messagesSnapshot`. The latch fires **once per store** (not once per eviction), reset only by `clearThreads()`/`clear()`, so a hot thread trimming on every append logs a single line and every later eviction is silent until a clear.
47
-
48
- ## Concurrency
49
-
50
- `onConcurrentRun` is per-runner (unlike the limits, which are process-global):
51
-
52
- - `"throw"` (default) — a second `run()` on a live thread throws `Error("Thread already running")`.
53
- - `"supersede"` — aborts the in-flight run (same path as `stop()`) and starts the new one. The superseded run's teardown is guarded on `store.currentRunId === request.input.runId` (so it cannot push history under the new run's id or reset the new run's state) and on `store.subject === nextSubject` (so releasing its ReplaySubject cannot null out the live run's subject).
54
-
55
- ## Lifecycle
56
-
57
- 1. `run({ threadId, agent, input })` — `sharedStore.getOrCreate(threadId)` (may evict other threads), then throw or supersede per `onConcurrentRun`. Create `ReplaySubject`s, run the agent, push events into the subjects and `currentEvents`, mark `isRunning`.
58
- 2. On completion or error: finalize, `sharedStore.appendRun(...)` with the compacted events (which enforces the run cap and byte ceiling), clear `isRunning` / `currentRunId` / `agent`, and release `store.subject` so the infinite ReplaySubject buffer becomes collectable. History is rebuilt from `historicRuns` afterwards.
59
- 3. `connect({ threadId })` — replays compacted `historicRuns`, then bridges the live subject while `isRunning || stopRequested`.
60
- 4. `stop({ threadId })` — sets `stopRequested = true`, aborts the agent; teardown runs in the run's `catch`.
61
-
62
- ## Config scope gotcha
63
-
64
- Limits reconfigure the shared store, so the **last-constructed runner wins for all in-memory threads**. A second runner passing limits that differ from an already-customized store logs a one-time clobber warning. Passing only `onConcurrentRun` leaves the limits untouched.
65
-
66
- ## When NOT to use
67
-
68
- - Multi-instance production deploys — each process has its own store.
69
- - Anywhere history loss is unacceptable — eviction is history loss, same as a restart.
70
- - Load-balanced serverless with cold starts — new workers see empty stores.
71
-
72
- ## When it is OK
73
-
74
- - Local development.
75
- - Single-instance preview environments.
76
- - Production single-instance deploys where scrollback is best-effort — the bounds make this safe against OOM, not durable.
77
- - Tests. Every `new InMemoryAgentRunner()` shares the same store, so use a fresh `threadId` per test or call `runner.clearThreads()` (which resets the map, byte total, and eviction warn latch) between tests. Tests that customize limits must restore them: `new InMemoryAgentRunner(ɵINMEMORY_DEFAULTS)` in an `afterEach` — a no-arg construction is inert and will NOT restore defaults.
78
-
79
- Source: `packages/runtime/src/v2/runtime/runner/in-memory.ts`.
@@ -1,90 +0,0 @@
1
- SqliteAgentRunner — file-backed agent runner in `@copilotkit/sqlite-runner`. Uses `better-sqlite3` as a required peer dep.
2
-
3
- ## Install
4
-
5
- ```bash
6
- pnpm add @copilotkit/sqlite-runner better-sqlite3
7
- ```
8
-
9
- If `better-sqlite3` is missing, the `import` of `@copilotkit/sqlite-runner` itself fails
10
- at module load (`Cannot find module 'better-sqlite3'`). The runner's constructor has a
11
- friendlier multi-line install hint as a fallback, but you will see the bare resolution
12
- error first — install the peer before the runner import resolves.
13
-
14
- ## Configure
15
-
16
- ```typescript
17
- import { CopilotRuntime } from "@copilotkit/runtime/v2";
18
- import { SqliteAgentRunner } from "@copilotkit/sqlite-runner";
19
-
20
- const runtime = new CopilotRuntime({
21
- agents: {
22
- /* ... */
23
- } as any,
24
- runner: new SqliteAgentRunner({
25
- dbPath: "./data/threads.db", // REQUIRED — default is ":memory:"
26
- }),
27
- });
28
- ```
29
-
30
- `dbPath: ":memory:"` is the default if omitted — that reverts to an in-memory store and
31
- loses data at restart. Always set a file path in production.
32
-
33
- ## Schema
34
-
35
- Three tables are created on first use (`packages/sqlite-runner/src/sqlite-runner.ts:75-109`):
36
-
37
- ```sql
38
- CREATE TABLE IF NOT EXISTS agent_runs (
39
- id INTEGER PRIMARY KEY AUTOINCREMENT,
40
- thread_id TEXT NOT NULL,
41
- run_id TEXT NOT NULL UNIQUE,
42
- parent_run_id TEXT,
43
- events TEXT NOT NULL, -- JSON-encoded BaseEvent[]
44
- input TEXT NOT NULL, -- JSON-encoded RunAgentInput
45
- created_at INTEGER NOT NULL,
46
- version INTEGER NOT NULL
47
- );
48
- CREATE TABLE IF NOT EXISTS run_state (
49
- thread_id TEXT PRIMARY KEY,
50
- is_running INTEGER DEFAULT 0,
51
- current_run_id TEXT,
52
- updated_at INTEGER NOT NULL
53
- );
54
- CREATE TABLE IF NOT EXISTS schema_version (
55
- version INTEGER PRIMARY KEY,
56
- applied_at INTEGER NOT NULL
57
- );
58
- CREATE INDEX IF NOT EXISTS idx_thread_id ON agent_runs(thread_id);
59
- CREATE INDEX IF NOT EXISTS idx_parent_run_id ON agent_runs(parent_run_id);
60
- ```
61
-
62
- `agent_runs` is append-only — one row per completed run, full event log in the `events`
63
- column. `run_state` gates concurrent runs (the `"Thread already running"` check).
64
- `schema_version` tracks applied migrations so future releases can upgrade existing
65
- databases in place.
66
-
67
- ## Retention
68
-
69
- There is no automatic retention. If you need bounded history, add a periodic purge:
70
-
71
- ```typescript
72
- import Database from "better-sqlite3";
73
-
74
- const db = new Database("./data/threads.db");
75
- setInterval(
76
- () => {
77
- const cutoff = Date.now() - 30 * 24 * 60 * 60 * 1000; // 30 days
78
- db.prepare("DELETE FROM agent_runs WHERE created_at < ?").run(cutoff);
79
- },
80
- 60 * 60 * 1000,
81
- );
82
- ```
83
-
84
- ## When NOT to use
85
-
86
- - Multi-instance deploys without shared storage — each instance would have its own DB file.
87
- Either put the DB on a shared volume (EFS, persistent disk) with a single writer, or
88
- choose Intelligence mode or a custom Redis/Postgres runner.
89
-
90
- Source: `packages/sqlite-runner/src/sqlite-runner.ts`.