@botbotgo/agent-harness 0.0.291 → 0.0.293

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.
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.290";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.292";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.290";
1
+ export const AGENT_HARNESS_VERSION = "0.0.292";
@@ -17,6 +17,7 @@ export declare class FilePersistence implements RuntimePersistence {
17
17
  private requestQueuePath;
18
18
  private requestControlPath;
19
19
  private traceItemsPath;
20
+ private writeSessionHead;
20
21
  initialize(): Promise<void>;
21
22
  sessionDir(sessionId: string): string;
22
23
  requestDir(sessionId: string, requestId: string): string;
@@ -31,6 +31,24 @@ export class FilePersistence {
31
31
  traceItemsPath(sessionId, requestId) {
32
32
  return path.join(this.requestDir(sessionId, requestId), "trace-items.ndjson");
33
33
  }
34
+ async writeSessionHead(sessionId, input) {
35
+ const sessionMetaPath = path.join(this.sessionDir(sessionId), "meta.json");
36
+ const sessionMeta = await readJson(sessionMetaPath);
37
+ await Promise.all([
38
+ writeJson(sessionMetaPath, {
39
+ ...sessionMeta,
40
+ status: input.status,
41
+ latestRequestId: input.latestRequestId,
42
+ updatedAt: input.updatedAt,
43
+ }),
44
+ writeJson(this.sessionIndexPath(sessionId), {
45
+ sessionId,
46
+ status: input.status,
47
+ latestRequestId: input.latestRequestId,
48
+ updatedAt: input.updatedAt,
49
+ }),
50
+ ]);
51
+ }
34
52
  async initialize() {
35
53
  await Promise.all([
36
54
  "indexes/sessions",
@@ -74,11 +92,14 @@ export class FilePersistence {
74
92
  await ensureDir(path.join(requestDir, "events"));
75
93
  await ensureDir(path.join(requestDir, "approvals"));
76
94
  const sessionMeta = await this.getSessionMeta(input.sessionId);
95
+ const parentRequestId = sessionMeta?.latestRequestId === input.requestId
96
+ ? null
97
+ : sessionMeta?.latestRequestId ?? null;
77
98
  const meta = {
78
99
  requestId: input.requestId,
79
100
  sessionId: input.sessionId,
80
101
  agentId: input.agentId,
81
- parentRequestId: sessionMeta?.latestRequestId ?? null,
102
+ parentRequestId,
82
103
  executionMode: input.executionMode,
83
104
  adapterKind: input.adapterKind ?? input.executionMode,
84
105
  createdAt: input.createdAt,
@@ -139,6 +160,11 @@ export class FilePersistence {
139
160
  workerStartedAt: null,
140
161
  }),
141
162
  ]);
163
+ await this.writeSessionHead(input.sessionId, {
164
+ latestRequestId: input.requestId,
165
+ status: "running",
166
+ updatedAt: input.createdAt,
167
+ });
142
168
  }
143
169
  async setRequestState(sessionId, requestId, state, checkpointRef) {
144
170
  const lifecyclePath = path.join(this.requestDir(sessionId, requestId), "lifecycle.json");
@@ -186,16 +212,9 @@ export class FilePersistence {
186
212
  resumable: next.resumable,
187
213
  updatedAt: now,
188
214
  });
189
- const sessionMetaPath = path.join(this.sessionDir(sessionId), "meta.json");
190
- const sessionMeta = await readJson(sessionMetaPath);
191
- sessionMeta.status = state;
192
- sessionMeta.updatedAt = now;
193
- sessionMeta.latestRequestId = requestId;
194
- await writeJson(sessionMetaPath, sessionMeta);
195
- await writeJson(this.sessionIndexPath(sessionId), {
196
- sessionId,
197
- status: state,
215
+ await this.writeSessionHead(sessionId, {
198
216
  latestRequestId: requestId,
217
+ status: state,
199
218
  updatedAt: now,
200
219
  });
201
220
  }
@@ -406,19 +425,20 @@ export class FilePersistence {
406
425
  }
407
426
  async getRequestInspection(sessionId, requestId) {
408
427
  const inspection = await readJson(path.join(this.requestDir(sessionId, requestId), "inspection.json"));
428
+ const traceItems = await this.listRequestTraceItems(sessionId, requestId);
409
429
  return {
410
430
  ...inspection,
411
- traceItems: (await this.listRequestTraceItems(sessionId, requestId))
412
- ?? (Array.isArray(inspection.traceItems)
413
- ? inspection.traceItems
414
- : Array.isArray(inspection.upstreamEvents)
415
- ? inspection.upstreamEvents
416
- : []),
431
+ traceItems,
417
432
  };
418
433
  }
419
434
  async updateRequestInspection(sessionId, requestId, patch) {
420
435
  const inspectionPath = path.join(this.requestDir(sessionId, requestId), "inspection.json");
421
436
  const current = await readJson(inspectionPath);
437
+ const traceItems = Array.isArray(current.traceItems)
438
+ ? current.traceItems
439
+ : Array.isArray(current.upstreamEvents)
440
+ ? current.upstreamEvents
441
+ : [];
422
442
  await writeJson(inspectionPath, {
423
443
  ...current,
424
444
  ...(patch.endedAt !== undefined ? { endedAt: patch.endedAt } : {}),
@@ -426,7 +446,7 @@ export class FilePersistence {
426
446
  ...(patch.currentAgentId !== undefined ? { currentAgentId: patch.currentAgentId } : {}),
427
447
  ...(patch.delegationChain ? { delegationChain: patch.delegationChain } : {}),
428
448
  ...(patch.runtimeSnapshot !== undefined ? { runtimeSnapshot: patch.runtimeSnapshot } : {}),
429
- traceItems: Array.isArray(current.traceItems) ? current.traceItems : [],
449
+ traceItems,
430
450
  });
431
451
  }
432
452
  async appendRequestTraceItem(sessionId, requestId, item) {
@@ -436,11 +456,14 @@ export class FilePersistence {
436
456
  const traceItemsPath = this.traceItemsPath(sessionId, requestId);
437
457
  if (await fileExists(traceItemsPath)) {
438
458
  const contents = await readFile(traceItemsPath, "utf8");
439
- return contents
459
+ const traceItems = contents
440
460
  .split("\n")
441
461
  .map((line) => line.trim())
442
462
  .filter((line) => line.length > 0)
443
463
  .map((line) => JSON.parse(line));
464
+ if (traceItems.length > 0) {
465
+ return traceItems;
466
+ }
444
467
  }
445
468
  const inspection = await readJson(path.join(this.requestDir(sessionId, requestId), "inspection.json"));
446
469
  return Array.isArray(inspection.traceItems)
@@ -568,6 +568,14 @@ export class SqlitePersistence {
568
568
  args: [input.sessionId, "default", input.agentId, input.status, input.requestId, input.createdAt, input.createdAt],
569
569
  });
570
570
  }
571
+ else {
572
+ steps.push({
573
+ sql: `UPDATE sessions
574
+ SET status = ?, latest_request_id = ?, updated_at = ?
575
+ WHERE session_id = ?`,
576
+ args: [input.status, input.requestId, input.createdAt, input.sessionId],
577
+ });
578
+ }
571
579
  steps.push({
572
580
  sql: `INSERT OR REPLACE INTO requests
573
581
  (request_id, session_id, agent_id, parent_request_id, execution_mode, adapter_kind, created_at, updated_at, state, previous_state, state_entered_at, last_transition_at, resumable, checkpoint_ref)
@@ -627,7 +635,10 @@ export class SqlitePersistence {
627
635
  await this.executeTransaction(steps);
628
636
  }
629
637
  async createRequest(input) {
630
- const parentRequestId = (await this.getSessionMeta(input.sessionId))?.latestRequestId ?? null;
638
+ const sessionMeta = await this.getSessionMeta(input.sessionId);
639
+ const parentRequestId = sessionMeta?.latestRequestId === input.requestId
640
+ ? null
641
+ : sessionMeta?.latestRequestId ?? null;
631
642
  await mkdir(path.join(this.requestDir(input.sessionId, input.requestId), "events"), { recursive: true });
632
643
  await this.execute(`INSERT OR REPLACE INTO requests
633
644
  (request_id, session_id, agent_id, parent_request_id, execution_mode, adapter_kind, created_at, updated_at, state, previous_state, state_entered_at, last_transition_at, resumable, checkpoint_ref)
@@ -662,6 +673,9 @@ export class SqlitePersistence {
662
673
  input.runtimeSnapshot ? JSON.stringify(input.runtimeSnapshot) : null,
663
674
  "[]",
664
675
  ]);
676
+ await this.execute(`UPDATE sessions
677
+ SET status = ?, latest_request_id = ?, updated_at = ?
678
+ WHERE session_id = ?`, ["running", input.requestId, input.createdAt, input.sessionId]);
665
679
  }
666
680
  async setRequestState(sessionId, requestId, state, checkpointRef) {
667
681
  const current = await this.getRequestLifecycle(sessionId, requestId);
@@ -50,10 +50,21 @@ export function createAcpStdioClient(options) {
50
50
  if (!trimmed) {
51
51
  continue;
52
52
  }
53
- const parsed = JSON.parse(trimmed);
53
+ let parsed;
54
+ try {
55
+ parsed = JSON.parse(trimmed);
56
+ }
57
+ catch {
58
+ continue;
59
+ }
54
60
  if (isNotification(parsed)) {
55
61
  for (const listener of Array.from(listeners)) {
56
- listener(parsed);
62
+ try {
63
+ listener(parsed);
64
+ }
65
+ catch {
66
+ // Ignore listener failures so one subscriber cannot tear down the transport.
67
+ }
57
68
  }
58
69
  continue;
59
70
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.291",
3
+ "version": "0.0.293",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",