@botbotgo/agent-harness 0.0.251 → 0.0.253

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 (46) hide show
  1. package/README.md +13 -14
  2. package/README.zh.md +11 -12
  3. package/dist/api.d.ts +13 -6
  4. package/dist/api.js +70 -6
  5. package/dist/config/agents/direct.yaml +3 -3
  6. package/dist/config/agents/orchestra.yaml +3 -3
  7. package/dist/config/catalogs/stores.yaml +3 -9
  8. package/dist/config/runtime/workspace.yaml +1 -2
  9. package/dist/contracts/runtime.d.ts +9 -14
  10. package/dist/flow/build-flow-graph.js +198 -67
  11. package/dist/flow/export-mermaid.js +314 -4
  12. package/dist/flow/export-sequence-mermaid.js +149 -2
  13. package/dist/flow/types.d.ts +11 -1
  14. package/dist/index.d.ts +2 -3
  15. package/dist/index.js +1 -1
  16. package/dist/package-version.d.ts +1 -1
  17. package/dist/package-version.js +1 -1
  18. package/dist/persistence/file-store.d.ts +3 -2
  19. package/dist/persistence/file-store.js +34 -8
  20. package/dist/persistence/sqlite-store.d.ts +2 -2
  21. package/dist/persistence/sqlite-store.js +64 -11
  22. package/dist/persistence/types.d.ts +3 -3
  23. package/dist/protocol/a2a/http.js +2 -4
  24. package/dist/resource/isolation.js +30 -2
  25. package/dist/runtime/harness/events/streaming.js +8 -8
  26. package/dist/runtime/harness/run/inspection.d.ts +2 -0
  27. package/dist/runtime/harness/run/inspection.js +91 -46
  28. package/dist/runtime/harness/run/stream-run.d.ts +2 -2
  29. package/dist/runtime/harness/run/stream-run.js +34 -23
  30. package/dist/runtime/harness/run/surface-semantics.d.ts +14 -0
  31. package/dist/runtime/harness/run/surface-semantics.js +106 -0
  32. package/dist/runtime/harness/run/thread-records.js +2 -34
  33. package/dist/runtime/harness/system/store.d.ts +6 -4
  34. package/dist/runtime/harness/system/store.js +76 -42
  35. package/dist/runtime/harness.js +5 -7
  36. package/dist/runtime/maintenance/checkpoint-maintenance.js +4 -119
  37. package/dist/runtime/maintenance/index.d.ts +0 -1
  38. package/dist/runtime/maintenance/index.js +0 -1
  39. package/dist/runtime/support/runtime-factories.js +2 -42
  40. package/dist/upstream-events.js +14 -0
  41. package/dist/utils/fs.js +3 -0
  42. package/package.json +1 -3
  43. package/dist/runtime/maintenance/sqlite-maintained-checkpoint-saver.d.ts +0 -9
  44. package/dist/runtime/maintenance/sqlite-maintained-checkpoint-saver.js +0 -39
  45. package/dist/runtime/support/sqlite-drivers.d.ts +0 -12
  46. package/dist/runtime/support/sqlite-drivers.js +0 -24
@@ -2,7 +2,7 @@ import { AGENT_INTERRUPT_SENTINEL_PREFIX, RuntimeOperationTimeoutError } from ".
2
2
  import { renderRuntimeFailure, renderToolFailure } from "../../support/harness-support.js";
3
3
  import { getBindingPrimaryModel } from "../../support/compiled-binding.js";
4
4
  import { createContentBlocksItem, createToolResultKey, } from "../events/streaming.js";
5
- import { consumeRunInspectionUpstreamEvent, projectRuntimeSurfaceFromSingleUpstreamEvent } from "./inspection.js";
5
+ import { projectRuntimeSurfaceFromSingleUpstreamEvent } from "./inspection.js";
6
6
  import { formatAgentName } from "../../../utils/agent-display.js";
7
7
  function normalizeStreamChunk(chunk) {
8
8
  if (typeof chunk === "string") {
@@ -73,44 +73,55 @@ export async function* streamHarnessRun(options) {
73
73
  const normalizedChunk = normalizeStreamChunk(rawChunk);
74
74
  if (normalizedChunk.kind === "upstream-event") {
75
75
  upstreamEventOrdinal += 1;
76
+ const projectionBinding = options.getBinding(currentAgentId) ?? options.binding;
76
77
  const surfaceProjection = projectRuntimeSurfaceFromSingleUpstreamEvent({
77
78
  event: {
78
79
  agentId: currentAgentId,
79
80
  agentName: currentAgentName,
80
81
  event: normalizedChunk.event,
81
82
  },
82
- binding: options.binding,
83
+ binding: projectionBinding,
83
84
  currentAgentId,
84
85
  currentAgentName,
85
- sourceEventId: `upstream:${upstreamEventOrdinal}`,
86
- });
87
- const inspection = consumeRunInspectionUpstreamEvent({
88
- event: normalizedChunk.event,
89
- currentAgentId,
90
86
  delegationChain,
91
- binding: options.binding,
87
+ sourceEventId: `upstream:${upstreamEventOrdinal}`,
92
88
  });
93
- currentAgentId = inspection.currentAgentId;
94
- currentAgentName = formatAgentName(currentAgentId);
95
- delegationChain = inspection.delegationChain;
89
+ currentAgentId = surfaceProjection.currentAgentId;
90
+ currentAgentName = surfaceProjection.currentAgentName;
91
+ delegationChain = surfaceProjection.delegationChain;
96
92
  await options.updateRunInspection(options.threadId, options.runId, {
97
93
  currentAgentId,
98
94
  delegationChain,
99
- appendUpstreamEvent: {
95
+ });
96
+ if (surfaceProjection.items.length === 0) {
97
+ await options.appendRunTraceItem(options.threadId, options.runId, {
100
98
  agentId: currentAgentId,
101
99
  agentName: currentAgentName,
102
100
  event: normalizedChunk.event,
103
- },
104
- });
105
- yield {
106
- type: "upstream-event",
107
- threadId: options.threadId,
108
- runId: options.runId,
109
- agentId: currentAgentId,
110
- agentName: currentAgentName,
111
- surfaceItems: surfaceProjection.items,
112
- event: normalizedChunk.event,
113
- };
101
+ });
102
+ yield {
103
+ type: "upstream-event",
104
+ threadId: options.threadId,
105
+ runId: options.runId,
106
+ event: normalizedChunk.event,
107
+ };
108
+ continue;
109
+ }
110
+ for (const surfaceItem of surfaceProjection.items) {
111
+ await options.appendRunTraceItem(options.threadId, options.runId, {
112
+ agentId: surfaceItem.agentId ?? currentAgentId,
113
+ agentName: surfaceItem.agentName ?? currentAgentName,
114
+ surfaceItem,
115
+ event: normalizedChunk.event,
116
+ });
117
+ yield {
118
+ type: "upstream-event",
119
+ threadId: options.threadId,
120
+ runId: options.runId,
121
+ surfaceItem,
122
+ event: normalizedChunk.event,
123
+ };
124
+ }
114
125
  continue;
115
126
  }
116
127
  nonUpstreamStreamActivityObserved = true;
@@ -0,0 +1,14 @@
1
+ import type { CompiledAgentBinding, RuntimeSurfaceKind } from "../../../contracts/types.js";
2
+ export declare function normalizeSurfaceToken(value: string): string;
3
+ export declare function buildSurfaceId(kind: RuntimeSurfaceKind, value: string): string;
4
+ export declare function stripStepPrefix(label: string): string;
5
+ export declare function resolveSurfaceDisplayName(input: {
6
+ kind: RuntimeSurfaceKind;
7
+ step: string;
8
+ binding?: CompiledAgentBinding;
9
+ }): string;
10
+ export declare function resolveSurfaceAction(input: {
11
+ kind: RuntimeSurfaceKind;
12
+ step?: string;
13
+ event?: unknown;
14
+ }): string;
@@ -0,0 +1,106 @@
1
+ import { readSkillMetadata } from "../../support/skill-metadata.js";
2
+ import { formatAgentName } from "../../../utils/agent-display.js";
3
+ import { getBindingMemorySources, getBindingSkills, } from "../../support/compiled-binding.js";
4
+ function asObject(value) {
5
+ return typeof value === "object" && value !== null ? value : null;
6
+ }
7
+ function readStringArray(value) {
8
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.trim().length > 0) : [];
9
+ }
10
+ function normalizeLabel(value) {
11
+ return value.replace(/\s+/g, " ").trim();
12
+ }
13
+ export function normalizeSurfaceToken(value) {
14
+ return value
15
+ .toLowerCase()
16
+ .replace(/[^a-z0-9]+/g, "-")
17
+ .replace(/^-+|-+$/g, "")
18
+ .slice(0, 80) || "item";
19
+ }
20
+ export function buildSurfaceId(kind, value) {
21
+ void kind;
22
+ return normalizeSurfaceToken(value);
23
+ }
24
+ export function stripStepPrefix(label) {
25
+ return normalizeLabel(label)
26
+ .replace(/^Calling LLM\s+/i, "")
27
+ .replace(/^Completed LLM\s+/i, "")
28
+ .replace(/^Calling tool\s+/i, "")
29
+ .replace(/^Completed tool\s+/i, "")
30
+ .replace(/^Tool\s+/i, "")
31
+ .replace(/\s+failed$/i, "")
32
+ .replace(/^Calling skill\s+/i, "")
33
+ .replace(/^Completed skill\s+/i, "")
34
+ .replace(/^Accessing memory\s+/i, "")
35
+ .replace(/^Completed memory\s+/i, "");
36
+ }
37
+ function isGenericMemoryMiddlewareName(value) {
38
+ return /^(memorymiddleware\.before[_\s]?agent|memory middleware before agent)$/i.test(normalizeLabel(value));
39
+ }
40
+ function canonicalMemoryName(memorySource) {
41
+ const normalized = normalizeLabel(memorySource.replace(/^memory\//i, ""));
42
+ const segments = normalized.split(/[\\/]/).filter(Boolean);
43
+ return (segments.at(-1) ?? normalized).toLowerCase() || "memory";
44
+ }
45
+ function isGenericSkillMiddlewareName(value) {
46
+ return /^(skillsmiddleware\.before[_\s]?agent|skills middleware before agent)$/i.test(normalizeLabel(value));
47
+ }
48
+ export function resolveSurfaceDisplayName(input) {
49
+ const baseName = stripStepPrefix(input.step) || formatAgentName(input.kind);
50
+ if (input.kind === "memory" && input.binding && isGenericMemoryMiddlewareName(baseName)) {
51
+ const memorySources = getBindingMemorySources(input.binding).filter((name) => name.trim().length > 0);
52
+ return memorySources.length === 1 ? canonicalMemoryName(memorySources[0]) : baseName;
53
+ }
54
+ if (input.kind !== "skill" || !input.binding || !isGenericSkillMiddlewareName(baseName)) {
55
+ return baseName;
56
+ }
57
+ const skillNames = getBindingSkills(input.binding)
58
+ .map((skillPath) => readSkillMetadata(skillPath).name)
59
+ .filter((name) => typeof name === "string" && name.trim().length > 0);
60
+ return skillNames.length === 1 ? skillNames[0] : baseName;
61
+ }
62
+ function normalizeActionHint(value) {
63
+ return value
64
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
65
+ .replace(/[.:/]+/g, " ")
66
+ .replace(/[_-]+/g, " ")
67
+ .replace(/\s+/g, " ")
68
+ .trim()
69
+ .toLowerCase();
70
+ }
71
+ function resolveMemoryAction(event, step) {
72
+ const typed = asObject(event);
73
+ const hints = [
74
+ typeof typed?.event === "string" ? typed.event : "",
75
+ typeof typed?.name === "string" ? typed.name : "",
76
+ typeof typed?.run_type === "string" ? typed.run_type : "",
77
+ ...readStringArray(typed?.tags),
78
+ ...readStringArray(typed?.ns),
79
+ step,
80
+ ].map(normalizeActionHint);
81
+ if (hints.some((value) => /\b(store|memorize|sync|formation|ingestion|archive|write)\b/.test(value))) {
82
+ return "memorize";
83
+ }
84
+ if (hints.some((value) => /\b(recall|retrieve|memorymiddleware|before agent|checkpoint|context)\b/.test(value)
85
+ || value.includes("accessing memory")
86
+ || value.includes("access memory"))) {
87
+ return "recall";
88
+ }
89
+ return "access";
90
+ }
91
+ export function resolveSurfaceAction(input) {
92
+ switch (input.kind) {
93
+ case "agent":
94
+ return "handoff";
95
+ case "llm":
96
+ return "call";
97
+ case "tool":
98
+ return "execute";
99
+ case "skill":
100
+ return "apply";
101
+ case "memory":
102
+ return resolveMemoryAction(input.event, input.step ?? "");
103
+ default:
104
+ return "run";
105
+ }
106
+ }
@@ -1,41 +1,13 @@
1
1
  import { isTerminalRunState, toInspectableApprovalRecord } from "./helpers.js";
2
2
  import { projectRuntimeTimeline } from "../events/timeline.js";
3
- import { createUpstreamTimelineReducer } from "../../../upstream-events.js";
4
- import { projectRuntimeSurfaceFromUpstreamEvents } from "./inspection.js";
5
- function unwrapPersistedUpstreamEvent(event) {
6
- if (typeof event !== "object" || event === null || Array.isArray(event)) {
7
- return event;
8
- }
9
- const typed = event;
10
- if (Object.prototype.hasOwnProperty.call(typed, "event")
11
- && typeof typed.event === "object"
12
- && typed.event !== null
13
- && !Array.isArray(typed.event)) {
14
- return typed.event;
15
- }
16
- return event;
17
- }
18
3
  function selectLatestPendingApproval(approvals) {
19
4
  return approvals
20
5
  .filter((approval) => approval.status === "pending")
21
6
  .sort((left, right) => right.requestedAt.localeCompare(left.requestedAt))[0];
22
7
  }
23
- function buildRunInspectionProjection(upstreamEvents) {
24
- const reducer = createUpstreamTimelineReducer();
25
- const history = upstreamEvents.flatMap((event) => reducer.consume(unwrapPersistedUpstreamEvent(event)));
26
- return {
27
- upstreamEvents,
28
- history,
29
- };
30
- }
31
8
  export async function buildRequestInspectionRecord(persistence, request) {
32
9
  const inspection = await persistence.getRunInspection(request.threadId, request.runId);
33
10
  const runtimeEvents = await persistence.listRunEvents(request.threadId, request.runId);
34
- const { upstreamEvents, history } = buildRunInspectionProjection(inspection.upstreamEvents);
35
- const runtimeSurface = projectRuntimeSurfaceFromUpstreamEvents({
36
- upstreamEvents,
37
- initialAgentId: request.agentId ?? inspection.currentAgentId ?? "agent",
38
- });
39
11
  return {
40
12
  requestId: request.runId,
41
13
  sessionId: request.threadId,
@@ -54,9 +26,7 @@ export async function buildRequestInspectionRecord(persistence, request) {
54
26
  currentAgentId: request.currentAgentId,
55
27
  delegationChain: request.delegationChain,
56
28
  runtimeSnapshot: request.runtimeSnapshot,
57
- upstreamEvents,
58
- history,
59
- runtimeSurface,
29
+ traceItems: inspection.traceItems,
60
30
  runtimeTimeline: projectRuntimeTimeline(runtimeEvents, {
61
31
  threadId: request.threadId,
62
32
  runId: request.runId,
@@ -82,9 +52,7 @@ function toRunRecord(request) {
82
52
  currentAgentId: request.currentAgentId,
83
53
  delegationChain: request.delegationChain,
84
54
  runtimeSnapshot: request.runtimeSnapshot,
85
- upstreamEvents: request.upstreamEvents,
86
- history: request.history,
87
- runtimeSurface: request.runtimeSurface,
55
+ traceItems: request.traceItems,
88
56
  runtimeTimeline: request.runtimeTimeline,
89
57
  };
90
58
  }
@@ -51,8 +51,13 @@ export declare class FileBackedStore {
51
51
  }
52
52
  export declare class SqliteBackedStore {
53
53
  readonly filePath: string;
54
- private readonly db;
54
+ private client;
55
+ private initialized;
56
+ private initialization;
55
57
  constructor(filePath: string);
58
+ private getClient;
59
+ private ensureInitialized;
60
+ private selectAll;
56
61
  batch(operations: Array<Record<string, unknown>>): Promise<readonly unknown[]>;
57
62
  get(namespace: string[], key: string): Promise<{
58
63
  value: unknown;
@@ -61,7 +66,6 @@ export declare class SqliteBackedStore {
61
66
  createdAt: Date;
62
67
  updatedAt: Date;
63
68
  } | null>;
64
- private getSync;
65
69
  search(namespacePrefix: string[]): Promise<Array<{
66
70
  value: unknown;
67
71
  key: string;
@@ -71,9 +75,7 @@ export declare class SqliteBackedStore {
71
75
  score?: number;
72
76
  }>>;
73
77
  put(namespace: string[], key: string, value: Record<string, any>, _index?: false | string[]): Promise<void>;
74
- private putSync;
75
78
  delete(namespace: string[], key: string): Promise<void>;
76
- private deleteSync;
77
79
  listNamespaces(): Promise<string[][]>;
78
80
  }
79
81
  export declare function createInMemoryStore(): StoreLike;
@@ -2,7 +2,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { mkdirSync } from "node:fs";
3
3
  import path from "node:path";
4
4
  import { InMemoryStore } from "@langchain/langgraph";
5
- import { loadBetterSqlite3 } from "../../support/sqlite-drivers.js";
5
+ import { createClient } from "@libsql/client";
6
6
  const NAMESPACE_SEPARATOR = "\u001f";
7
7
  function encodeValue(value) {
8
8
  if (value instanceof Date) {
@@ -148,83 +148,117 @@ export class FileBackedStore {
148
148
  }
149
149
  export class SqliteBackedStore {
150
150
  filePath;
151
- db;
151
+ client = null;
152
+ initialized = false;
153
+ initialization = null;
152
154
  constructor(filePath) {
153
155
  this.filePath = filePath;
154
156
  mkdirSync(path.dirname(filePath), { recursive: true });
155
- const SqliteDatabase = loadBetterSqlite3();
156
- this.db = new SqliteDatabase(filePath);
157
- this.db.pragma("journal_mode = WAL");
158
- this.db.exec(`
159
- CREATE TABLE IF NOT EXISTS store_entries (
160
- namespace TEXT NOT NULL,
161
- namespace_json TEXT NOT NULL,
162
- key TEXT NOT NULL,
163
- value_json TEXT NOT NULL,
164
- created_at TEXT NOT NULL,
165
- updated_at TEXT NOT NULL,
166
- PRIMARY KEY (namespace, key)
167
- );
168
- CREATE INDEX IF NOT EXISTS idx_store_entries_namespace ON store_entries(namespace);
169
- `);
157
+ }
158
+ async getClient() {
159
+ if (!this.client) {
160
+ this.client = createClient({ url: `file:${this.filePath}` });
161
+ }
162
+ return this.client;
163
+ }
164
+ async ensureInitialized() {
165
+ if (this.initialized) {
166
+ return;
167
+ }
168
+ if (this.initialization) {
169
+ await this.initialization;
170
+ return;
171
+ }
172
+ this.initialization = (async () => {
173
+ const client = await this.getClient();
174
+ await client.execute("PRAGMA journal_mode=WAL");
175
+ await client.execute("PRAGMA foreign_keys=ON");
176
+ await client.execute("PRAGMA busy_timeout=5000");
177
+ await client.execute(`
178
+ CREATE TABLE IF NOT EXISTS store_entries (
179
+ namespace TEXT NOT NULL,
180
+ namespace_json TEXT NOT NULL,
181
+ key TEXT NOT NULL,
182
+ value_json TEXT NOT NULL,
183
+ created_at TEXT NOT NULL,
184
+ updated_at TEXT NOT NULL,
185
+ PRIMARY KEY (namespace, key)
186
+ )
187
+ `);
188
+ await client.execute("CREATE INDEX IF NOT EXISTS idx_store_entries_namespace ON store_entries(namespace)");
189
+ this.initialized = true;
190
+ this.initialization = null;
191
+ })();
192
+ await this.initialization;
193
+ }
194
+ async selectAll(sql, args = []) {
195
+ await this.ensureInitialized();
196
+ const client = await this.getClient();
197
+ const result = await client.execute({ sql, args });
198
+ return result.rows;
170
199
  }
171
200
  async batch(operations) {
172
- const results = this.db.transaction((items) => items.map((operation) => {
201
+ const results = [];
202
+ for (const operation of operations) {
173
203
  const namespace = Array.isArray(operation.namespace) ? operation.namespace.filter((item) => typeof item === "string") : [];
174
204
  const key = typeof operation.key === "string" ? operation.key : "";
175
205
  if ("value" in operation) {
176
- this.putSync(namespace, key, operation.value);
177
- return undefined;
206
+ await this.put(namespace, key, operation.value);
207
+ results.push(undefined);
208
+ continue;
178
209
  }
179
210
  if (operation.delete === true) {
180
- this.deleteSync(namespace, key);
181
- return undefined;
211
+ await this.delete(namespace, key);
212
+ results.push(undefined);
213
+ continue;
182
214
  }
183
- return this.getSync(namespace, key);
184
- }))(operations);
215
+ results.push(await this.get(namespace, key));
216
+ }
185
217
  return results;
186
218
  }
187
219
  async get(namespace, key) {
188
- return this.getSync(namespace, key);
189
- }
190
- getSync(namespace, key) {
191
- const row = this.db.prepare(`SELECT namespace, namespace_json, key, value_json, created_at, updated_at
220
+ const rows = await this.selectAll(`SELECT namespace, namespace_json, key, value_json, created_at, updated_at
192
221
  FROM store_entries
193
- WHERE namespace = ? AND key = ?`).get(serializeNamespace(namespace), key);
222
+ WHERE namespace = ? AND key = ?`, [serializeNamespace(namespace), key]);
223
+ const row = rows[0];
194
224
  return row ? parseRow(row) : null;
195
225
  }
196
226
  async search(namespacePrefix) {
197
227
  const prefix = serializeNamespace(namespacePrefix);
198
- const rows = this.db.prepare(`SELECT namespace, namespace_json, key, value_json, created_at, updated_at
228
+ const rows = await this.selectAll(`SELECT namespace, namespace_json, key, value_json, created_at, updated_at
199
229
  FROM store_entries
200
230
  WHERE namespace = ? OR namespace LIKE ?
201
- ORDER BY namespace ASC, key ASC`).all(prefix, `${prefix}${NAMESPACE_SEPARATOR}%`);
231
+ ORDER BY namespace ASC, key ASC`, [prefix, `${prefix}${NAMESPACE_SEPARATOR}%`]);
202
232
  return rows.map((row) => parseRow(row));
203
233
  }
204
234
  async put(namespace, key, value, _index) {
205
- this.putSync(namespace, key, value);
206
- }
207
- putSync(namespace, key, value) {
235
+ await this.ensureInitialized();
236
+ const client = await this.getClient();
208
237
  const now = new Date().toISOString();
209
238
  const serializedNamespace = serializeNamespace(namespace);
210
239
  const encodedValue = JSON.stringify(encodeValue(value));
211
- this.db.prepare(`INSERT INTO store_entries (namespace, namespace_json, key, value_json, created_at, updated_at)
240
+ await client.execute({
241
+ sql: `INSERT INTO store_entries (namespace, namespace_json, key, value_json, created_at, updated_at)
212
242
  VALUES (?, ?, ?, ?, ?, ?)
213
243
  ON CONFLICT(namespace, key) DO UPDATE SET
214
244
  namespace_json = excluded.namespace_json,
215
245
  value_json = excluded.value_json,
216
- updated_at = excluded.updated_at`).run(serializedNamespace, JSON.stringify(namespace), key, encodedValue, now, now);
246
+ updated_at = excluded.updated_at`,
247
+ args: [serializedNamespace, JSON.stringify(namespace), key, encodedValue, now, now],
248
+ });
217
249
  }
218
250
  async delete(namespace, key) {
219
- this.deleteSync(namespace, key);
220
- }
221
- deleteSync(namespace, key) {
222
- this.db.prepare(`DELETE FROM store_entries WHERE namespace = ? AND key = ?`).run(serializeNamespace(namespace), key);
251
+ await this.ensureInitialized();
252
+ const client = await this.getClient();
253
+ await client.execute({
254
+ sql: `DELETE FROM store_entries WHERE namespace = ? AND key = ?`,
255
+ args: [serializeNamespace(namespace), key],
256
+ });
223
257
  }
224
258
  async listNamespaces() {
225
- const rows = this.db.prepare(`SELECT DISTINCT namespace_json
259
+ const rows = await this.selectAll(`SELECT DISTINCT namespace_json
226
260
  FROM store_entries
227
- ORDER BY namespace ASC`).all();
261
+ ORDER BY namespace ASC`);
228
262
  return rows.map((row) => JSON.parse(row.namespace_json));
229
263
  }
230
264
  }
@@ -618,8 +618,7 @@ export class AgentHarnessRuntime {
618
618
  currentAgentId: request.currentAgentId,
619
619
  delegationChain: request.delegationChain,
620
620
  runtimeSnapshot: request.runtimeSnapshot,
621
- upstreamEvents: request.upstreamEvents,
622
- history: request.history,
621
+ traceItems: request.traceItems,
623
622
  runtimeTimeline: request.runtimeTimeline,
624
623
  }
625
624
  : null;
@@ -687,8 +686,7 @@ export class AgentHarnessRuntime {
687
686
  currentAgentId: request.currentAgentId,
688
687
  delegationChain: request.delegationChain,
689
688
  runtimeSnapshot: request.runtimeSnapshot,
690
- upstreamEvents: request.upstreamEvents,
691
- history: request.history,
689
+ traceItems: request.traceItems,
692
690
  runtimeTimeline: request.runtimeTimeline,
693
691
  })),
694
692
  pendingDecision: session.pendingDecision,
@@ -1662,6 +1660,7 @@ export class AgentHarnessRuntime {
1662
1660
  isNewThread,
1663
1661
  runCreatedEventPromise,
1664
1662
  releaseRunSlotPromise,
1663
+ getBinding: (agentId) => getWorkspaceBinding(this.workspace, agentId),
1665
1664
  loadPriorHistory: (threadId, runId) => this.loadPriorHistory(threadId, runId),
1666
1665
  stream: (binding, message, threadId, priorHistory, streamOptions) => this.runtimeAdapter.stream(binding, message, threadId, priorHistory, streamOptions),
1667
1666
  invokeWithHistory: (binding, input, threadId, runId) => this.invokeWithHistory(binding, input, threadId, runId),
@@ -1671,6 +1670,7 @@ export class AgentHarnessRuntime {
1671
1670
  appendAssistantMessage: (threadId, runId, content) => appendLifecycleAssistantMessage(this.persistence, threadId, runId, content),
1672
1671
  clearRunRequest: (threadId, runId) => this.persistence.clearRunRequest(threadId, runId),
1673
1672
  updateRunInspection: (threadId, runId, patch) => this.persistence.updateRunInspection(threadId, runId, patch),
1673
+ appendRunTraceItem: (threadId, runId, item) => this.persistence.appendRunTraceItem(threadId, runId, item),
1674
1674
  emitSyntheticFallback: (threadId, runId, selectedAgentId, error) => this.runtimeEventOperations.emitSyntheticFallback(threadId, runId, selectedAgentId, error),
1675
1675
  });
1676
1676
  for await (const item of stream) {
@@ -1837,9 +1837,7 @@ function toSessionRecord(record) {
1837
1837
  function toRequestRecord(record) {
1838
1838
  return {
1839
1839
  ...toRequestSummary(record),
1840
- upstreamEvents: record.upstreamEvents,
1841
- history: record.history,
1842
- runtimeSurface: record.runtimeSurface,
1840
+ traceItems: record.traceItems,
1843
1841
  runtimeTimeline: record.runtimeTimeline,
1844
1842
  };
1845
1843
  }
@@ -1,9 +1,6 @@
1
1
  import path from "node:path";
2
- import { SqliteSaver } from "@langchain/langgraph-checkpoint-sqlite";
3
- import { listProtectedCheckpointThreadIds } from "../../persistence/sqlite-store.js";
4
2
  import { fileExists } from "../../utils/fs.js";
5
3
  import { getRuntimeDefaults } from "../../workspace/support/workspace-ref-utils.js";
6
- import { ManagedSqliteSaver } from "./sqlite-maintained-checkpoint-saver.js";
7
4
  function asObject(value) {
8
5
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
9
6
  }
@@ -72,128 +69,16 @@ export function discoverCheckpointMaintenanceTargets(workspace) {
72
69
  }
73
70
  return Array.from(deduped.values());
74
71
  }
75
- function backfillCheckpointMetadata(db, nowMs = Date.now()) {
76
- db.exec(`
77
- CREATE TABLE IF NOT EXISTS checkpoint_maintenance_meta (
78
- thread_id TEXT NOT NULL,
79
- checkpoint_ns TEXT NOT NULL DEFAULT '',
80
- checkpoint_id TEXT NOT NULL,
81
- created_at_ms INTEGER NOT NULL,
82
- PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id)
83
- );`);
84
- db.prepare(`INSERT OR IGNORE INTO checkpoint_maintenance_meta
85
- (thread_id, checkpoint_ns, checkpoint_id, created_at_ms)
86
- SELECT thread_id, checkpoint_ns, checkpoint_id, ?
87
- FROM checkpoints`).run(nowMs);
88
- }
89
- function deleteCheckpointRows(db, rows) {
90
- if (rows.length === 0) {
91
- return 0;
92
- }
93
- const deleteCheckpoint = db.prepare(`DELETE FROM checkpoints
94
- WHERE thread_id = ? AND checkpoint_ns = ? AND checkpoint_id = ?`);
95
- const deleteWrites = db.prepare(`DELETE FROM writes
96
- WHERE thread_id = ? AND checkpoint_ns = ? AND checkpoint_id = ?`);
97
- const deleteMeta = db.prepare(`DELETE FROM checkpoint_maintenance_meta
98
- WHERE thread_id = ? AND checkpoint_ns = ? AND checkpoint_id = ?`);
99
- db.transaction((items) => {
100
- for (const row of items) {
101
- deleteCheckpoint.run(row.thread_id, row.checkpoint_ns, row.checkpoint_id);
102
- deleteWrites.run(row.thread_id, row.checkpoint_ns, row.checkpoint_id);
103
- deleteMeta.run(row.thread_id, row.checkpoint_ns, row.checkpoint_id);
104
- }
105
- })(rows);
106
- return rows.length;
107
- }
108
- function selectOldestRows(db, limit) {
109
- return db
110
- .prepare(`SELECT
111
- meta.thread_id,
112
- meta.checkpoint_ns,
113
- meta.checkpoint_id,
114
- meta.created_at_ms,
115
- COALESCE(LENGTH(cp.checkpoint), 0) + COALESCE(LENGTH(cp.metadata), 0) + COALESCE(SUM(LENGTH(w.value)), 0) AS size_bytes
116
- FROM checkpoint_maintenance_meta AS meta
117
- JOIN checkpoints AS cp
118
- ON cp.thread_id = meta.thread_id
119
- AND cp.checkpoint_ns = meta.checkpoint_ns
120
- AND cp.checkpoint_id = meta.checkpoint_id
121
- LEFT JOIN writes AS w
122
- ON w.thread_id = meta.thread_id
123
- AND w.checkpoint_ns = meta.checkpoint_ns
124
- AND w.checkpoint_id = meta.checkpoint_id
125
- GROUP BY meta.thread_id, meta.checkpoint_ns, meta.checkpoint_id, meta.created_at_ms, cp.checkpoint, cp.metadata
126
- ORDER BY meta.created_at_ms ASC, meta.checkpoint_id ASC
127
- LIMIT ?`)
128
- .all(limit);
129
- }
130
- function totalCheckpointBytes(db) {
131
- const checkpointsBytes = db
132
- .prepare(`SELECT COALESCE(SUM(LENGTH(checkpoint) + LENGTH(metadata)), 0) AS total FROM checkpoints`)
133
- .get();
134
- const writesBytes = db
135
- .prepare(`SELECT COALESCE(SUM(LENGTH(value)), 0) AS total FROM writes`)
136
- .get();
137
- return Number(checkpointsBytes.total ?? 0) + Number(writesBytes.total ?? 0);
138
- }
139
72
  export function maintainSqliteCheckpoints(dbPath, config, nowMs = Date.now()) {
140
73
  return maintainSqliteCheckpointsInternal(dbPath, config, nowMs);
141
74
  }
142
- async function maintainSqliteCheckpointsInternal(dbPath, config, nowMs) {
75
+ async function maintainSqliteCheckpointsInternal(dbPath, config, _nowMs) {
143
76
  if (!(await fileExists(dbPath))) {
144
77
  return { deletedCount: 0 };
145
78
  }
146
- const saver = new ManagedSqliteSaver(SqliteSaver.fromConnString(dbPath).db);
147
- const db = saver.db;
148
- try {
149
- saver.prepareMaintenance();
150
- backfillCheckpointMetadata(db, nowMs);
151
- const protectedThreadIds = await listProtectedCheckpointThreadIds(path.join(path.dirname(dbPath), "runtime.sqlite"));
152
- let deletedCount = 0;
153
- if (config.policies.maxAgeSeconds !== undefined) {
154
- const cutoffMs = nowMs - config.policies.maxAgeSeconds * 1000;
155
- const expired = db
156
- .prepare(`SELECT
157
- meta.thread_id,
158
- meta.checkpoint_ns,
159
- meta.checkpoint_id,
160
- meta.created_at_ms,
161
- 0 AS size_bytes
162
- FROM checkpoint_maintenance_meta AS meta
163
- WHERE meta.created_at_ms <= ?
164
- ORDER BY meta.created_at_ms ASC, meta.checkpoint_id ASC
165
- LIMIT ?`)
166
- .all(cutoffMs, config.sqlite.sweepBatchSize * 4);
167
- deletedCount += deleteCheckpointRows(db, expired.filter((row) => !protectedThreadIds.has(row.thread_id)).slice(0, config.sqlite.sweepBatchSize));
168
- }
169
- if (config.policies.maxBytes !== undefined) {
170
- let currentBytes = totalCheckpointBytes(db);
171
- while (currentBytes > config.policies.maxBytes) {
172
- const oldest = selectOldestRows(db, config.sqlite.sweepBatchSize * 4).filter((row) => !protectedThreadIds.has(row.thread_id));
173
- if (oldest.length === 0) {
174
- break;
175
- }
176
- let reclaimed = 0;
177
- const toDelete = [];
178
- for (const row of oldest) {
179
- toDelete.push(row);
180
- reclaimed += Number(row.size_bytes ?? 0);
181
- if (currentBytes - reclaimed <= config.policies.maxBytes) {
182
- break;
183
- }
184
- }
185
- deletedCount += deleteCheckpointRows(db, toDelete);
186
- currentBytes = totalCheckpointBytes(db);
187
- }
188
- }
189
- if (deletedCount > 0 && config.sqlite.vacuum) {
190
- db.exec("VACUUM");
191
- }
192
- return { deletedCount };
193
- }
194
- finally {
195
- db.close();
196
- }
79
+ void config;
80
+ void path.dirname(dbPath);
81
+ throw new Error("Checkpoint maintenance for SqliteSaver is not supported in this runtime right now");
197
82
  }
198
83
  export class CheckpointMaintenanceLoop {
199
84
  targets;
@@ -1,4 +1,3 @@
1
1
  export * from "./checkpoint-maintenance.js";
2
2
  export * from "./file-checkpoint-saver.js";
3
3
  export * from "./runtime-record-maintenance.js";
4
- export * from "./sqlite-maintained-checkpoint-saver.js";