pi-famulus 0.1.3 → 0.1.4
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/README.md +3 -1
- package/package.json +8 -6
- package/src/agents/builtins.ts +5 -22
- package/src/agents/definition.ts +4 -6
- package/src/bash-override.ts +8 -21
- package/src/behavior-guidelines.ts +40 -16
- package/src/comms/comms.ts +7 -3
- package/src/comms/tools.ts +11 -36
- package/src/format.ts +31 -14
- package/src/index.ts +123 -33
- package/src/manager-client.ts +265 -114
- package/src/monitor.ts +14 -33
- package/src/prompts.generated.ts +183 -0
- package/src/shell-exec.ts +6 -2
- package/src/subagent/admission.ts +224 -0
- package/src/subagent/agent-records.ts +66 -3
- package/src/subagent/child-bash.ts +6 -14
- package/src/subagent/overrun.ts +36 -21
- package/src/subagent/pi-runtime.ts +116 -31
- package/src/subagent/registry.ts +165 -42
- package/src/subagent/runner.ts +335 -60
- package/src/subagent/tool.ts +49 -72
- package/src/subagent/types.ts +60 -5
- package/src/subagent/usage.ts +48 -0
- package/src/task-tools.ts +15 -25
- package/src/tui/message-renderers.ts +17 -1
- package/src/wake.ts +66 -37
- package/src/work-index.ts +4 -0
package/src/subagent/registry.ts
CHANGED
|
@@ -26,9 +26,17 @@ import type {
|
|
|
26
26
|
ChildRunRequest,
|
|
27
27
|
ChildRunner,
|
|
28
28
|
ChildStatus,
|
|
29
|
+
ChildTokenUsage,
|
|
30
|
+
ChildWallUsage,
|
|
29
31
|
DisposableChildHandle,
|
|
30
32
|
} from "./types";
|
|
31
33
|
|
|
34
|
+
async function awaitDisposals(disposals: Array<void | Promise<void>>): Promise<void> {
|
|
35
|
+
const results = await Promise.allSettled(disposals);
|
|
36
|
+
const errors = results.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
37
|
+
if (errors.length > 0) throw new AggregateError(errors, "Child session cleanup failed");
|
|
38
|
+
}
|
|
39
|
+
|
|
32
40
|
// ---------------------------------------------------------------------------
|
|
33
41
|
// Appendix B public record shape
|
|
34
42
|
// ---------------------------------------------------------------------------
|
|
@@ -40,6 +48,8 @@ export interface RunRecord {
|
|
|
40
48
|
childId: string;
|
|
41
49
|
name: string;
|
|
42
50
|
agent: string;
|
|
51
|
+
workKind?: string;
|
|
52
|
+
queueMs?: number;
|
|
43
53
|
model?: string;
|
|
44
54
|
status: ChildStatus;
|
|
45
55
|
/** User-authored prompt (after chain interpolation), without injected preamble. */
|
|
@@ -51,6 +61,8 @@ export interface RunRecord {
|
|
|
51
61
|
endedAt?: number;
|
|
52
62
|
/** User turns so far: 1 for the launch, +1 per accepted resume. */
|
|
53
63
|
turn?: number;
|
|
64
|
+
tokenUsage?: ChildTokenUsage;
|
|
65
|
+
wallUsage?: ChildWallUsage;
|
|
54
66
|
}[];
|
|
55
67
|
status: "running" | "completed" | "partial" | "failed" | "interrupted";
|
|
56
68
|
createdAt: number;
|
|
@@ -64,7 +76,7 @@ export interface RunRegistry {
|
|
|
64
76
|
findChild(runId: string, childIdOrName: string): ChildHandle | undefined;
|
|
65
77
|
lineage(runIdA: string, runIdB: string): boolean; // v1: same runId
|
|
66
78
|
onTransition(cb: (run: RunRecord) => void): void; // fleet widget / notifications
|
|
67
|
-
disposeRun(runId: string): void
|
|
79
|
+
disposeRun(runId: string): Promise<void>;
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
// ---------------------------------------------------------------------------
|
|
@@ -94,6 +106,8 @@ export interface ActiveChildInfo {
|
|
|
94
106
|
runId: string;
|
|
95
107
|
name: string;
|
|
96
108
|
agent: string;
|
|
109
|
+
workKind?: string;
|
|
110
|
+
queueMs?: number;
|
|
97
111
|
model?: string;
|
|
98
112
|
status: ChildStatus;
|
|
99
113
|
startedAt: number;
|
|
@@ -105,6 +119,7 @@ interface InternalChild {
|
|
|
105
119
|
runId: string;
|
|
106
120
|
name: string;
|
|
107
121
|
agent: string;
|
|
122
|
+
workKind?: string;
|
|
108
123
|
/** Best-effort model id for fleet / ls (set when startChild runs). */
|
|
109
124
|
model?: string;
|
|
110
125
|
status: ChildStatus;
|
|
@@ -115,7 +130,11 @@ interface InternalChild {
|
|
|
115
130
|
endedAt?: number;
|
|
116
131
|
turn: number;
|
|
117
132
|
handle?: ChildHandle;
|
|
133
|
+
starting?: Promise<ChildHandle>;
|
|
118
134
|
shouldStart?: () => boolean;
|
|
135
|
+
/** Initial admission wait while runner.start() has not returned its handle. */
|
|
136
|
+
queueStartedAt?: number;
|
|
137
|
+
queueMs: number;
|
|
119
138
|
}
|
|
120
139
|
|
|
121
140
|
interface InternalRun {
|
|
@@ -185,6 +204,14 @@ class FailedChildHandle implements ChildHandle {
|
|
|
185
204
|
conversation() {
|
|
186
205
|
return [];
|
|
187
206
|
}
|
|
207
|
+
|
|
208
|
+
tokenUsage() {
|
|
209
|
+
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
wallUsage(): ChildWallUsage {
|
|
213
|
+
return { llmMs: 0, toolMs: 0, queueMs: 0, otherMs: 0, approximate: false };
|
|
214
|
+
}
|
|
188
215
|
}
|
|
189
216
|
|
|
190
217
|
export class SubagentRegistry implements RunRegistry {
|
|
@@ -229,16 +256,17 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
229
256
|
};
|
|
230
257
|
this.runs.set(run.runId, run);
|
|
231
258
|
this.emit(run);
|
|
232
|
-
return snapshot(run);
|
|
259
|
+
return snapshot(run, this.now());
|
|
233
260
|
}
|
|
234
261
|
|
|
235
262
|
get(runId: string): RunRecord | undefined {
|
|
236
263
|
const run = this.runs.get(runId);
|
|
237
|
-
return run ? snapshot(run) : undefined;
|
|
264
|
+
return run ? snapshot(run, this.now()) : undefined;
|
|
238
265
|
}
|
|
239
266
|
|
|
240
267
|
list(): RunRecord[] {
|
|
241
|
-
|
|
268
|
+
const now = this.now();
|
|
269
|
+
return [...this.runs.values()].map((run) => snapshot(run, now));
|
|
242
270
|
}
|
|
243
271
|
|
|
244
272
|
handle(childId: string): ChildHandle | undefined {
|
|
@@ -262,7 +290,7 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
262
290
|
this.transitionCbs.add(cb);
|
|
263
291
|
}
|
|
264
292
|
|
|
265
|
-
disposeRun(runId: string): void {
|
|
293
|
+
async disposeRun(runId: string): Promise<void> {
|
|
266
294
|
const run = this.runs.get(runId);
|
|
267
295
|
if (!run) return;
|
|
268
296
|
const now = this.now();
|
|
@@ -271,6 +299,10 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
271
299
|
// "running" record (ghost agents in ls).
|
|
272
300
|
for (const child of run.children) {
|
|
273
301
|
if (child.status === "pending" || child.status === "running") {
|
|
302
|
+
if (child.status === "pending" && child.queueStartedAt !== undefined) {
|
|
303
|
+
child.queueMs = Math.max(0, now - child.queueStartedAt);
|
|
304
|
+
child.queueStartedAt = undefined;
|
|
305
|
+
}
|
|
274
306
|
child.status = "interrupted";
|
|
275
307
|
child.endedAt = now;
|
|
276
308
|
child.result = {
|
|
@@ -284,17 +316,26 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
284
316
|
this.recomputeRunStatus(run);
|
|
285
317
|
this.emit(run);
|
|
286
318
|
this.runs.delete(runId);
|
|
319
|
+
const disposals: Array<void | Promise<void>> = [];
|
|
287
320
|
for (const child of run.children) {
|
|
288
321
|
this.children.delete(child.childId);
|
|
289
322
|
const handle = child.handle as DisposableChildHandle | undefined;
|
|
290
|
-
if (!handle)
|
|
323
|
+
if (!handle) {
|
|
324
|
+
// Custom runners may not expose a handle until startup completes.
|
|
325
|
+
if (child.starting) disposals.push(child.starting.then(async (lateHandle) => {
|
|
326
|
+
await lateHandle.interrupt().catch(() => {});
|
|
327
|
+
await (lateHandle as DisposableChildHandle).dispose?.();
|
|
328
|
+
}, () => {}));
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
291
331
|
void handle.interrupt().catch(() => {});
|
|
292
332
|
try {
|
|
293
|
-
handle.dispose?.();
|
|
294
|
-
} catch {
|
|
295
|
-
|
|
333
|
+
disposals.push(handle.dispose?.());
|
|
334
|
+
} catch (error) {
|
|
335
|
+
disposals.push(Promise.reject(error));
|
|
296
336
|
}
|
|
297
337
|
}
|
|
338
|
+
await awaitDisposals(disposals);
|
|
298
339
|
}
|
|
299
340
|
|
|
300
341
|
// -------------------------------------------------------------------------
|
|
@@ -302,7 +343,7 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
302
343
|
// -------------------------------------------------------------------------
|
|
303
344
|
|
|
304
345
|
/** Allocate a pending child inside a run. Returns the child id. */
|
|
305
|
-
addChild(runId: string, info: { name: string; agent: string }): string {
|
|
346
|
+
addChild(runId: string, info: { name: string; agent: string; workKind?: string }): string {
|
|
306
347
|
const run = this.runs.get(runId);
|
|
307
348
|
if (!run) throw new Error(`unknown run ${runId}`);
|
|
308
349
|
const child: InternalChild = {
|
|
@@ -310,9 +351,12 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
310
351
|
runId,
|
|
311
352
|
name: info.name,
|
|
312
353
|
agent: info.agent,
|
|
354
|
+
workKind: info.workKind ?? "other",
|
|
313
355
|
status: "pending",
|
|
314
356
|
startedAt: this.now(),
|
|
357
|
+
queueStartedAt: this.now(),
|
|
315
358
|
turn: 1,
|
|
359
|
+
queueMs: 0,
|
|
316
360
|
};
|
|
317
361
|
run.children.push(child);
|
|
318
362
|
this.children.set(child.childId, child);
|
|
@@ -329,6 +373,7 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
329
373
|
const child = this.children.get(req.childId);
|
|
330
374
|
if (!child) throw new Error(`unknown child ${req.childId} (addChild first)`);
|
|
331
375
|
child.shouldStart = opts?.shouldStart;
|
|
376
|
+
child.workKind = req.workKind ?? child.workKind ?? "other";
|
|
332
377
|
child.prompt = req.taskPrompt ?? req.prompt;
|
|
333
378
|
child.preamble = req.agent.systemPrompt || undefined;
|
|
334
379
|
child.model = req.model ?? req.agent.model;
|
|
@@ -343,12 +388,28 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
343
388
|
return this.failWithoutSession(child, (err as Error).message);
|
|
344
389
|
}
|
|
345
390
|
|
|
346
|
-
|
|
391
|
+
child.queueStartedAt = this.now();
|
|
392
|
+
let handle: ChildHandle;
|
|
393
|
+
try {
|
|
394
|
+
child.starting = runner.start(req, (startingHandle) => { child.handle = startingHandle; });
|
|
395
|
+
handle = await child.starting;
|
|
396
|
+
} catch (error) {
|
|
397
|
+
this.closeInitialQueue(child, this.now());
|
|
398
|
+
throw error;
|
|
399
|
+
} finally {
|
|
400
|
+
child.starting = undefined;
|
|
401
|
+
}
|
|
402
|
+
// Teardown already owns this handle and its asynchronous cleanup.
|
|
403
|
+
if (!this.children.has(child.childId)) return handle;
|
|
404
|
+
this.closeInitialQueue(child, this.now());
|
|
347
405
|
child.handle = handle;
|
|
348
|
-
//
|
|
349
|
-
//
|
|
406
|
+
// Preserve the session's effective model and thinking setting, not a raw
|
|
407
|
+
// request suffix that may have fallen back to a different parent model.
|
|
350
408
|
const resolved = handle.resolvedModel();
|
|
351
|
-
if (resolved)
|
|
409
|
+
if (resolved) {
|
|
410
|
+
const thinking = handle.effectiveThinkingLevel?.();
|
|
411
|
+
child.model = `${resolved}${thinking ? `:${thinking}` : ""}`;
|
|
412
|
+
}
|
|
352
413
|
// Generation-1 result wiring (later generations are wired in admitChild,
|
|
353
414
|
// where the handle is already visible).
|
|
354
415
|
handle.result.then((result) => this.settleChild(child.childId, result));
|
|
@@ -370,7 +431,10 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
370
431
|
* and wires result settlement for resumed generations. Returns the slot
|
|
371
432
|
* releaser.
|
|
372
433
|
*/
|
|
373
|
-
async
|
|
434
|
+
async reserveChildSlot(
|
|
435
|
+
childId: string,
|
|
436
|
+
ticket?: { current: () => boolean },
|
|
437
|
+
): Promise<{ admit: () => void; release: () => void }> {
|
|
374
438
|
await this.acquireSlot();
|
|
375
439
|
let released = false;
|
|
376
440
|
const release = () => {
|
|
@@ -383,27 +447,47 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
383
447
|
release();
|
|
384
448
|
throw new Error(`unknown child ${childId}`);
|
|
385
449
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
450
|
+
const checkCurrent = () => {
|
|
451
|
+
if (child.shouldStart && !child.shouldStart()) throw new ChildCancelledError();
|
|
452
|
+
// A request settled while waiting (interrupt/dispose or a newer resume
|
|
453
|
+
// queued behind other children) must hand this local reservation on.
|
|
454
|
+
const stale = ticket ? !ticket.current() : (child.handle?.status() ?? "pending") !== "pending";
|
|
455
|
+
if (stale) throw new ChildCancelledError("settled while queued");
|
|
456
|
+
};
|
|
457
|
+
try {
|
|
458
|
+
checkCurrent();
|
|
459
|
+
} catch (error) {
|
|
460
|
+
this.closeInitialQueue(child, this.now());
|
|
396
461
|
release();
|
|
397
|
-
throw
|
|
462
|
+
throw error;
|
|
398
463
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
464
|
+
let admitted = false;
|
|
465
|
+
return {
|
|
466
|
+
release,
|
|
467
|
+
admit: () => {
|
|
468
|
+
if (admitted) return;
|
|
469
|
+
checkCurrent();
|
|
470
|
+
this.closeInitialQueue(child, this.now());
|
|
471
|
+
admitted = true;
|
|
472
|
+
this.transitionChild(child, "running");
|
|
473
|
+
const handle = child.handle;
|
|
474
|
+
if (handle) {
|
|
475
|
+
// Resume generations: wire settlement only once global admission also succeeds.
|
|
476
|
+
handle.result.then((result) => this.settleChild(childId, result));
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
async admitChild(childId: string, ticket?: { current: () => boolean }): Promise<() => void> {
|
|
483
|
+
const reservation = await this.reserveChildSlot(childId, ticket);
|
|
484
|
+
try {
|
|
485
|
+
reservation.admit();
|
|
486
|
+
return reservation.release;
|
|
487
|
+
} catch (error) {
|
|
488
|
+
reservation.release();
|
|
489
|
+
throw error;
|
|
405
490
|
}
|
|
406
|
-
return release;
|
|
407
491
|
}
|
|
408
492
|
|
|
409
493
|
/**
|
|
@@ -428,6 +512,8 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
428
512
|
result: child.result,
|
|
429
513
|
startedAt: child.startedAt,
|
|
430
514
|
endedAt: child.endedAt,
|
|
515
|
+
queueMs: child.queueMs,
|
|
516
|
+
queueStartedAt: child.queueStartedAt,
|
|
431
517
|
};
|
|
432
518
|
const accepted = handle.resume(message, opts);
|
|
433
519
|
// Mark the child queued before awaiting: with a free slot, admitChild's
|
|
@@ -436,6 +522,8 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
436
522
|
child.result = undefined;
|
|
437
523
|
child.endedAt = undefined;
|
|
438
524
|
child.startedAt = this.now();
|
|
525
|
+
child.queueMs = 0;
|
|
526
|
+
child.queueStartedAt = child.startedAt;
|
|
439
527
|
child.turn += 1;
|
|
440
528
|
try {
|
|
441
529
|
await accepted;
|
|
@@ -448,6 +536,8 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
448
536
|
child.result = previous.result;
|
|
449
537
|
child.startedAt = previous.startedAt;
|
|
450
538
|
child.endedAt = previous.endedAt;
|
|
539
|
+
child.queueMs = previous.queueMs;
|
|
540
|
+
child.queueStartedAt = previous.queueStartedAt;
|
|
451
541
|
}
|
|
452
542
|
throw err;
|
|
453
543
|
}
|
|
@@ -477,12 +567,17 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
477
567
|
finalizeRun(runId: string, error: string): void {
|
|
478
568
|
const run = this.runs.get(runId);
|
|
479
569
|
if (!run) return;
|
|
570
|
+
const now = this.now();
|
|
480
571
|
let changed = false;
|
|
481
572
|
for (const child of run.children) {
|
|
482
573
|
if (child.status === "pending" && !child.handle) {
|
|
574
|
+
if (child.queueStartedAt !== undefined) {
|
|
575
|
+
child.queueMs = (child.queueMs ?? 0) + Math.max(0, now - child.queueStartedAt);
|
|
576
|
+
child.queueStartedAt = undefined;
|
|
577
|
+
}
|
|
483
578
|
child.status = "interrupted";
|
|
484
579
|
child.result = { status: "interrupted", text: "", error, durationMs: 0 };
|
|
485
|
-
child.endedAt =
|
|
580
|
+
child.endedAt = now;
|
|
486
581
|
changed = true;
|
|
487
582
|
}
|
|
488
583
|
}
|
|
@@ -502,6 +597,11 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
502
597
|
runId: child.runId,
|
|
503
598
|
name: child.name,
|
|
504
599
|
agent: child.agent,
|
|
600
|
+
workKind: child.workKind,
|
|
601
|
+
queueMs:
|
|
602
|
+
child.status === "pending" && child.queueStartedAt !== undefined
|
|
603
|
+
? (child.queueMs ?? 0) + Math.max(0, this.now() - child.queueStartedAt)
|
|
604
|
+
: child.queueMs,
|
|
505
605
|
model: child.model,
|
|
506
606
|
status: child.status,
|
|
507
607
|
startedAt: child.startedAt,
|
|
@@ -513,10 +613,8 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
513
613
|
}
|
|
514
614
|
|
|
515
615
|
/** Dispose every run (session shutdown). */
|
|
516
|
-
disposeAll(): void {
|
|
517
|
-
|
|
518
|
-
this.disposeRun(runId);
|
|
519
|
-
}
|
|
616
|
+
async disposeAll(): Promise<void> {
|
|
617
|
+
await awaitDisposals([...this.runs.keys()].map((runId) => this.disposeRun(runId)));
|
|
520
618
|
}
|
|
521
619
|
|
|
522
620
|
// -------------------------------------------------------------------------
|
|
@@ -535,9 +633,15 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
535
633
|
const child = this.children.get(childId);
|
|
536
634
|
if (!child) return;
|
|
537
635
|
if (child.status !== "pending" && child.status !== "running") return; // already terminal
|
|
636
|
+
const settledAt = this.now();
|
|
637
|
+
if (child.status === "pending" && child.queueStartedAt !== undefined) {
|
|
638
|
+
child.queueMs = Math.max(0, settledAt - child.queueStartedAt);
|
|
639
|
+
child.queueStartedAt = undefined;
|
|
640
|
+
}
|
|
641
|
+
if (child.queueMs === undefined && result.queueMs !== undefined) child.queueMs = result.queueMs;
|
|
538
642
|
child.status = result.status;
|
|
539
643
|
child.result = result;
|
|
540
|
-
child.endedAt =
|
|
644
|
+
child.endedAt = settledAt;
|
|
541
645
|
child.shouldStart = undefined;
|
|
542
646
|
const run = this.runs.get(child.runId);
|
|
543
647
|
if (run) {
|
|
@@ -550,8 +654,11 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
550
654
|
if (child.status === status) return;
|
|
551
655
|
child.status = status;
|
|
552
656
|
if (status === "running") {
|
|
657
|
+
const startedAt = this.now();
|
|
658
|
+
child.queueMs = Math.max(0, startedAt - (child.queueStartedAt ?? child.startedAt));
|
|
659
|
+
child.queueStartedAt = undefined;
|
|
553
660
|
// (Re-)start: elapsed time and any previous generation's result reset.
|
|
554
|
-
child.startedAt =
|
|
661
|
+
child.startedAt = startedAt;
|
|
555
662
|
child.result = undefined;
|
|
556
663
|
child.endedAt = undefined;
|
|
557
664
|
}
|
|
@@ -579,9 +686,15 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
579
686
|
else run.status = "partial";
|
|
580
687
|
}
|
|
581
688
|
|
|
689
|
+
private closeInitialQueue(child: InternalChild, at: number): void {
|
|
690
|
+
if (child.queueStartedAt === undefined) return;
|
|
691
|
+
child.queueMs += Math.max(0, at - child.queueStartedAt);
|
|
692
|
+
child.queueStartedAt = undefined;
|
|
693
|
+
}
|
|
694
|
+
|
|
582
695
|
private emit(run: InternalRun): void {
|
|
583
696
|
if (this.transitionCbs.size === 0) return;
|
|
584
|
-
const record = snapshot(run);
|
|
697
|
+
const record = snapshot(run, this.now());
|
|
585
698
|
for (const cb of this.transitionCbs) {
|
|
586
699
|
try {
|
|
587
700
|
cb(record);
|
|
@@ -630,7 +743,7 @@ export class SubagentRegistry implements RunRegistry {
|
|
|
630
743
|
}
|
|
631
744
|
}
|
|
632
745
|
|
|
633
|
-
function snapshot(run: InternalRun): RunRecord {
|
|
746
|
+
function snapshot(run: InternalRun, now: number): RunRecord {
|
|
634
747
|
return {
|
|
635
748
|
runId: run.runId,
|
|
636
749
|
kind: run.kind,
|
|
@@ -640,6 +753,8 @@ function snapshot(run: InternalRun): RunRecord {
|
|
|
640
753
|
childId: c.childId,
|
|
641
754
|
name: c.name,
|
|
642
755
|
agent: c.agent,
|
|
756
|
+
...(c.workKind !== undefined ? { workKind: c.workKind } : {}),
|
|
757
|
+
...(c.queueMs !== undefined ? { queueMs: c.queueMs } : {}),
|
|
643
758
|
...(c.model !== undefined ? { model: c.model } : {}),
|
|
644
759
|
status: c.status,
|
|
645
760
|
...(c.prompt !== undefined ? { prompt: c.prompt } : {}),
|
|
@@ -648,6 +763,14 @@ function snapshot(run: InternalRun): RunRecord {
|
|
|
648
763
|
startedAt: c.startedAt,
|
|
649
764
|
endedAt: c.endedAt,
|
|
650
765
|
turn: c.turn,
|
|
766
|
+
tokenUsage: c.handle?.tokenUsage() ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
767
|
+
wallUsage: c.handle?.wallUsage() ?? {
|
|
768
|
+
llmMs: 0,
|
|
769
|
+
toolMs: 0,
|
|
770
|
+
queueMs: c.queueMs + (c.queueStartedAt === undefined ? 0 : Math.max(0, now - c.queueStartedAt)),
|
|
771
|
+
otherMs: c.status === "running" ? Math.max(0, now - c.startedAt) : 0,
|
|
772
|
+
approximate: c.status === "running",
|
|
773
|
+
},
|
|
651
774
|
})),
|
|
652
775
|
};
|
|
653
776
|
}
|