@llm4ts/runner 2.52.0 → 2.54.0
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/AgentTree.d.ts +17 -0
- package/dist/AgentTree.d.ts.map +1 -1
- package/dist/AgentTree.js +91 -24
- package/dist/AgentTree.js.map +1 -1
- package/dist/ExecutorRoster.d.ts +4 -4
- package/dist/ExecutorRoster.d.ts.map +1 -1
- package/dist/FlowRunner.d.ts +3 -3
- package/dist/FlowRunner.d.ts.map +1 -1
- package/dist/Profile.d.ts +1 -1
- package/dist/Profile.d.ts.map +1 -1
- package/dist/Terminal.d.ts.map +1 -1
- package/dist/Terminal.js +4 -0
- package/dist/Terminal.js.map +1 -1
- package/dist/Watch.d.ts +1 -1
- package/dist/Watch.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/AgentTree.ts +111 -12
- package/src/Terminal.ts +4 -0
- package/src/index.ts +1 -1
package/src/AgentTree.ts
CHANGED
|
@@ -26,8 +26,12 @@ export type TreeInput =
|
|
|
26
26
|
|
|
27
27
|
export type LaneStatus = "running" | "done" | "failed"
|
|
28
28
|
|
|
29
|
+
/** What a lane stands for: a story's coder (ADR 0022), a roundtable attendee (ADR 0046), or a taskforce specialist (ADR 0047). */
|
|
30
|
+
export type LaneKind = "story" | "attendee" | "specialist"
|
|
31
|
+
|
|
29
32
|
export interface TreeLane {
|
|
30
33
|
readonly id: string
|
|
34
|
+
readonly kind: LaneKind
|
|
31
35
|
/** The lane's open stages below `story <id>`, innermost last. */
|
|
32
36
|
readonly stages: ReadonlyArray<string>
|
|
33
37
|
readonly executor: string | undefined
|
|
@@ -68,6 +72,24 @@ export interface TreeLane {
|
|
|
68
72
|
readonly pause: { readonly label: string; readonly since: number } | undefined
|
|
69
73
|
/** Tasks running beside the lane's coder, each on a coder of its own (ADR 0034). */
|
|
70
74
|
readonly taskCoders: ReadonlyArray<TreeTaskCoder>
|
|
75
|
+
/** A specialist's last report (ADR 0047); other lanes have none. */
|
|
76
|
+
readonly report:
|
|
77
|
+
| {
|
|
78
|
+
readonly brief: string
|
|
79
|
+
readonly status: string
|
|
80
|
+
readonly summary: string
|
|
81
|
+
readonly attempt: number
|
|
82
|
+
}
|
|
83
|
+
| undefined
|
|
84
|
+
/** An attendee's last turn (ADR 0046); a story lane has none. */
|
|
85
|
+
readonly turn:
|
|
86
|
+
| {
|
|
87
|
+
readonly id: number
|
|
88
|
+
readonly kind: string
|
|
89
|
+
readonly summary: string
|
|
90
|
+
readonly blocking: boolean
|
|
91
|
+
}
|
|
92
|
+
| undefined
|
|
71
93
|
}
|
|
72
94
|
|
|
73
95
|
/** A task running beside a story's coder, in its own worktree (ADR 0034). */
|
|
@@ -257,7 +279,8 @@ const logged = (state: TreeState, entry: TreeLogEntry): TreeState => ({
|
|
|
257
279
|
log: [...state.log, entry]
|
|
258
280
|
})
|
|
259
281
|
|
|
260
|
-
|
|
282
|
+
/** The stage that opens a lane: a story's, a roundtable attendee's or a taskforce specialist's (names may hold spaces). */
|
|
283
|
+
const laneStage = /^(story|attendee|specialist) (.+)$/u
|
|
261
284
|
const expandedTools = 20
|
|
262
285
|
|
|
263
286
|
const updateLane = (
|
|
@@ -401,10 +424,18 @@ const reduceEvent = (state: TreeState, at: number, event: FlowEvent): TreeState
|
|
|
401
424
|
}
|
|
402
425
|
switch (event._tag) {
|
|
403
426
|
case "StageStarted": {
|
|
404
|
-
const
|
|
427
|
+
const opened = laneStage.exec(event.stage)
|
|
428
|
+
const story = opened?.[2]
|
|
405
429
|
if (story !== undefined && event.lane === story) {
|
|
430
|
+
const kind: LaneKind =
|
|
431
|
+
opened?.[1] === "attendee"
|
|
432
|
+
? "attendee"
|
|
433
|
+
: opened?.[1] === "specialist"
|
|
434
|
+
? "specialist"
|
|
435
|
+
: "story"
|
|
406
436
|
const fresh: TreeLane = {
|
|
407
437
|
id: story,
|
|
438
|
+
kind,
|
|
408
439
|
stages: [],
|
|
409
440
|
executor: event.executor,
|
|
410
441
|
startedAt: at,
|
|
@@ -423,7 +454,9 @@ const reduceEvent = (state: TreeState, at: number, event: FlowEvent): TreeState
|
|
|
423
454
|
task: undefined,
|
|
424
455
|
children: [],
|
|
425
456
|
pause: undefined,
|
|
426
|
-
taskCoders: []
|
|
457
|
+
taskCoders: [],
|
|
458
|
+
report: undefined,
|
|
459
|
+
turn: undefined
|
|
427
460
|
}
|
|
428
461
|
return {
|
|
429
462
|
...current,
|
|
@@ -444,7 +477,7 @@ const reduceEvent = (state: TreeState, at: number, event: FlowEvent): TreeState
|
|
|
444
477
|
}
|
|
445
478
|
case "StageCompleted":
|
|
446
479
|
case "StageFailed": {
|
|
447
|
-
if (lane !== undefined && event.stage ===
|
|
480
|
+
if (lane !== undefined && event.stage === `${lane.kind} ${lane.id}`) {
|
|
448
481
|
const status: LaneStatus = event._tag === "StageFailed" ? "failed" : "done"
|
|
449
482
|
const closed = updateLane(current, lane.id, (open) => ({
|
|
450
483
|
...open,
|
|
@@ -542,6 +575,43 @@ const reduceEvent = (state: TreeState, at: number, event: FlowEvent): TreeState
|
|
|
542
575
|
: {})
|
|
543
576
|
}))
|
|
544
577
|
}
|
|
578
|
+
case "RoundtableTurn": {
|
|
579
|
+
const what = `#${event.turn} ${event.kind}${event.blocking ? " (blocking)" : ""}${
|
|
580
|
+
event.answers.length === 0 ? "" : ` → ${event.answers.map((id) => `#${id}`).join(", ")}`
|
|
581
|
+
}: ${event.summary}`
|
|
582
|
+
if (lane === undefined) {
|
|
583
|
+
// The Chair and the Owner have no seat at the table: their words are the run's.
|
|
584
|
+
return logged(current, { at, source: "run", who: event.lane, what })
|
|
585
|
+
}
|
|
586
|
+
const spoken = updateLane(current, lane.id, (open) => ({
|
|
587
|
+
...open,
|
|
588
|
+
stages: [`item ${event.item} r${event.round}`],
|
|
589
|
+
turn: {
|
|
590
|
+
id: event.turn,
|
|
591
|
+
kind: event.kind,
|
|
592
|
+
summary: event.summary,
|
|
593
|
+
blocking: event.blocking
|
|
594
|
+
}
|
|
595
|
+
}))
|
|
596
|
+
return logged(spoken, { at, source: "lane", who: lane.id, what })
|
|
597
|
+
}
|
|
598
|
+
case "BriefReported": {
|
|
599
|
+
const what = `${event.brief} ${event.status}${event.attempt > 1 ? ` (attempt ${event.attempt})` : ""}: ${event.summary}`
|
|
600
|
+
if (lane === undefined) {
|
|
601
|
+
// A name without a lane of its own: its report is the run's.
|
|
602
|
+
return logged(current, { at, source: "run", who: event.lane, what })
|
|
603
|
+
}
|
|
604
|
+
const handed = updateLane(current, lane.id, (open) => ({
|
|
605
|
+
...open,
|
|
606
|
+
report: {
|
|
607
|
+
brief: event.brief,
|
|
608
|
+
status: event.status,
|
|
609
|
+
summary: event.summary,
|
|
610
|
+
attempt: event.attempt
|
|
611
|
+
}
|
|
612
|
+
}))
|
|
613
|
+
return logged(handed, { at, source: "lane", who: lane.id, what })
|
|
614
|
+
}
|
|
545
615
|
case "StoryJudged": {
|
|
546
616
|
const verdict: TreeVerdict = {
|
|
547
617
|
lane: event.lane,
|
|
@@ -1266,6 +1336,21 @@ const statusMark = (lane: TreeLane, now: number | undefined, idleAfterMs: number
|
|
|
1266
1336
|
}
|
|
1267
1337
|
|
|
1268
1338
|
/** `3/5 wire session cookie`, or `2/5 tasks` between tasks, or nothing before the plan. */
|
|
1339
|
+
/** An attendee's last turn as one line: `#4 objection (blocking): …`. */
|
|
1340
|
+
const turnText = (lane: TreeLane): string =>
|
|
1341
|
+
lane.turn === undefined
|
|
1342
|
+
? ""
|
|
1343
|
+
: `#${lane.turn.id} ${lane.turn.kind}${lane.turn.blocking ? " (blocking)" : ""}: ${lane.turn.summary}`
|
|
1344
|
+
|
|
1345
|
+
/** A specialist's last report as one line: `B3 PASS: …`. */
|
|
1346
|
+
const reportText = (lane: TreeLane): string =>
|
|
1347
|
+
lane.report === undefined
|
|
1348
|
+
? ""
|
|
1349
|
+
: `${lane.report.brief} ${lane.report.status}${lane.report.attempt > 1 ? ` (attempt ${lane.report.attempt})` : ""}: ${lane.report.summary}`
|
|
1350
|
+
|
|
1351
|
+
/** A lane without a coder of its own: an attendee borrows the room's seat, a specialist its role's. */
|
|
1352
|
+
const seatless = (lane: TreeLane): boolean => lane.kind === "attendee" || lane.kind === "specialist"
|
|
1353
|
+
|
|
1269
1354
|
const taskText = (lane: TreeLane): string =>
|
|
1270
1355
|
lane.task !== undefined
|
|
1271
1356
|
? `${lane.task.index}/${lane.task.count} ${lane.task.title}`
|
|
@@ -1287,14 +1372,22 @@ const laneLine = (
|
|
|
1287
1372
|
selected: boolean,
|
|
1288
1373
|
idleAfterMs: number
|
|
1289
1374
|
): Line => {
|
|
1290
|
-
const task =
|
|
1291
|
-
|
|
1375
|
+
const task =
|
|
1376
|
+
lane.kind === "attendee"
|
|
1377
|
+
? turnText(lane)
|
|
1378
|
+
: lane.kind === "specialist"
|
|
1379
|
+
? reportText(lane)
|
|
1380
|
+
: taskText(lane)
|
|
1381
|
+
const stage =
|
|
1382
|
+
lane.stages.at(-1) ??
|
|
1383
|
+
(lane.kind === "attendee" ? "listening" : lane.kind === "specialist" ? "idle" : "starting")
|
|
1292
1384
|
const head: Line = [
|
|
1293
1385
|
span(selected ? "▸ " : " "),
|
|
1294
1386
|
statusMark(lane, now, idleAfterMs),
|
|
1295
1387
|
span(" "),
|
|
1296
1388
|
span(lane.id, "bold"),
|
|
1297
|
-
|
|
1389
|
+
// An attendee borrows the room's one seat, a specialist its role's: no executor of its own to show.
|
|
1390
|
+
...(seatless(lane) ? [] : [span(` ${cloneName(lane.executor ?? "(leasing)", lane.clone)}`)]),
|
|
1298
1391
|
...(task.length === 0 ? [] : [span(" · "), span(task)]),
|
|
1299
1392
|
// A task is a stage of its own name: say it once.
|
|
1300
1393
|
...(stage === lane.task?.title ? [] : [span(" · "), span(stage, "dim")]),
|
|
@@ -1416,8 +1509,9 @@ const detailBox = (
|
|
|
1416
1509
|
expanded: boolean
|
|
1417
1510
|
): Array<Line> => {
|
|
1418
1511
|
const inner = width - 4
|
|
1419
|
-
const checklist: Array<Line> =
|
|
1420
|
-
|
|
1512
|
+
const checklist: Array<Line> = seatless(lane)
|
|
1513
|
+
? []
|
|
1514
|
+
: lane.tasks.length === 0
|
|
1421
1515
|
? [[span("no task plan yet", "dim")]]
|
|
1422
1516
|
: lane.tasks.map((task): Line => {
|
|
1423
1517
|
const beside = lane.taskCoders.find((coder) => coder.index === task.index)
|
|
@@ -1447,9 +1541,14 @@ const detailBox = (
|
|
|
1447
1541
|
: lane.tools.length === 0
|
|
1448
1542
|
? []
|
|
1449
1543
|
: [[span("tools "), span(lane.tools.slice(-3).join(" · "), "dim")]]
|
|
1450
|
-
const title =
|
|
1451
|
-
lane.
|
|
1452
|
-
|
|
1544
|
+
const title =
|
|
1545
|
+
lane.kind === "attendee"
|
|
1546
|
+
? `${lane.id} · ${lane.turn === undefined ? "listening" : turnText(lane)}`
|
|
1547
|
+
: lane.kind === "specialist"
|
|
1548
|
+
? `${lane.id} · ${lane.report === undefined ? "idle" : reportText(lane)}`
|
|
1549
|
+
: `${lane.id} · ${cloneName(lane.executor ?? "(leasing)", lane.clone)}${
|
|
1550
|
+
lane.task === undefined ? "" : ` · task ${lane.task.index}/${lane.task.count}`
|
|
1551
|
+
}`
|
|
1453
1552
|
return box(
|
|
1454
1553
|
width,
|
|
1455
1554
|
"running",
|
package/src/Terminal.ts
CHANGED
|
@@ -42,6 +42,8 @@ export const rendersEvent = (verbosity: Verbosity, event: FlowEvent): boolean =>
|
|
|
42
42
|
case "UsageProgress":
|
|
43
43
|
case "ExecutorReleased":
|
|
44
44
|
case "StoryJudged":
|
|
45
|
+
case "RoundtableTurn":
|
|
46
|
+
case "BriefReported":
|
|
45
47
|
case "Timed":
|
|
46
48
|
case "TasksPlanned":
|
|
47
49
|
case "TaskStarted":
|
|
@@ -253,6 +255,8 @@ export const terminalLine = (
|
|
|
253
255
|
case "BlackboardRun":
|
|
254
256
|
case "UsageProgress":
|
|
255
257
|
case "StoryJudged":
|
|
258
|
+
case "RoundtableTurn":
|
|
259
|
+
case "BriefReported":
|
|
256
260
|
case "Timed":
|
|
257
261
|
case "TasksPlanned":
|
|
258
262
|
case "TaskStarted":
|
package/src/index.ts
CHANGED
|
@@ -42,6 +42,6 @@ export { makeChat } from "@llm4ts/flow/Chat"
|
|
|
42
42
|
export { makePlanStore } from "@llm4ts/flow/Persistence"
|
|
43
43
|
export { defaultPlanInstructions, planFrom, writeBrief } from "@llm4ts/flow/Planner"
|
|
44
44
|
export { defaultPlanPath, parsePlan, Plan } from "@llm4ts/flow/Plan"
|
|
45
|
-
export { AssistantMessage, Info } from "@llm4ts/flow/FlowEvents"
|
|
45
|
+
export { AssistantMessage, BriefReported, Info, RoundtableTurn } from "@llm4ts/flow/FlowEvents"
|
|
46
46
|
export { FlowAborted, FlowLlmError } from "@llm4ts/flow/FlowError"
|
|
47
47
|
export { loadPack } from "@llm4ts/flow/Pack"
|