@botbotgo/agent-harness 0.0.247 → 0.0.249
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.
- package/dist/api.d.ts +1 -0
- package/dist/api.js +2 -0
- package/dist/contracts/runtime.d.ts +7 -0
- package/dist/flow/build-flow-graph.js +31 -5
- package/dist/flow/export-sequence-mermaid.js +11 -2
- package/dist/flow/types.d.ts +1 -0
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/persistence/file-store.js +3 -0
- package/dist/persistence/sqlite-store.js +23 -9
- package/dist/persistence/types.d.ts +1 -0
- package/dist/runtime/harness/events/streaming.js +1 -0
- package/dist/runtime/harness/run/stream-run.js +9 -1
- package/dist/runtime/harness/run/thread-records.js +16 -1
- package/dist/runtime/harness.js +3 -0
- package/dist/utils/agent-display.d.ts +1 -0
- package/dist/utils/agent-display.js +18 -0
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
package/dist/api.js
CHANGED
|
@@ -65,6 +65,7 @@ function toPublicRunListeners(listeners) {
|
|
|
65
65
|
sessionId: item.threadId,
|
|
66
66
|
requestId: item.runId,
|
|
67
67
|
agentId: item.agentId,
|
|
68
|
+
agentName: item.agentName,
|
|
68
69
|
event: item.event,
|
|
69
70
|
})
|
|
70
71
|
: undefined,
|
|
@@ -142,6 +143,7 @@ function toPublicRequestSummary(run) {
|
|
|
142
143
|
requestId: run.runId,
|
|
143
144
|
sessionId: run.threadId,
|
|
144
145
|
agentId: run.agentId,
|
|
146
|
+
parentRunId: run.parentRunId,
|
|
145
147
|
executionMode: run.executionMode,
|
|
146
148
|
adapterKind: run.adapterKind,
|
|
147
149
|
createdAt: run.createdAt,
|
|
@@ -98,6 +98,10 @@ export type RuntimeHistoryItem = {
|
|
|
98
98
|
isError?: boolean;
|
|
99
99
|
key: string;
|
|
100
100
|
};
|
|
101
|
+
export type AgentReference = {
|
|
102
|
+
id: string;
|
|
103
|
+
name: string;
|
|
104
|
+
};
|
|
101
105
|
export type RuntimeQueueDiagnostics = {
|
|
102
106
|
status: HealthStatus;
|
|
103
107
|
activeRunSlots: number;
|
|
@@ -414,6 +418,7 @@ export type UpstreamRuntimeEventItem = {
|
|
|
414
418
|
threadId: string;
|
|
415
419
|
runId: string;
|
|
416
420
|
agentId: string;
|
|
421
|
+
agentName?: string;
|
|
417
422
|
event: UpstreamRuntimeEvent;
|
|
418
423
|
};
|
|
419
424
|
export type RuntimeListeners = {
|
|
@@ -461,6 +466,7 @@ export type HarnessStreamItem = {
|
|
|
461
466
|
threadId: string;
|
|
462
467
|
runId: string;
|
|
463
468
|
agentId: string;
|
|
469
|
+
agentName?: string;
|
|
464
470
|
event: UpstreamRuntimeEvent;
|
|
465
471
|
} | {
|
|
466
472
|
type: "result";
|
|
@@ -476,6 +482,7 @@ export type ThreadRunRecord = {
|
|
|
476
482
|
runId: string;
|
|
477
483
|
threadId: string;
|
|
478
484
|
agentId: string;
|
|
485
|
+
parentRunId?: string;
|
|
479
486
|
executionMode: string;
|
|
480
487
|
adapterKind?: string;
|
|
481
488
|
createdAt: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { projectRuntimeTimeline } from "../runtime/harness/events/timeline.js";
|
|
2
2
|
import { createUpstreamTimelineReducer } from "../upstream-events.js";
|
|
3
|
+
import { formatAgentName } from "../utils/agent-display.js";
|
|
3
4
|
function asObject(value) {
|
|
4
5
|
return typeof value === "object" && value !== null ? value : null;
|
|
5
6
|
}
|
|
@@ -17,7 +18,8 @@ function extractUpstreamEventEnvelope(value) {
|
|
|
17
18
|
? nestedEvent
|
|
18
19
|
: value;
|
|
19
20
|
const agentId = readString(typed?.agentId);
|
|
20
|
-
|
|
21
|
+
const agentName = readString(typed?.agentName);
|
|
22
|
+
return { event, agentId: agentId ?? undefined, agentName: agentName ?? undefined };
|
|
21
23
|
}
|
|
22
24
|
function collectNestedAgentNames(value, names = new Set()) {
|
|
23
25
|
if (Array.isArray(value)) {
|
|
@@ -352,6 +354,9 @@ function deriveInitialAgentId(input, runtimeTimeline) {
|
|
|
352
354
|
}
|
|
353
355
|
return "agent";
|
|
354
356
|
}
|
|
357
|
+
function deriveAgentName(agentId, explicitName) {
|
|
358
|
+
return explicitName && explicitName.trim().length > 0 ? explicitName.trim() : formatAgentName(agentId);
|
|
359
|
+
}
|
|
355
360
|
function extractDelegatedAgentId(event) {
|
|
356
361
|
const typed = asObject(event);
|
|
357
362
|
if (!typed) {
|
|
@@ -389,15 +394,21 @@ function convertUpstreamEventsWithAgents(upstreamEvents, initialAgentId) {
|
|
|
389
394
|
const projections = [];
|
|
390
395
|
const delegationNodes = [];
|
|
391
396
|
let currentAgentId = initialAgentId;
|
|
397
|
+
let currentAgentName = deriveAgentName(initialAgentId);
|
|
392
398
|
let ordinal = 0;
|
|
393
399
|
upstreamEvents.forEach((event, index) => {
|
|
394
400
|
const sourceEventId = `upstream:${index + 1}`;
|
|
395
401
|
const envelope = extractUpstreamEventEnvelope(event);
|
|
396
402
|
if (envelope.agentId && envelope.agentId !== currentAgentId) {
|
|
397
403
|
currentAgentId = envelope.agentId;
|
|
404
|
+
currentAgentName = deriveAgentName(currentAgentId, envelope.agentName);
|
|
405
|
+
}
|
|
406
|
+
else if (envelope.agentName) {
|
|
407
|
+
currentAgentName = deriveAgentName(currentAgentId, envelope.agentName);
|
|
398
408
|
}
|
|
399
409
|
const nestedAgentId = extractAgentFromNestedMessages(envelope.event, currentAgentId);
|
|
400
410
|
if (nestedAgentId && nestedAgentId !== currentAgentId) {
|
|
411
|
+
const nestedAgentName = deriveAgentName(nestedAgentId);
|
|
401
412
|
ordinal += 1;
|
|
402
413
|
delegationNodes.push({
|
|
403
414
|
id: `delegate:${slugify(currentAgentId)}:${slugify(nestedAgentId)}:${ordinal}`,
|
|
@@ -410,19 +421,24 @@ function convertUpstreamEventsWithAgents(upstreamEvents, initialAgentId) {
|
|
|
410
421
|
threadId: "",
|
|
411
422
|
runId: "",
|
|
412
423
|
agentId: nestedAgentId,
|
|
424
|
+
agentName: nestedAgentName,
|
|
413
425
|
sourceEventIds: [sourceEventId],
|
|
414
426
|
detail: {
|
|
415
427
|
fromAgentId: currentAgentId,
|
|
428
|
+
fromAgentName: currentAgentName,
|
|
416
429
|
toAgentId: nestedAgentId,
|
|
430
|
+
toAgentName: nestedAgentName,
|
|
417
431
|
},
|
|
418
432
|
});
|
|
419
433
|
currentAgentId = nestedAgentId;
|
|
434
|
+
currentAgentName = nestedAgentName;
|
|
420
435
|
}
|
|
421
436
|
const emitted = reducer.consume(envelope.event);
|
|
422
437
|
for (const projection of emitted) {
|
|
423
438
|
projections.push({
|
|
424
439
|
projection,
|
|
425
440
|
agentId: currentAgentId,
|
|
441
|
+
agentName: currentAgentName,
|
|
426
442
|
sourceEventId,
|
|
427
443
|
});
|
|
428
444
|
}
|
|
@@ -430,6 +446,7 @@ function convertUpstreamEventsWithAgents(upstreamEvents, initialAgentId) {
|
|
|
430
446
|
if (!delegatedAgentId || delegatedAgentId === currentAgentId) {
|
|
431
447
|
return;
|
|
432
448
|
}
|
|
449
|
+
const delegatedAgentName = deriveAgentName(delegatedAgentId);
|
|
433
450
|
ordinal += 1;
|
|
434
451
|
delegationNodes.push({
|
|
435
452
|
id: `delegate:${slugify(initialAgentId)}:${slugify(delegatedAgentId)}:${ordinal}`,
|
|
@@ -442,13 +459,17 @@ function convertUpstreamEventsWithAgents(upstreamEvents, initialAgentId) {
|
|
|
442
459
|
threadId: "",
|
|
443
460
|
runId: "",
|
|
444
461
|
agentId: delegatedAgentId,
|
|
462
|
+
agentName: delegatedAgentName,
|
|
445
463
|
sourceEventIds: [sourceEventId],
|
|
446
464
|
detail: {
|
|
447
465
|
fromAgentId: currentAgentId,
|
|
466
|
+
fromAgentName: currentAgentName,
|
|
448
467
|
toAgentId: delegatedAgentId,
|
|
468
|
+
toAgentName: delegatedAgentName,
|
|
449
469
|
},
|
|
450
470
|
});
|
|
451
471
|
currentAgentId = delegatedAgentId;
|
|
472
|
+
currentAgentName = delegatedAgentName;
|
|
452
473
|
});
|
|
453
474
|
return { projections, delegationNodes };
|
|
454
475
|
}
|
|
@@ -479,7 +500,7 @@ function buildAttempts(projectionRecords, delegationNodes, runtimeGroups, thread
|
|
|
479
500
|
currentGroup = segmentGroups[nextSegmentIndex] ?? currentGroup;
|
|
480
501
|
}
|
|
481
502
|
}
|
|
482
|
-
function createAttempt(kind, label, projection, agentId) {
|
|
503
|
+
function createAttempt(kind, label, projection, agentId, agentName) {
|
|
483
504
|
ordinal += 1;
|
|
484
505
|
const attempt = {
|
|
485
506
|
id: `attempt:${runId}:${slugify(kind)}:${slugify(label)}:${ordinal}`,
|
|
@@ -487,6 +508,7 @@ function buildAttempts(projectionRecords, delegationNodes, runtimeGroups, thread
|
|
|
487
508
|
label,
|
|
488
509
|
status: deriveStatusFromProjection(projection),
|
|
489
510
|
agentId,
|
|
511
|
+
agentName,
|
|
490
512
|
groupId: currentGroup?.id,
|
|
491
513
|
sourceEventIds: [],
|
|
492
514
|
attemptKey: buildAttemptKey(kind, label, currentGroup?.id),
|
|
@@ -589,7 +611,7 @@ function buildAttempts(projectionRecords, delegationNodes, runtimeGroups, thread
|
|
|
589
611
|
const attemptKey = buildAttemptKey(kind, label, currentGroup?.id);
|
|
590
612
|
let attempt;
|
|
591
613
|
if (projection.type === "step" && projection.status === "started") {
|
|
592
|
-
attempt = createAttempt(kind, label, projection, record.agentId);
|
|
614
|
+
attempt = createAttempt(kind, label, projection, record.agentId, record.agentName);
|
|
593
615
|
activeAttemptsByKey.set(attemptKey, attempt);
|
|
594
616
|
}
|
|
595
617
|
else if (projection.type === "tool-result") {
|
|
@@ -597,16 +619,17 @@ function buildAttempts(projectionRecords, delegationNodes, runtimeGroups, thread
|
|
|
597
619
|
const existing = toolAttemptsByName.get(toolName) ?? [];
|
|
598
620
|
attempt = [...existing].reverse().find((candidate) => candidate.groupId === currentGroup?.id) ?? existing[existing.length - 1];
|
|
599
621
|
if (!attempt) {
|
|
600
|
-
attempt = createAttempt("tool", `Calling tool ${titleCase(toolName)}`, projection, record.agentId);
|
|
622
|
+
attempt = createAttempt("tool", `Calling tool ${titleCase(toolName)}`, projection, record.agentId, record.agentName);
|
|
601
623
|
}
|
|
602
624
|
}
|
|
603
625
|
else {
|
|
604
626
|
attempt = activeAttemptsByKey.get(attemptKey);
|
|
605
627
|
if (!attempt) {
|
|
606
|
-
attempt = createAttempt(kind, label, projection, record.agentId);
|
|
628
|
+
attempt = createAttempt(kind, label, projection, record.agentId, record.agentName);
|
|
607
629
|
}
|
|
608
630
|
}
|
|
609
631
|
attempt.agentId = attempt.agentId ?? record.agentId;
|
|
632
|
+
attempt.agentName = attempt.agentName ?? record.agentName;
|
|
610
633
|
attempt.projectionKeys.push(projection.key);
|
|
611
634
|
attempt.sourceEventIds.push(record.sourceEventId);
|
|
612
635
|
if (projection.type === "step") {
|
|
@@ -684,6 +707,7 @@ function buildAttempts(projectionRecords, delegationNodes, runtimeGroups, thread
|
|
|
684
707
|
threadId,
|
|
685
708
|
runId,
|
|
686
709
|
agentId: attempt.agentId,
|
|
710
|
+
agentName: attempt.agentName,
|
|
687
711
|
groupId: attempt.groupId,
|
|
688
712
|
sequenceStart: attempt.sequenceStart,
|
|
689
713
|
sequenceEnd: attempt.sequenceEnd,
|
|
@@ -730,11 +754,13 @@ export function buildFlowGraph(input) {
|
|
|
730
754
|
const { nodes: runtimeNodes, edges: runtimeEdges, groups: runtimeGroups } = buildRuntimeNodes(runtimeTimeline);
|
|
731
755
|
for (const node of runtimeNodes) {
|
|
732
756
|
node.agentId = typeof node.detail.agentId === "string" ? node.detail.agentId : initialAgentId;
|
|
757
|
+
node.agentName = deriveAgentName(node.agentId);
|
|
733
758
|
}
|
|
734
759
|
const projectionRecords = input.upstreamProjections
|
|
735
760
|
? input.upstreamProjections.map((projection, index) => ({
|
|
736
761
|
projection,
|
|
737
762
|
agentId: initialAgentId,
|
|
763
|
+
agentName: deriveAgentName(initialAgentId),
|
|
738
764
|
sourceEventId: "key" in projection ? projection.key : `projection:${index + 1}`,
|
|
739
765
|
}))
|
|
740
766
|
: upstreamContext.projections;
|
|
@@ -5,6 +5,13 @@ function sanitizeAlias(value) {
|
|
|
5
5
|
function escapeLabel(value) {
|
|
6
6
|
return value.replace(/"/g, '\\"');
|
|
7
7
|
}
|
|
8
|
+
function formatAgentParticipantLabel(node) {
|
|
9
|
+
const agentId = node.agentId ?? "agent";
|
|
10
|
+
if (node.agentName && node.agentName !== agentId) {
|
|
11
|
+
return `Agent:${agentId} (${node.agentName})`;
|
|
12
|
+
}
|
|
13
|
+
return `Agent:${agentId}`;
|
|
14
|
+
}
|
|
8
15
|
function selectNodes(graph, options) {
|
|
9
16
|
const includedKinds = options.includeKinds
|
|
10
17
|
? new Set(options.includeKinds)
|
|
@@ -33,7 +40,7 @@ function getParticipantsForNode(node) {
|
|
|
33
40
|
const agentParticipant = {
|
|
34
41
|
id: `agent:${node.agentId ?? "agent"}`,
|
|
35
42
|
alias: sanitizeAlias(`Agent_${node.agentId ?? "agent"}`),
|
|
36
|
-
label:
|
|
43
|
+
label: formatAgentParticipantLabel(node),
|
|
37
44
|
};
|
|
38
45
|
if (node.kind === "run") {
|
|
39
46
|
return [
|
|
@@ -48,7 +55,9 @@ function getParticipantsForNode(node) {
|
|
|
48
55
|
{
|
|
49
56
|
id: `agent:${fromAgentId}`,
|
|
50
57
|
alias: sanitizeAlias(`Agent_${fromAgentId}`),
|
|
51
|
-
label:
|
|
58
|
+
label: typeof node.detail.fromAgentName === "string" && node.detail.fromAgentName !== fromAgentId
|
|
59
|
+
? `Agent:${fromAgentId} (${node.detail.fromAgentName})`
|
|
60
|
+
: `Agent:${fromAgentId}`,
|
|
52
61
|
},
|
|
53
62
|
agentParticipant,
|
|
54
63
|
];
|
package/dist/flow/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.248";
|
package/dist/package-version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.248";
|
|
@@ -67,10 +67,12 @@ export class FilePersistence {
|
|
|
67
67
|
const runDir = this.runDir(input.threadId, input.runId);
|
|
68
68
|
await ensureDir(path.join(runDir, "events"));
|
|
69
69
|
await ensureDir(path.join(runDir, "approvals"));
|
|
70
|
+
const threadMeta = await this.getThreadMeta(input.threadId);
|
|
70
71
|
const meta = {
|
|
71
72
|
runId: input.runId,
|
|
72
73
|
threadId: input.threadId,
|
|
73
74
|
agentId: input.agentId,
|
|
75
|
+
parentRunId: threadMeta?.latestRunId ?? null,
|
|
74
76
|
executionMode: input.executionMode,
|
|
75
77
|
adapterKind: input.adapterKind ?? input.executionMode,
|
|
76
78
|
createdAt: input.createdAt,
|
|
@@ -266,6 +268,7 @@ export class FilePersistence {
|
|
|
266
268
|
runId: meta.runId,
|
|
267
269
|
threadId: meta.threadId,
|
|
268
270
|
agentId: meta.agentId,
|
|
271
|
+
...(meta.parentRunId ? { parentRunId: meta.parentRunId } : {}),
|
|
269
272
|
executionMode: meta.executionMode,
|
|
270
273
|
adapterKind: meta.adapterKind ?? meta.executionMode,
|
|
271
274
|
createdAt: meta.createdAt,
|
|
@@ -4,7 +4,7 @@ import { createClient } from "@libsql/client";
|
|
|
4
4
|
import { fileExists, readJson, writeJson } from "../utils/fs.js";
|
|
5
5
|
import { SqliteRunContextStore } from "./sqlite-run-context-store.js";
|
|
6
6
|
import { SqliteRunQueueStore } from "./sqlite-run-queue-store.js";
|
|
7
|
-
const RUNTIME_SQLITE_SCHEMA_VERSION =
|
|
7
|
+
const RUNTIME_SQLITE_SCHEMA_VERSION = 5;
|
|
8
8
|
const RUNTIME_SQLITE_SCHEMA_FAMILY = "agent-harness-runtime";
|
|
9
9
|
function asRow(value) {
|
|
10
10
|
return value;
|
|
@@ -168,6 +168,7 @@ export class SqlitePersistence {
|
|
|
168
168
|
run_id TEXT PRIMARY KEY,
|
|
169
169
|
thread_id TEXT NOT NULL,
|
|
170
170
|
agent_id TEXT NOT NULL,
|
|
171
|
+
parent_run_id TEXT,
|
|
171
172
|
execution_mode TEXT NOT NULL,
|
|
172
173
|
adapter_kind TEXT,
|
|
173
174
|
created_at TEXT NOT NULL,
|
|
@@ -403,6 +404,7 @@ export class SqlitePersistence {
|
|
|
403
404
|
runId: asString(row.run_id),
|
|
404
405
|
threadId: asString(row.thread_id),
|
|
405
406
|
agentId: asString(row.agent_id),
|
|
407
|
+
...(asNullableString(row.parent_run_id) ? { parentRunId: asNullableString(row.parent_run_id) } : {}),
|
|
406
408
|
executionMode: asString(row.execution_mode),
|
|
407
409
|
adapterKind: asNullableString(row.adapter_kind) ?? undefined,
|
|
408
410
|
createdAt: asString(row.created_at),
|
|
@@ -473,12 +475,19 @@ export class SqlitePersistence {
|
|
|
473
475
|
SELECT run_id, thread_id, created_at, NULL, updated_at, agent_id, json_array(agent_id), NULL, '[]'
|
|
474
476
|
FROM runs
|
|
475
477
|
`);
|
|
478
|
+
await this.rawExecute("ALTER TABLE runs ADD COLUMN parent_run_id TEXT");
|
|
476
479
|
await this.rawExecute("INSERT OR REPLACE INTO runtime_metadata (key, value) VALUES (?, ?)", ["schema_version", String(RUNTIME_SQLITE_SCHEMA_VERSION)]);
|
|
477
480
|
return;
|
|
478
481
|
}
|
|
479
482
|
if (version === "3") {
|
|
480
483
|
await this.rawExecute("ALTER TABLE run_inspection ADD COLUMN upstream_events_json TEXT NOT NULL DEFAULT '[]'");
|
|
481
484
|
await this.rawExecute("UPDATE run_inspection SET upstream_events_json = '[]' WHERE upstream_events_json IS NULL");
|
|
485
|
+
await this.rawExecute("ALTER TABLE runs ADD COLUMN parent_run_id TEXT");
|
|
486
|
+
await this.rawExecute("INSERT OR REPLACE INTO runtime_metadata (key, value) VALUES (?, ?)", ["schema_version", String(RUNTIME_SQLITE_SCHEMA_VERSION)]);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
if (version === "4") {
|
|
490
|
+
await this.rawExecute("ALTER TABLE runs ADD COLUMN parent_run_id TEXT");
|
|
482
491
|
await this.rawExecute("INSERT OR REPLACE INTO runtime_metadata (key, value) VALUES (?, ?)", ["schema_version", String(RUNTIME_SQLITE_SCHEMA_VERSION)]);
|
|
483
492
|
return;
|
|
484
493
|
}
|
|
@@ -493,6 +502,7 @@ export class SqlitePersistence {
|
|
|
493
502
|
VALUES (?, ?, ?, ?, ?, ?, ?)`, [input.threadId, "default", input.agentId, input.status, input.runId, input.createdAt, input.createdAt]);
|
|
494
503
|
}
|
|
495
504
|
async bootstrapRun(input) {
|
|
505
|
+
const parentRunId = input.createThread ? null : (await this.getThreadMeta(input.threadId))?.latestRunId ?? null;
|
|
496
506
|
await mkdir(this.threadDir(input.threadId), { recursive: true });
|
|
497
507
|
await mkdir(path.join(this.runDir(input.threadId, input.runId), "events"), { recursive: true });
|
|
498
508
|
const steps = [];
|
|
@@ -506,12 +516,13 @@ export class SqlitePersistence {
|
|
|
506
516
|
}
|
|
507
517
|
steps.push({
|
|
508
518
|
sql: `INSERT OR REPLACE INTO runs
|
|
509
|
-
(run_id, thread_id, agent_id, execution_mode, adapter_kind, created_at, updated_at, state, previous_state, state_entered_at, last_transition_at, resumable, checkpoint_ref)
|
|
510
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
519
|
+
(run_id, thread_id, agent_id, parent_run_id, execution_mode, adapter_kind, created_at, updated_at, state, previous_state, state_entered_at, last_transition_at, resumable, checkpoint_ref)
|
|
520
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
511
521
|
args: [
|
|
512
522
|
input.runId,
|
|
513
523
|
input.threadId,
|
|
514
524
|
input.agentId,
|
|
525
|
+
parentRunId,
|
|
515
526
|
input.executionMode,
|
|
516
527
|
input.adapterKind ?? input.executionMode ?? null,
|
|
517
528
|
input.createdAt,
|
|
@@ -562,13 +573,15 @@ export class SqlitePersistence {
|
|
|
562
573
|
await this.executeTransaction(steps);
|
|
563
574
|
}
|
|
564
575
|
async createRun(input) {
|
|
576
|
+
const parentRunId = (await this.getThreadMeta(input.threadId))?.latestRunId ?? null;
|
|
565
577
|
await mkdir(path.join(this.runDir(input.threadId, input.runId), "events"), { recursive: true });
|
|
566
578
|
await this.execute(`INSERT OR REPLACE INTO runs
|
|
567
|
-
(run_id, thread_id, agent_id, execution_mode, adapter_kind, created_at, updated_at, state, previous_state, state_entered_at, last_transition_at, resumable, checkpoint_ref)
|
|
568
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
579
|
+
(run_id, thread_id, agent_id, parent_run_id, execution_mode, adapter_kind, created_at, updated_at, state, previous_state, state_entered_at, last_transition_at, resumable, checkpoint_ref)
|
|
580
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
569
581
|
input.runId,
|
|
570
582
|
input.threadId,
|
|
571
583
|
input.agentId,
|
|
584
|
+
parentRunId,
|
|
572
585
|
input.executionMode,
|
|
573
586
|
input.adapterKind ?? input.executionMode ?? null,
|
|
574
587
|
input.createdAt,
|
|
@@ -698,7 +711,7 @@ export class SqlitePersistence {
|
|
|
698
711
|
["runs.thread_id = ?", filter.threadId],
|
|
699
712
|
["runs.state = ?", filter.state],
|
|
700
713
|
]);
|
|
701
|
-
const rows = await this.selectAll(`SELECT runs.run_id, runs.thread_id, runs.agent_id, runs.execution_mode, runs.adapter_kind, runs.created_at, runs.updated_at, runs.state, runs.checkpoint_ref, runs.resumable,
|
|
714
|
+
const rows = await this.selectAll(`SELECT runs.run_id, runs.thread_id, runs.agent_id, runs.parent_run_id, runs.execution_mode, runs.adapter_kind, runs.created_at, runs.updated_at, runs.state, runs.checkpoint_ref, runs.resumable,
|
|
702
715
|
run_inspection.started_at, run_inspection.ended_at, run_inspection.last_activity_at, run_inspection.current_agent_id, run_inspection.delegation_chain_json, run_inspection.runtime_snapshot_json
|
|
703
716
|
FROM runs
|
|
704
717
|
LEFT JOIN run_inspection ON run_inspection.run_id = runs.run_id
|
|
@@ -707,7 +720,7 @@ export class SqlitePersistence {
|
|
|
707
720
|
return rows.map((row) => this.mapRunSummary(row));
|
|
708
721
|
}
|
|
709
722
|
async getRun(runId) {
|
|
710
|
-
const row = await this.selectOne(`SELECT runs.run_id, runs.thread_id, runs.agent_id, runs.execution_mode, runs.adapter_kind, runs.created_at, runs.updated_at, runs.state, runs.checkpoint_ref, runs.resumable,
|
|
723
|
+
const row = await this.selectOne(`SELECT runs.run_id, runs.thread_id, runs.agent_id, runs.parent_run_id, runs.execution_mode, runs.adapter_kind, runs.created_at, runs.updated_at, runs.state, runs.checkpoint_ref, runs.resumable,
|
|
711
724
|
run_inspection.started_at, run_inspection.ended_at, run_inspection.last_activity_at, run_inspection.current_agent_id, run_inspection.delegation_chain_json, run_inspection.runtime_snapshot_json
|
|
712
725
|
FROM runs
|
|
713
726
|
LEFT JOIN run_inspection ON run_inspection.run_id = runs.run_id
|
|
@@ -737,7 +750,7 @@ export class SqlitePersistence {
|
|
|
737
750
|
};
|
|
738
751
|
}
|
|
739
752
|
async listThreadRuns(threadId) {
|
|
740
|
-
const rows = await this.selectAll(`SELECT runs.run_id, runs.thread_id, runs.agent_id, runs.execution_mode, runs.adapter_kind, runs.created_at, runs.updated_at, runs.state, runs.checkpoint_ref, runs.resumable,
|
|
753
|
+
const rows = await this.selectAll(`SELECT runs.run_id, runs.thread_id, runs.agent_id, runs.parent_run_id, runs.execution_mode, runs.adapter_kind, runs.created_at, runs.updated_at, runs.state, runs.checkpoint_ref, runs.resumable,
|
|
741
754
|
run_inspection.started_at, run_inspection.ended_at, run_inspection.last_activity_at, run_inspection.current_agent_id, run_inspection.delegation_chain_json, run_inspection.runtime_snapshot_json
|
|
742
755
|
FROM runs
|
|
743
756
|
LEFT JOIN run_inspection ON run_inspection.run_id = runs.run_id
|
|
@@ -770,7 +783,7 @@ export class SqlitePersistence {
|
|
|
770
783
|
return rows.map((row) => this.mapApproval(row));
|
|
771
784
|
}
|
|
772
785
|
async getRunMeta(threadId, runId) {
|
|
773
|
-
const row = await this.selectOne(`SELECT run_id, thread_id, agent_id, execution_mode, adapter_kind, created_at, updated_at
|
|
786
|
+
const row = await this.selectOne(`SELECT run_id, thread_id, agent_id, parent_run_id, execution_mode, adapter_kind, created_at, updated_at
|
|
774
787
|
FROM runs
|
|
775
788
|
WHERE thread_id = ? AND run_id = ?`, [threadId, runId]);
|
|
776
789
|
if (!row) {
|
|
@@ -780,6 +793,7 @@ export class SqlitePersistence {
|
|
|
780
793
|
runId: asString(row.run_id),
|
|
781
794
|
threadId: asString(row.thread_id),
|
|
782
795
|
agentId: asString(row.agent_id),
|
|
796
|
+
parentRunId: asNullableString(row.parent_run_id),
|
|
783
797
|
executionMode: asString(row.execution_mode),
|
|
784
798
|
adapterKind: asNullableString(row.adapter_kind) ?? undefined,
|
|
785
799
|
createdAt: asString(row.created_at),
|
|
@@ -3,6 +3,7 @@ import { renderRuntimeFailure, renderToolFailure } from "../../support/harness-s
|
|
|
3
3
|
import { getBindingPrimaryModel } from "../../support/compiled-binding.js";
|
|
4
4
|
import { createContentBlocksItem, createToolResultKey, } from "../events/streaming.js";
|
|
5
5
|
import { consumeRunInspectionUpstreamEvent } from "./inspection.js";
|
|
6
|
+
import { formatAgentName } from "../../../utils/agent-display.js";
|
|
6
7
|
function normalizeStreamChunk(chunk) {
|
|
7
8
|
if (typeof chunk === "string") {
|
|
8
9
|
if (chunk.startsWith(AGENT_INTERRUPT_SENTINEL_PREFIX)) {
|
|
@@ -45,6 +46,7 @@ export async function* streamHarnessRun(options) {
|
|
|
45
46
|
let streamActivityObserved = false;
|
|
46
47
|
let nonUpstreamStreamActivityObserved = false;
|
|
47
48
|
let currentAgentId = options.selectedAgentId;
|
|
49
|
+
let currentAgentName = formatAgentName(options.selectedAgentId);
|
|
48
50
|
let delegationChain = [options.selectedAgentId];
|
|
49
51
|
let syntheticFallback;
|
|
50
52
|
try {
|
|
@@ -76,17 +78,23 @@ export async function* streamHarnessRun(options) {
|
|
|
76
78
|
binding: options.binding,
|
|
77
79
|
});
|
|
78
80
|
currentAgentId = inspection.currentAgentId;
|
|
81
|
+
currentAgentName = formatAgentName(currentAgentId);
|
|
79
82
|
delegationChain = inspection.delegationChain;
|
|
80
83
|
await options.updateRunInspection(options.threadId, options.runId, {
|
|
81
84
|
currentAgentId,
|
|
82
85
|
delegationChain,
|
|
83
|
-
appendUpstreamEvent:
|
|
86
|
+
appendUpstreamEvent: {
|
|
87
|
+
agentId: currentAgentId,
|
|
88
|
+
agentName: currentAgentName,
|
|
89
|
+
event: normalizedChunk.event,
|
|
90
|
+
},
|
|
84
91
|
});
|
|
85
92
|
yield {
|
|
86
93
|
type: "upstream-event",
|
|
87
94
|
threadId: options.threadId,
|
|
88
95
|
runId: options.runId,
|
|
89
96
|
agentId: currentAgentId,
|
|
97
|
+
agentName: currentAgentName,
|
|
90
98
|
event: normalizedChunk.event,
|
|
91
99
|
};
|
|
92
100
|
continue;
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { isTerminalRunState, toInspectableApprovalRecord } from "./helpers.js";
|
|
2
2
|
import { projectRuntimeTimeline } from "../events/timeline.js";
|
|
3
3
|
import { createUpstreamTimelineReducer } from "../../../upstream-events.js";
|
|
4
|
+
function unwrapPersistedUpstreamEvent(event) {
|
|
5
|
+
if (typeof event !== "object" || event === null || Array.isArray(event)) {
|
|
6
|
+
return event;
|
|
7
|
+
}
|
|
8
|
+
const typed = event;
|
|
9
|
+
if (Object.prototype.hasOwnProperty.call(typed, "event")
|
|
10
|
+
&& typeof typed.event === "object"
|
|
11
|
+
&& typed.event !== null
|
|
12
|
+
&& !Array.isArray(typed.event)) {
|
|
13
|
+
return typed.event;
|
|
14
|
+
}
|
|
15
|
+
return event;
|
|
16
|
+
}
|
|
4
17
|
function selectLatestPendingApproval(approvals) {
|
|
5
18
|
return approvals
|
|
6
19
|
.filter((approval) => approval.status === "pending")
|
|
@@ -8,7 +21,7 @@ function selectLatestPendingApproval(approvals) {
|
|
|
8
21
|
}
|
|
9
22
|
function buildRunInspectionProjection(upstreamEvents) {
|
|
10
23
|
const reducer = createUpstreamTimelineReducer();
|
|
11
|
-
const history = upstreamEvents.flatMap((event) => reducer.consume(event));
|
|
24
|
+
const history = upstreamEvents.flatMap((event) => reducer.consume(unwrapPersistedUpstreamEvent(event)));
|
|
12
25
|
return {
|
|
13
26
|
upstreamEvents,
|
|
14
27
|
history,
|
|
@@ -22,6 +35,7 @@ export async function buildRequestInspectionRecord(persistence, request) {
|
|
|
22
35
|
requestId: request.runId,
|
|
23
36
|
sessionId: request.threadId,
|
|
24
37
|
agentId: request.agentId,
|
|
38
|
+
parentRunId: request.parentRunId,
|
|
25
39
|
executionMode: request.executionMode,
|
|
26
40
|
adapterKind: request.adapterKind,
|
|
27
41
|
createdAt: request.createdAt,
|
|
@@ -48,6 +62,7 @@ function toRunRecord(request) {
|
|
|
48
62
|
runId: request.requestId,
|
|
49
63
|
threadId: request.sessionId,
|
|
50
64
|
agentId: request.agentId,
|
|
65
|
+
parentRunId: request.parentRunId,
|
|
51
66
|
executionMode: request.executionMode,
|
|
52
67
|
adapterKind: request.adapterKind,
|
|
53
68
|
createdAt: request.createdAt,
|
package/dist/runtime/harness.js
CHANGED
|
@@ -385,6 +385,7 @@ export class AgentHarnessRuntime {
|
|
|
385
385
|
requestId: request.runId,
|
|
386
386
|
sessionId: request.threadId,
|
|
387
387
|
agentId: request.agentId,
|
|
388
|
+
parentRunId: request.parentRunId,
|
|
388
389
|
executionMode: request.executionMode,
|
|
389
390
|
adapterKind: request.adapterKind,
|
|
390
391
|
createdAt: request.createdAt,
|
|
@@ -410,6 +411,7 @@ export class AgentHarnessRuntime {
|
|
|
410
411
|
runId: request.requestId,
|
|
411
412
|
threadId: request.sessionId,
|
|
412
413
|
agentId: request.agentId,
|
|
414
|
+
parentRunId: request.parentRunId,
|
|
413
415
|
executionMode: request.executionMode,
|
|
414
416
|
adapterKind: request.adapterKind,
|
|
415
417
|
createdAt: request.createdAt,
|
|
@@ -1800,6 +1802,7 @@ function toRequestSummary(summary) {
|
|
|
1800
1802
|
requestId: summary.runId,
|
|
1801
1803
|
sessionId: summary.threadId,
|
|
1802
1804
|
agentId: summary.agentId,
|
|
1805
|
+
parentRunId: summary.parentRunId,
|
|
1803
1806
|
executionMode: summary.executionMode,
|
|
1804
1807
|
adapterKind: summary.adapterKind,
|
|
1805
1808
|
createdAt: summary.createdAt,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function formatAgentName(agentId: string): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function normalizeSegment(value) {
|
|
2
|
+
return value
|
|
3
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
4
|
+
.replace(/[_-]+/g, " ")
|
|
5
|
+
.replace(/\s+/g, " ")
|
|
6
|
+
.trim();
|
|
7
|
+
}
|
|
8
|
+
export function formatAgentName(agentId) {
|
|
9
|
+
const normalized = normalizeSegment(agentId);
|
|
10
|
+
if (!normalized) {
|
|
11
|
+
return "Agent";
|
|
12
|
+
}
|
|
13
|
+
return normalized
|
|
14
|
+
.split(" ")
|
|
15
|
+
.filter(Boolean)
|
|
16
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
17
|
+
.join(" ");
|
|
18
|
+
}
|