@marcoscale98/pi-extensible-workflows 5.17.0-fork.1 → 6.2.1-fork.1
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 +145 -0
- package/README.md +2 -2
- package/dist/src/agent-execution.d.ts +43 -10
- package/dist/src/agent-execution.js +442 -162
- package/dist/src/background-widget.d.ts +5 -1
- package/dist/src/background-widget.js +5 -10
- package/dist/src/decoders.d.ts +2 -3
- package/dist/src/decoders.js +59 -37
- package/dist/src/execution.d.ts +6 -2
- package/dist/src/execution.js +48 -7
- package/dist/src/host-delivery.js +5 -8
- package/dist/src/host-navigator.js +5 -2
- package/dist/src/host-phases.d.ts +1 -0
- package/dist/src/host-recovery.d.ts +11 -8
- package/dist/src/host-recovery.js +14 -22
- package/dist/src/host-runtime.js +56 -5
- package/dist/src/host-view.d.ts +6 -1
- package/dist/src/host-view.js +46 -20
- package/dist/src/host.d.ts +2 -2
- package/dist/src/host.js +246 -118
- package/dist/src/index.d.ts +1 -2
- package/dist/src/index.js +1985 -1690
- package/dist/src/index.js.map +3 -3
- package/dist/src/paths.d.ts +8 -5
- package/dist/src/paths.js +24 -13
- package/dist/src/persistence.d.ts +1 -0
- package/dist/src/persistence.js +1 -0
- package/dist/src/pi-runtime-runner.js +4 -1
- package/dist/src/registry.d.ts +9 -7
- package/dist/src/registry.js +29 -71
- package/dist/src/runtime/agent-runner.d.ts +2 -0
- package/dist/src/script-tools.d.ts +27 -0
- package/dist/src/script-tools.js +87 -0
- package/dist/src/session-lease.d.ts +1 -1
- package/dist/src/session-lease.js +45 -11
- package/dist/src/settings.d.ts +19 -3
- package/dist/src/settings.js +63 -50
- package/dist/src/store.d.ts +3 -1
- package/dist/src/store.js +17 -1
- package/dist/src/trajectory.d.ts +12 -3
- package/dist/src/trajectory.js +32 -11
- package/dist/src/types.d.ts +129 -45
- package/dist/src/types.js +5 -8
- package/dist/src/utils.d.ts +21 -1
- package/dist/src/utils.js +46 -6
- package/dist/src/validation.d.ts +14 -3
- package/dist/src/validation.js +143 -87
- package/dist/starter/index.js +8 -11
- package/dist/starter/index.js.map +1 -1
- package/dist/starter/review-loop.d.ts +0 -13
- package/dist/starter/review-loop.js +8 -9
- package/dist/subagents/index.js +904 -956
- package/dist/subagents/index.js.map +3 -3
- package/dist/subagents/src/contracts.d.ts +48 -31
- package/dist/subagents/src/contracts.js +20 -9
- package/dist/subagents/src/index.d.ts +1 -1
- package/dist/subagents/src/index.js +14 -8
- package/dist/subagents/src/manager.js +52 -73
- package/dist/subagents/src/navigator.js +3 -14
- package/dist/subagents/src/view.d.ts +1 -1
- package/dist/subagents/src/view.js +15 -68
- package/dist/subagents/src/worktree.js +1 -1
- package/dist/trajectory/assets/index.html +35 -13
- package/dist/trajectory/index.js +576 -932
- package/dist/trajectory/index.js.map +3 -3
- package/dist/trajectory/src/assets/index.html +35 -13
- package/dist/trajectory/src/index.js +134 -104
- package/dist/trajectory/src/server.js +268 -27
- package/dist/trajectory/src/server.js.map +3 -3
- package/dist/trajectory/src/startup-mutex.d.ts +17 -0
- package/dist/trajectory/src/startup-mutex.js +172 -0
- package/examples/workflow-extension-template/README.md +4 -7
- package/examples/workflow-extension-template/extension.test.mjs +4 -8
- package/examples/workflow-extension-template/index.js +0 -3
- package/package.json +10 -10
- package/skills/pi-extensible-workflows/SKILL.md +12 -8
- package/src/agent-execution.ts +412 -164
- package/src/background-widget.ts +5 -11
- package/src/decoders.ts +51 -37
- package/src/execution.ts +46 -9
- package/src/host-delivery.ts +5 -8
- package/src/host-navigator.ts +4 -2
- package/src/host-phases.ts +1 -1
- package/src/host-recovery.ts +23 -28
- package/src/host-runtime.ts +44 -6
- package/src/host-view.ts +41 -16
- package/src/host.ts +229 -142
- package/src/index.ts +1 -2
- package/src/paths.ts +18 -9
- package/src/persistence.ts +1 -0
- package/src/pi-runtime-runner.ts +3 -1
- package/src/registry.ts +28 -64
- package/src/runtime/agent-runner.ts +2 -0
- package/src/script-tools.ts +76 -0
- package/src/session-lease.ts +34 -6
- package/src/settings.ts +56 -50
- package/src/store.ts +18 -2
- package/src/trajectory.ts +32 -15
- package/src/types.ts +82 -34
- package/src/utils.ts +42 -5
- package/src/validation.ts +121 -80
- package/starter/index.ts +0 -1
- package/starter/review-loop.ts +8 -9
- package/starter/roles/developer.md +0 -1
- package/starter/roles/oracle.md +0 -1
- package/starter/roles/researcher.md +0 -1
- package/starter/roles/reviewer.md +0 -1
- package/starter/roles/scout.md +0 -1
- package/subagents/README.md +10 -16
- package/subagents/src/contracts.ts +21 -11
- package/subagents/src/index.ts +17 -8
- package/subagents/src/manager.ts +48 -128
- package/subagents/src/navigator.ts +4 -13
- package/subagents/src/view.ts +16 -63
- package/subagents/src/worktree.ts +1 -1
- package/trajectory/src/assets/index.html +35 -13
- package/trajectory/src/index.ts +112 -91
- package/trajectory/src/server.ts +46 -10
- package/trajectory/src/startup-mutex.ts +127 -0
- package/dist/src/roles.d.ts +0 -70
- package/dist/src/roles.js +0 -325
- package/dist/starter/roles/developer.md +0 -6
- package/dist/starter/roles/oracle.md +0 -18
- package/dist/starter/roles/researcher.md +0 -20
- package/dist/starter/roles/reviewer.md +0 -19
- package/dist/starter/roles/scout.md +0 -18
- package/examples/workflow-extension-template/roles/reviewer.md +0 -4
- package/src/roles.ts +0 -326
|
@@ -22,6 +22,11 @@ export type BackgroundWidgetAPI = Pick<ExtensionAPI, "appendEntry" | "on"> & {
|
|
|
22
22
|
registerEntryRenderer?: ExtensionAPI["registerEntryRenderer"];
|
|
23
23
|
registerShortcut?: ExtensionAPI["registerShortcut"];
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Repaint interval. Fast enough that the spinner reads as motion rather than a
|
|
27
|
+
* stutter; the underlying data is only re-read when an event says it changed.
|
|
28
|
+
*/
|
|
29
|
+
export declare const REPAINT_MS = 125;
|
|
25
30
|
/**
|
|
26
31
|
* How long an agent may go without an event before the widget says so.
|
|
27
32
|
*
|
|
@@ -55,7 +60,6 @@ interface ReceiptAgent {
|
|
|
55
60
|
name: string;
|
|
56
61
|
state: string;
|
|
57
62
|
model?: string;
|
|
58
|
-
role?: string;
|
|
59
63
|
requestedModel?: string;
|
|
60
64
|
tools?: readonly string[];
|
|
61
65
|
/** Accepted for rendering older receipt entries; new receipts persist granted tools. */
|
|
@@ -25,7 +25,7 @@ const ENTRY_TYPE = "piewf-run-receipt";
|
|
|
25
25
|
* Repaint interval. Fast enough that the spinner reads as motion rather than a
|
|
26
26
|
* stutter; the underlying data is only re-read when an event says it changed.
|
|
27
27
|
*/
|
|
28
|
-
const REPAINT_MS = 125;
|
|
28
|
+
export const REPAINT_MS = 125;
|
|
29
29
|
/**
|
|
30
30
|
* Filesystem rescan interval. Shell-only activity has no event, but it does not
|
|
31
31
|
* need to be polled at the animation cadence.
|
|
@@ -191,7 +191,7 @@ function renderableAgent(value) {
|
|
|
191
191
|
return false;
|
|
192
192
|
if (value.model.thinking !== undefined && typeof value.model.thinking !== "string")
|
|
193
193
|
return false;
|
|
194
|
-
for (const key of ["id", "label", "parentId", "
|
|
194
|
+
for (const key of ["id", "label", "parentId", "requestedModel"])
|
|
195
195
|
if (value[key] !== undefined && typeof value[key] !== "string")
|
|
196
196
|
return false;
|
|
197
197
|
for (const key of ["attempts", "startedAt", "durationMs", "lastEventAt"])
|
|
@@ -554,8 +554,7 @@ function renderFrame(runs, now, width, offset = 0, theme, scrolling = false, siz
|
|
|
554
554
|
? mark(agent.state, now, paint, run.state)
|
|
555
555
|
: paint(silent >= STALL_MS ? ROLE.failed : ROLE.warn, "⚠")} ${
|
|
556
556
|
// The label is what the workflow called this agent — `reviewer #2`,
|
|
557
|
-
// `scout (api)` —
|
|
558
|
-
// agents of one role are otherwise indistinguishable.
|
|
557
|
+
// `scout (api)` — preserving an explicit label when supplied.
|
|
559
558
|
agent.label ?? agent.name}${silent === undefined
|
|
560
559
|
? ""
|
|
561
560
|
: ` ${paint(silent >= STALL_MS ? ROLE.failed : ROLE.warn, `${silent >= STALL_MS ? "stalled" : "quiet"} ${formatElapsed(silent)}`)}`}`,
|
|
@@ -696,18 +695,15 @@ function receiptFor(run, fallback) {
|
|
|
696
695
|
agents: agents.map((agent) => ({
|
|
697
696
|
id: agent.id,
|
|
698
697
|
...(agent.parentId === undefined ? {} : { parentId: agent.parentId }),
|
|
699
|
-
//
|
|
700
|
-
// from. Two agents of one role are otherwise indistinguishable.
|
|
698
|
+
// Preserve explicit display labels.
|
|
701
699
|
name: agent.label ?? agent.name,
|
|
702
700
|
state: agent.state,
|
|
703
|
-
//
|
|
704
|
-
// name alone does not say whether it reasoned cheaply or deeply.
|
|
701
|
+
// Show both model and thinking level.
|
|
705
702
|
...(agent.model.model
|
|
706
703
|
? {
|
|
707
704
|
model: `${agent.model.model}${agent.model.thinking ? `:${agent.model.thinking}` : ""}`,
|
|
708
705
|
}
|
|
709
706
|
: {}),
|
|
710
|
-
...(agent.role ? { role: agent.role } : {}),
|
|
711
707
|
...(agent.requestedModel ? { requestedModel: agent.requestedModel } : {}),
|
|
712
708
|
tools: [...agent.tools],
|
|
713
709
|
// Cache reads dwarf real input and cost almost nothing, so the split is
|
|
@@ -782,7 +778,6 @@ export function renderReceipt(data, expanded, theme) {
|
|
|
782
778
|
lines.push(`${prefix}${lastAgent ? "╰─" : "├─"} ${glyph(agent.state)} ${agent.name} ${theme.fg("muted", detail)}`);
|
|
783
779
|
const under = `${prefix}${lastAgent ? " " : "│ "} `;
|
|
784
780
|
const meta = [
|
|
785
|
-
agent.role ? `role ${agent.role}` : "",
|
|
786
781
|
agent.requestedModel && agent.requestedModel !== agent.model
|
|
787
782
|
? `via ${agent.requestedModel}`
|
|
788
783
|
: "",
|
package/dist/src/decoders.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type PreparedAgentConfiguration, type BudgetApprovalRequest, type JsonValue, type LaunchSnapshot, type RunRecord, type WorkflowBudgetUsage, type WorkflowExtensionSettings } from "./types.js";
|
|
2
2
|
import type { OwnershipRecord } from "./agent-execution.js";
|
|
3
3
|
export interface EffectiveSystemPrompt {
|
|
4
4
|
sessionId: string;
|
|
@@ -13,7 +13,6 @@ export interface RunSummaryAgent {
|
|
|
13
13
|
name: string;
|
|
14
14
|
label?: string;
|
|
15
15
|
state: string;
|
|
16
|
-
role?: string;
|
|
17
16
|
attempts: number;
|
|
18
17
|
}
|
|
19
18
|
export interface RunSummaryArtifacts {
|
|
@@ -59,7 +58,7 @@ export type Journal = {
|
|
|
59
58
|
awaiting?: Record<string, AwaitingCheckpoint>;
|
|
60
59
|
decisions?: Record<string, PendingWorkflowDecision>;
|
|
61
60
|
};
|
|
62
|
-
export declare function
|
|
61
|
+
export declare function decodePreparedAgentConfiguration(value: unknown): PreparedAgentConfiguration | undefined;
|
|
63
62
|
export declare function decodeWorkflowExtensions(value: unknown): WorkflowExtensionSettings | undefined;
|
|
64
63
|
export declare function decodePersistedRun(value: unknown, allowLegacyAgentSessions?: boolean): PersistedRun | undefined;
|
|
65
64
|
export declare function isPersistedRun(value: unknown): value is PersistedRun;
|
package/dist/src/decoders.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AGENT_STATES, BUDGET_DIMENSIONS, BUDGET_EVENT_TYPES, RUN_STATES, isContextFileScope } from "./types.js";
|
|
1
|
+
import { AGENT_STATES, BUDGET_DIMENSIONS, BUDGET_EVENT_TYPES, RUN_STATES, isContextFileScope, LAUNCH_SNAPSHOT_IDENTITY_VERSION } from "./types.js";
|
|
2
2
|
import { finiteNumber, isThinkingLevel, isWorkflowErrorCode, jsonValue, object, positiveInteger, validWorkflowExtensionNamespace } from "./utils.js";
|
|
3
3
|
const INVALID_PERSISTED_VALUE = Symbol("invalid persisted value");
|
|
4
4
|
function integer(value) { return finiteNumber(value) && Number.isInteger(value); }
|
|
@@ -64,28 +64,21 @@ function decodeAgentResourceSelectors(value) {
|
|
|
64
64
|
return { ...(skills === undefined ? {} : { skills }), ...(extensions === undefined ? {} : { extensions }), ...(tools === undefined ? {} : { tools }) };
|
|
65
65
|
}
|
|
66
66
|
function decodeContextFileScopes(value) { return decodeArray(value, (scope) => isContextFileScope(scope) ? scope : undefined); }
|
|
67
|
-
export function
|
|
68
|
-
if (!object(value))
|
|
67
|
+
export function decodePreparedAgentConfiguration(value) {
|
|
68
|
+
if (!object(value) || !jsonValue(value) || typeof value.projectTrusted !== "boolean" || typeof value.systemPromptAppend !== "string")
|
|
69
69
|
return undefined;
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const skills = value.skills === undefined ? undefined : decodeStringArray(value.skills);
|
|
76
|
-
const extensions = value.extensions === undefined ? undefined : decodeStringArray(value.extensions);
|
|
77
|
-
const overrideSystemPrompt = optionalBoolean(value.overrideSystemPrompt);
|
|
70
|
+
const model = decodeModelSpec(value.model);
|
|
71
|
+
const tools = decodeStringArray(value.tools);
|
|
72
|
+
const skills = decodeStringArray(value.skills);
|
|
73
|
+
const extensions = decodeStringArray(value.extensions);
|
|
74
|
+
const settings = decodeWorkflowExtensions(value.settings);
|
|
78
75
|
const contextFiles = value.contextFiles === undefined ? undefined : decodeContextFileScopes(value.contextFiles);
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (
|
|
76
|
+
const label = optionalString(value.label);
|
|
77
|
+
const systemPrompt = optionalString(value.systemPrompt);
|
|
78
|
+
const excludeTools = value.excludeTools === undefined ? undefined : decodeStringArray(value.excludeTools);
|
|
79
|
+
if (!model || !tools || !skills || !extensions || !settings || label === INVALID_PERSISTED_VALUE || systemPrompt === INVALID_PERSISTED_VALUE || value.contextFiles !== undefined && !contextFiles || value.excludeTools !== undefined && !excludeTools)
|
|
83
80
|
return undefined;
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
...(prompt === undefined ? {} : { prompt }), ...(description === undefined ? {} : { description }), ...(foldedModel === undefined ? {} : { model: foldedModel }),
|
|
87
|
-
...(tools === undefined ? {} : { tools }), ...(skills === undefined ? {} : { skills }), ...(extensions === undefined ? {} : { extensions }), ...(overrideSystemPrompt === undefined ? {} : { overrideSystemPrompt }), ...(contextFiles === undefined ? {} : { contextFiles }), ...(extensionSettings === undefined ? {} : { extensionSettings }),
|
|
88
|
-
};
|
|
81
|
+
return { model, tools, skills, extensions, settings, projectTrusted: value.projectTrusted, systemPromptAppend: value.systemPromptAppend, ...(contextFiles === undefined ? {} : { contextFiles }), ...(excludeTools === undefined ? {} : { excludeTools }), ...(label === undefined ? {} : { label }), ...(systemPrompt === undefined ? {} : { systemPrompt }) };
|
|
89
82
|
}
|
|
90
83
|
function decodeWorkflowMetadata(value) {
|
|
91
84
|
if (!object(value) || typeof value.name !== "string")
|
|
@@ -211,17 +204,25 @@ function decodeScheduledAgentOptions(value) {
|
|
|
211
204
|
const parentBreadcrumb = optionalString(value.parentBreadcrumb);
|
|
212
205
|
const worktreeOwner = optionalString(value.worktreeOwner);
|
|
213
206
|
const model = optionalString(value.model);
|
|
214
|
-
const role = typeof value.role === "string" ? value.role : undefined;
|
|
215
207
|
const contextFiles = value.contextFiles === undefined ? undefined : decodeContextFileScopes(value.contextFiles);
|
|
216
208
|
const schema = value.schema === undefined ? undefined : decodeJsonObject(value.schema);
|
|
217
209
|
const retries = optionalNumber(value.retries);
|
|
218
210
|
const timeoutMs = value.timeoutMs;
|
|
211
|
+
if (value.projectTrusted !== undefined && typeof value.projectTrusted !== "boolean")
|
|
212
|
+
return undefined;
|
|
213
|
+
const rawCapabilities = value.capabilities;
|
|
214
|
+
const capabilities = rawCapabilities === undefined ? undefined : object(rawCapabilities) ? { tools: decodeStringArray(rawCapabilities.tools), skills: decodeStringArray(rawCapabilities.skills), extensions: decodeStringArray(rawCapabilities.extensions) } : undefined;
|
|
215
|
+
if (rawCapabilities !== undefined && (!capabilities?.tools || !capabilities.skills || !capabilities.extensions))
|
|
216
|
+
return undefined;
|
|
217
|
+
const configuration = value.configuration === undefined ? undefined : decodePreparedAgentConfiguration(value.configuration);
|
|
218
|
+
if (value.configuration !== undefined && configuration === undefined)
|
|
219
|
+
return undefined;
|
|
219
220
|
const agentOptions = value.agentOptions === undefined ? undefined : decodeJsonObject(value.agentOptions);
|
|
220
221
|
const agentIdentity = value.agentIdentity === undefined ? undefined : decodeIdentity(value.agentIdentity);
|
|
221
222
|
const sessionPath = optionalString(value.sessionPath);
|
|
222
223
|
const continuity = value.continuity === undefined ? undefined : isAgentContinuity(value.continuity) ? value.continuity : INVALID_PERSISTED_VALUE;
|
|
223
224
|
const extensionSettings = value.extensionSettings === undefined ? undefined : decodeWorkflowExtensions(value.extensionSettings);
|
|
224
|
-
if (sessionPath === INVALID_PERSISTED_VALUE || continuity === INVALID_PERSISTED_VALUE || requestedLabel === INVALID_PERSISTED_VALUE || parentBreadcrumb === INVALID_PERSISTED_VALUE || worktreeOwner === INVALID_PERSISTED_VALUE || model === INVALID_PERSISTED_VALUE || value.skills !== undefined && !skills || value.extensions !== undefined && !extensions || (value.
|
|
225
|
+
if (sessionPath === INVALID_PERSISTED_VALUE || continuity === INVALID_PERSISTED_VALUE || requestedLabel === INVALID_PERSISTED_VALUE || parentBreadcrumb === INVALID_PERSISTED_VALUE || worktreeOwner === INVALID_PERSISTED_VALUE || model === INVALID_PERSISTED_VALUE || value.skills !== undefined && !skills || value.extensions !== undefined && !extensions || (value.contextFiles !== undefined && !contextFiles) || (value.schema !== undefined && !schema) || retries === INVALID_PERSISTED_VALUE || (retries !== undefined && !integer(retries)) || (timeoutMs !== undefined && timeoutMs !== null && !finiteNumber(timeoutMs)) || (value.agentOptions !== undefined && !agentOptions) || (value.agentIdentity !== undefined && !agentIdentity) || (value.extensionSettings !== undefined && !extensionSettings))
|
|
225
226
|
return undefined;
|
|
226
227
|
return {
|
|
227
228
|
label: value.label,
|
|
@@ -232,7 +233,6 @@ function decodeScheduledAgentOptions(value) {
|
|
|
232
233
|
...(skills === undefined ? {} : { skills }), ...(extensions === undefined ? {} : { extensions }),
|
|
233
234
|
...(worktreeOwner === undefined ? {} : { worktreeOwner }),
|
|
234
235
|
...(model === undefined ? {} : { model }),
|
|
235
|
-
...(role === undefined ? {} : { role }),
|
|
236
236
|
...(contextFiles === undefined ? {} : { contextFiles }),
|
|
237
237
|
...(schema === undefined ? {} : { schema }),
|
|
238
238
|
...(retries === undefined ? {} : { retries }),
|
|
@@ -240,6 +240,9 @@ function decodeScheduledAgentOptions(value) {
|
|
|
240
240
|
...(sessionPath === undefined ? {} : { sessionPath }),
|
|
241
241
|
...(continuity === undefined ? {} : { continuity }),
|
|
242
242
|
...(agentOptions === undefined ? {} : { agentOptions }),
|
|
243
|
+
...(configuration === undefined ? {} : { configuration }),
|
|
244
|
+
...(value.projectTrusted === undefined ? {} : { projectTrusted: value.projectTrusted }),
|
|
245
|
+
...(capabilities?.tools && capabilities.skills && capabilities.extensions ? { capabilities: { tools: capabilities.tools, skills: capabilities.skills, extensions: capabilities.extensions } } : {}),
|
|
243
246
|
...(agentIdentity === undefined ? {} : { agentIdentity }),
|
|
244
247
|
...(extensionSettings === undefined ? {} : { extensionSettings }),
|
|
245
248
|
};
|
|
@@ -288,12 +291,11 @@ function decodeAgentResourceInspection(value) {
|
|
|
288
291
|
const sources = sourceRecord === undefined ? undefined : {
|
|
289
292
|
global: decodeAgentResourceSelectors(sourceRecord.global),
|
|
290
293
|
project: decodeAgentResourceSelectors(sourceRecord.project),
|
|
291
|
-
...(sourceRecord.role === undefined ? {} : { role: decodeAgentResourceSelectors(sourceRecord.role) }),
|
|
292
294
|
...(sourceRecord.call === undefined ? {} : { call: decodeAgentResourceSelectors(sourceRecord.call) }),
|
|
293
295
|
};
|
|
294
|
-
if (!selectors || !skills || !extensions || !tools || !unmatchedSkills || !unmatchedExtensions || !unmatchedTools || rawSources !== undefined && (!sources || !sources.global || !sources.project || sources.
|
|
296
|
+
if (!selectors || !skills || !extensions || !tools || !unmatchedSkills || !unmatchedExtensions || !unmatchedTools || rawSources !== undefined && (!sources || !sources.global || !sources.project || sources.call === undefined && sourceRecord?.call !== undefined))
|
|
295
297
|
return undefined;
|
|
296
|
-
return { selectors: { skills: [...(selectors.skills ?? [])], extensions: [...(selectors.extensions ?? [])], tools: [...(selectors.tools ?? [])] }, skills, extensions, tools, unmatchedSkills, unmatchedExtensions, unmatchedTools, ...(sources === undefined ? {} : { selectorSources: { global: sources.global ?? {}, project: sources.project ?? {}, ...(sources.
|
|
298
|
+
return { selectors: { skills: [...(selectors.skills ?? [])], extensions: [...(selectors.extensions ?? [])], tools: [...(selectors.tools ?? [])] }, skills, extensions, tools, unmatchedSkills, unmatchedExtensions, unmatchedTools, ...(sources === undefined ? {} : { selectorSources: { global: sources.global ?? {}, project: sources.project ?? {}, ...(sources.call === undefined ? {} : { call: sources.call }) } }) };
|
|
297
299
|
}
|
|
298
300
|
function decodeAgentSetupSummary(value) {
|
|
299
301
|
if (!object(value) || typeof value.cwd !== "string")
|
|
@@ -337,7 +339,6 @@ function decodeAgent(value) {
|
|
|
337
339
|
const worktreeOwner = optionalString(value.worktreeOwner);
|
|
338
340
|
const handle = optionalString(value.handle);
|
|
339
341
|
const continuity = value.continuity === undefined ? undefined : isAgentContinuity(value.continuity) ? value.continuity : INVALID_PERSISTED_VALUE;
|
|
340
|
-
const role = optionalString(value.role);
|
|
341
342
|
const requestedModel = optionalString(value.requestedModel);
|
|
342
343
|
const startedAt = optionalNumber(value.startedAt);
|
|
343
344
|
const durationMs = optionalNumber(value.durationMs);
|
|
@@ -346,7 +347,7 @@ function decodeAgent(value) {
|
|
|
346
347
|
const toolCalls = value.toolCalls === undefined ? undefined : decodeArray(value.toolCalls, decodeAgentToolCall);
|
|
347
348
|
const activity = value.activity === undefined ? undefined : decodeAgentActivity(value.activity);
|
|
348
349
|
const lastEventAt = optionalNumber(value.lastEventAt);
|
|
349
|
-
if (systemPrompt === INVALID_PERSISTED_VALUE || prompt === INVALID_PERSISTED_VALUE || label === INVALID_PERSISTED_VALUE || parentId === INVALID_PERSISTED_VALUE || resultPath === INVALID_PERSISTED_VALUE || parentBreadcrumb === INVALID_PERSISTED_VALUE || worktreeOwner === INVALID_PERSISTED_VALUE ||
|
|
350
|
+
if (systemPrompt === INVALID_PERSISTED_VALUE || prompt === INVALID_PERSISTED_VALUE || label === INVALID_PERSISTED_VALUE || parentId === INVALID_PERSISTED_VALUE || resultPath === INVALID_PERSISTED_VALUE || parentBreadcrumb === INVALID_PERSISTED_VALUE || worktreeOwner === INVALID_PERSISTED_VALUE || requestedModel === INVALID_PERSISTED_VALUE || startedAt === INVALID_PERSISTED_VALUE || durationMs === INVALID_PERSISTED_VALUE || lastEventAt === INVALID_PERSISTED_VALUE || handle === INVALID_PERSISTED_VALUE || continuity === INVALID_PERSISTED_VALUE || handle !== undefined && !positiveInteger(value.turn))
|
|
350
351
|
return undefined;
|
|
351
352
|
if (!model || !tools || value.structuralPath !== undefined && !structuralPath || value.attemptDetails !== undefined && !attemptDetails || value.accounting !== undefined && !accounting || value.toolCalls !== undefined && !toolCalls || value.activity !== undefined && !activity)
|
|
352
353
|
return undefined;
|
|
@@ -365,7 +366,6 @@ function decodeAgent(value) {
|
|
|
365
366
|
...(worktreeOwner === undefined ? {} : { worktreeOwner }),
|
|
366
367
|
...(handle === undefined ? {} : { handle, turn: value.turn }),
|
|
367
368
|
...(continuity === undefined ? {} : { continuity }),
|
|
368
|
-
...(role === undefined ? {} : { role }),
|
|
369
369
|
...(requestedModel === undefined ? {} : { requestedModel }),
|
|
370
370
|
model,
|
|
371
371
|
tools,
|
|
@@ -434,6 +434,28 @@ function decodeRunEvent(value) {
|
|
|
434
434
|
return undefined;
|
|
435
435
|
return { type: value.type, message: value.message, ...(timestamp === undefined ? {} : { timestamp }) };
|
|
436
436
|
}
|
|
437
|
+
function decodeScriptCall(value) {
|
|
438
|
+
if (!object(value) || value.kind !== "shell" && value.kind !== "tool" || typeof value.name !== "string" || typeof value.path !== "string" || !finiteNumber(value.startedAt))
|
|
439
|
+
return undefined;
|
|
440
|
+
const shell = value.kind === "shell";
|
|
441
|
+
if (shell && !jsonValue(value.input))
|
|
442
|
+
return undefined;
|
|
443
|
+
const inputBytes = shell ? optionalNumber(value.inputBytes) : undefined;
|
|
444
|
+
const phase = optionalString(value.phase);
|
|
445
|
+
const finishedAt = optionalNumber(value.finishedAt);
|
|
446
|
+
let error;
|
|
447
|
+
if (value.error !== undefined) {
|
|
448
|
+
if (shell)
|
|
449
|
+
error = decodeWorkflowError(value.error);
|
|
450
|
+
else if (object(value.error) && typeof value.error.code === "string")
|
|
451
|
+
error = { code: isWorkflowErrorCode(value.error.code) ? value.error.code : "INTERNAL_ERROR" };
|
|
452
|
+
if (!error)
|
|
453
|
+
return undefined;
|
|
454
|
+
}
|
|
455
|
+
if (inputBytes === INVALID_PERSISTED_VALUE || phase === INVALID_PERSISTED_VALUE || finishedAt === INVALID_PERSISTED_VALUE)
|
|
456
|
+
return undefined;
|
|
457
|
+
return { kind: value.kind, name: value.name, path: value.path, ...(shell && jsonValue(value.input) ? { input: value.input } : {}), ...(inputBytes === undefined ? {} : { inputBytes }), ...(phase === undefined ? {} : { phase }), startedAt: value.startedAt, ...(finishedAt === undefined ? {} : { finishedAt }), ...(error === undefined ? {} : { error }) };
|
|
458
|
+
}
|
|
437
459
|
function decodeDelivery(value) {
|
|
438
460
|
if (!object(value))
|
|
439
461
|
return undefined;
|
|
@@ -467,6 +489,9 @@ export function decodePersistedRun(value, allowLegacyAgentSessions = false) {
|
|
|
467
489
|
const budgetEvents = value.budgetEvents === undefined ? undefined : decodeArray(value.budgetEvents, decodeBudgetEvent);
|
|
468
490
|
const events = value.events === undefined ? undefined : decodeArray(value.events, decodeRunEvent);
|
|
469
491
|
const delivery = value.delivery === undefined ? undefined : decodeDelivery(value.delivery);
|
|
492
|
+
const scriptCalls = value.scriptCalls === undefined ? undefined : decodeArray(value.scriptCalls, decodeScriptCall);
|
|
493
|
+
if (value.scriptCalls !== undefined && !scriptCalls)
|
|
494
|
+
return undefined;
|
|
470
495
|
if (!agentSessions || !agents || parentRunId === INVALID_PERSISTED_VALUE || value.retry !== undefined && !retry || phase === INVALID_PERSISTED_VALUE || value.phaseHistory !== undefined && !phaseHistory || phaseHistoryIndex === INVALID_PERSISTED_VALUE || activeShells === INVALID_PERSISTED_VALUE || activeShellStartedAt === INVALID_PERSISTED_VALUE || value.activeShellsByPhase !== undefined && !activeShellsByPhase || value.error !== undefined && !error || failedAt === INVALID_PERSISTED_VALUE || value.budget !== undefined && !budget || budgetVersion === INVALID_PERSISTED_VALUE || value.budgetVersion !== undefined && !integer(budgetVersion) || value.usage !== undefined && !usage || value.budgetEvents !== undefined && !budgetEvents || value.events !== undefined && !events || value.delivery !== undefined && !delivery)
|
|
471
496
|
return undefined;
|
|
472
497
|
if (value.agentSessions === undefined && !allowLegacyAgentSessions)
|
|
@@ -487,6 +512,7 @@ export function decodePersistedRun(value, allowLegacyAgentSessions = false) {
|
|
|
487
512
|
...(activeShells === undefined ? {} : { activeShells }),
|
|
488
513
|
...(activeShellStartedAt === undefined ? {} : { activeShellStartedAt }),
|
|
489
514
|
...(activeShellsByPhase === undefined ? {} : { activeShellsByPhase }),
|
|
515
|
+
...(scriptCalls === undefined ? {} : { scriptCalls }),
|
|
490
516
|
...(error === undefined ? {} : { error }),
|
|
491
517
|
...(failedAt === undefined ? {} : { failedAt }),
|
|
492
518
|
...(budget === undefined ? {} : { budget }),
|
|
@@ -513,14 +539,12 @@ export function decodeLaunchSnapshot(value) {
|
|
|
513
539
|
const phases = value.phases === undefined ? undefined : decodeStringArray(value.phases);
|
|
514
540
|
const models = decodeStringArray(value.models);
|
|
515
541
|
const tools = decodeStringArray(value.tools);
|
|
516
|
-
const
|
|
517
|
-
const roles = value.roles === undefined ? undefined : decodeRecord(value.roles, decodeAgentDefinition);
|
|
518
|
-
const projectRoles = value.projectRoles === undefined ? undefined : decodeStringArray(value.projectRoles);
|
|
542
|
+
const agentConfigurations = decodeRecord(value.agentConfigurations, decodePreparedAgentConfiguration);
|
|
519
543
|
const schemas = decodeArray(value.schemas, decodeJsonObject);
|
|
520
|
-
if (identityVersion
|
|
544
|
+
if (identityVersion !== LAUNCH_SNAPSHOT_IDENTITY_VERSION || launchMode !== undefined && !isLaunchMode(launchMode) || args === undefined || !metadata || !settings || value.settingsSources !== undefined && !settingsSources || value.budget !== undefined && !budget || settingsPath === INVALID_PERSISTED_VALUE || value.modelAliases !== undefined && !modelAliases || value.phases !== undefined && !phases || !models || !tools || !agentConfigurations || !schemas)
|
|
521
545
|
return undefined;
|
|
522
546
|
return {
|
|
523
|
-
|
|
547
|
+
identityVersion: LAUNCH_SNAPSHOT_IDENTITY_VERSION,
|
|
524
548
|
...(launchMode === undefined ? {} : { launchMode }),
|
|
525
549
|
script: value.script,
|
|
526
550
|
args,
|
|
@@ -533,9 +557,7 @@ export function decodeLaunchSnapshot(value) {
|
|
|
533
557
|
...(phases === undefined ? {} : { phases }),
|
|
534
558
|
models,
|
|
535
559
|
tools,
|
|
536
|
-
|
|
537
|
-
...(roles === undefined ? {} : { roles }),
|
|
538
|
-
...(projectRoles === undefined ? {} : { projectRoles }),
|
|
560
|
+
agentConfigurations,
|
|
539
561
|
schemas,
|
|
540
562
|
};
|
|
541
563
|
}
|
package/dist/src/execution.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { RunStore } from "./persistence.js";
|
|
2
2
|
import type { AgentAttempt } from "./agent-execution.js";
|
|
3
|
-
import type { AgentIdentity, JsonValue, ShellIdentity, ShellOptions, ShellResult, WorkflowBridge, WorkflowExecution } from "./types.js";
|
|
3
|
+
import type { AgentIdentity, JsonValue, ShellIdentity, ShellOptions, ShellResult, ToolIdentity, WorkflowBridge, WorkflowExecution } from "./types.js";
|
|
4
4
|
export declare const RPC_LIMIT_BYTES: number;
|
|
5
5
|
export declare const HEARTBEAT_TIMEOUT_MS = 5000;
|
|
6
|
+
/** Script handle names may not start with this: registered-function handles are journaled under it. */
|
|
7
|
+
export declare const FUNCTION_HANDLE_PREFIX = "function-handle";
|
|
6
8
|
export declare function encoded(value: JsonValue): string;
|
|
7
9
|
export declare function encoded(value: unknown): asserts value is JsonValue;
|
|
10
|
+
/** The journal path of a script tool call; the arguments' digest keeps calls with different arguments apart whatever order they start in. */
|
|
11
|
+
export declare function toolIdentityPath(identifier: string, args: JsonValue, identity: ToolIdentity): string;
|
|
8
12
|
export declare function agentHandleTurnPath(handle: string, turn: number): string;
|
|
9
13
|
export declare function agentIdentityPath(identity: AgentIdentity): string;
|
|
10
14
|
export declare function shellIdentityPath(identity: ShellIdentity): string;
|
|
@@ -16,4 +20,4 @@ export declare function executeShellCommand(command: string, options: ShellOptio
|
|
|
16
20
|
export declare function runWorkflow(script: string, args?: JsonValue, bridge?: WorkflowBridge, signal?: AbortSignal): WorkflowExecution;
|
|
17
21
|
export declare function persistActiveAgentAttempt(store: RunStore, id: string, active: AgentAttempt): Promise<void>;
|
|
18
22
|
export declare function persistAgentAttempts(store: RunStore, id: string, attempts: readonly AgentAttempt[]): Promise<void>;
|
|
19
|
-
export type { AgentIdentity, FunctionIdentity, ShellIdentity, WorkflowBridge, WorkflowExecution } from "./types.js";
|
|
23
|
+
export type { AgentIdentity, FunctionIdentity, ShellIdentity, ToolIdentity, WorkflowBridge, WorkflowExecution } from "./types.js";
|
package/dist/src/execution.js
CHANGED
|
@@ -4,8 +4,8 @@ import { tmpdir } from "node:os";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { StringDecoder } from "node:string_decoder";
|
|
6
6
|
import { structuralPath as operationPath } from "./persistence.js";
|
|
7
|
-
import { WorkflowError,
|
|
8
|
-
import { asWorkflowError, errorText, fail, isWorkflowAuthored, isWorkflowErrorCode, jsonValue, markWorkflowAuthored, object, positiveInteger } from "./utils.js";
|
|
7
|
+
import { WorkflowError, sumAccounting, zeroAccounting } from "./types.js";
|
|
8
|
+
import { asWorkflowError, errorText, fail, isWorkflowAuthored, isWorkflowErrorCode, jsonDigest, jsonValue, markWorkflowAuthored, object, positiveInteger } from "./utils.js";
|
|
9
9
|
import { instrumentWorkflow, validateAgentOptions, validateShellCommand, validateShellOptions } from "./validation.js";
|
|
10
10
|
export const RPC_LIMIT_BYTES = 10 * 1024 * 1024;
|
|
11
11
|
export const HEARTBEAT_TIMEOUT_MS = 5000;
|
|
@@ -35,6 +35,8 @@ function isRpcMessage(value) {
|
|
|
35
35
|
}
|
|
36
36
|
const HEARTBEAT_INTERVAL_MS = 1000;
|
|
37
37
|
const OUTCOME_ERRORS = new Set(["AGENT_TIMEOUT", "AGENT_FAILED", "RESULT_INVALID"]);
|
|
38
|
+
/** Script handle names may not start with this: registered-function handles are journaled under it. */
|
|
39
|
+
export const FUNCTION_HANDLE_PREFIX = "function-handle";
|
|
38
40
|
const WORK_RESULT_BRAND = "__workResult";
|
|
39
41
|
const childSource = String.raw `
|
|
40
42
|
"use strict";
|
|
@@ -145,15 +147,13 @@ const internalAgent = (...values) => {
|
|
|
145
147
|
void result.then(() => agentInflight.delete(occurrenceKey), () => agentInflight.delete(occurrenceKey));
|
|
146
148
|
return guardedAgentResult(result);
|
|
147
149
|
};
|
|
148
|
-
const AGENT_HANDLE_KEYS = ["name", "role", "model", "tools", "skills", "extensions", "contextFiles", "label"];
|
|
149
150
|
const agentHandleNames = new Set();
|
|
150
151
|
const agentHandleInflight = new Set();
|
|
151
152
|
const internalAgentCreate = (...values) => {
|
|
152
153
|
if (values.length !== 1 || !values[0] || typeof values[0] !== "object" || Array.isArray(values[0])) throw workError("INVALID_METADATA", "agent.create requires one options object");
|
|
153
154
|
const options = values[0];
|
|
154
155
|
const name = named(options.name, "agent.create");
|
|
155
|
-
|
|
156
|
-
if (unsupported) throw workError("INVALID_METADATA", "agent.create option is unsupported: " + unsupported);
|
|
156
|
+
if (name.startsWith("${FUNCTION_HANDLE_PREFIX}/")) throw workError("INVALID_METADATA", "Agent handle names may not start with ${FUNCTION_HANDLE_PREFIX}/");
|
|
157
157
|
if (agentHandleNames.has(name)) throw workError("INVALID_METADATA", "Duplicate agent handle name: " + name);
|
|
158
158
|
agentHandleNames.add(name);
|
|
159
159
|
const config = Object.freeze(Object.fromEntries(Object.entries(options).filter(([key]) => key !== "name")));
|
|
@@ -268,6 +268,30 @@ const functions = Object.freeze(Object.fromEntries(Object.entries(config.functio
|
|
|
268
268
|
Object.defineProperty(result, "toJSON", { value() { throw workError("INVALID_METADATA", "Workflow function result is a Promise; await it before serialization"); } });
|
|
269
269
|
return result;
|
|
270
270
|
}])));
|
|
271
|
+
// tools.<id>(args) runs a Pi session tool through the host. Any identifier resolves, so a resumed run
|
|
272
|
+
// replays journaled calls even when the tool is gone; the host rejects identifiers it cannot call.
|
|
273
|
+
// A call is the n-th call with the same arguments in its scope, so replay does not depend on the
|
|
274
|
+
// order in which concurrent calls start.
|
|
275
|
+
const NOT_TOOLS = new Set(["then", "toJSON", "toString", "valueOf", "constructor"]);
|
|
276
|
+
const sortedJson = value => Array.isArray(value) ? value.map(sortedJson) : value && typeof value === "object" ? Object.fromEntries(Object.keys(value).sort().map(key => [key, sortedJson(value[key])])) : value;
|
|
277
|
+
const toolOccurrences = new Map();
|
|
278
|
+
const toolCall = id => (...values) => {
|
|
279
|
+
if (worktreeOwners.getStore()) throw workError("INVALID_METADATA", "tools." + id + " is unavailable inside withWorktree: session tools resolve paths against the session working directory");
|
|
280
|
+
if (values.length > 1 || values[0] !== undefined && (!values[0] || typeof values[0] !== "object" || Array.isArray(values[0]))) throw workError("INVALID_METADATA", "tools." + id + " takes one arguments object");
|
|
281
|
+
const args = values[0] === undefined ? {} : values[0];
|
|
282
|
+
const structuralPath = inheritedAgentPath.getStore() || [];
|
|
283
|
+
const key = JSON.stringify([structuralPath, id, sortedJson(args)]);
|
|
284
|
+
const occurrence = (toolOccurrences.get(key) || 0) + 1;
|
|
285
|
+
toolOccurrences.set(key, occurrence);
|
|
286
|
+
return guardedResult(rpc("tool", [id, args, { structuralPath: [...structuralPath], occurrence }]), "tool");
|
|
287
|
+
};
|
|
288
|
+
const tools = new Proxy(Object.create(null), {
|
|
289
|
+
get: (_target, key) => typeof key === "string" && !NOT_TOOLS.has(key) ? toolCall(key) : undefined,
|
|
290
|
+
// Probing would branch on the session that resumed the run; the launch already checks named tools.
|
|
291
|
+
has: () => { throw workError("INVALID_METADATA", "Workflow scripts cannot probe tools with 'in'; call tools.<name>(...) directly, and the launch checks that the tool exists"); },
|
|
292
|
+
set: () => false,
|
|
293
|
+
defineProperty: () => false,
|
|
294
|
+
});
|
|
271
295
|
const recordEntries = (value, kind) => {
|
|
272
296
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw workError("INVALID_METADATA", kind + " must be a record");
|
|
273
297
|
return Object.entries(value);
|
|
@@ -328,7 +352,7 @@ const pipeline = async (operationName, items, stages) => {
|
|
|
328
352
|
return Object.fromEntries(results.map(result => [result.name, result.value]));
|
|
329
353
|
};
|
|
330
354
|
const safeMath = Object.fromEntries(Object.getOwnPropertyNames(Math).filter(name => name !== "random").map(name => [name, Math[name]]));
|
|
331
|
-
const sandbox = { agent, shell, withWorktree: rejectWorktree, prompt, checkpoint, parallel, pipeline, phase, log, args: config.args, Promise, JSON, Math: Object.freeze(safeMath) };
|
|
355
|
+
const sandbox = { agent, shell, withWorktree: rejectWorktree, prompt, checkpoint, parallel, pipeline, phase, log, tools, args: config.args, Promise, JSON, Math: Object.freeze(safeMath) };
|
|
332
356
|
for (const [name, fn] of Object.entries(functions)) Object.defineProperty(sandbox, name, { value: fn, writable: false, configurable: false });
|
|
333
357
|
for (const name of ["Date","eval","Function","WebAssembly","process","require","module","exports","console","fetch","XMLHttpRequest","WebSocket","performance","crypto","setTimeout","setInterval","setImmediate","queueMicrotask","Intl","SharedArrayBuffer","Atomics"]) sandbox[name] = undefined;
|
|
334
358
|
const context = vm.createContext(sandbox, { codeGeneration: { strings: false, wasm: false } });
|
|
@@ -378,6 +402,15 @@ function readShellIdentity(value) {
|
|
|
378
402
|
const identity = readAgentIdentity(value);
|
|
379
403
|
return { structuralPath: identity.structuralPath, callSite: identity.callSite, occurrence: identity.occurrence, ...(identity.worktreeOwner ? { worktreeOwner: identity.worktreeOwner } : {}) };
|
|
380
404
|
}
|
|
405
|
+
function readToolIdentity(value) {
|
|
406
|
+
if (!object(value) || !Array.isArray(value.structuralPath) || !value.structuralPath.every((part) => typeof part === "string" && Boolean(part.trim())) || !positiveInteger(value.occurrence))
|
|
407
|
+
fail("INTERNAL_ERROR", "Invalid workflow tool identity");
|
|
408
|
+
return { structuralPath: [...value.structuralPath], occurrence: value.occurrence };
|
|
409
|
+
}
|
|
410
|
+
/** The journal path of a script tool call; the arguments' digest keeps calls with different arguments apart whatever order they start in. */
|
|
411
|
+
export function toolIdentityPath(identifier, args, identity) {
|
|
412
|
+
return operationPath("tool", ...identity.structuralPath, identifier, `args:${jsonDigest(args)}`, String(identity.occurrence));
|
|
413
|
+
}
|
|
381
414
|
export function agentHandleTurnPath(handle, turn) {
|
|
382
415
|
return operationPath("agent", "handle", handle, `turn:${String(turn)}`);
|
|
383
416
|
}
|
|
@@ -622,7 +655,7 @@ export function runWorkflow(script, args = null, bridge = {}, signal) {
|
|
|
622
655
|
const opts = validateAgentOptions(values[1]);
|
|
623
656
|
const identity = readAgentIdentity(values[2]);
|
|
624
657
|
const path = agentIdentityPath(identity);
|
|
625
|
-
const label = typeof opts.label === "string" ? opts.label :
|
|
658
|
+
const label = typeof opts.label === "string" ? opts.label : "agent";
|
|
626
659
|
try {
|
|
627
660
|
const result = await bridge.agent(values[0], opts, controller.signal, identity);
|
|
628
661
|
value = branded({ name: label, ok: true, value: result ?? null });
|
|
@@ -681,6 +714,14 @@ export function runWorkflow(script, args = null, bridge = {}, signal) {
|
|
|
681
714
|
value = branded({ name, ok: false, failedAt: name, error: workerErrorShape(typed) });
|
|
682
715
|
}
|
|
683
716
|
}
|
|
717
|
+
else if (method === "tool") {
|
|
718
|
+
if (typeof values[0] !== "string" || !object(values[1]))
|
|
719
|
+
fail("INTERNAL_ERROR", "tool requires an identifier and object arguments");
|
|
720
|
+
const identity = readToolIdentity(values[2]);
|
|
721
|
+
if (!bridge.tool)
|
|
722
|
+
fail("UNKNOWN_TOOL", `tools.${values[0]} is unavailable: this run has no session tools`);
|
|
723
|
+
value = await bridge.tool(values[0], values[1], controller.signal, identity);
|
|
724
|
+
}
|
|
684
725
|
else if (method === "worktree") {
|
|
685
726
|
if (!bridge.worktree || typeof values[0] !== "string" || !values[0])
|
|
686
727
|
fail("INTERNAL_ERROR", "worktree requires an active host bridge and scope");
|
|
@@ -101,13 +101,14 @@ const WORKFLOW_ERROR_PROSE = {
|
|
|
101
101
|
REGISTRY_FROZEN: (detail) => `Workflow extension registration is closed: ${detail}.`,
|
|
102
102
|
GLOBAL_COLLISION: (detail) => `The workflow global name is already in use: ${detail}.`,
|
|
103
103
|
MISSING_WORKFLOW: (detail) => `The registered workflow function is unavailable: ${detail}.`,
|
|
104
|
-
UNKNOWN_MODEL: (detail) => `The workflow requested the unavailable model ${detail.replace(/^(?:Unknown model
|
|
104
|
+
UNKNOWN_MODEL: (detail) => `The workflow requested the unavailable model ${detail.replace(/^(?:Unknown model|Invalid model spec|Required model is unavailable):\s*/, "")}.`,
|
|
105
105
|
UNKNOWN_TOOL: (detail) => `The workflow requested the unavailable tool ${detail.replace(/^Unknown tool:\s*/, "")}.`,
|
|
106
|
-
|
|
106
|
+
UNKNOWN_AGENT: (detail) => `The workflow requested an unavailable owned agent: ${detail}.`,
|
|
107
107
|
RUN_OWNED: (detail) => /already owned|active ownership/.test(detail) ? "The workflow session is already in use." : `The workflow session is already in use: ${detail}.`,
|
|
108
108
|
RUN_NOT_FOUND: (detail) => /^Unknown workflow run\b/.test(detail) ? "The workflow run was not found." : `The workflow run was not found: ${detail}.`,
|
|
109
109
|
RPC_LIMIT_EXCEEDED: (detail) => `The workflow communication data exceeded its size limit: ${detail}.`,
|
|
110
110
|
SHELL_FAILED: (detail) => `The workflow shell command failed: ${detail}.`,
|
|
111
|
+
TOOL_FAILED: (detail) => `The workflow tool call failed: ${detail}.`,
|
|
111
112
|
AGENT_TIMEOUT: (detail) => `The workflow agent timed out: ${detail}.`,
|
|
112
113
|
AGENT_FAILED: (detail) => `The workflow agent failed: ${detail}.`,
|
|
113
114
|
AGENT_RESULT_COLLECTED: (detail) => `The nested agent result was already collected: ${detail}.`,
|
|
@@ -204,7 +205,6 @@ function boundedWorkflowFailureDiagnostics(value) {
|
|
|
204
205
|
...(value.failedAgent ? { failedAgent: {
|
|
205
206
|
id: utf8Prefix(value.failedAgent.id, 128),
|
|
206
207
|
...(value.failedAgent.label ? { label: utf8Prefix(value.failedAgent.label, 128) } : {}),
|
|
207
|
-
...(value.failedAgent.role ? { role: utf8Prefix(value.failedAgent.role, 128) } : {}),
|
|
208
208
|
structuralPath: value.failedAgent.structuralPath.slice(0, 8).map((part) => utf8Prefix(part, 128)),
|
|
209
209
|
attempt: value.failedAgent.attempt,
|
|
210
210
|
...(value.failedAgent.transport ? { transport: utf8Prefix(value.failedAgent.transport, 128) } : {}),
|
|
@@ -213,7 +213,6 @@ function boundedWorkflowFailureDiagnostics(value) {
|
|
|
213
213
|
completedSiblingAgents: (value.completedSiblingAgents ?? []).slice(0, 16).map((agent) => ({
|
|
214
214
|
id: utf8Prefix(agent.id, 128),
|
|
215
215
|
...(agent.label ? { label: utf8Prefix(agent.label, 128) } : {}),
|
|
216
|
-
...(agent.role ? { role: utf8Prefix(agent.role, 128) } : {}),
|
|
217
216
|
structuralPath: agent.structuralPath.slice(0, 8).map((part) => utf8Prefix(part, 128)),
|
|
218
217
|
})),
|
|
219
218
|
completedSiblingPaths: value.completedSiblingPaths.slice(0, 16).map((path) => path.slice(0, 8).map((part) => utf8Prefix(part, 128))),
|
|
@@ -305,7 +304,6 @@ export async function createWorkflowFailureDiagnostics(store, metadata, error, r
|
|
|
305
304
|
const failedAgent = failedAgentRecord ? {
|
|
306
305
|
id: failedAgentRecord.id,
|
|
307
306
|
...(failedAgentRecord.label ?? failedAgentRecord.name ? { label: failedAgentRecord.label ?? failedAgentRecord.name } : {}),
|
|
308
|
-
...(failedAgentRecord.role ? { role: failedAgentRecord.role } : {}),
|
|
309
307
|
structuralPath: [...(failedAgentRecord.structuralPath ?? [])],
|
|
310
308
|
attempt: Math.max(1, failedAttempt?.attempt ?? failedAgentRecord.attempts),
|
|
311
309
|
...(failedAttempt?.transport ? { transport: failedAttempt.transport } : {}),
|
|
@@ -318,7 +316,6 @@ export async function createWorkflowFailureDiagnostics(store, metadata, error, r
|
|
|
318
316
|
}).map((agent) => ({
|
|
319
317
|
id: agent.id,
|
|
320
318
|
...(agent.label ?? agent.name ? { label: agent.label ?? agent.name } : {}),
|
|
321
|
-
...(agent.role ? { role: agent.role } : {}),
|
|
322
319
|
structuralPath: [...(agent.structuralPath ?? [])],
|
|
323
320
|
}));
|
|
324
321
|
const completedSiblingPaths = completedSiblingAgents.map((agent) => [...agent.structuralPath]);
|
|
@@ -346,9 +343,9 @@ export async function createWorkflowFailureDiagnostics(store, metadata, error, r
|
|
|
346
343
|
});
|
|
347
344
|
}
|
|
348
345
|
export function formatWorkflowFailureDiagnostics(diagnostic) {
|
|
349
|
-
const failedAgent = diagnostic.failedAgent ? `${diagnostic.failedAgent.label ?? diagnostic.failedAgent.id}
|
|
346
|
+
const failedAgent = diagnostic.failedAgent ? `${diagnostic.failedAgent.label ?? diagnostic.failedAgent.id} attempt=${String(diagnostic.failedAgent.attempt)} path=${diagnostic.failedAgent.structuralPath.join(" > ") || "(root)"}${diagnostic.failedAgent.session ? ` session=${diagnostic.failedAgent.session.transport}/${diagnostic.failedAgent.session.sessionId}` : ""}` : "(not persisted)";
|
|
350
347
|
const siblingAgents = diagnostic.completedSiblingAgents;
|
|
351
|
-
const siblings = siblingAgents ? siblingAgents.map((agent) => `${agent.label ?? agent.id}
|
|
348
|
+
const siblings = siblingAgents ? siblingAgents.map((agent) => `${agent.label ?? agent.id} path=${agent.structuralPath.join(" > ") || "(root)"}`).join(", ") || "(none)" : diagnostic.completedSiblingPaths.map((path) => path.join(" > ") || "(root)").join(", ") || "(none)";
|
|
352
349
|
const retry = diagnostic.retry ? [` Retry: ${diagnostic.retry.action}`, ` Replayable completed paths: ${diagnostic.retry.completedPaths.join(", ") || "(none)"}`, ` Incomplete paths: ${diagnostic.retry.incompletePaths.join(", ") || "(unknown)"}`, ` Named worktrees: ${diagnostic.retry.namedWorktrees.join(", ") || "(none)"}`, ` Warning: ${diagnostic.retry.warning}`] : [];
|
|
353
350
|
return [`✗ Workflow: ${diagnostic.workflowName}`, ` Run: ${diagnostic.runId}`, ` State: ${diagnostic.state}`, ` Error: ${diagnostic.error.code}: ${diagnostic.error.message}`, ` Failed at: ${diagnostic.failedAt ?? "(unknown)"}`, ` Failed agent: ${failedAgent}`, ` Completed sibling ${siblingAgents ? "agents" : "paths"}: ${siblings}`, ...retry, ` Artifacts: state=${diagnostic.artifacts.statePath} journal=${diagnostic.artifacts.journalPath}`].join("\n");
|
|
354
351
|
}
|
|
@@ -827,9 +827,10 @@ export function registerWorkflowNavigator(deps) {
|
|
|
827
827
|
const styles = themeWorkflowProgressStyles(theme);
|
|
828
828
|
const agent = selectedAgentRecord();
|
|
829
829
|
const actions = actionMode ? { title: agent ? "Agent actions" : "Run actions", options: actionOptions(), index: actionIndex } : undefined;
|
|
830
|
-
const
|
|
830
|
+
const formatPhaseLines = (scrollTop) => formatWorkflowPhaseDashboard(view.run, view.snapshot, width, { scrollTop, nodeId: selectedNodeId, expandedNodeIds: [...expandedNodeIds], ...(narrow && !detailsMode && !actionMode ? { treeOnly: true } : {}), ...(narrow && (detailsMode || actionMode) ? { detailsOnly: true } : {}), ...(actions ? { actions } : {}) }, styles, progressNow());
|
|
831
|
+
const phaseLines = formatPhaseLines(0);
|
|
831
832
|
const statusLines = stopStatus ? truncateToVisualLines(styles.error(stopStatus), Number.MAX_SAFE_INTEGER, width, 0).visualLines.map((line) => line.trimEnd()) : [];
|
|
832
|
-
|
|
833
|
+
let content = [...statusLines, ...phaseLines];
|
|
833
834
|
const rows = terminalRows();
|
|
834
835
|
const hintRows = rows >= 3 ? 1 : 0;
|
|
835
836
|
const confirmRows = inlineConfirm.rows(width, styles);
|
|
@@ -857,6 +858,8 @@ export function registerWorkflowNavigator(deps) {
|
|
|
857
858
|
selectionNeedsScroll = false;
|
|
858
859
|
}
|
|
859
860
|
dashboardOffset = Math.max(0, Math.min(maxOffset, dashboardOffset));
|
|
861
|
+
if (!narrow && !actionMode)
|
|
862
|
+
content = [...statusLines, ...formatPhaseLines(Math.max(0, dashboardOffset - statusLines.length))];
|
|
860
863
|
const selectedNode = selectedNodeId ? tree.byId.get(selectedNodeId) : undefined;
|
|
861
864
|
const enterAction = selectedNode?.kind === "workflow" ? "run actions" : selectedNode?.kind === "agent" ? "agent actions" : selectedNode?.children.length ? "expand/collapse" : narrow ? "inspect" : "focus details";
|
|
862
865
|
const hint = truncateToVisualLines(theme.fg("dim", inlineConfirm.active() ? inlineConfirm.hint(keybindings) : actionMode ? `${keyLabel("tui.select.up", "↑")}/${keyLabel("tui.select.down", "↓")} actions · ${keyLabel("tui.select.confirm", "enter")} run · ${keyLabel("tui.editor.cursorLeft", "←")} tree · ${keyLabel("tui.select.cancel", "esc")} tree` : `${keyLabel("tui.select.up", "↑")}/${keyLabel("tui.select.down", "↓")} tree · ${keyLabel("tui.editor.cursorLeft", "←")}/${keyLabel("tui.editor.cursorRight", "→")} collapse/expand · ${keyLabel("tui.select.confirm", "enter")} ${enterAction} · a actions · ${keyLabel("tui.select.cancel", "esc")} ${narrow && detailsMode ? "tree" : "back"}${content.length > viewport ? ` · ${keyLabel("tui.select.pageUp", "pgup")}/${keyLabel("tui.select.pageDown", "pgdn")} scroll` : ""} · auto-refresh 1s`), Number.MAX_SAFE_INTEGER, width, 1).visualLines[0] ?? "";
|
|
@@ -45,6 +45,7 @@ export interface WorkflowPhaseSelection {
|
|
|
45
45
|
expandedNodeIds?: readonly string[] | undefined;
|
|
46
46
|
treeOnly?: boolean | undefined;
|
|
47
47
|
detailsOnly?: boolean | undefined;
|
|
48
|
+
scrollTop?: number | undefined;
|
|
48
49
|
actions?: {
|
|
49
50
|
title: string;
|
|
50
51
|
options: readonly string[];
|