@esso0428/pi-subagents 0.17.6 → 0.17.7
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/CHANGELOG.md +9 -0
- package/CONTRIBUTING.md +4 -0
- package/dist/abortable.d.ts +13 -0
- package/dist/abortable.d.ts.map +1 -0
- package/dist/abortable.js +43 -0
- package/dist/abortable.js.map +1 -0
- package/dist/agent-color.d.ts +36 -0
- package/dist/agent-color.d.ts.map +1 -0
- package/dist/agent-color.js +124 -0
- package/dist/agent-color.js.map +1 -0
- package/dist/agent-file-toggle.d.ts +126 -0
- package/dist/agent-file-toggle.d.ts.map +1 -0
- package/dist/agent-file-toggle.js +259 -0
- package/dist/agent-file-toggle.js.map +1 -0
- package/dist/agent-history.d.ts +4 -0
- package/dist/agent-history.d.ts.map +1 -1
- package/dist/agent-history.js +47 -1
- package/dist/agent-history.js.map +1 -1
- package/dist/agent-manager.d.ts +370 -56
- package/dist/agent-manager.d.ts.map +1 -1
- package/dist/agent-manager.js +1123 -409
- package/dist/agent-manager.js.map +1 -1
- package/dist/agent-runner.d.ts +100 -10
- package/dist/agent-runner.d.ts.map +1 -1
- package/dist/agent-runner.js +166 -21
- package/dist/agent-runner.js.map +1 -1
- package/dist/agent-types.d.ts +57 -5
- package/dist/agent-types.d.ts.map +1 -1
- package/dist/agent-types.js +164 -32
- package/dist/agent-types.js.map +1 -1
- package/dist/child-context.d.ts +3 -0
- package/dist/child-context.d.ts.map +1 -0
- package/dist/child-context.js +13 -0
- package/dist/child-context.js.map +1 -0
- package/dist/cross-extension-rpc.d.ts +23 -3
- package/dist/cross-extension-rpc.d.ts.map +1 -1
- package/dist/cross-extension-rpc.js +79 -17
- package/dist/cross-extension-rpc.js.map +1 -1
- package/dist/custom-agents.d.ts +38 -1
- package/dist/custom-agents.d.ts.map +1 -1
- package/dist/custom-agents.js +164 -12
- package/dist/custom-agents.js.map +1 -1
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1908 -495
- package/dist/index.js.map +1 -1
- package/dist/invocation-config.d.ts +87 -2
- package/dist/invocation-config.d.ts.map +1 -1
- package/dist/invocation-config.js +71 -3
- package/dist/invocation-config.js.map +1 -1
- package/dist/mention-clone.d.ts +88 -0
- package/dist/mention-clone.d.ts.map +1 -0
- package/dist/mention-clone.js +154 -0
- package/dist/mention-clone.js.map +1 -0
- package/dist/mention.d.ts +82 -0
- package/dist/mention.d.ts.map +1 -0
- package/dist/mention.js +132 -0
- package/dist/mention.js.map +1 -0
- package/dist/model-resolver.d.ts +17 -0
- package/dist/model-resolver.d.ts.map +1 -1
- package/dist/model-resolver.js +15 -0
- package/dist/model-resolver.js.map +1 -1
- package/dist/model-scope.d.ts +50 -0
- package/dist/model-scope.d.ts.map +1 -0
- package/dist/model-scope.js +49 -0
- package/dist/model-scope.js.map +1 -0
- package/dist/nested-tools.d.ts +57 -0
- package/dist/nested-tools.d.ts.map +1 -0
- package/dist/nested-tools.js +301 -0
- package/dist/nested-tools.js.map +1 -0
- package/dist/output-file.d.ts +22 -3
- package/dist/output-file.d.ts.map +1 -1
- package/dist/output-file.js +58 -7
- package/dist/output-file.js.map +1 -1
- package/dist/prompts.d.ts +23 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +20 -2
- package/dist/prompts.js.map +1 -1
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +36 -15
- package/dist/schedule.js.map +1 -1
- package/dist/settings.d.ts +228 -2
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +94 -0
- package/dist/settings.js.map +1 -1
- package/dist/status-note.d.ts +49 -1
- package/dist/status-note.d.ts.map +1 -1
- package/dist/status-note.js +62 -1
- package/dist/status-note.js.map +1 -1
- package/dist/structured-output.d.ts +62 -0
- package/dist/structured-output.d.ts.map +1 -0
- package/dist/structured-output.js +113 -0
- package/dist/structured-output.js.map +1 -0
- package/dist/types.d.ts +176 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/agent-mention.d.ts +83 -0
- package/dist/ui/agent-mention.d.ts.map +1 -0
- package/dist/ui/agent-mention.js +188 -0
- package/dist/ui/agent-mention.js.map +1 -0
- package/dist/ui/agent-widget.d.ts +96 -75
- package/dist/ui/agent-widget.d.ts.map +1 -1
- package/dist/ui/agent-widget.js +397 -420
- package/dist/ui/agent-widget.js.map +1 -1
- package/dist/ui/conversation-blocks.d.ts.map +1 -1
- package/dist/ui/conversation-blocks.js +6 -0
- package/dist/ui/conversation-blocks.js.map +1 -1
- package/dist/ui/conversation-timeline.d.ts +10 -2
- package/dist/ui/conversation-timeline.d.ts.map +1 -1
- package/dist/ui/conversation-timeline.js +130 -23
- package/dist/ui/conversation-timeline.js.map +1 -1
- package/dist/ui/conversation-viewer.d.ts +15 -5
- package/dist/ui/conversation-viewer.d.ts.map +1 -1
- package/dist/ui/conversation-viewer.js +202 -50
- package/dist/ui/conversation-viewer.js.map +1 -1
- package/dist/ui/fleet-list.d.ts +198 -0
- package/dist/ui/fleet-list.d.ts.map +1 -0
- package/dist/ui/fleet-list.js +487 -0
- package/dist/ui/fleet-list.js.map +1 -0
- package/dist/ui/schedule-menu.d.ts.map +1 -1
- package/dist/ui/schedule-menu.js +6 -7
- package/dist/ui/schedule-menu.js.map +1 -1
- package/dist/ui/select-item.d.ts +28 -0
- package/dist/ui/select-item.d.ts.map +1 -0
- package/dist/ui/select-item.js +35 -0
- package/dist/ui/select-item.js.map +1 -0
- package/dist/ui/workflow-card.d.ts +176 -0
- package/dist/ui/workflow-card.d.ts.map +1 -0
- package/dist/ui/workflow-card.js +333 -0
- package/dist/ui/workflow-card.js.map +1 -0
- package/dist/ui/workflow-dialog.d.ts +306 -0
- package/dist/ui/workflow-dialog.d.ts.map +1 -0
- package/dist/ui/workflow-dialog.js +844 -0
- package/dist/ui/workflow-dialog.js.map +1 -0
- package/dist/ui/workflow-menu.d.ts +61 -0
- package/dist/ui/workflow-menu.d.ts.map +1 -0
- package/dist/ui/workflow-menu.js +148 -0
- package/dist/ui/workflow-menu.js.map +1 -0
- package/dist/usage.d.ts +86 -1
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +72 -1
- package/dist/usage.js.map +1 -1
- package/dist/workflow/collisions.d.ts +96 -0
- package/dist/workflow/collisions.d.ts.map +1 -0
- package/dist/workflow/collisions.js +89 -0
- package/dist/workflow/collisions.js.map +1 -0
- package/dist/workflow/entry.d.ts +33 -0
- package/dist/workflow/entry.d.ts.map +1 -0
- package/dist/workflow/entry.js +30 -0
- package/dist/workflow/entry.js.map +1 -0
- package/dist/workflow/host.d.ts +63 -0
- package/dist/workflow/host.d.ts.map +1 -0
- package/dist/workflow/host.js +363 -0
- package/dist/workflow/host.js.map +1 -0
- package/dist/workflow/journal.d.ts +98 -0
- package/dist/workflow/journal.d.ts.map +1 -0
- package/dist/workflow/journal.js +121 -0
- package/dist/workflow/journal.js.map +1 -0
- package/dist/workflow/json-schema.d.ts +52 -0
- package/dist/workflow/json-schema.d.ts.map +1 -0
- package/dist/workflow/json-schema.js +112 -0
- package/dist/workflow/json-schema.js.map +1 -0
- package/dist/workflow/meta.d.ts +68 -0
- package/dist/workflow/meta.d.ts.map +1 -0
- package/dist/workflow/meta.js +318 -0
- package/dist/workflow/meta.js.map +1 -0
- package/dist/workflow/progress.d.ts +225 -0
- package/dist/workflow/progress.d.ts.map +1 -0
- package/dist/workflow/progress.js +362 -0
- package/dist/workflow/progress.js.map +1 -0
- package/dist/workflow/runtime.d.ts +335 -0
- package/dist/workflow/runtime.d.ts.map +1 -0
- package/dist/workflow/runtime.js +831 -0
- package/dist/workflow/runtime.js.map +1 -0
- package/dist/workflow/saved.d.ts +91 -0
- package/dist/workflow/saved.d.ts.map +1 -0
- package/dist/workflow/saved.js +204 -0
- package/dist/workflow/saved.js.map +1 -0
- package/dist/workflow/task.d.ts +137 -0
- package/dist/workflow/task.d.ts.map +1 -0
- package/dist/workflow/task.js +208 -0
- package/dist/workflow/task.js.map +1 -0
- package/dist/workflow/tool-description.d.ts +39 -0
- package/dist/workflow/tool-description.d.ts.map +1 -0
- package/dist/workflow/tool-description.js +200 -0
- package/dist/workflow/tool-description.js.map +1 -0
- package/dist/workflow/worker-source.d.ts +48 -0
- package/dist/workflow/worker-source.d.ts.map +1 -0
- package/dist/workflow/worker-source.js +779 -0
- package/dist/workflow/worker-source.js.map +1 -0
- package/dist/worktree.d.ts +10 -3
- package/dist/worktree.d.ts.map +1 -1
- package/dist/worktree.js +58 -54
- package/dist/worktree.js.map +1 -1
- package/dist/xml.d.ts +11 -0
- package/dist/xml.d.ts.map +1 -0
- package/dist/xml.js +13 -0
- package/dist/xml.js.map +1 -0
- package/docs/rpc.md +183 -0
- package/docs/superpowers/plans/2026-09-30-upstream-event-workflow-partial-history.md +195 -0
- package/docs/superpowers/specs/2026-09-30-upstream-event-workflow-partial-history-design.md +49 -0
- package/docs/workflows.md +437 -0
- package/examples/agent-tool-description.md +7 -7
- package/examples/workflows/compose.js +51 -0
- package/examples/workflows/fan-out-audit.js +47 -0
- package/examples/workflows/gated-fix.js +60 -0
- package/examples/workflows/lib/count-child.js +27 -0
- package/examples/workflows/review-panel.js +63 -0
- package/examples/workflows/structured-findings.js +78 -0
- package/package.json +1 -1
- package/src/abortable.ts +43 -0
- package/src/agent-color.ts +161 -0
- package/src/agent-file-toggle.ts +269 -0
- package/src/agent-history.ts +54 -2
- package/src/agent-manager.ts +1263 -402
- package/src/agent-runner.ts +251 -27
- package/src/agent-types.ts +188 -32
- package/src/child-context.ts +15 -0
- package/src/cross-extension-rpc.ts +96 -20
- package/src/custom-agents.ts +170 -13
- package/src/index.ts +2024 -537
- package/src/invocation-config.ts +118 -3
- package/src/mention-clone.ts +196 -0
- package/src/mention.ts +141 -0
- package/src/model-resolver.ts +18 -0
- package/src/model-scope.ts +70 -0
- package/src/nested-tools.ts +424 -0
- package/src/output-file.ts +61 -6
- package/src/prompts.ts +45 -2
- package/src/schedule.ts +35 -14
- package/src/settings.ts +312 -2
- package/src/status-note.ts +66 -1
- package/src/structured-output.ts +130 -0
- package/src/types.ts +177 -10
- package/src/ui/agent-mention.ts +216 -0
- package/src/ui/agent-widget.ts +389 -441
- package/src/ui/conversation-blocks.ts +6 -0
- package/src/ui/conversation-timeline.ts +139 -25
- package/src/ui/conversation-viewer.ts +212 -48
- package/src/ui/fleet-list.ts +558 -0
- package/src/ui/schedule-menu.ts +9 -8
- package/src/ui/select-item.ts +45 -0
- package/src/ui/workflow-card.ts +470 -0
- package/src/ui/workflow-dialog.ts +1115 -0
- package/src/ui/workflow-menu.ts +193 -0
- package/src/usage.ts +109 -2
- package/src/workflow/collisions.ts +123 -0
- package/src/workflow/entry.ts +47 -0
- package/src/workflow/host.ts +403 -0
- package/src/workflow/journal.ts +164 -0
- package/src/workflow/json-schema.ts +128 -0
- package/src/workflow/meta.ts +325 -0
- package/src/workflow/progress.ts +550 -0
- package/src/workflow/runtime.ts +1219 -0
- package/src/workflow/saved.ts +217 -0
- package/src/workflow/task.ts +302 -0
- package/src/workflow/tool-description.ts +200 -0
- package/src/workflow/worker-source.ts +781 -0
- package/src/worktree.ts +69 -55
- package/src/xml.ts +13 -0
- package/vitest.config.ts +0 -18
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* journal.ts — the record a workflow run leaves so a later run can skip work.
|
|
3
|
+
*
|
|
4
|
+
* ## What resume actually buys
|
|
5
|
+
*
|
|
6
|
+
* The documented iteration loop is "edit the persisted script and re-run it".
|
|
7
|
+
* Without a journal that re-pays every agent from scratch, which for a 40-agent
|
|
8
|
+
* audit is the entire cost of the run — to change one line of the last stage.
|
|
9
|
+
* With one, the unchanged prefix comes back from disk and only the edit runs.
|
|
10
|
+
*
|
|
11
|
+
* ## Why a *prefix*, and not a lookup table
|
|
12
|
+
*
|
|
13
|
+
* Each entry is keyed by both its position in the run and a hash of everything
|
|
14
|
+
* that decides what that agent does. A replay walks positions in order and
|
|
15
|
+
* stops reusing at the first entry that does not match — every call from there
|
|
16
|
+
* on runs live. Reusing later matches out of order would be reusing a result
|
|
17
|
+
* produced under different upstream conditions: the same prompt at position 12
|
|
18
|
+
* of a *different* run is not the same work, because what fed it changed.
|
|
19
|
+
*
|
|
20
|
+
* A failed agent is journaled as a failure and never replayed as one. Resuming
|
|
21
|
+
* a run that died at agent 5 exists to retry agent 5, so the prefix ends there
|
|
22
|
+
* and 5 onwards run live — the alternative would make a failure permanent.
|
|
23
|
+
*
|
|
24
|
+
* ## Runs that use `agent({ resume })`
|
|
25
|
+
*
|
|
26
|
+
* Those are not replayed at all. A replayed agent is text from a file, not a
|
|
27
|
+
* live child, so there is no conversation in this run for a later `resume` to
|
|
28
|
+
* continue — and the id map that would find one belongs to the run that did
|
|
29
|
+
* the spawning. Rather than replay a prefix that strands the first `resume`
|
|
30
|
+
* call, a journal carrying one declines the whole cache and the run pays in
|
|
31
|
+
* full. Coarse on purpose: the alternative is tracking which label each entry
|
|
32
|
+
* ran under and capping the prefix below the earliest one that gets resumed,
|
|
33
|
+
* which is a second key concept for a case that costs one run.
|
|
34
|
+
*
|
|
35
|
+
* ## Ordering under concurrency
|
|
36
|
+
*
|
|
37
|
+
* Positions are assigned as calls arrive, and with `pipeline` that order
|
|
38
|
+
* depends on which agent finished first. A replay usually reproduces it, since
|
|
39
|
+
* cached calls answer in journal order, but it is not guaranteed. That is why
|
|
40
|
+
* the key is checked as well as the position: a run that interleaves
|
|
41
|
+
* differently loses cache hits, it never returns another agent's answer.
|
|
42
|
+
*
|
|
43
|
+
* The file is JSON Lines, appended as each agent settles, so a run that is
|
|
44
|
+
* killed mid-flight still leaves everything it had finished.
|
|
45
|
+
*/
|
|
46
|
+
/** One settled agent call, as replayed. */
|
|
47
|
+
export interface WorkflowJournalEntry {
|
|
48
|
+
/** Position in the run — the same counter that names `wf-agent-N`. */
|
|
49
|
+
index: number;
|
|
50
|
+
/** Hash of the call's payload; a mismatch ends the replayable prefix. */
|
|
51
|
+
key: string;
|
|
52
|
+
/** Whether the agent succeeded. A failure ends the prefix on replay. */
|
|
53
|
+
ok: boolean;
|
|
54
|
+
/** The agent's answer, when it had one. */
|
|
55
|
+
text?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Whether the call continued an earlier child (`agent({ resume })`).
|
|
58
|
+
*
|
|
59
|
+
* A replayed agent leaves no session behind in the run that replays it — the
|
|
60
|
+
* conversation belongs to the run that actually spawned it, and the host's
|
|
61
|
+
* id map is per-run — so a later `resume` would have nothing to continue.
|
|
62
|
+
* Recording it lets the next run decline to replay at all rather than fail
|
|
63
|
+
* partway through, which is why the flag is on the journal and not derived.
|
|
64
|
+
*/
|
|
65
|
+
resumed?: true;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The fields that decide what an agent does.
|
|
69
|
+
*
|
|
70
|
+
* Deliberately not the whole payload: `phaseIndex` and `phaseTitle` move the
|
|
71
|
+
* row around in the progress tree without changing a single token the agent
|
|
72
|
+
* sees, so re-grouping phases should not throw away an hour of results.
|
|
73
|
+
*/
|
|
74
|
+
export interface JournalKeyInput {
|
|
75
|
+
prompt: string;
|
|
76
|
+
label?: string;
|
|
77
|
+
model?: string;
|
|
78
|
+
agentType?: string;
|
|
79
|
+
effort?: string;
|
|
80
|
+
isolation?: string;
|
|
81
|
+
gate?: string;
|
|
82
|
+
resume?: string;
|
|
83
|
+
/** Serialized `agent({ schema })`, when the call asked for one. */
|
|
84
|
+
schema?: string;
|
|
85
|
+
}
|
|
86
|
+
/** Stable hash of a call's payload. Field order is fixed here, not by the caller. */
|
|
87
|
+
export declare function journalKey(input: JournalKeyInput): string;
|
|
88
|
+
/**
|
|
89
|
+
* Read a journal file into position order.
|
|
90
|
+
*
|
|
91
|
+
* Never throws: a missing, truncated or hand-mangled journal means "nothing to
|
|
92
|
+
* replay", which costs tokens. Refusing to run would cost the whole run.
|
|
93
|
+
* A partial last line is normal — the file is appended to while agents settle.
|
|
94
|
+
*/
|
|
95
|
+
export declare function readJournal(path: string): WorkflowJournalEntry[];
|
|
96
|
+
/** Append one settled call. Failure to write is not failure to run. */
|
|
97
|
+
export declare function appendJournal(path: string, entry: WorkflowJournalEntry): void;
|
|
98
|
+
//# sourceMappingURL=journal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../../src/workflow/journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAKH,2CAA2C;AAC3C,MAAM,WAAW,oBAAoB;IACnC,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,EAAE,EAAE,OAAO,CAAC;IACZ,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAkBzD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAsBhE;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAM7E"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* journal.ts — the record a workflow run leaves so a later run can skip work.
|
|
3
|
+
*
|
|
4
|
+
* ## What resume actually buys
|
|
5
|
+
*
|
|
6
|
+
* The documented iteration loop is "edit the persisted script and re-run it".
|
|
7
|
+
* Without a journal that re-pays every agent from scratch, which for a 40-agent
|
|
8
|
+
* audit is the entire cost of the run — to change one line of the last stage.
|
|
9
|
+
* With one, the unchanged prefix comes back from disk and only the edit runs.
|
|
10
|
+
*
|
|
11
|
+
* ## Why a *prefix*, and not a lookup table
|
|
12
|
+
*
|
|
13
|
+
* Each entry is keyed by both its position in the run and a hash of everything
|
|
14
|
+
* that decides what that agent does. A replay walks positions in order and
|
|
15
|
+
* stops reusing at the first entry that does not match — every call from there
|
|
16
|
+
* on runs live. Reusing later matches out of order would be reusing a result
|
|
17
|
+
* produced under different upstream conditions: the same prompt at position 12
|
|
18
|
+
* of a *different* run is not the same work, because what fed it changed.
|
|
19
|
+
*
|
|
20
|
+
* A failed agent is journaled as a failure and never replayed as one. Resuming
|
|
21
|
+
* a run that died at agent 5 exists to retry agent 5, so the prefix ends there
|
|
22
|
+
* and 5 onwards run live — the alternative would make a failure permanent.
|
|
23
|
+
*
|
|
24
|
+
* ## Runs that use `agent({ resume })`
|
|
25
|
+
*
|
|
26
|
+
* Those are not replayed at all. A replayed agent is text from a file, not a
|
|
27
|
+
* live child, so there is no conversation in this run for a later `resume` to
|
|
28
|
+
* continue — and the id map that would find one belongs to the run that did
|
|
29
|
+
* the spawning. Rather than replay a prefix that strands the first `resume`
|
|
30
|
+
* call, a journal carrying one declines the whole cache and the run pays in
|
|
31
|
+
* full. Coarse on purpose: the alternative is tracking which label each entry
|
|
32
|
+
* ran under and capping the prefix below the earliest one that gets resumed,
|
|
33
|
+
* which is a second key concept for a case that costs one run.
|
|
34
|
+
*
|
|
35
|
+
* ## Ordering under concurrency
|
|
36
|
+
*
|
|
37
|
+
* Positions are assigned as calls arrive, and with `pipeline` that order
|
|
38
|
+
* depends on which agent finished first. A replay usually reproduces it, since
|
|
39
|
+
* cached calls answer in journal order, but it is not guaranteed. That is why
|
|
40
|
+
* the key is checked as well as the position: a run that interleaves
|
|
41
|
+
* differently loses cache hits, it never returns another agent's answer.
|
|
42
|
+
*
|
|
43
|
+
* The file is JSON Lines, appended as each agent settles, so a run that is
|
|
44
|
+
* killed mid-flight still leaves everything it had finished.
|
|
45
|
+
*/
|
|
46
|
+
import { createHash } from "node:crypto";
|
|
47
|
+
import { appendFileSync, readFileSync } from "node:fs";
|
|
48
|
+
/** Stable hash of a call's payload. Field order is fixed here, not by the caller. */
|
|
49
|
+
export function journalKey(input) {
|
|
50
|
+
const canonical = JSON.stringify([
|
|
51
|
+
input.prompt,
|
|
52
|
+
input.label ?? null,
|
|
53
|
+
input.model ?? null,
|
|
54
|
+
input.agentType ?? null,
|
|
55
|
+
input.effort ?? null,
|
|
56
|
+
input.isolation ?? null,
|
|
57
|
+
input.gate ?? null,
|
|
58
|
+
input.resume ?? null,
|
|
59
|
+
// Appended only when present, which looks like a hack and is not: adding a
|
|
60
|
+
// ninth slot unconditionally would change the canonical form of every entry
|
|
61
|
+
// and invalidate every journal already on disk. Conditional, a schema-less
|
|
62
|
+
// call keys exactly as it always did, and adding or changing a schema still
|
|
63
|
+
// produces a different key.
|
|
64
|
+
...(input.schema !== undefined ? [input.schema] : []),
|
|
65
|
+
]);
|
|
66
|
+
return createHash("sha256").update(canonical).digest("hex").slice(0, 32);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Read a journal file into position order.
|
|
70
|
+
*
|
|
71
|
+
* Never throws: a missing, truncated or hand-mangled journal means "nothing to
|
|
72
|
+
* replay", which costs tokens. Refusing to run would cost the whole run.
|
|
73
|
+
* A partial last line is normal — the file is appended to while agents settle.
|
|
74
|
+
*/
|
|
75
|
+
export function readJournal(path) {
|
|
76
|
+
let raw;
|
|
77
|
+
try {
|
|
78
|
+
raw = readFileSync(path, "utf-8");
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
const entries = [];
|
|
84
|
+
for (const line of raw.split("\n")) {
|
|
85
|
+
if (line.trim() === "")
|
|
86
|
+
continue;
|
|
87
|
+
try {
|
|
88
|
+
const parsed = JSON.parse(line);
|
|
89
|
+
if (!isEntry(parsed))
|
|
90
|
+
continue;
|
|
91
|
+
entries.push(parsed);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// A half-written final line, or someone editing the file. Skipping it
|
|
95
|
+
// keeps what came before, and a shorter prefix is still a useful one.
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
entries.sort((a, b) => a.index - b.index);
|
|
99
|
+
return entries;
|
|
100
|
+
}
|
|
101
|
+
/** Append one settled call. Failure to write is not failure to run. */
|
|
102
|
+
export function appendJournal(path, entry) {
|
|
103
|
+
try {
|
|
104
|
+
appendFileSync(path, `${JSON.stringify(entry)}\n`, "utf-8");
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// A journal that cannot be written costs a future resume, nothing more.
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function isEntry(value) {
|
|
111
|
+
if (typeof value !== "object" || value === null)
|
|
112
|
+
return false;
|
|
113
|
+
const entry = value;
|
|
114
|
+
return (Number.isInteger(entry.index) &&
|
|
115
|
+
entry.index >= 0 &&
|
|
116
|
+
typeof entry.key === "string" &&
|
|
117
|
+
typeof entry.ok === "boolean" &&
|
|
118
|
+
(entry.text === undefined || typeof entry.text === "string") &&
|
|
119
|
+
(entry.resumed === undefined || entry.resumed === true));
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal.js","sourceRoot":"","sources":["../../src/workflow/journal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* json-schema.ts — validating a script-supplied JSON Schema.
|
|
3
|
+
*
|
|
4
|
+
* `agent(prompt, { schema })` hands us a raw JSON Schema written by a model, to
|
|
5
|
+
* be used two ways: as a tool's `parameters` (so the provider fills the fields)
|
|
6
|
+
* and as the check that decides whether what came back is usable.
|
|
7
|
+
*
|
|
8
|
+
* ## Which typebox
|
|
9
|
+
*
|
|
10
|
+
* **`typebox`, not `@sinclair/typebox`.** They are different packages and both
|
|
11
|
+
* are installed here. `@sinclair/typebox` (0.34) dispatches on a `Kind` symbol
|
|
12
|
+
* that a schema arriving over the wire does not carry, so `Value.Check` throws
|
|
13
|
+
* `Unknown type` on a plain JSON Schema — and `Type.Unsafe` does not help, it
|
|
14
|
+
* stamps a `Kind` that is not registered. `typebox` v1 is a standards JSON
|
|
15
|
+
* Schema validator and takes the schema as-is. It is also the package pi itself
|
|
16
|
+
* types `ToolDefinition.parameters` against, so the same schema object serves
|
|
17
|
+
* both roles with no conversion.
|
|
18
|
+
*
|
|
19
|
+
* ## Why we validate at all
|
|
20
|
+
*
|
|
21
|
+
* Nothing in pi checks a tool call's arguments against the tool's `parameters`.
|
|
22
|
+
* `validateToolCall`/`validateToolArguments` exist in `pi-ai` but are never
|
|
23
|
+
* called from either shipped package, so a schema on a tool is a *prompt to the
|
|
24
|
+
* provider*, not an enforcement point. Every guarantee the script gets about
|
|
25
|
+
* the shape of its result is made here.
|
|
26
|
+
*
|
|
27
|
+
* Pure and pi-free on purpose, so `runtime.ts` can import it without dragging
|
|
28
|
+
* sessions and models into the runtime's tests.
|
|
29
|
+
*/
|
|
30
|
+
export interface CompiledSchema {
|
|
31
|
+
/** The schema as given, for the tool's `parameters` and the journal key. */
|
|
32
|
+
readonly schema: Record<string, unknown>;
|
|
33
|
+
/** `true`, or a human-readable account of what is wrong. */
|
|
34
|
+
check(value: unknown): true | string;
|
|
35
|
+
}
|
|
36
|
+
export type SchemaCompilation = {
|
|
37
|
+
ok: true;
|
|
38
|
+
compiled: CompiledSchema;
|
|
39
|
+
} | {
|
|
40
|
+
ok: false;
|
|
41
|
+
message: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Turn a script-supplied schema into something we can check against.
|
|
45
|
+
*
|
|
46
|
+
* Rejects up front rather than at the first tool call. A schema whose root is
|
|
47
|
+
* not an object cannot be a tool's input schema at all, so it would break every
|
|
48
|
+
* request the child makes rather than just the last one — and the author should
|
|
49
|
+
* hear about that before a model is paid to discover it.
|
|
50
|
+
*/
|
|
51
|
+
export declare function compileJsonSchema(schema: unknown): SchemaCompilation;
|
|
52
|
+
//# sourceMappingURL=json-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-schema.d.ts","sourceRoot":"","sources":["../../src/workflow/json-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAUH,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,4DAA4D;IAC5D,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC;CACtC;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnC;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,iBAAiB,CA0CpE"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* json-schema.ts — validating a script-supplied JSON Schema.
|
|
3
|
+
*
|
|
4
|
+
* `agent(prompt, { schema })` hands us a raw JSON Schema written by a model, to
|
|
5
|
+
* be used two ways: as a tool's `parameters` (so the provider fills the fields)
|
|
6
|
+
* and as the check that decides whether what came back is usable.
|
|
7
|
+
*
|
|
8
|
+
* ## Which typebox
|
|
9
|
+
*
|
|
10
|
+
* **`typebox`, not `@sinclair/typebox`.** They are different packages and both
|
|
11
|
+
* are installed here. `@sinclair/typebox` (0.34) dispatches on a `Kind` symbol
|
|
12
|
+
* that a schema arriving over the wire does not carry, so `Value.Check` throws
|
|
13
|
+
* `Unknown type` on a plain JSON Schema — and `Type.Unsafe` does not help, it
|
|
14
|
+
* stamps a `Kind` that is not registered. `typebox` v1 is a standards JSON
|
|
15
|
+
* Schema validator and takes the schema as-is. It is also the package pi itself
|
|
16
|
+
* types `ToolDefinition.parameters` against, so the same schema object serves
|
|
17
|
+
* both roles with no conversion.
|
|
18
|
+
*
|
|
19
|
+
* ## Why we validate at all
|
|
20
|
+
*
|
|
21
|
+
* Nothing in pi checks a tool call's arguments against the tool's `parameters`.
|
|
22
|
+
* `validateToolCall`/`validateToolArguments` exist in `pi-ai` but are never
|
|
23
|
+
* called from either shipped package, so a schema on a tool is a *prompt to the
|
|
24
|
+
* provider*, not an enforcement point. Every guarantee the script gets about
|
|
25
|
+
* the shape of its result is made here.
|
|
26
|
+
*
|
|
27
|
+
* Pure and pi-free on purpose, so `runtime.ts` can import it without dragging
|
|
28
|
+
* sessions and models into the runtime's tests.
|
|
29
|
+
*/
|
|
30
|
+
import { Check, Errors } from "typebox/value";
|
|
31
|
+
/** Largest schema we will accept, serialized. */
|
|
32
|
+
const MAX_SCHEMA_BYTES = 64 * 1024;
|
|
33
|
+
/** How many validation errors are quoted back to the model. */
|
|
34
|
+
const MAX_REPORTED_ERRORS = 5;
|
|
35
|
+
/**
|
|
36
|
+
* Turn a script-supplied schema into something we can check against.
|
|
37
|
+
*
|
|
38
|
+
* Rejects up front rather than at the first tool call. A schema whose root is
|
|
39
|
+
* not an object cannot be a tool's input schema at all, so it would break every
|
|
40
|
+
* request the child makes rather than just the last one — and the author should
|
|
41
|
+
* hear about that before a model is paid to discover it.
|
|
42
|
+
*/
|
|
43
|
+
export function compileJsonSchema(schema) {
|
|
44
|
+
if (typeof schema !== "object" || schema === null || Array.isArray(schema)) {
|
|
45
|
+
return { ok: false, message: "agent() opts.schema must be a JSON Schema object." };
|
|
46
|
+
}
|
|
47
|
+
const root = schema;
|
|
48
|
+
if (root.type !== "object") {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
message: 'agent() opts.schema must have `type: "object"` at its root — it becomes the tool\'s input schema, '
|
|
52
|
+
+ "and a non-object root is not something a model can be asked to fill.",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
let serialized;
|
|
56
|
+
try {
|
|
57
|
+
serialized = JSON.stringify(root);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return { ok: false, message: "agent() opts.schema must be JSON-serializable." };
|
|
61
|
+
}
|
|
62
|
+
if (serialized.length > MAX_SCHEMA_BYTES) {
|
|
63
|
+
return {
|
|
64
|
+
ok: false,
|
|
65
|
+
message: `agent() opts.schema is too large (${serialized.length} bytes; the limit is ${MAX_SCHEMA_BYTES}).`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// Smoke-tested here so a schema the validator cannot walk fails at the call
|
|
69
|
+
// that wrote it, with the schema in hand, rather than inside a child's tool
|
|
70
|
+
// handler where the only symptom is an agent that never returns.
|
|
71
|
+
try {
|
|
72
|
+
Check(root, {});
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
message: `agent() opts.schema is not a schema this runtime can validate: ${error instanceof Error ? error.message : String(error)}`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return { ok: true, compiled: { schema: root, check: value => checkAgainst(root, value) } };
|
|
81
|
+
}
|
|
82
|
+
function checkAgainst(schema, value) {
|
|
83
|
+
let valid;
|
|
84
|
+
try {
|
|
85
|
+
valid = Check(schema, value);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
// Reported rather than thrown: a schema that compiled but trips on a
|
|
89
|
+
// particular value must fail that call, not the run.
|
|
90
|
+
return `the value could not be validated: ${error instanceof Error ? error.message : String(error)}`;
|
|
91
|
+
}
|
|
92
|
+
if (valid)
|
|
93
|
+
return true;
|
|
94
|
+
const reported = [];
|
|
95
|
+
try {
|
|
96
|
+
for (const error of Errors(schema, value)) {
|
|
97
|
+
// `instancePath` is JSON Pointer (`/a/b`); the model wrote the schema in
|
|
98
|
+
// JavaScript, so it reads `$.a.b` far more easily.
|
|
99
|
+
const path = String(error.instancePath ?? "");
|
|
100
|
+
const where = path === "" ? "$" : `$${path.replace(/\//g, ".")}`;
|
|
101
|
+
reported.push(`${where}: ${error.message}`);
|
|
102
|
+
if (reported.length >= MAX_REPORTED_ERRORS)
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Errors() can trip where Check() merely returned false. A vaguer message
|
|
108
|
+
// still names the right problem.
|
|
109
|
+
}
|
|
110
|
+
return reported.length > 0 ? reported.join("; ") : "the value does not match the required schema";
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=json-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-schema.js","sourceRoot":"","sources":["../../src/workflow/json-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* meta.ts — extract and validate a workflow script's `meta` block.
|
|
3
|
+
*
|
|
4
|
+
* Workflow scripts open with `export const meta = { ... }`, but the script body
|
|
5
|
+
* runs through `node:vm`, which has no module loader — `export` is a syntax
|
|
6
|
+
* error there. The block also has to be readable *before* execution, because the
|
|
7
|
+
* declared phases seed the progress groups the UI renders from the first frame.
|
|
8
|
+
*
|
|
9
|
+
* Claude Code solves this by parsing with acorn and requiring `meta` to be a
|
|
10
|
+
* pure literal (no variables, calls, spreads, or template interpolation). We
|
|
11
|
+
* take the same contract without the dependency: scan to the matching brace,
|
|
12
|
+
* then evaluate *only* that fragment in an empty vm context. A pure literal has
|
|
13
|
+
* nothing to call, so evaluating it cannot reach anything — and anything that
|
|
14
|
+
* isn't a pure literal either throws (unbound identifier) or is rejected below.
|
|
15
|
+
*
|
|
16
|
+
* The scanner is string-, comment-, and regex-aware. That matters: a workflow's
|
|
17
|
+
* `detail` text routinely contains braces, and `phases: [{ title: "a}b" }]` must
|
|
18
|
+
* not terminate the scan early.
|
|
19
|
+
*/
|
|
20
|
+
/** A phase declared up front, so the UI can show it before any agent runs. */
|
|
21
|
+
export interface WorkflowPhaseMeta {
|
|
22
|
+
title: string;
|
|
23
|
+
detail?: string;
|
|
24
|
+
/** Set when a phase pins a model; display-only, the runtime does not read it. */
|
|
25
|
+
model?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface WorkflowMeta {
|
|
28
|
+
name: string;
|
|
29
|
+
description: string;
|
|
30
|
+
/** Shown in the saved-workflow listing. Not used by the runtime. */
|
|
31
|
+
whenToUse?: string;
|
|
32
|
+
phases?: WorkflowPhaseMeta[];
|
|
33
|
+
}
|
|
34
|
+
export interface MetaExtraction {
|
|
35
|
+
meta: WorkflowMeta;
|
|
36
|
+
/**
|
|
37
|
+
* The script with the leading `export ` stripped, so `const meta = {...}`
|
|
38
|
+
* compiles inside the vm. Byte offsets after the keyword are untouched, which
|
|
39
|
+
* keeps stack-trace line numbers aligned with what the author wrote.
|
|
40
|
+
*/
|
|
41
|
+
body: string;
|
|
42
|
+
}
|
|
43
|
+
export declare class WorkflowMetaError extends Error {
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Whether `source` even claims to be a workflow script.
|
|
47
|
+
*
|
|
48
|
+
* The cheap half of {@link extractMeta}, exported so a directory of `.js` files
|
|
49
|
+
* can be told apart from a directory of workflows without evaluating anything.
|
|
50
|
+
* A saved-workflow folder is a normal folder — it may hold a build artifact, a
|
|
51
|
+
* config, someone's scratch script — and those should neither be offered as
|
|
52
|
+
* workflows nor produce a parser error when named.
|
|
53
|
+
*/
|
|
54
|
+
export declare function hasMetaDeclaration(source: string): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Pull `meta` off the front of a workflow script and hand back the runnable body.
|
|
57
|
+
*
|
|
58
|
+
* Throws {@link WorkflowMetaError} with author-facing guidance for every
|
|
59
|
+
* rejection — these messages are shown verbatim to whoever wrote the script.
|
|
60
|
+
*/
|
|
61
|
+
export declare function extractMeta(source: string): MetaExtraction;
|
|
62
|
+
/** The label a `SubagentWorkflow` call renders under, from whichever field it carries. */
|
|
63
|
+
export declare function workflowCallName(args: {
|
|
64
|
+
script?: string;
|
|
65
|
+
scriptPath?: string;
|
|
66
|
+
name?: string;
|
|
67
|
+
}): string;
|
|
68
|
+
//# sourceMappingURL=meta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../src/workflow/meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAc/C;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE1D;AAwID;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CA6E1D;AAYD,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAmBtG"}
|