@botbotgo/agent-harness 0.0.250 → 0.0.252

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 (48) 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/resource/resource-impl.js +1 -4
  26. package/dist/runtime/harness/events/streaming.js +8 -8
  27. package/dist/runtime/harness/run/inspection.d.ts +2 -0
  28. package/dist/runtime/harness/run/inspection.js +91 -46
  29. package/dist/runtime/harness/run/stream-run.d.ts +2 -2
  30. package/dist/runtime/harness/run/stream-run.js +34 -23
  31. package/dist/runtime/harness/run/surface-semantics.d.ts +14 -0
  32. package/dist/runtime/harness/run/surface-semantics.js +106 -0
  33. package/dist/runtime/harness/run/thread-records.js +2 -34
  34. package/dist/runtime/harness/system/store.d.ts +6 -4
  35. package/dist/runtime/harness/system/store.js +76 -42
  36. package/dist/runtime/harness.js +7 -7
  37. package/dist/runtime/maintenance/checkpoint-maintenance.js +4 -119
  38. package/dist/runtime/maintenance/index.d.ts +0 -1
  39. package/dist/runtime/maintenance/index.js +0 -1
  40. package/dist/runtime/support/runtime-env.d.ts +1 -0
  41. package/dist/runtime/support/runtime-env.js +5 -0
  42. package/dist/runtime/support/runtime-factories.js +2 -42
  43. package/dist/upstream-events.js +14 -0
  44. package/package.json +1 -3
  45. package/dist/runtime/maintenance/sqlite-maintained-checkpoint-saver.d.ts +0 -9
  46. package/dist/runtime/maintenance/sqlite-maintained-checkpoint-saver.js +0 -39
  47. package/dist/runtime/support/sqlite-drivers.d.ts +0 -12
  48. package/dist/runtime/support/sqlite-drivers.js +0 -24
@@ -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";
@@ -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";
@@ -1,2 +1,3 @@
1
1
  export declare function augmentExecutablePath(pathValue: string | undefined, env?: Record<string, string | undefined> | NodeJS.ProcessEnv): string;
2
2
  export declare function createRuntimeEnv(env: Record<string, string> | undefined, baseEnv?: Record<string, string | undefined> | NodeJS.ProcessEnv): Record<string, string>;
3
+ export declare function normalizeProcessExecutablePath(env?: NodeJS.ProcessEnv): string;
@@ -55,3 +55,8 @@ export function createRuntimeEnv(env, baseEnv = process.env) {
55
55
  merged.PATH = augmentExecutablePath(combinedPath, { ...base, ...(env ?? {}) });
56
56
  return merged;
57
57
  }
58
+ export function normalizeProcessExecutablePath(env = process.env) {
59
+ const normalized = augmentExecutablePath(env.PATH, env);
60
+ env.PATH = normalized;
61
+ return normalized;
62
+ }
@@ -2,42 +2,6 @@ import path from "node:path";
2
2
  import { MemorySaver } from "@langchain/langgraph";
3
3
  import { FileCheckpointSaver } from "../maintenance/file-checkpoint-saver.js";
4
4
  import { createInMemoryStore, FileBackedStore, SqliteBackedStore } from "../harness/system/store.js";
5
- import { loadLanggraphSqliteCheckpointModule } from "./sqlite-drivers.js";
6
- function createManagedSqliteSaver(SqliteSaver, db) {
7
- class RuntimeManagedSqliteSaver extends SqliteSaver {
8
- setup() {
9
- super.setup();
10
- this.db.exec(`
11
- CREATE TABLE IF NOT EXISTS checkpoint_maintenance_meta (
12
- thread_id TEXT NOT NULL,
13
- checkpoint_ns TEXT NOT NULL DEFAULT '',
14
- checkpoint_id TEXT NOT NULL,
15
- created_at_ms INTEGER NOT NULL,
16
- PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id)
17
- );`);
18
- }
19
- async put(config, checkpoint, metadata) {
20
- const result = await super.put(config, checkpoint, metadata);
21
- const threadId = result.configurable?.thread_id;
22
- const checkpointNs = result.configurable?.checkpoint_ns ?? "";
23
- const checkpointId = result.configurable?.checkpoint_id;
24
- if (!threadId || !checkpointId) {
25
- throw new Error("Missing checkpoint identity after SqliteSaver.put");
26
- }
27
- this.db
28
- .prepare(`INSERT OR IGNORE INTO checkpoint_maintenance_meta
29
- (thread_id, checkpoint_ns, checkpoint_id, created_at_ms)
30
- VALUES (?, ?, ?, ?)`)
31
- .run(threadId, checkpointNs, checkpointId, Date.now());
32
- return result;
33
- }
34
- async deleteThread(threadId) {
35
- await super.deleteThread(threadId);
36
- this.db.prepare(`DELETE FROM checkpoint_maintenance_meta WHERE thread_id = ?`).run(threadId);
37
- }
38
- }
39
- return new RuntimeManagedSqliteSaver(db);
40
- }
41
5
  export function createStoreForConfig(storeConfig, runRoot) {
42
6
  const kind = typeof storeConfig.kind === "string" ? storeConfig.kind : "FileStore";
43
7
  switch (kind) {
@@ -67,12 +31,8 @@ export function createCheckpointerForConfig(checkpointerConfig, runRoot) {
67
31
  switch (kind) {
68
32
  case "MemorySaver":
69
33
  return new MemorySaver();
70
- case "SqliteSaver": {
71
- const configuredPath = typeof checkpointerConfig.path === "string" ? String(checkpointerConfig.path) : "checkpoints.sqlite";
72
- const resolvedPath = path.isAbsolute(configuredPath) ? configuredPath : path.join(runRoot, configuredPath);
73
- const { SqliteSaver } = loadLanggraphSqliteCheckpointModule();
74
- return createManagedSqliteSaver(SqliteSaver, SqliteSaver.fromConnString(resolvedPath).db);
75
- }
34
+ case "SqliteSaver":
35
+ throw new Error("Checkpointer kind SqliteSaver is not supported in this runtime right now");
76
36
  case "FileCheckpointer": {
77
37
  const configuredPath = typeof checkpointerConfig.path === "string" ? String(checkpointerConfig.path) : "checkpoints.json";
78
38
  return new FileCheckpointSaver(path.isAbsolute(configuredPath) ? configuredPath : path.join(runRoot, configuredPath));
@@ -117,6 +117,20 @@ export function createUpstreamTimelineReducer() {
117
117
  });
118
118
  }
119
119
  }
120
+ if (context.eventName === "on_chat_model_end") {
121
+ const stepName = context.name || "model";
122
+ const key = createProjectionKey(["llm", "completed", stepName]);
123
+ if (!emittedStepKeys.has(key)) {
124
+ emittedStepKeys.add(key);
125
+ projections.push({
126
+ type: "step",
127
+ step: buildStepLabel("llm", "completed", stepName),
128
+ category: "llm",
129
+ status: "completed",
130
+ key,
131
+ });
132
+ }
133
+ }
120
134
  if (context.eventName === "on_tool_start"
121
135
  || (context.eventName === "on_chain_start" && context.runType === "tool")
122
136
  || context.eventName === "on_chain_start") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.250",
3
+ "version": "0.0.252",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -46,14 +46,12 @@
46
46
  "@langchain/core": "^1.1.33",
47
47
  "@langchain/google": "^0.1.7",
48
48
  "@langchain/langgraph": "^1.2.6",
49
- "@langchain/langgraph-checkpoint-sqlite": "^1.0.1",
50
49
  "@langchain/ollama": "^1.2.6",
51
50
  "@langchain/openai": "^1.1.0",
52
51
  "@libsql/client": "^0.17.0",
53
52
  "@llamaindex/ollama": "^0.1.23",
54
53
  "@modelcontextprotocol/sdk": "^1.12.0",
55
54
  "@qdrant/js-client-rest": "^1.17.0",
56
- "better-sqlite3": "^12.8.0",
57
55
  "deepagents": "^1.9.0",
58
56
  "langchain": "^1.3.1",
59
57
  "llamaindex": "^0.12.1",
@@ -1,9 +0,0 @@
1
- import { SqliteSaver } from "@langchain/langgraph-checkpoint-sqlite";
2
- import type { RunnableConfig } from "@langchain/core/runnables";
3
- export declare class ManagedSqliteSaver extends SqliteSaver {
4
- constructor(db: ConstructorParameters<typeof SqliteSaver>[0]);
5
- prepareMaintenance(): void;
6
- setup(): void;
7
- put(config: RunnableConfig, checkpoint: Parameters<SqliteSaver["put"]>[1], metadata: Parameters<SqliteSaver["put"]>[2]): Promise<RunnableConfig<Record<string, any>>>;
8
- deleteThread(threadId: string): Promise<void>;
9
- }
@@ -1,39 +0,0 @@
1
- import { SqliteSaver } from "@langchain/langgraph-checkpoint-sqlite";
2
- export class ManagedSqliteSaver extends SqliteSaver {
3
- constructor(db) {
4
- super(db);
5
- }
6
- prepareMaintenance() {
7
- this.setup();
8
- }
9
- setup() {
10
- super.setup();
11
- this.db.exec(`
12
- CREATE TABLE IF NOT EXISTS checkpoint_maintenance_meta (
13
- thread_id TEXT NOT NULL,
14
- checkpoint_ns TEXT NOT NULL DEFAULT '',
15
- checkpoint_id TEXT NOT NULL,
16
- created_at_ms INTEGER NOT NULL,
17
- PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id)
18
- );`);
19
- }
20
- async put(config, checkpoint, metadata) {
21
- const result = await super.put(config, checkpoint, metadata);
22
- const threadId = result.configurable?.thread_id;
23
- const checkpointNs = result.configurable?.checkpoint_ns ?? "";
24
- const checkpointId = result.configurable?.checkpoint_id;
25
- if (!threadId || !checkpointId) {
26
- throw new Error("Missing checkpoint identity after SqliteSaver.put");
27
- }
28
- this.db
29
- .prepare(`INSERT OR IGNORE INTO checkpoint_maintenance_meta
30
- (thread_id, checkpoint_ns, checkpoint_id, created_at_ms)
31
- VALUES (?, ?, ?, ?)`)
32
- .run(threadId, checkpointNs, checkpointId, Date.now());
33
- return result;
34
- }
35
- async deleteThread(threadId) {
36
- await super.deleteThread(threadId);
37
- this.db.prepare(`DELETE FROM checkpoint_maintenance_meta WHERE thread_id = ?`).run(threadId);
38
- }
39
- }
@@ -1,12 +0,0 @@
1
- type BetterSqlite3Constructor = typeof import("better-sqlite3");
2
- type SqliteCheckpointModule = typeof import("@langchain/langgraph-checkpoint-sqlite");
3
- declare const defaultBetterSqlite3Loader: () => BetterSqlite3Constructor;
4
- declare const defaultLanggraphSqliteCheckpointLoader: () => SqliteCheckpointModule;
5
- export declare function loadBetterSqlite3(): BetterSqlite3Constructor;
6
- export declare function loadLanggraphSqliteCheckpointModule(): SqliteCheckpointModule;
7
- export declare function setSqliteModuleLoadersForTest(loaders: {
8
- betterSqlite3?: typeof defaultBetterSqlite3Loader;
9
- langgraphCheckpointSqlite?: typeof defaultLanggraphSqliteCheckpointLoader;
10
- }): void;
11
- export declare function resetSqliteModuleLoadersForTest(): void;
12
- export {};
@@ -1,24 +0,0 @@
1
- import { createRequire } from "node:module";
2
- const require = createRequire(import.meta.url);
3
- const defaultBetterSqlite3Loader = () => require("better-sqlite3");
4
- const defaultLanggraphSqliteCheckpointLoader = () => require("@langchain/langgraph-checkpoint-sqlite");
5
- let betterSqlite3Loader = defaultBetterSqlite3Loader;
6
- let langgraphSqliteCheckpointLoader = defaultLanggraphSqliteCheckpointLoader;
7
- export function loadBetterSqlite3() {
8
- return betterSqlite3Loader();
9
- }
10
- export function loadLanggraphSqliteCheckpointModule() {
11
- return langgraphSqliteCheckpointLoader();
12
- }
13
- export function setSqliteModuleLoadersForTest(loaders) {
14
- if (loaders.betterSqlite3) {
15
- betterSqlite3Loader = loaders.betterSqlite3;
16
- }
17
- if (loaders.langgraphCheckpointSqlite) {
18
- langgraphSqliteCheckpointLoader = loaders.langgraphCheckpointSqlite;
19
- }
20
- }
21
- export function resetSqliteModuleLoadersForTest() {
22
- betterSqlite3Loader = defaultBetterSqlite3Loader;
23
- langgraphSqliteCheckpointLoader = defaultLanggraphSqliteCheckpointLoader;
24
- }