@marcoscale98/pi-extensible-workflows 5.14.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 +536 -0
- package/README.md +64 -0
- package/dist/src/agent-execution.d.ts +338 -0
- package/dist/src/agent-execution.js +1633 -0
- package/dist/src/background-widget.d.ts +74 -0
- package/dist/src/background-widget.js +1340 -0
- package/dist/src/budget.d.ts +38 -0
- package/dist/src/budget.js +188 -0
- package/dist/src/changelog.d.ts +6 -0
- package/dist/src/changelog.js +112 -0
- package/dist/src/decoders.d.ts +96 -0
- package/dist/src/decoders.js +629 -0
- package/dist/src/execution.d.ts +19 -0
- package/dist/src/execution.js +749 -0
- package/dist/src/herdr.d.ts +53 -0
- package/dist/src/herdr.js +270 -0
- package/dist/src/host-delivery.d.ts +95 -0
- package/dist/src/host-delivery.js +376 -0
- package/dist/src/host-navigator.d.ts +83 -0
- package/dist/src/host-navigator.js +1087 -0
- package/dist/src/host-phases.d.ts +89 -0
- package/dist/src/host-phases.js +320 -0
- package/dist/src/host-recovery.d.ts +141 -0
- package/dist/src/host-recovery.js +356 -0
- package/dist/src/host-runtime.d.ts +78 -0
- package/dist/src/host-runtime.js +378 -0
- package/dist/src/host-view.d.ts +116 -0
- package/dist/src/host-view.js +868 -0
- package/dist/src/host.d.ts +40 -0
- package/dist/src/host.js +1641 -0
- package/dist/src/index.d.ts +29 -0
- package/dist/src/index.js +13725 -0
- package/dist/src/index.js.map +6 -0
- package/dist/src/io.d.ts +14 -0
- package/dist/src/io.js +82 -0
- package/dist/src/package-identity.d.ts +4 -0
- package/dist/src/package-identity.js +6 -0
- package/dist/src/paths.d.ts +14 -0
- package/dist/src/paths.js +51 -0
- package/dist/src/persistence.d.ts +5 -0
- package/dist/src/persistence.js +5 -0
- package/dist/src/pi-runtime-adapter.d.ts +27 -0
- package/dist/src/pi-runtime-adapter.js +243 -0
- package/dist/src/pi-runtime-runner.d.ts +42 -0
- package/dist/src/pi-runtime-runner.js +505 -0
- package/dist/src/registry.d.ts +48 -0
- package/dist/src/registry.js +379 -0
- package/dist/src/retention.d.ts +17 -0
- package/dist/src/retention.js +195 -0
- package/dist/src/runtime/agent-runner.d.ts +143 -0
- package/dist/src/runtime/agent-runner.js +12 -0
- package/dist/src/runtime/index.d.ts +2 -0
- package/dist/src/runtime/index.js +2 -0
- package/dist/src/runtime/namespace.d.ts +14 -0
- package/dist/src/runtime/namespace.js +1 -0
- package/dist/src/runtime/workflow-result.d.ts +2 -0
- package/dist/src/runtime/workflow-result.js +6 -0
- package/dist/src/session-handoff.d.ts +2 -0
- package/dist/src/session-handoff.js +82 -0
- package/dist/src/session-lease.d.ts +12 -0
- package/dist/src/session-lease.js +180 -0
- package/dist/src/store.d.ts +95 -0
- package/dist/src/store.js +951 -0
- package/dist/src/subagent-manager-handle.d.ts +4 -0
- package/dist/src/subagent-manager-handle.js +6 -0
- package/dist/src/tool-timing.d.ts +12 -0
- package/dist/src/tool-timing.js +33 -0
- package/dist/src/trajectory-contracts.d.ts +8 -0
- package/dist/src/trajectory-contracts.js +9 -0
- package/dist/src/trajectory-host-handle.d.ts +12 -0
- package/dist/src/trajectory-host-handle.js +6 -0
- package/dist/src/trajectory.d.ts +128 -0
- package/dist/src/trajectory.js +594 -0
- package/dist/src/types.d.ts +960 -0
- package/dist/src/types.js +60 -0
- package/dist/src/utils.d.ts +57 -0
- package/dist/src/utils.js +225 -0
- package/dist/src/validation.d.ts +29 -0
- package/dist/src/validation.js +1100 -0
- package/dist/src/workflow-artifacts.d.ts +14 -0
- package/dist/src/workflow-artifacts.js +40 -0
- package/dist/starter/index.d.ts +1 -0
- package/dist/starter/index.js +103 -0
- package/dist/starter/index.js.map +6 -0
- package/dist/starter/review-loop.d.ts +72 -0
- package/dist/starter/review-loop.js +43 -0
- package/dist/starter/roles/developer.md +6 -0
- package/dist/starter/roles/oracle.md +18 -0
- package/dist/starter/roles/researcher.md +20 -0
- package/dist/starter/roles/reviewer.md +19 -0
- package/dist/starter/roles/scout.md +18 -0
- package/dist/subagents/index.d.ts +8 -0
- package/dist/subagents/index.js +8021 -0
- package/dist/subagents/index.js.map +6 -0
- package/dist/subagents/src/contracts.d.ts +173 -0
- package/dist/subagents/src/contracts.js +68 -0
- package/dist/subagents/src/decode.d.ts +15 -0
- package/dist/subagents/src/decode.js +182 -0
- package/dist/subagents/src/index.d.ts +12 -0
- package/dist/subagents/src/index.js +180 -0
- package/dist/subagents/src/manager.d.ts +3 -0
- package/dist/subagents/src/manager.js +1636 -0
- package/dist/subagents/src/navigator.d.ts +5 -0
- package/dist/subagents/src/navigator.js +627 -0
- package/dist/subagents/src/view.d.ts +70 -0
- package/dist/subagents/src/view.js +387 -0
- package/dist/subagents/src/worktree.d.ts +34 -0
- package/dist/subagents/src/worktree.js +68 -0
- package/dist/trajectory/assets/favicon.png +0 -0
- package/dist/trajectory/assets/index.html +772 -0
- package/dist/trajectory/assets/marked.min.js +6 -0
- package/dist/trajectory/assets/morphdom.min.js +1 -0
- package/dist/trajectory/index.d.ts +5 -0
- package/dist/trajectory/index.js +3459 -0
- package/dist/trajectory/index.js.map +6 -0
- package/dist/trajectory/src/assets/favicon.png +0 -0
- package/dist/trajectory/src/assets/index.html +772 -0
- package/dist/trajectory/src/assets/marked.min.js +6 -0
- package/dist/trajectory/src/assets/morphdom.min.js +1 -0
- package/dist/trajectory/src/export.d.ts +25 -0
- package/dist/trajectory/src/export.js +80 -0
- package/dist/trajectory/src/index.d.ts +26 -0
- package/dist/trajectory/src/index.js +732 -0
- package/dist/trajectory/src/server.d.ts +7 -0
- package/dist/trajectory/src/server.js +2534 -0
- package/dist/trajectory/src/server.js.map +6 -0
- package/examples/advanced-patterns/auto-model-router.mjs +78 -0
- package/examples/workflow-extension-template/README.md +37 -0
- package/examples/workflow-extension-template/extension.test.mjs +59 -0
- package/examples/workflow-extension-template/index.js +51 -0
- package/examples/workflow-extension-template/roles/reviewer.md +4 -0
- package/package.json +105 -0
- package/skills/pi-extensible-workflows/SKILL.md +160 -0
- package/src/agent-execution.ts +1533 -0
- package/src/background-widget.ts +1496 -0
- package/src/budget.ts +109 -0
- package/src/changelog.ts +114 -0
- package/src/decoders.ts +567 -0
- package/src/execution.ts +652 -0
- package/src/herdr.ts +240 -0
- package/src/host-delivery.ts +346 -0
- package/src/host-navigator.ts +871 -0
- package/src/host-phases.ts +264 -0
- package/src/host-recovery.ts +333 -0
- package/src/host-runtime.ts +373 -0
- package/src/host-view.ts +828 -0
- package/src/host.ts +1502 -0
- package/src/index.ts +29 -0
- package/src/io.ts +73 -0
- package/src/package-identity.ts +7 -0
- package/src/paths.ts +49 -0
- package/src/persistence.ts +11 -0
- package/src/pi-runtime-adapter.ts +247 -0
- package/src/pi-runtime-runner.ts +436 -0
- package/src/registry.ts +321 -0
- package/src/retention.ts +178 -0
- package/src/runtime/agent-runner.ts +158 -0
- package/src/runtime/index.ts +2 -0
- package/src/runtime/namespace.ts +16 -0
- package/src/runtime/workflow-result.ts +8 -0
- package/src/session-handoff.ts +78 -0
- package/src/session-lease.ts +125 -0
- package/src/store.ts +832 -0
- package/src/subagent-manager-handle.ts +8 -0
- package/src/tool-timing.ts +47 -0
- package/src/trajectory-contracts.ts +13 -0
- package/src/trajectory-host-handle.ts +16 -0
- package/src/trajectory.ts +543 -0
- package/src/types.ts +374 -0
- package/src/utils.ts +192 -0
- package/src/validation.ts +910 -0
- package/src/workflow-artifacts.ts +35 -0
- package/starter/index.ts +35 -0
- package/starter/prompts/council.md +16 -0
- package/starter/prompts/deep-research.md +16 -0
- package/starter/prompts/oracle.md +14 -0
- package/starter/prompts/parallel-review.md +22 -0
- package/starter/prompts/parallel-scout.md +16 -0
- package/starter/prompts/review-loop.md +14 -0
- package/starter/prompts/review.md +14 -0
- package/starter/prompts/scout.md +14 -0
- package/starter/review-loop.ts +73 -0
- package/starter/roles/developer.md +6 -0
- package/starter/roles/oracle.md +18 -0
- package/starter/roles/researcher.md +20 -0
- package/starter/roles/reviewer.md +19 -0
- package/starter/roles/scout.md +18 -0
- package/subagents/README.md +145 -0
- package/subagents/index.ts +8 -0
- package/subagents/src/contracts.ts +176 -0
- package/subagents/src/decode.ts +158 -0
- package/subagents/src/index.ts +194 -0
- package/subagents/src/manager.ts +1560 -0
- package/subagents/src/navigator.ts +488 -0
- package/subagents/src/view.ts +376 -0
- package/subagents/src/worktree.ts +99 -0
- package/trajectory/index.ts +5 -0
- package/trajectory/src/assets/favicon.png +0 -0
- package/trajectory/src/assets/index.html +772 -0
- package/trajectory/src/assets/marked.min.js +6 -0
- package/trajectory/src/assets/morphdom.min.js +1 -0
- package/trajectory/src/export.ts +85 -0
- package/trajectory/src/index.ts +604 -0
- package/trajectory/src/server.ts +447 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { DEFAULT_MAX_BYTES } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { structuralPath as operationPath } from "./persistence.js";
|
|
4
|
+
import { ERROR_CODES, WorkflowError } from "./types.js";
|
|
5
|
+
import { errorCode, errorText, fail, isWorkflowAuthored, object, SerialLane } from "./utils.js";
|
|
6
|
+
const FAILURE_DELIVERY_STATES = new Set(["failed", "stopped", "interrupted", "budget_exhausted"]);
|
|
7
|
+
export class ForegroundDeliveryController {
|
|
8
|
+
options;
|
|
9
|
+
foregroundDeliveries = new Map();
|
|
10
|
+
pendingFailureDiagnostics = new Map();
|
|
11
|
+
foregroundResumeClaims = new WeakSet();
|
|
12
|
+
terminalDeliveryLanes = new WeakMap();
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
}
|
|
16
|
+
claimForegroundDelivery = async (store, toolCallId) => {
|
|
17
|
+
let claim = "detached";
|
|
18
|
+
await store.updateState((current) => {
|
|
19
|
+
const delivery = current.delivery;
|
|
20
|
+
if (delivery?.toolCallId !== toolCallId || delivery.mode !== "foreground")
|
|
21
|
+
return current;
|
|
22
|
+
if (delivery.state === "delivered") {
|
|
23
|
+
claim = "delivered";
|
|
24
|
+
return current;
|
|
25
|
+
}
|
|
26
|
+
if (delivery.state !== "attached")
|
|
27
|
+
return current;
|
|
28
|
+
claim = "claimed";
|
|
29
|
+
return { ...current, delivery: { ...delivery, state: "delivered" } };
|
|
30
|
+
});
|
|
31
|
+
return claim;
|
|
32
|
+
};
|
|
33
|
+
deliverTerminal = (store, content, failure = false) => {
|
|
34
|
+
const lane = this.terminalDeliveryLanes.get(store) ?? new SerialLane();
|
|
35
|
+
this.terminalDeliveryLanes.set(store, lane);
|
|
36
|
+
return lane.run(async () => {
|
|
37
|
+
let claimed;
|
|
38
|
+
await store.updateState((current) => {
|
|
39
|
+
if (failure && !FAILURE_DELIVERY_STATES.has(current.state))
|
|
40
|
+
return current;
|
|
41
|
+
if (current.delivery?.state === "delivered") {
|
|
42
|
+
this.foregroundResumeClaims.delete(store);
|
|
43
|
+
return current;
|
|
44
|
+
}
|
|
45
|
+
if (this.foregroundResumeClaims.has(store) && current.delivery?.mode === "foreground" && current.delivery.state === "attached") {
|
|
46
|
+
this.foregroundResumeClaims.delete(store);
|
|
47
|
+
return current;
|
|
48
|
+
}
|
|
49
|
+
if (current.delivery?.mode === "foreground" && current.delivery.state === "attached") {
|
|
50
|
+
claimed = true;
|
|
51
|
+
return { ...current, delivery: { ...current.delivery, mode: "background", state: "delivered" } };
|
|
52
|
+
}
|
|
53
|
+
if (!current.delivery) {
|
|
54
|
+
claimed = true;
|
|
55
|
+
return current;
|
|
56
|
+
}
|
|
57
|
+
claimed = true;
|
|
58
|
+
return { ...current, delivery: { ...current.delivery, mode: "background", state: "delivered" } };
|
|
59
|
+
});
|
|
60
|
+
if (claimed !== true)
|
|
61
|
+
return;
|
|
62
|
+
if (failure && !FAILURE_DELIVERY_STATES.has((await store.load()).run.state)) {
|
|
63
|
+
await store.updateState((current) => !FAILURE_DELIVERY_STATES.has(current.state) && current.delivery?.state === "delivered" ? { ...current, delivery: { ...current.delivery, state: "pending" } } : current);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.options.deliver?.(typeof content === "function" ? await content() : content);
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
foregroundDeliveryCandidates = (runId) => [...this.foregroundDeliveries.entries()].filter(([, delivery]) => this.options.runs.has(delivery.store.runId) && !delivery.detached && delivery.store.runId === runId);
|
|
70
|
+
moveForegroundToBackground = async (runId) => {
|
|
71
|
+
const candidates = this.foregroundDeliveryCandidates(runId);
|
|
72
|
+
if (!candidates.length)
|
|
73
|
+
throw new WorkflowError("RUN_NOT_FOUND", `No attached foreground workflow ${runId}`);
|
|
74
|
+
return candidates[0]?.[1].detach() ?? fail("RUN_NOT_FOUND", "No attached foreground workflow is running");
|
|
75
|
+
};
|
|
76
|
+
isForegroundAttached = (runId) => this.foregroundDeliveryCandidates(runId).length > 0;
|
|
77
|
+
deliverDetachedTerminal = async (toolCallId, content, failure = false) => {
|
|
78
|
+
const delivery = this.foregroundDeliveries.get(toolCallId);
|
|
79
|
+
if (!delivery)
|
|
80
|
+
return;
|
|
81
|
+
if ((await delivery.store.load()).run.delivery?.mode !== "background")
|
|
82
|
+
return;
|
|
83
|
+
this.pendingFailureDiagnostics.delete(toolCallId);
|
|
84
|
+
await this.deliverTerminal(delivery.store, content, failure);
|
|
85
|
+
this.foregroundDeliveries.delete(toolCallId);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const workflowFailureDiagnostics = new WeakMap();
|
|
89
|
+
export function markWorkflowFailureDiagnostics(error, diagnostic) { workflowFailureDiagnostics.set(error, diagnostic); }
|
|
90
|
+
function workflowDetail(message) {
|
|
91
|
+
const detail = message.trim().replace(new RegExp(`\\b(?:${ERROR_CODES.join("|")})\\b:?\\s*`, "g"), "").replace(/^\s*[A-Z][A-Z0-9_]+:\s*/, "").split("\n").filter((line) => !/^\s*at\s/.test(line)).join("\n").replace(/^Run \S+(?=\s(?:exceeded|is))/i, "Run").replace(/\b[0-9a-f]{8}-[0-9a-f-]{27,}\b/gi, "the workflow").replace(/^(?:Pi )session \S+(?=\s(?:is|has))/i, "session").replace(/^(Unknown scheduler run|Missing production ownership record|Persisted agent belongs to another run):\s*\S+/i, "$1").replace(/\b(?:runId|sessionId|callSite|occurrence|failedAt|id)[:=]\s*\S+/gi, "").replace(/\s{2,}/g, " ").trim();
|
|
92
|
+
return detail || "No further details were provided";
|
|
93
|
+
}
|
|
94
|
+
const WORKFLOW_ERROR_PROSE = {
|
|
95
|
+
CONFIG_ERROR: (detail) => `The workflow configuration is invalid: ${detail}.`,
|
|
96
|
+
INVALID_SETTINGS: (detail) => `The workflow settings are invalid: ${detail}.`,
|
|
97
|
+
INVALID_SYNTAX: (detail) => `The workflow source is invalid: ${detail}.`,
|
|
98
|
+
INVALID_METADATA: (detail) => `The workflow metadata is invalid: ${detail}.`,
|
|
99
|
+
DUPLICATE_NAME: (detail) => `The workflow contains a duplicate name: ${detail}.`,
|
|
100
|
+
INVALID_SCHEMA: (detail) => `The workflow schema is invalid: ${detail}.`,
|
|
101
|
+
REGISTRY_FROZEN: (detail) => `Workflow extension registration is closed: ${detail}.`,
|
|
102
|
+
GLOBAL_COLLISION: (detail) => `The workflow global name is already in use: ${detail}.`,
|
|
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(?: for role [^:]+)?|Invalid model spec):\s*/, "")}.`,
|
|
105
|
+
UNKNOWN_TOOL: (detail) => `The workflow requested the unavailable tool ${detail.replace(/^Unknown tool:\s*/, "")}.`,
|
|
106
|
+
UNKNOWN_AGENT_TYPE: (detail) => `The workflow requested the unavailable agent role ${detail.replace(/^Unknown agent role:\s*/, "")}.`,
|
|
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
|
+
RUN_NOT_FOUND: (detail) => /^Unknown workflow run\b/.test(detail) ? "The workflow run was not found." : `The workflow run was not found: ${detail}.`,
|
|
109
|
+
RPC_LIMIT_EXCEEDED: (detail) => `The workflow communication data exceeded its size limit: ${detail}.`,
|
|
110
|
+
SHELL_FAILED: (detail) => `The workflow shell command failed: ${detail}.`,
|
|
111
|
+
AGENT_TIMEOUT: (detail) => `The workflow agent timed out: ${detail}.`,
|
|
112
|
+
AGENT_FAILED: (detail) => `The workflow agent failed: ${detail}.`,
|
|
113
|
+
AGENT_RESULT_COLLECTED: (detail) => `The nested agent result was already collected: ${detail}.`,
|
|
114
|
+
RESULT_INVALID: (detail) => `The workflow produced an invalid result: ${detail}.`,
|
|
115
|
+
CANCELLED: (detail) => `The workflow was cancelled: ${detail}.`,
|
|
116
|
+
WORKER_UNRESPONSIVE: (detail) => `The workflow worker stopped responding: ${detail}.`,
|
|
117
|
+
WORKTREE_FAILED: (detail) => `The workflow worktree operation failed: ${detail}.`,
|
|
118
|
+
RESUME_INCOMPATIBLE: (detail) => `The workflow cannot resume this run: ${detail}.`,
|
|
119
|
+
BUDGET_EXHAUSTED: (detail) => `The workflow budget was exhausted: ${detail}.`,
|
|
120
|
+
INTERNAL_ERROR: (detail) => `The workflow encountered an internal error: ${detail}.`,
|
|
121
|
+
};
|
|
122
|
+
export function formatWorkflowFailure(error) {
|
|
123
|
+
if (isWorkflowAuthored(error))
|
|
124
|
+
return errorText(error);
|
|
125
|
+
const code = errorCode(error);
|
|
126
|
+
if (code)
|
|
127
|
+
return WORKFLOW_ERROR_PROSE[code](workflowDetail(errorText(error)));
|
|
128
|
+
if (error instanceof Error)
|
|
129
|
+
return error.message || "The workflow failed without an error message.";
|
|
130
|
+
return `The workflow failed with value ${String(error)}.`;
|
|
131
|
+
}
|
|
132
|
+
export function workflowFailedAt(error) { return object(error) && typeof error.failedAt === "string" && error.failedAt ? error.failedAt : undefined; }
|
|
133
|
+
export const DELIVERY_LIMIT_BYTES = 4 * 1024;
|
|
134
|
+
export const WORKFLOW_LOG_ENTRY = "workflow-log";
|
|
135
|
+
function positiveFinite(value) { return value !== undefined && Number.isFinite(value) && value > 0; }
|
|
136
|
+
export function completionDescriptor(options) {
|
|
137
|
+
return JSON.stringify({ state: "completed", runId: options.runId, ...(options.resultPath === undefined ? {} : { resultPath: options.resultPath }), resultBytes: options.resultBytes, inlined: false });
|
|
138
|
+
}
|
|
139
|
+
function deliveryEnvelope(mode, content, runId) {
|
|
140
|
+
const timestamp = Date.now();
|
|
141
|
+
if (mode === "foreground")
|
|
142
|
+
return JSON.stringify({ role: "toolResult", toolCallId: runId, toolName: "workflow", content: [{ type: "text", text: content }, { type: "text", text: `Workflow run ID: ${runId}` }], isError: false, timestamp });
|
|
143
|
+
return JSON.stringify({ role: "custom", customType: "workflow", content, display: true, timestamp });
|
|
144
|
+
}
|
|
145
|
+
function fitsMainContext(options, content) {
|
|
146
|
+
let usage;
|
|
147
|
+
let model;
|
|
148
|
+
try {
|
|
149
|
+
usage = options.context?.getContextUsage?.();
|
|
150
|
+
model = options.context?.getModel?.() ?? options.context?.model;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
if (!usage || usage.tokens === null || !Number.isFinite(usage.tokens) || usage.tokens < 0 || !positiveFinite(model?.maxTokens))
|
|
156
|
+
return false;
|
|
157
|
+
const contextWindow = positiveFinite(model.contextWindow) ? Math.min(model.contextWindow, usage.contextWindow) : usage.contextWindow;
|
|
158
|
+
if (!positiveFinite(contextWindow))
|
|
159
|
+
return false;
|
|
160
|
+
const deliveryTokens = Math.ceil(Buffer.byteLength(deliveryEnvelope(options.mode, content, options.runId), "utf8") / 4);
|
|
161
|
+
return usage.tokens + deliveryTokens + model.maxTokens <= contextWindow;
|
|
162
|
+
}
|
|
163
|
+
export function completionDelivery(options) {
|
|
164
|
+
const descriptor = completionDescriptor(options);
|
|
165
|
+
if (!Number.isSafeInteger(options.resultBytes) || options.resultBytes < 0 || options.resultBytes > DEFAULT_MAX_BYTES)
|
|
166
|
+
return { content: descriptor, inlined: false };
|
|
167
|
+
const serialized = JSON.stringify(options.value);
|
|
168
|
+
if (typeof serialized !== "string")
|
|
169
|
+
return { content: descriptor, inlined: false };
|
|
170
|
+
const locations = options.worktrees.length ? ` Changes: ${options.worktrees.map(({ branch, path }) => `${branch} (${path})`).join(", ")}.` : "";
|
|
171
|
+
const inlineContent = options.mode === "foreground" ? serialized : `Workflow ${options.name} completed: ${serialized}${locations}`;
|
|
172
|
+
if (Buffer.byteLength(inlineContent, "utf8") > DEFAULT_MAX_BYTES)
|
|
173
|
+
return { content: descriptor, inlined: false };
|
|
174
|
+
return fitsMainContext(options, inlineContent) ? { content: inlineContent, inlined: true } : { content: descriptor, inlined: false };
|
|
175
|
+
}
|
|
176
|
+
export async function completionDeliveryFromStore(options) {
|
|
177
|
+
const { store, ...deliveryOptions } = options;
|
|
178
|
+
try {
|
|
179
|
+
return completionDelivery({ ...deliveryOptions, worktrees: await store.changedWorktrees() });
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Worktree metadata must not block successful result delivery.
|
|
183
|
+
return { content: completionDescriptor(deliveryOptions), inlined: false };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
export function utf8Prefix(value, maxBytes) {
|
|
187
|
+
const bytes = Buffer.from(value);
|
|
188
|
+
let end = Math.min(bytes.length, maxBytes);
|
|
189
|
+
while (end < bytes.length && end > 0 && ((bytes[end] ?? 0) & 0xc0) === 0x80)
|
|
190
|
+
end -= 1;
|
|
191
|
+
return bytes.subarray(0, end).toString("utf8");
|
|
192
|
+
}
|
|
193
|
+
const DIAGNOSTIC_LIMIT_BYTES = DELIVERY_LIMIT_BYTES - 512;
|
|
194
|
+
export function failureDiagnosticsFrom(error) {
|
|
195
|
+
return error instanceof WorkflowError ? workflowFailureDiagnostics.get(error) : undefined;
|
|
196
|
+
}
|
|
197
|
+
function boundedWorkflowFailureDiagnostics(value) {
|
|
198
|
+
let bounded = {
|
|
199
|
+
runId: utf8Prefix(value.runId, 128),
|
|
200
|
+
workflowName: utf8Prefix(value.workflowName, 256),
|
|
201
|
+
state: value.state,
|
|
202
|
+
failedAt: value.failedAt === null ? null : utf8Prefix(value.failedAt, 1024),
|
|
203
|
+
error: { code: value.error.code, message: utf8Prefix(value.error.message, 1024) },
|
|
204
|
+
...(value.failedAgent ? { failedAgent: {
|
|
205
|
+
id: utf8Prefix(value.failedAgent.id, 128),
|
|
206
|
+
...(value.failedAgent.label ? { label: utf8Prefix(value.failedAgent.label, 128) } : {}),
|
|
207
|
+
...(value.failedAgent.role ? { role: utf8Prefix(value.failedAgent.role, 128) } : {}),
|
|
208
|
+
structuralPath: value.failedAgent.structuralPath.slice(0, 8).map((part) => utf8Prefix(part, 128)),
|
|
209
|
+
attempt: value.failedAgent.attempt,
|
|
210
|
+
...(value.failedAgent.transport ? { transport: utf8Prefix(value.failedAgent.transport, 128) } : {}),
|
|
211
|
+
...(value.failedAgent.session ? { session: structuredClone(value.failedAgent.session) } : {}),
|
|
212
|
+
} } : {}),
|
|
213
|
+
completedSiblingAgents: (value.completedSiblingAgents ?? []).slice(0, 16).map((agent) => ({
|
|
214
|
+
id: utf8Prefix(agent.id, 128),
|
|
215
|
+
...(agent.label ? { label: utf8Prefix(agent.label, 128) } : {}),
|
|
216
|
+
...(agent.role ? { role: utf8Prefix(agent.role, 128) } : {}),
|
|
217
|
+
structuralPath: agent.structuralPath.slice(0, 8).map((part) => utf8Prefix(part, 128)),
|
|
218
|
+
})),
|
|
219
|
+
completedSiblingPaths: value.completedSiblingPaths.slice(0, 16).map((path) => path.slice(0, 8).map((part) => utf8Prefix(part, 128))),
|
|
220
|
+
...(value.retry ? { retry: { sourceRunId: utf8Prefix(value.retry.sourceRunId, 128), action: utf8Prefix(value.retry.action, 256), completedPaths: value.retry.completedPaths.slice(0, 16).map((path) => utf8Prefix(path, 256)), incompletePaths: value.retry.incompletePaths.slice(0, 16).map((path) => utf8Prefix(path, 256)), namedWorktrees: value.retry.namedWorktrees.slice(0, 16).map((name) => utf8Prefix(name, 128)), warning: utf8Prefix(value.retry.warning, 512) } } : {}),
|
|
221
|
+
artifacts: { runDirectory: utf8Prefix(value.artifacts.runDirectory, 1024), statePath: utf8Prefix(value.artifacts.statePath, 1024), journalPath: utf8Prefix(value.artifacts.journalPath, 1024) },
|
|
222
|
+
};
|
|
223
|
+
const size = () => Buffer.byteLength(JSON.stringify(bounded));
|
|
224
|
+
while (size() > DIAGNOSTIC_LIMIT_BYTES) {
|
|
225
|
+
if (bounded.completedSiblingAgents?.length || bounded.completedSiblingPaths.length) {
|
|
226
|
+
bounded = { ...bounded, completedSiblingAgents: bounded.completedSiblingAgents?.slice(0, -1) ?? [], completedSiblingPaths: bounded.completedSiblingPaths.slice(0, -1) };
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (bounded.retry && (bounded.retry.completedPaths.length || bounded.retry.incompletePaths.length || bounded.retry.namedWorktrees.length)) {
|
|
230
|
+
const retry = { ...bounded.retry };
|
|
231
|
+
if (retry.completedPaths.length)
|
|
232
|
+
retry.completedPaths = retry.completedPaths.slice(0, -1);
|
|
233
|
+
else if (retry.incompletePaths.length)
|
|
234
|
+
retry.incompletePaths = retry.incompletePaths.slice(0, -1);
|
|
235
|
+
else
|
|
236
|
+
retry.namedWorktrees = retry.namedWorktrees.slice(0, -1);
|
|
237
|
+
bounded = { ...bounded, retry };
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
if (Buffer.byteLength(bounded.artifacts.runDirectory) > 256) {
|
|
241
|
+
bounded = { ...bounded, artifacts: { ...bounded.artifacts, runDirectory: utf8Prefix(bounded.artifacts.runDirectory, 256) } };
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (Buffer.byteLength(bounded.error.message) > 256) {
|
|
245
|
+
bounded = { ...bounded, error: { ...bounded.error, message: utf8Prefix(bounded.error.message, 256) } };
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (bounded.failedAt !== null && Buffer.byteLength(bounded.failedAt) > 256) {
|
|
249
|
+
bounded = { ...bounded, failedAt: utf8Prefix(bounded.failedAt, 256) };
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (bounded.failedAgent && bounded.failedAgent.structuralPath.length > 4) {
|
|
253
|
+
bounded = { ...bounded, failedAgent: { ...bounded.failedAgent, structuralPath: bounded.failedAgent.structuralPath.slice(0, 4) } };
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (bounded.failedAgent?.structuralPath.some((part) => Buffer.byteLength(part) > 64)) {
|
|
257
|
+
bounded = { ...bounded, failedAgent: { ...bounded.failedAgent, structuralPath: bounded.failedAgent.structuralPath.map((part) => utf8Prefix(part, 64)) } };
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (Buffer.byteLength(bounded.artifacts.statePath) > 512 || Buffer.byteLength(bounded.artifacts.journalPath) > 512) {
|
|
261
|
+
bounded = { ...bounded, artifacts: { ...bounded.artifacts, statePath: utf8Prefix(bounded.artifacts.statePath, 512), journalPath: utf8Prefix(bounded.artifacts.journalPath, 512) } };
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (Buffer.byteLength(bounded.workflowName) > 128) {
|
|
265
|
+
bounded = { ...bounded, workflowName: utf8Prefix(bounded.workflowName, 128) };
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
return bounded;
|
|
271
|
+
}
|
|
272
|
+
async function diagnosticNamedWorktrees(store, run) {
|
|
273
|
+
const names = new Set();
|
|
274
|
+
try {
|
|
275
|
+
for (const name of await store.validNamedWorktrees())
|
|
276
|
+
names.add(name);
|
|
277
|
+
}
|
|
278
|
+
catch { /* Do not block failure delivery on an invalid worktree record. */ }
|
|
279
|
+
for (const name of run.retry?.namedWorktrees ?? []) {
|
|
280
|
+
try {
|
|
281
|
+
await store.resolveNamedWorktree(name);
|
|
282
|
+
names.add(name);
|
|
283
|
+
}
|
|
284
|
+
catch { /* Do not advertise stale inherited worktrees. */ }
|
|
285
|
+
}
|
|
286
|
+
return [...names];
|
|
287
|
+
}
|
|
288
|
+
export function incompleteRetryPaths(paths, completedPaths) {
|
|
289
|
+
return [...new Set(paths)].filter((path) => !completedPaths.some((completedPath) => completedPath === path || completedPath.startsWith(`${path}/`)));
|
|
290
|
+
}
|
|
291
|
+
export async function createWorkflowFailureDiagnostics(store, metadata, error, run) {
|
|
292
|
+
const failedAt = workflowFailedAt(error) ?? null;
|
|
293
|
+
const failedAgents = run.agents.filter((agent) => agent.state === "failed");
|
|
294
|
+
const failedAgentRecord = failedAgents.find((agent) => {
|
|
295
|
+
if (failedAt === null)
|
|
296
|
+
return false;
|
|
297
|
+
try {
|
|
298
|
+
return failedAt.includes(`${operationPath("agent", ...(agent.structuralPath ?? []))}/`);
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
}) ?? failedAgents.at(-1);
|
|
304
|
+
const failedAttempt = failedAgentRecord ? [...(failedAgentRecord.attemptDetails ?? [])].reverse().find((attempt) => attempt.error) ?? failedAgentRecord.attemptDetails?.at(-1) : undefined;
|
|
305
|
+
const failedAgent = failedAgentRecord ? {
|
|
306
|
+
id: failedAgentRecord.id,
|
|
307
|
+
...(failedAgentRecord.label ?? failedAgentRecord.name ? { label: failedAgentRecord.label ?? failedAgentRecord.name } : {}),
|
|
308
|
+
...(failedAgentRecord.role ? { role: failedAgentRecord.role } : {}),
|
|
309
|
+
structuralPath: [...(failedAgentRecord.structuralPath ?? [])],
|
|
310
|
+
attempt: Math.max(1, failedAttempt?.attempt ?? failedAgentRecord.attempts),
|
|
311
|
+
...(failedAttempt?.transport ? { transport: failedAttempt.transport } : {}),
|
|
312
|
+
...(failedAttempt?.session ? { session: failedAttempt.session } : {}),
|
|
313
|
+
} : undefined;
|
|
314
|
+
const completedSiblingAgents = run.agents.filter((agent) => {
|
|
315
|
+
if (agent.state !== "completed" || agent.id === failedAgentRecord?.id)
|
|
316
|
+
return false;
|
|
317
|
+
return failedAgentRecord?.parentId === undefined ? agent.parentId === undefined : agent.parentId === failedAgentRecord.parentId;
|
|
318
|
+
}).map((agent) => ({
|
|
319
|
+
id: agent.id,
|
|
320
|
+
...(agent.label ?? agent.name ? { label: agent.label ?? agent.name } : {}),
|
|
321
|
+
...(agent.role ? { role: agent.role } : {}),
|
|
322
|
+
structuralPath: [...(agent.structuralPath ?? [])],
|
|
323
|
+
}));
|
|
324
|
+
const completedSiblingPaths = completedSiblingAgents.map((agent) => [...agent.structuralPath]);
|
|
325
|
+
let journalCompletedPaths = [];
|
|
326
|
+
try {
|
|
327
|
+
journalCompletedPaths = (await store.replayableOperations()).map(({ path }) => path);
|
|
328
|
+
}
|
|
329
|
+
catch { /* Preserve failure diagnostics when retry history is unavailable. */ }
|
|
330
|
+
const completedPaths = run.retry ? [...new Set([...run.retry.completedPaths, ...journalCompletedPaths])] : journalCompletedPaths.length ? journalCompletedPaths : run.agents.filter((agent) => agent.state === "completed").map((agent) => operationPath("agent", ...(agent.structuralPath ?? [])));
|
|
331
|
+
const namedWorktrees = await diagnosticNamedWorktrees(store, run);
|
|
332
|
+
const retry = run.state === "failed" ? {
|
|
333
|
+
sourceRunId: run.id,
|
|
334
|
+
action: `workflow_retry({ runId: ${JSON.stringify(run.id)} })`,
|
|
335
|
+
completedPaths,
|
|
336
|
+
incompletePaths: incompleteRetryPaths([...(run.retry?.incompletePaths ?? []), ...(failedAt ? [failedAt] : [])], completedPaths),
|
|
337
|
+
namedWorktrees,
|
|
338
|
+
warning: "Retry re-executes incomplete operations; external side effects before failure are not guaranteed exactly once.",
|
|
339
|
+
} : undefined;
|
|
340
|
+
return boundedWorkflowFailureDiagnostics({
|
|
341
|
+
runId: run.id, workflowName: metadata.name, state: run.state, failedAt,
|
|
342
|
+
error: { code: errorCode(error) ?? "INTERNAL_ERROR", message: errorText(error) || "The workflow failed without an error message." },
|
|
343
|
+
...(failedAgent ? { failedAgent } : {}), completedSiblingAgents, completedSiblingPaths,
|
|
344
|
+
...(retry ? { retry } : {}),
|
|
345
|
+
artifacts: { runDirectory: store.directory, statePath: join(store.directory, "state.json"), journalPath: join(store.directory, "journal.json") },
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
export function formatWorkflowFailureDiagnostics(diagnostic) {
|
|
349
|
+
const failedAgent = diagnostic.failedAgent ? `${diagnostic.failedAgent.label ?? diagnostic.failedAgent.id}${diagnostic.failedAgent.role ? ` role=${diagnostic.failedAgent.role}` : ""} 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
|
+
const siblingAgents = diagnostic.completedSiblingAgents;
|
|
351
|
+
const siblings = siblingAgents ? siblingAgents.map((agent) => `${agent.label ?? agent.id}${agent.role ? ` role=${agent.role}` : ""} path=${agent.structuralPath.join(" > ") || "(root)"}`).join(", ") || "(none)" : diagnostic.completedSiblingPaths.map((path) => path.join(" > ") || "(root)").join(", ") || "(none)";
|
|
352
|
+
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
|
+
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
|
+
}
|
|
355
|
+
function deliveryPart(value, maxBytes) { return utf8Prefix(value.replace(/\s+/g, " ").trim(), maxBytes) || "(unknown)"; }
|
|
356
|
+
export function formatWorkflowFailureDelivery(diagnostic) {
|
|
357
|
+
const name = deliveryPart(diagnostic.workflowName, 128);
|
|
358
|
+
const runId = deliveryPart(diagnostic.runId, 128);
|
|
359
|
+
const error = `${diagnostic.error.code}: ${deliveryPart(diagnostic.error.message, 768)}`;
|
|
360
|
+
const failedPath = diagnostic.failedAt ? `; failed path=${deliveryPart(diagnostic.failedAt, 512)}` : "";
|
|
361
|
+
const nextAction = diagnostic.retry ? `; next action: ${deliveryPart(diagnostic.retry.action, 256)}` : "";
|
|
362
|
+
const artifacts = `; artifacts: runDirectory=${deliveryPart(diagnostic.artifacts.runDirectory, 512)} statePath=${deliveryPart(diagnostic.artifacts.statePath, 512)} journalPath=${deliveryPart(diagnostic.artifacts.journalPath, 512)}`;
|
|
363
|
+
const line = `Workflow ${name} failed (runId=${runId}): error=${error}${failedPath}${nextAction}${artifacts}`;
|
|
364
|
+
return Buffer.byteLength(line) <= DELIVERY_LIMIT_BYTES ? line : utf8Prefix(line, DELIVERY_LIMIT_BYTES);
|
|
365
|
+
}
|
|
366
|
+
export function formatWorkflowFailureDeliveryFallback(workflowName, runId, runDirectory, error, retryable = true) {
|
|
367
|
+
const code = errorCode(error) ?? "INTERNAL_ERROR";
|
|
368
|
+
const failedPath = workflowFailedAt(error);
|
|
369
|
+
const nextAction = retryable && code !== "BUDGET_EXHAUSTED" && code !== "CANCELLED" ? `; next action: workflow_retry({ runId: ${JSON.stringify(runId)} })` : "";
|
|
370
|
+
const line = `Workflow ${deliveryPart(workflowName, 128)} failed (runId=${deliveryPart(runId, 128)}): error=${code}: ${deliveryPart(formatWorkflowFailure(error), 768)}${failedPath ? `; failed path=${deliveryPart(failedPath, 512)}` : ""}${nextAction}; artifacts: runDirectory=${deliveryPart(runDirectory, 512)} statePath=${deliveryPart(join(runDirectory, "state.json"), 512)} journalPath=${deliveryPart(join(runDirectory, "journal.json"), 512)}`;
|
|
371
|
+
return Buffer.byteLength(line) <= DELIVERY_LIMIT_BYTES ? line : utf8Prefix(line, DELIVERY_LIMIT_BYTES);
|
|
372
|
+
}
|
|
373
|
+
export function serializeWorkflowFailureDiagnostics(diagnostic) { return JSON.stringify(diagnostic); }
|
|
374
|
+
export function isWorkflowFailureDiagnostics(value) {
|
|
375
|
+
return object(value) && typeof value.runId === "string" && typeof value.workflowName === "string" && typeof value.state === "string" && "failedAt" in value && object(value.error) && object(value.artifacts);
|
|
376
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { type ExtensionUIContext, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { RunStore, type PersistedRun } from "./persistence.js";
|
|
3
|
+
import { type WorkflowRegistryApi } from "./registry.js";
|
|
4
|
+
import { type WorkflowRecoveryContext, type createWorkflowRecovery } from "./host-recovery.js";
|
|
5
|
+
import { type WorkflowRunRecord } from "./host-runtime.js";
|
|
6
|
+
import { type TrajectoryPublisherProvider } from "./trajectory-host-handle.js";
|
|
7
|
+
import { type HardTerminalRunState, type JsonValue, type LaunchSnapshot, type LiveSessionHandoff, type PreparedAgentSession, type WorkflowAgentSession } from "./types.js";
|
|
8
|
+
type UiSelect = (title: string, options: string[]) => Promise<string | undefined>;
|
|
9
|
+
type UiInput = (title: string, placeholder?: string) => Promise<string | undefined>;
|
|
10
|
+
type UiSetStatus = (key: string, text?: string) => void;
|
|
11
|
+
type UiCustom = ExtensionUIContext["custom"];
|
|
12
|
+
type NavigatorStoredRun = {
|
|
13
|
+
store: RunStore;
|
|
14
|
+
loaded: {
|
|
15
|
+
run: PersistedRun;
|
|
16
|
+
snapshot: Readonly<LaunchSnapshot>;
|
|
17
|
+
};
|
|
18
|
+
resolvedAt: number | undefined;
|
|
19
|
+
};
|
|
20
|
+
type NavigatorRunDependencies = ReadonlyMap<string, readonly string[]>;
|
|
21
|
+
type ManualDeletionPlan = {
|
|
22
|
+
ordered: readonly NavigatorStoredRun[];
|
|
23
|
+
skipped: readonly {
|
|
24
|
+
entry: NavigatorStoredRun;
|
|
25
|
+
dependentIds: readonly string[];
|
|
26
|
+
}[];
|
|
27
|
+
};
|
|
28
|
+
export declare function manualDeletionPlan(entries: readonly NavigatorStoredRun[], state: "completed" | "failed", dependencies: NavigatorRunDependencies): ManualDeletionPlan;
|
|
29
|
+
export type UiHostCapabilities = {
|
|
30
|
+
select?: UiSelect;
|
|
31
|
+
input?: UiInput;
|
|
32
|
+
setStatus?: UiSetStatus;
|
|
33
|
+
custom?: UiCustom;
|
|
34
|
+
};
|
|
35
|
+
type ReportBlocked = (active: boolean, label?: string) => void;
|
|
36
|
+
export declare function uiHostCapabilities(ui: unknown): UiHostCapabilities | undefined;
|
|
37
|
+
export type WorkflowNavigatorDependencies = {
|
|
38
|
+
pi: Pick<ExtensionAPI, "registerCommand">;
|
|
39
|
+
home: string | undefined;
|
|
40
|
+
clipboard: (value: string) => Promise<void>;
|
|
41
|
+
extensionAgentDir: string;
|
|
42
|
+
runs: Map<string, WorkflowRunRecord>;
|
|
43
|
+
terminalRunStates: Map<string, HardTerminalRunState>;
|
|
44
|
+
hardTerminalRunStates: ReadonlySet<string>;
|
|
45
|
+
ensureSessionLease: (cwd: string, sessionId: string) => Promise<void>;
|
|
46
|
+
answerCheckpoint: (runId: string, name: string, approved: boolean, silent?: boolean) => Promise<boolean>;
|
|
47
|
+
recovery: ReturnType<typeof createWorkflowRecovery>;
|
|
48
|
+
stopWorkflowRun: (runId: string) => Promise<{
|
|
49
|
+
runId: string;
|
|
50
|
+
state: string;
|
|
51
|
+
stopped: boolean;
|
|
52
|
+
reason?: "unknown_run" | "already_terminal";
|
|
53
|
+
}>;
|
|
54
|
+
moveForegroundToBackground: (runId: string) => Promise<{
|
|
55
|
+
runId: string;
|
|
56
|
+
state: "running";
|
|
57
|
+
detached: true;
|
|
58
|
+
}>;
|
|
59
|
+
isForegroundAttached: (runId: string) => boolean;
|
|
60
|
+
liveAgents: {
|
|
61
|
+
get(runId: string, agentId: string): Readonly<{
|
|
62
|
+
session?: WorkflowAgentSession;
|
|
63
|
+
prepared?: Readonly<PreparedAgentSession>;
|
|
64
|
+
handoff?: LiveSessionHandoff;
|
|
65
|
+
}> | undefined;
|
|
66
|
+
overlay(run: PersistedRun): PersistedRun;
|
|
67
|
+
};
|
|
68
|
+
registry: WorkflowRegistryApi;
|
|
69
|
+
projectTrusted: (context: unknown) => boolean;
|
|
70
|
+
resumeHostContext: (context: unknown) => WorkflowRecoveryContext;
|
|
71
|
+
resumeSelectedWorkflow: (runId: string, foreground: boolean, context: unknown, budgetPatch?: unknown) => Promise<{
|
|
72
|
+
workflowName: string;
|
|
73
|
+
state: "running" | "completed" | "awaiting_approval";
|
|
74
|
+
attached: boolean;
|
|
75
|
+
value?: JsonValue;
|
|
76
|
+
}>;
|
|
77
|
+
reportBlocked?: ReportBlocked;
|
|
78
|
+
setNavigatorOpen?: (open: boolean) => void;
|
|
79
|
+
trajectoryProvider: TrajectoryPublisherProvider;
|
|
80
|
+
coordinateRunMutation?: <T>(task: () => Promise<T>) => Promise<T>;
|
|
81
|
+
};
|
|
82
|
+
export declare function registerWorkflowNavigator(deps: WorkflowNavigatorDependencies): void;
|
|
83
|
+
export {};
|