@botbotgo/agent-harness 0.0.95 → 0.0.97

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 (114) hide show
  1. package/README.md +1 -114
  2. package/README.zh.md +1 -70
  3. package/dist/api.d.ts +5 -5
  4. package/dist/config/workflows/langgraph-workflows.yaml +363 -111
  5. package/dist/config/workflows/runtime-profiles.yaml +94 -0
  6. package/dist/contracts/core.d.ts +9 -0
  7. package/dist/contracts/core.js +1 -0
  8. package/dist/contracts/runtime.d.ts +421 -0
  9. package/dist/contracts/runtime.js +1 -0
  10. package/dist/contracts/types.d.ts +3 -571
  11. package/dist/contracts/types.js +3 -1
  12. package/dist/contracts/workspace.d.ts +229 -0
  13. package/dist/contracts/workspace.js +1 -0
  14. package/dist/package-version.d.ts +1 -1
  15. package/dist/package-version.js +1 -1
  16. package/dist/runtime/adapter/compat/deepagent-compat.d.ts +16 -0
  17. package/dist/runtime/adapter/compat/deepagent-compat.js +45 -0
  18. package/dist/runtime/adapter/compat/openai-compatible.d.ts +2 -0
  19. package/dist/runtime/adapter/compat/openai-compatible.js +43 -0
  20. package/dist/runtime/adapter/index.d.ts +15 -0
  21. package/dist/runtime/adapter/index.js +15 -0
  22. package/dist/runtime/adapter/langgraph/presets.js +165 -0
  23. package/dist/runtime/{langgraph-profiles.d.ts → adapter/langgraph/profiles.d.ts} +1 -1
  24. package/dist/runtime/adapter/langgraph/profiles.js +206 -0
  25. package/dist/runtime/adapter/model/invocation-request.d.ts +10 -0
  26. package/dist/runtime/adapter/model/invocation-request.js +46 -0
  27. package/dist/runtime/adapter/model/message-assembly.d.ts +6 -0
  28. package/dist/runtime/adapter/model/message-assembly.js +21 -0
  29. package/dist/runtime/adapter/model/model-providers.d.ts +2 -0
  30. package/dist/runtime/adapter/model/model-providers.js +27 -0
  31. package/dist/runtime/adapter/resilience.d.ts +12 -0
  32. package/dist/runtime/adapter/resilience.js +60 -0
  33. package/dist/runtime/{declared-middleware.d.ts → adapter/tool/declared-middleware.d.ts} +1 -1
  34. package/dist/runtime/adapter/tool/interrupt-policy.d.ts +8 -0
  35. package/dist/runtime/adapter/tool/interrupt-policy.js +34 -0
  36. package/dist/runtime/adapter/tool/provider-tool.d.ts +2 -0
  37. package/dist/runtime/adapter/tool/provider-tool.js +25 -0
  38. package/dist/runtime/adapter/tool/resolved-tool.d.ts +18 -0
  39. package/dist/runtime/adapter/tool/resolved-tool.js +62 -0
  40. package/dist/runtime/adapter/tool/tool-arguments.d.ts +7 -0
  41. package/dist/runtime/adapter/tool/tool-arguments.js +87 -0
  42. package/dist/runtime/{tool-hitl.d.ts → adapter/tool/tool-hitl.d.ts} +2 -2
  43. package/dist/runtime/adapter/tool/tool-name-mapping.d.ts +13 -0
  44. package/dist/runtime/adapter/tool/tool-name-mapping.js +101 -0
  45. package/dist/runtime/agent-runtime-adapter.d.ts +5 -20
  46. package/dist/runtime/agent-runtime-adapter.js +42 -544
  47. package/dist/runtime/checkpoint-maintenance.d.ts +1 -45
  48. package/dist/runtime/checkpoint-maintenance.js +1 -259
  49. package/dist/runtime/file-checkpoint-saver.d.ts +1 -20
  50. package/dist/runtime/file-checkpoint-saver.js +1 -106
  51. package/dist/runtime/{event-bus.d.ts → harness/events/event-bus.d.ts} +1 -1
  52. package/dist/runtime/{event-sink.d.ts → harness/events/event-sink.d.ts} +1 -1
  53. package/dist/runtime/{event-sink.js → harness/events/event-sink.js} +1 -1
  54. package/dist/runtime/harness/events/events.d.ts +23 -0
  55. package/dist/runtime/harness/events/events.js +61 -0
  56. package/dist/runtime/harness/events/streaming.d.ts +19 -0
  57. package/dist/runtime/harness/events/streaming.js +96 -0
  58. package/dist/runtime/harness/index.d.ts +16 -0
  59. package/dist/runtime/harness/index.js +16 -0
  60. package/dist/runtime/harness/run/helpers.d.ts +33 -0
  61. package/dist/runtime/harness/run/helpers.js +74 -0
  62. package/dist/runtime/harness/run/resources.d.ts +7 -0
  63. package/dist/runtime/harness/run/resources.js +58 -0
  64. package/dist/runtime/harness/run/resume.d.ts +6 -0
  65. package/dist/runtime/harness/run/resume.js +56 -0
  66. package/dist/runtime/harness/run/routing.d.ts +12 -0
  67. package/dist/runtime/harness/run/routing.js +47 -0
  68. package/dist/runtime/harness/run/run-lifecycle.d.ts +37 -0
  69. package/dist/runtime/harness/run/run-lifecycle.js +109 -0
  70. package/dist/runtime/harness/run/run-queue.d.ts +17 -0
  71. package/dist/runtime/harness/run/run-queue.js +43 -0
  72. package/dist/runtime/{health-monitor.d.ts → harness/system/health-monitor.d.ts} +3 -3
  73. package/dist/runtime/{health-monitor.js → harness/system/health-monitor.js} +2 -2
  74. package/dist/runtime/{inventory.d.ts → harness/system/inventory.d.ts} +2 -2
  75. package/dist/runtime/{inventory.js → harness/system/inventory.js} +4 -4
  76. package/dist/runtime/{policy-engine.d.ts → harness/system/policy-engine.d.ts} +1 -1
  77. package/dist/runtime/{policy-engine.js → harness/system/policy-engine.js} +1 -1
  78. package/dist/runtime/{skill-requirements.d.ts → harness/system/skill-requirements.d.ts} +1 -1
  79. package/dist/runtime/{skill-requirements.js → harness/system/skill-requirements.js} +1 -1
  80. package/dist/runtime/{thread-memory-sync.d.ts → harness/system/thread-memory-sync.d.ts} +2 -2
  81. package/dist/runtime/{thread-memory-sync.js → harness/system/thread-memory-sync.js} +1 -1
  82. package/dist/runtime/harness.d.ts +2 -7
  83. package/dist/runtime/harness.js +158 -477
  84. package/dist/runtime/index.d.ts +7 -7
  85. package/dist/runtime/index.js +7 -7
  86. package/dist/runtime/maintenance/checkpoint-maintenance.d.ts +45 -0
  87. package/dist/runtime/maintenance/checkpoint-maintenance.js +259 -0
  88. package/dist/runtime/maintenance/file-checkpoint-saver.d.ts +20 -0
  89. package/dist/runtime/maintenance/file-checkpoint-saver.js +106 -0
  90. package/dist/runtime/maintenance/index.d.ts +4 -0
  91. package/dist/runtime/maintenance/index.js +4 -0
  92. package/dist/runtime/{runtime-record-maintenance.d.ts → maintenance/runtime-record-maintenance.d.ts} +1 -1
  93. package/dist/runtime/{runtime-record-maintenance.js → maintenance/runtime-record-maintenance.js} +2 -2
  94. package/dist/runtime/maintenance/sqlite-maintained-checkpoint-saver.d.ts +9 -0
  95. package/dist/runtime/maintenance/sqlite-maintained-checkpoint-saver.js +39 -0
  96. package/dist/runtime/parsing/stream-event-parsing.d.ts +6 -0
  97. package/dist/runtime/parsing/stream-event-parsing.js +231 -0
  98. package/dist/runtime/sqlite-maintained-checkpoint-saver.d.ts +1 -9
  99. package/dist/runtime/sqlite-maintained-checkpoint-saver.js +1 -39
  100. package/dist/runtime/support/harness-support.d.ts +4 -4
  101. package/dist/runtime/support/harness-support.js +14 -3
  102. package/dist/runtime/support/runtime-factories.d.ts +1 -1
  103. package/dist/runtime/support/runtime-factories.js +1 -1
  104. package/dist/workspace/agent-binding-compiler.js +39 -3
  105. package/dist/workspace/object-loader.js +5 -1
  106. package/package.json +4 -4
  107. package/dist/runtime/langgraph-presets.js +0 -165
  108. package/dist/runtime/langgraph-profiles.js +0 -206
  109. /package/dist/runtime/{langgraph-presets.d.ts → adapter/langgraph/presets.d.ts} +0 -0
  110. /package/dist/runtime/{declared-middleware.js → adapter/tool/declared-middleware.js} +0 -0
  111. /package/dist/runtime/{tool-hitl.js → adapter/tool/tool-hitl.js} +0 -0
  112. /package/dist/runtime/{event-bus.js → harness/events/event-bus.js} +0 -0
  113. /package/dist/runtime/{store.d.ts → harness/system/store.d.ts} +0 -0
  114. /package/dist/runtime/{store.js → harness/system/store.js} +0 -0
@@ -1,45 +1 @@
1
- import type { WorkspaceBundle } from "../contracts/types.js";
2
- type CheckpointMaintenanceConfig = {
3
- enabled: boolean;
4
- schedule: {
5
- intervalSeconds: number;
6
- runOnStartup: boolean;
7
- };
8
- policies: {
9
- maxAgeSeconds?: number;
10
- maxBytes?: number;
11
- };
12
- sqlite: {
13
- sweepBatchSize: number;
14
- vacuum: boolean;
15
- };
16
- };
17
- type CheckpointMaintenanceTarget = {
18
- agentId: string;
19
- dbPath: string;
20
- };
21
- export type MaintenanceLoopStatus = {
22
- lastStartedAt?: string;
23
- lastCompletedAt?: string;
24
- lastFailedAt?: string;
25
- consecutiveFailures: number;
26
- lastError?: string;
27
- };
28
- export declare function readCheckpointMaintenanceConfig(workspace: WorkspaceBundle): CheckpointMaintenanceConfig | null;
29
- export declare function discoverCheckpointMaintenanceTargets(workspace: WorkspaceBundle): CheckpointMaintenanceTarget[];
30
- export declare function maintainSqliteCheckpoints(dbPath: string, config: CheckpointMaintenanceConfig, nowMs?: number): Promise<{
31
- deletedCount: number;
32
- }>;
33
- export declare class CheckpointMaintenanceLoop {
34
- private readonly targets;
35
- private readonly config;
36
- private timer;
37
- private running;
38
- private status;
39
- constructor(targets: CheckpointMaintenanceTarget[], config: CheckpointMaintenanceConfig);
40
- runOnce(nowMs?: number): Promise<void>;
41
- getStatus(): MaintenanceLoopStatus;
42
- start(): Promise<void>;
43
- stop(): Promise<void>;
44
- }
45
- export {};
1
+ export * from "./maintenance/checkpoint-maintenance.js";
@@ -1,259 +1 @@
1
- import path from "node:path";
2
- import { SqliteSaver } from "@langchain/langgraph-checkpoint-sqlite";
3
- import { listProtectedCheckpointThreadIds } from "../persistence/sqlite-store.js";
4
- import { fileExists } from "../utils/fs.js";
5
- import { getRuntimeDefaults } from "../workspace/support/workspace-ref-utils.js";
6
- import { ManagedSqliteSaver } from "./sqlite-maintained-checkpoint-saver.js";
7
- function asObject(value) {
8
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
9
- }
10
- function readPositiveNumber(value, label, allowUndefined = true) {
11
- if (value === undefined && allowUndefined) {
12
- return undefined;
13
- }
14
- if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
15
- throw new Error(`${label} must be a positive number`);
16
- }
17
- return value;
18
- }
19
- export function readCheckpointMaintenanceConfig(workspace) {
20
- const runtimeDefaults = getRuntimeDefaults(workspace.refs);
21
- const maintenance = asObject(runtimeDefaults?.maintenance);
22
- const checkpoints = asObject(maintenance?.checkpoints);
23
- if (!checkpoints || checkpoints.enabled !== true) {
24
- return null;
25
- }
26
- const schedule = asObject(checkpoints.schedule);
27
- const policies = asObject(checkpoints.policies);
28
- const sqlite = asObject(checkpoints.sqlite);
29
- const config = {
30
- enabled: true,
31
- schedule: {
32
- intervalSeconds: readPositiveNumber(schedule?.intervalSeconds, "runtime.maintenance.checkpoints.schedule.intervalSeconds") ?? 3600,
33
- runOnStartup: schedule?.runOnStartup !== false,
34
- },
35
- policies: {
36
- maxAgeSeconds: readPositiveNumber(policies?.maxAgeSeconds, "runtime.maintenance.checkpoints.policies.maxAgeSeconds"),
37
- maxBytes: readPositiveNumber(policies?.maxBytes, "runtime.maintenance.checkpoints.policies.maxBytes"),
38
- },
39
- sqlite: {
40
- sweepBatchSize: readPositiveNumber(sqlite?.sweepBatchSize, "runtime.maintenance.checkpoints.sqlite.sweepBatchSize") ?? 200,
41
- vacuum: sqlite?.vacuum === true,
42
- },
43
- };
44
- if (config.policies.maxAgeSeconds === undefined && config.policies.maxBytes === undefined) {
45
- throw new Error("runtime.maintenance.checkpoints.enabled requires at least one cleanup policy");
46
- }
47
- return config;
48
- }
49
- function resolveSqliteCheckpointPath(binding) {
50
- const config = binding.harnessRuntime.checkpointer;
51
- if (!config || typeof config === "boolean") {
52
- return null;
53
- }
54
- const kind = typeof config.kind === "string" ? config.kind : "FileCheckpointer";
55
- if (kind !== "SqliteSaver") {
56
- return null;
57
- }
58
- const configuredPath = typeof config.path === "string" ? String(config.path) : "checkpoints.sqlite";
59
- return path.isAbsolute(configuredPath) ? configuredPath : path.join(binding.harnessRuntime.runRoot, configuredPath);
60
- }
61
- export function discoverCheckpointMaintenanceTargets(workspace) {
62
- const deduped = new Map();
63
- for (const binding of workspace.bindings.values()) {
64
- const dbPath = resolveSqliteCheckpointPath(binding);
65
- if (!dbPath) {
66
- continue;
67
- }
68
- deduped.set(dbPath, {
69
- agentId: binding.agent.id,
70
- dbPath,
71
- });
72
- }
73
- return Array.from(deduped.values());
74
- }
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
- export function maintainSqliteCheckpoints(dbPath, config, nowMs = Date.now()) {
140
- return maintainSqliteCheckpointsInternal(dbPath, config, nowMs);
141
- }
142
- async function maintainSqliteCheckpointsInternal(dbPath, config, nowMs) {
143
- if (!(await fileExists(dbPath))) {
144
- return { deletedCount: 0 };
145
- }
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
- }
197
- }
198
- export class CheckpointMaintenanceLoop {
199
- targets;
200
- config;
201
- timer = null;
202
- running = false;
203
- status = {
204
- consecutiveFailures: 0,
205
- };
206
- constructor(targets, config) {
207
- this.targets = targets;
208
- this.config = config;
209
- }
210
- async runOnce(nowMs = Date.now()) {
211
- this.status = {
212
- ...this.status,
213
- lastStartedAt: new Date(nowMs).toISOString(),
214
- };
215
- try {
216
- for (const target of this.targets) {
217
- await maintainSqliteCheckpoints(target.dbPath, this.config, nowMs);
218
- }
219
- this.status = {
220
- ...this.status,
221
- lastCompletedAt: new Date(nowMs).toISOString(),
222
- consecutiveFailures: 0,
223
- lastError: undefined,
224
- };
225
- }
226
- catch (error) {
227
- this.status = {
228
- ...this.status,
229
- lastFailedAt: new Date(nowMs).toISOString(),
230
- consecutiveFailures: this.status.consecutiveFailures + 1,
231
- lastError: error instanceof Error ? error.message : String(error),
232
- };
233
- throw error;
234
- }
235
- }
236
- getStatus() {
237
- return { ...this.status };
238
- }
239
- async start() {
240
- if (this.running) {
241
- return;
242
- }
243
- this.running = true;
244
- if (this.config.schedule.runOnStartup) {
245
- await this.runOnce();
246
- }
247
- this.timer = setInterval(() => {
248
- void this.runOnce();
249
- }, this.config.schedule.intervalSeconds * 1000);
250
- this.timer.unref?.();
251
- }
252
- async stop() {
253
- if (this.timer) {
254
- clearInterval(this.timer);
255
- this.timer = null;
256
- }
257
- this.running = false;
258
- }
259
- }
1
+ export * from "./maintenance/checkpoint-maintenance.js";
@@ -1,20 +1 @@
1
- import { MemorySaver } from "@langchain/langgraph";
2
- type MemorySaverConfig = Parameters<MemorySaver["getTuple"]>[0];
3
- type MemorySaverListOptions = Parameters<MemorySaver["list"]>[1];
4
- type MemorySaverPutCheckpoint = Parameters<MemorySaver["put"]>[1];
5
- type MemorySaverPutMetadata = Parameters<MemorySaver["put"]>[2];
6
- type MemorySaverPutWrites = Parameters<MemorySaver["putWrites"]>[1];
7
- type MemorySaverPutResult = ReturnType<MemorySaver["put"]>;
8
- export declare class FileCheckpointSaver extends MemorySaver {
9
- private readonly filePath;
10
- private loaded;
11
- constructor(filePath: string);
12
- private ensureLoaded;
13
- private persist;
14
- getTuple(config: MemorySaverConfig): Promise<import("@langchain/langgraph").CheckpointTuple | undefined>;
15
- list(config: MemorySaverConfig, options?: MemorySaverListOptions): AsyncGenerator<import("@langchain/langgraph").CheckpointTuple, void, unknown>;
16
- put(config: MemorySaverConfig, checkpoint: MemorySaverPutCheckpoint, metadata: MemorySaverPutMetadata): MemorySaverPutResult;
17
- putWrites(config: MemorySaverConfig, writes: MemorySaverPutWrites, taskId: string): Promise<void>;
18
- deleteThread(threadId: string): Promise<void>;
19
- }
20
- export { FileCheckpointSaver as FileCheckpointer };
1
+ export * from "./maintenance/file-checkpoint-saver.js";
@@ -1,106 +1 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
2
- import path from "node:path";
3
- import { MemorySaver } from "@langchain/langgraph";
4
- function encodeBinary(value) {
5
- if (value instanceof Uint8Array) {
6
- return {
7
- __type: "Uint8Array",
8
- data: Array.from(value),
9
- };
10
- }
11
- if (Array.isArray(value)) {
12
- return value.map((item) => encodeBinary(item));
13
- }
14
- if (typeof value === "object" && value) {
15
- return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, encodeBinary(entry)]));
16
- }
17
- return value;
18
- }
19
- function decodeBinary(value) {
20
- if (Array.isArray(value)) {
21
- return value.map((item) => decodeBinary(item));
22
- }
23
- if (typeof value === "object" && value) {
24
- const typed = value;
25
- if (typed.__type === "Uint8Array" && Array.isArray(typed.data)) {
26
- return new Uint8Array(typed.data.map((item) => Number(item)));
27
- }
28
- return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, decodeBinary(entry)]));
29
- }
30
- return value;
31
- }
32
- function pruneThreadEntries(record, threadId) {
33
- for (const key of Object.keys(record)) {
34
- if (key.includes(threadId)) {
35
- delete record[key];
36
- continue;
37
- }
38
- const value = record[key];
39
- if (typeof value === "object" && value && !Array.isArray(value)) {
40
- pruneThreadEntries(value, threadId);
41
- if (Object.keys(value).length === 0) {
42
- delete record[key];
43
- }
44
- }
45
- }
46
- }
47
- export class FileCheckpointSaver extends MemorySaver {
48
- filePath;
49
- loaded = false;
50
- constructor(filePath) {
51
- super();
52
- this.filePath = filePath;
53
- }
54
- async ensureLoaded() {
55
- if (this.loaded) {
56
- return;
57
- }
58
- try {
59
- const raw = await readFile(this.filePath, "utf8");
60
- const parsed = JSON.parse(raw);
61
- this.storage = decodeBinary(parsed.storage ?? {});
62
- this.writes = decodeBinary(parsed.writes ?? {});
63
- }
64
- catch {
65
- this.storage = {};
66
- this.writes = {};
67
- }
68
- this.loaded = true;
69
- }
70
- async persist() {
71
- await mkdir(path.dirname(this.filePath), { recursive: true });
72
- await writeFile(this.filePath, JSON.stringify({
73
- storage: this.storage,
74
- writes: this.writes,
75
- }, (_, value) => encodeBinary(value), 2), "utf8");
76
- }
77
- async getTuple(config) {
78
- await this.ensureLoaded();
79
- return super.getTuple(config);
80
- }
81
- async *list(config, options) {
82
- await this.ensureLoaded();
83
- for await (const item of super.list(config, options)) {
84
- yield item;
85
- }
86
- }
87
- async put(config, checkpoint, metadata) {
88
- await this.ensureLoaded();
89
- const result = await super.put(config, checkpoint, metadata);
90
- await this.persist();
91
- return result;
92
- }
93
- async putWrites(config, writes, taskId) {
94
- await this.ensureLoaded();
95
- const result = await super.putWrites(config, writes, taskId);
96
- await this.persist();
97
- return result;
98
- }
99
- async deleteThread(threadId) {
100
- await this.ensureLoaded();
101
- pruneThreadEntries(this.storage, threadId);
102
- pruneThreadEntries(this.writes, threadId);
103
- await this.persist();
104
- }
105
- }
106
- export { FileCheckpointSaver as FileCheckpointer };
1
+ export * from "./maintenance/file-checkpoint-saver.js";
@@ -1,4 +1,4 @@
1
- import type { HarnessEvent, HarnessEventListener, HarnessEventProjection, RuntimeEventSink } from "../contracts/types.js";
1
+ import type { HarnessEvent, HarnessEventListener, HarnessEventProjection, RuntimeEventSink } from "../../../contracts/types.js";
2
2
  export declare class EventBus implements RuntimeEventSink {
3
3
  private readonly sink;
4
4
  publish(event: HarnessEvent): void;
@@ -1,4 +1,4 @@
1
- import type { HarnessEvent, HarnessEventListener, HarnessEventProjection, RuntimeEventSink } from "../contracts/types.js";
1
+ import type { HarnessEvent, HarnessEventListener, HarnessEventProjection, RuntimeEventSink } from "../../../contracts/types.js";
2
2
  export declare class RuntimeEventSinkImpl implements RuntimeEventSink {
3
3
  private readonly emitter;
4
4
  private readonly projections;
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from "node:events";
2
- import { getEventSubscribers } from "../extensions.js";
2
+ import { getEventSubscribers } from "../../../extensions.js";
3
3
  function dispatchListener(listener, event) {
4
4
  void Promise.resolve(listener(event));
5
5
  }
@@ -0,0 +1,23 @@
1
+ import type { HarnessEvent, InternalApprovalRecord, MessageContent, RunResult } from "../../../contracts/types.js";
2
+ import type { RuntimePersistence } from "../../../persistence/types.js";
3
+ type EventPersistence = Pick<RuntimePersistence, "appendEvent" | "setRunState" | "createApproval" | "createArtifact">;
4
+ type EventRuntime = {
5
+ persistence: EventPersistence;
6
+ publishEvent: (event: HarnessEvent) => void;
7
+ trackBackgroundTask: (task: Promise<void>) => void;
8
+ backgroundEventTypes: ReadonlySet<string>;
9
+ };
10
+ export declare function emitHarnessEvent(runtime: EventRuntime, threadId: string, runId: string, sequence: number, eventType: string, payload: Record<string, unknown>, source?: HarnessEvent["source"]): Promise<HarnessEvent>;
11
+ export declare function emitRunCreatedEvent(runtime: EventRuntime, threadId: string, runId: string, payload: Record<string, unknown>): Promise<HarnessEvent>;
12
+ export declare function setRunStateAndEmitEvent(runtime: EventRuntime, threadId: string, runId: string, sequence: number, state: RunResult["state"], options: {
13
+ previousState: string | null;
14
+ checkpointRef?: string | null;
15
+ error?: string;
16
+ }): Promise<HarnessEvent>;
17
+ export declare function persistApproval(runtime: EventRuntime, threadId: string, runId: string, checkpointRef: string, input: MessageContent, interruptContent?: string): Promise<InternalApprovalRecord>;
18
+ export declare function requestApprovalAndEmitEvent(runtime: EventRuntime, threadId: string, runId: string, input: MessageContent, interruptContent: string | undefined, checkpointRef: string, sequence: number): Promise<{
19
+ approval: InternalApprovalRecord;
20
+ event: HarnessEvent;
21
+ }>;
22
+ export declare function emitSyntheticFallbackEvent(runtime: EventRuntime, threadId: string, runId: string, selectedAgentId: string, error: unknown, sequence?: number): Promise<void>;
23
+ export {};
@@ -0,0 +1,61 @@
1
+ import { extractMessageText } from "../../../utils/message-content.js";
2
+ import { createHarnessEvent, createPendingApproval } from "../../support/harness-support.js";
3
+ export async function emitHarnessEvent(runtime, threadId, runId, sequence, eventType, payload, source = "runtime") {
4
+ const event = createHarnessEvent(threadId, runId, sequence, eventType, payload, source);
5
+ if (runtime.backgroundEventTypes.has(event.eventType)) {
6
+ runtime.trackBackgroundTask(runtime.persistence.appendEvent(event).catch(() => {
7
+ // Fail open for telemetry-style event persistence.
8
+ }));
9
+ }
10
+ else {
11
+ await runtime.persistence.appendEvent(event);
12
+ }
13
+ runtime.publishEvent(event);
14
+ return event;
15
+ }
16
+ export async function emitRunCreatedEvent(runtime, threadId, runId, payload) {
17
+ return emitHarnessEvent(runtime, threadId, runId, 1, "run.created", payload);
18
+ }
19
+ export async function setRunStateAndEmitEvent(runtime, threadId, runId, sequence, state, options) {
20
+ await runtime.persistence.setRunState(threadId, runId, state, options.checkpointRef ?? null);
21
+ return emitHarnessEvent(runtime, threadId, runId, sequence, "run.state.changed", {
22
+ previousState: options.previousState,
23
+ state,
24
+ checkpointRef: options.checkpointRef ?? null,
25
+ ...(options.error ? { error: options.error } : {}),
26
+ });
27
+ }
28
+ export async function persistApproval(runtime, threadId, runId, checkpointRef, input, interruptContent) {
29
+ const approval = createPendingApproval(threadId, runId, checkpointRef, extractMessageText(input), interruptContent);
30
+ await runtime.persistence.createApproval(approval);
31
+ const artifact = await runtime.persistence.createArtifact(threadId, runId, {
32
+ artifactId: `artifact-approval-${runId}`,
33
+ kind: "approval-packet",
34
+ path: `artifacts/approval-${runId}.json`,
35
+ createdAt: approval.requestedAt,
36
+ }, approval);
37
+ await emitHarnessEvent(runtime, threadId, runId, 5, "artifact.created", {
38
+ artifactId: artifact.artifactId,
39
+ kind: artifact.kind,
40
+ path: artifact.path,
41
+ });
42
+ return approval;
43
+ }
44
+ export async function requestApprovalAndEmitEvent(runtime, threadId, runId, input, interruptContent, checkpointRef, sequence) {
45
+ const approval = await persistApproval(runtime, threadId, runId, checkpointRef, input, interruptContent);
46
+ const event = await emitHarnessEvent(runtime, threadId, runId, sequence, "approval.requested", {
47
+ approvalId: approval.approvalId,
48
+ pendingActionId: approval.pendingActionId,
49
+ toolName: approval.toolName,
50
+ toolCallId: approval.toolCallId,
51
+ allowedDecisions: approval.allowedDecisions,
52
+ checkpointRef,
53
+ });
54
+ return { approval, event };
55
+ }
56
+ export async function emitSyntheticFallbackEvent(runtime, threadId, runId, selectedAgentId, error, sequence = 3) {
57
+ await emitHarnessEvent(runtime, threadId, runId, sequence, "runtime.synthetic_fallback", {
58
+ reason: error instanceof Error ? error.message : String(error),
59
+ selectedAgentId,
60
+ });
61
+ }
@@ -0,0 +1,19 @@
1
+ import type { HarnessEvent, HarnessStreamItem, RunListeners, RunResult } from "../../../contracts/types.js";
2
+ export declare function emitOutputDeltaAndCreateItem(emit: (threadId: string, runId: string, sequence: number, eventType: string, payload: Record<string, unknown>) => Promise<HarnessEvent>, threadId: string, runId: string, agentId: string, content: string): Promise<HarnessStreamItem>;
3
+ export declare function createContentBlocksItem(threadId: string, runId: string, agentId: string, contentBlocks: unknown[]): HarnessStreamItem;
4
+ export declare function createToolResultKey(toolName: string, output: unknown, isError?: boolean): string;
5
+ export declare function dispatchRunListeners(stream: AsyncGenerator<HarnessStreamItem>, listeners: RunListeners, options: {
6
+ notifyListener: <T>(listener: ((value: T) => void | Promise<void>) | undefined, value: T) => Promise<void>;
7
+ getThread: (threadId: string) => Promise<{
8
+ currentState: RunResult["state"];
9
+ latestRunId: string;
10
+ entryAgentId: string;
11
+ runs: Array<{
12
+ agentId: string;
13
+ }>;
14
+ pendingDecision?: {
15
+ approvalId?: string;
16
+ pendingActionId?: string;
17
+ };
18
+ } | null>;
19
+ }): Promise<RunResult>;
@@ -0,0 +1,96 @@
1
+ import { createFallbackRunResultFromLatestEvent, mergeRunResultOutput } from "../run/helpers.js";
2
+ export async function emitOutputDeltaAndCreateItem(emit, threadId, runId, agentId, content) {
3
+ await emit(threadId, runId, 3, "output.delta", {
4
+ content,
5
+ });
6
+ return {
7
+ type: "content",
8
+ threadId,
9
+ runId,
10
+ agentId,
11
+ content,
12
+ };
13
+ }
14
+ export function createContentBlocksItem(threadId, runId, agentId, contentBlocks) {
15
+ return {
16
+ type: "content-blocks",
17
+ threadId,
18
+ runId,
19
+ agentId,
20
+ contentBlocks,
21
+ };
22
+ }
23
+ export function createToolResultKey(toolName, output, isError) {
24
+ let serializedOutput = "";
25
+ try {
26
+ serializedOutput = JSON.stringify(output);
27
+ }
28
+ catch {
29
+ serializedOutput = String(output);
30
+ }
31
+ return JSON.stringify([toolName, serializedOutput, isError === true]);
32
+ }
33
+ export async function dispatchRunListeners(stream, listeners, options) {
34
+ let latestEvent;
35
+ let latestResult;
36
+ let output = "";
37
+ for await (const item of stream) {
38
+ if (item.type === "event") {
39
+ latestEvent = item.event;
40
+ await options.notifyListener(listeners.onEvent, item.event);
41
+ continue;
42
+ }
43
+ if (item.type === "upstream-event") {
44
+ await options.notifyListener(listeners.onUpstreamEvent, item.event);
45
+ continue;
46
+ }
47
+ if (item.type === "result") {
48
+ latestResult = item.result;
49
+ continue;
50
+ }
51
+ if (item.type === "content") {
52
+ output += item.content;
53
+ await options.notifyListener(listeners.onChunk, item.content);
54
+ continue;
55
+ }
56
+ if (item.type === "content-blocks") {
57
+ await options.notifyListener(listeners.onContentBlocks, item.contentBlocks);
58
+ continue;
59
+ }
60
+ if (item.type === "reasoning") {
61
+ await options.notifyListener(listeners.onReasoning, item.content);
62
+ continue;
63
+ }
64
+ if (item.type === "step") {
65
+ await options.notifyListener(listeners.onStep, item.content);
66
+ continue;
67
+ }
68
+ if (item.type === "tool-result") {
69
+ await options.notifyListener(listeners.onToolResult, {
70
+ toolName: item.toolName,
71
+ output: item.output,
72
+ isError: item.isError,
73
+ });
74
+ }
75
+ }
76
+ if (!latestEvent) {
77
+ throw new Error("run did not emit any events");
78
+ }
79
+ if (latestResult) {
80
+ return mergeRunResultOutput(latestResult, output);
81
+ }
82
+ const thread = await options.getThread(latestEvent.threadId);
83
+ if (!thread) {
84
+ throw new Error(`Unknown thread ${latestEvent.threadId}`);
85
+ }
86
+ return createFallbackRunResultFromLatestEvent({
87
+ latestEvent,
88
+ currentState: thread.currentState,
89
+ latestRunId: thread.latestRunId,
90
+ entryAgentId: thread.entryAgentId,
91
+ latestAgentId: thread.runs[0]?.agentId,
92
+ approvalId: thread.pendingDecision?.approvalId,
93
+ pendingActionId: thread.pendingDecision?.pendingActionId,
94
+ output,
95
+ });
96
+ }
@@ -0,0 +1,16 @@
1
+ export * from "./events/event-bus.js";
2
+ export * from "./events/event-sink.js";
3
+ export * from "./events/events.js";
4
+ export * from "./system/health-monitor.js";
5
+ export * from "./run/helpers.js";
6
+ export * from "./system/inventory.js";
7
+ export * from "./system/policy-engine.js";
8
+ export * from "./run/resources.js";
9
+ export * from "./run/resume.js";
10
+ export * from "./run/routing.js";
11
+ export * from "./run/run-lifecycle.js";
12
+ export * from "./run/run-queue.js";
13
+ export * from "./system/skill-requirements.js";
14
+ export * from "./system/store.js";
15
+ export * from "./events/streaming.js";
16
+ export * from "./system/thread-memory-sync.js";