pi-subagents 0.58.0 → 0.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +102 -0
- package/docs/agents.md +5 -3
- package/docs/configuration.md +4 -4
- package/docs/extension-api.md +1 -1
- package/docs/models.md +24 -1
- package/docs/observability.md +1 -1
- package/docs/tool-reference.md +93 -5
- package/docs/workflows.md +94 -3
- package/package.json +3 -1
- package/prompts/review-loop.md +2 -2
- package/skills/council-mode/SKILL.md +48 -243
- package/skills/council-mode/references/pass-contracts.md +150 -0
- package/skills/pi-subagents/SKILL.md +87 -37
- package/skills/pi-subagents/references/constraints-and-recipes.md +29 -233
- package/skills/pi-subagents/references/execution-controls.md +52 -7
- package/skills/pi-subagents/references/management-authoring-rpc.md +3 -4
- package/skills/pi-subagents/references/multi-lane-orchestration.md +13 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +54 -26
- package/skills/pi-subagents/references/review-and-validation.md +73 -0
- package/src/agents/agent-management.ts +159 -42
- package/src/agents/agent-serializer.ts +4 -2
- package/src/agents/agents.ts +67 -26
- package/src/agents/runtime-agent-registry.ts +9 -16
- package/src/api/background-work.ts +5 -1
- package/src/api/delegation.ts +0 -7
- package/src/api/preflight.ts +6 -9
- package/src/api/shared-types.ts +2 -0
- package/src/extension/fanout-child.ts +5 -3
- package/src/extension/index.ts +51 -23
- package/src/extension/public-execution.ts +16 -2
- package/src/extension/schemas.ts +36 -10
- package/src/extension/tool-description.ts +24 -5
- package/src/intercom/result-intercom.ts +2 -0
- package/src/profiles/profiles.ts +5 -6
- package/src/runs/background/active-async-capacity.ts +2 -2
- package/src/runs/background/async-execution.ts +52 -37
- package/src/runs/background/async-job-tracker.ts +17 -12
- package/src/runs/background/async-resume.ts +23 -25
- package/src/runs/background/async-status-snapshot.ts +23 -261
- package/src/runs/background/async-status.ts +110 -8
- package/src/runs/background/chain-append.ts +6 -3
- package/src/runs/background/chain-root-attachment.ts +60 -8
- package/src/runs/background/control-channel.ts +3 -2
- package/src/runs/background/fleet-view.ts +21 -11
- package/src/runs/background/notify.ts +158 -6
- package/src/runs/background/result-files.ts +2 -1
- package/src/runs/background/result-watcher.ts +2 -0
- package/src/runs/background/resume-guidance.ts +1 -1
- package/src/runs/background/retained-children.ts +1 -1
- package/src/runs/background/run-status.ts +30 -9
- package/src/runs/background/scheduled-runs.ts +86 -7
- package/src/runs/background/stale-run-reconciler.ts +10 -4
- package/src/runs/background/steering.ts +4 -14
- package/src/runs/background/subagent-runner.ts +351 -358
- package/src/runs/background/subagent-wait.ts +68 -12
- package/src/runs/background/terminal-run-index.ts +1 -1
- package/src/runs/background/wait-completions.ts +25 -1
- package/src/runs/background/wait-config.ts +23 -9
- package/src/runs/background/wait-tool.ts +9 -2
- package/src/runs/foreground/async-steering-action.ts +2 -2
- package/src/runs/foreground/execution.ts +125 -122
- package/src/runs/foreground/foreground-control.ts +3 -0
- package/src/runs/foreground/foreground-history.ts +1 -0
- package/src/runs/foreground/subagent-executor.ts +576 -240
- package/src/runs/foreground/workflow-detach-reconcile.ts +99 -200
- package/src/runs/shared/abort-recovery.ts +119 -0
- package/src/runs/shared/async-status-projection.ts +597 -0
- package/src/runs/shared/background-process-options.ts +9 -0
- package/src/runs/shared/child-identity.ts +19 -4
- package/src/runs/shared/child-launch-plan.ts +151 -0
- package/src/runs/shared/completion-evidence.ts +89 -0
- package/src/runs/shared/completion-guard.ts +1 -1
- package/src/runs/shared/dynamic-fanout.ts +2 -2
- package/src/runs/shared/host-step-status.ts +230 -0
- package/src/runs/shared/lane-metadata.ts +105 -0
- package/src/runs/shared/mcp-config-sources.ts +42 -6
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +93 -143
- package/src/runs/shared/mcp-direct-tool-grant.ts +194 -0
- package/src/runs/shared/model-fallback.ts +9 -2
- package/src/runs/shared/mutation-evidence.ts +52 -3
- package/src/runs/shared/nested-events.ts +6 -2
- package/src/runs/shared/nested-render.ts +7 -3
- package/src/runs/shared/parallel-handoff.ts +419 -7
- package/src/runs/shared/parallel-utils.ts +7 -0
- package/src/runs/shared/pi-args.ts +67 -3
- package/src/runs/shared/single-output.ts +72 -22
- package/src/runs/shared/subagent-prompt-runtime.ts +33 -6
- package/src/runs/shared/workflow-graph.ts +15 -0
- package/src/runs/shared/worktree-cleanup-plan.ts +847 -0
- package/src/runs/shared/worktree.ts +18 -0
- package/src/shared/child-session-name.ts +46 -0
- package/src/shared/extension-context.ts +24 -0
- package/src/shared/formatters.ts +5 -2
- package/src/shared/launch-contract.ts +1 -1
- package/src/shared/settings.ts +9 -103
- package/src/shared/types.ts +232 -30
- package/src/shared/utils.ts +35 -55
- package/src/slash/delegation-adapters.ts +1 -8
- package/src/slash/delegation-request.ts +0 -4
- package/src/slash/slash-bridge.ts +1 -2
- package/src/slash/slash-commands.ts +369 -90
- package/src/slash/slash-live-state.ts +22 -11
- package/src/tui/fleet-status.ts +134 -75
- package/src/tui/fleet.ts +11 -5
- package/src/tui/render-helpers.ts +31 -0
- package/src/tui/render.ts +895 -121
- package/src/watchdog/change-signature.ts +40 -1
- package/src/watchdog/turn-delta.ts +1 -1
- package/src/workflows/chat-progress.ts +6 -3
- package/src/workflows/host-command.ts +235 -0
- package/src/workflows/scripted-workflow.ts +503 -38
- package/src/workflows/workflow-child-summary.ts +9 -5
- package/src/workflows/workflow-preflight.ts +270 -0
- package/src/workflows/workflow-receipt.ts +43 -4
- package/src/workflows/workflow-settlement.ts +246 -0
- package/src/runs/shared/turn-budget.ts +0 -98
|
@@ -6,18 +6,29 @@ import { getAgentDir, getProjectConfigDir } from "../shared/utils.ts";
|
|
|
6
6
|
const CUSTOM_TOOL_DESCRIPTION_FILE = "subagent-tool-description.md";
|
|
7
7
|
const CUSTOM_TOOL_DESCRIPTION_MAX_BYTES = 50 * 1024;
|
|
8
8
|
const EXTERNAL_CLI_RUNNER_GUIDANCE = "External CLI agents (codex-exec, codex-exec-writer, claude-code, claude-code-writer, cursor-agent, cursor-agent-writer) use their own runner contract and do not support native Pi child options such as model override, structured output, acceptance/agent contract, tool budget, fast mode, fork context, skills, or native Pi tools unless the runner explicitly implements them.";
|
|
9
|
+
const WORKFLOW_RESUME_KEY_GUIDANCE = "Each workflow key identifies one result lane: use a new stable workflow key for every distinct retained resume pass; same-key calls are reused only when launch parameters are identical, and incompatible parameters are rejected.";
|
|
10
|
+
const WORKFLOW_OUTPUT_BINDING_GUIDANCE = "For durable workflow child files, set output on runs.run/runs.all; task filename prose is not an output declaration, and return the child's outputReference, outputPathMapping, or artifactPaths instead of inventing a literal path.";
|
|
11
|
+
const WORKFLOW_LANES_GUIDANCE = "For bounded parallel sequential chains, use runs.lanes([{key,stages:[{key,agent,task},{key,resume:'previous',task},...]}]); first stages run together, later stages sequence per lane, and the bounded board reports lane-local failures. Only an explicit structuredOutput.verdict === 'blocked' blocks a successful stage; reviewer prose is not parsed.";
|
|
12
|
+
const WORKFLOW_SCRIPT_PORTABILITY_GUIDANCE = "workflowScript rejects nested async function, arrow, and method helpers; use top-level await, plain helper functions that return runs.run(...), or explicit Promise chains instead.";
|
|
13
|
+
const WORKFLOW_HOST_GUIDANCE = "For one non-interactive operator-owned command, await runs.host(key,{kind:'command',command,timeoutMs,output?,role?,provider?}). runs.host has no per-step cwd: commands and relative output paths use the workflow cwd; set cwd on the outer subagent request instead (for example, {cwd:'/path/to/worktree',workflowScript:'...'}), or put a trusted directory change in the command (for example, 'cd /path/to/worktree && npm test'). v1 supports only command steps; output is bounded and command failure fails the workflow.";
|
|
14
|
+
const AGENT_CAPABILITY_GUIDANCE = "For capability selection, use { action: \"list\", capabilities: true } for compact prompt-free rows.";
|
|
9
15
|
|
|
10
|
-
export const DEFAULT_SUBAGENT_TOOL_DESCRIPTION = `Delegate to configured subagents. For execution, omit action and use {agent, task?} for one child, workflowScript for inline orchestration, or workflowScriptPath to load a script from the request cwd. The script inputs are mutually exclusive. Use action:'validate' with either script input to check it without launching children. For multi-step or parallel work, make exactly one top-level subagent call with async:true; launch children only inside that workflow and do not make another top-level call for them. Use runs.run('key',{agent,task}) for one child, await runs.all([{key:'a',agent:'reviewer',task:'...'},{key:'b',agent:'reviewer',task:'...'}]) for ordinary parallel children, and read its ordered array result with indexes, destructuring, or .map(...), not by key property. ${EXTERNAL_CLI_RUNNER_GUIDANCE} Use action only for management/control. Use guide or the pi-subagents skill for advanced workflow details.`;
|
|
16
|
+
export const DEFAULT_SUBAGENT_TOOL_DESCRIPTION = `Delegate to configured subagents. For execution, omit action and use {agent, task?} for one child, workflowScript for inline orchestration, or workflowScriptPath to load a script from the request cwd. The script inputs are mutually exclusive. Use action:'validate' with either script input to check it without launching children. For multi-step or parallel work, make exactly one top-level subagent call with async:true; launch children only inside that workflow and do not make another top-level call for them. Use runs.run('key',{agent,task}) for one child, await runs.all([{key:'a',agent:'reviewer',task:'...'},{key:'b',agent:'reviewer',task:'...'}]) for ordinary parallel children, and read its ordered array result with indexes, destructuring, or .map(...), not by key property. ${WORKFLOW_SCRIPT_PORTABILITY_GUIDANCE} ${WORKFLOW_LANES_GUIDANCE} ${WORKFLOW_HOST_GUIDANCE} ${EXTERNAL_CLI_RUNNER_GUIDANCE} Use action only for management/control. Use guide or the pi-subagents skill for advanced workflow details.`;
|
|
11
17
|
|
|
12
18
|
export const SUBAGENT_TOOL_PROMPT_SNIPPET = "Delegate to subagents; orchestrate in one workflowScript call.";
|
|
13
19
|
|
|
14
20
|
export const SUBAGENT_TOOL_PROMPT_GUIDELINES = [
|
|
15
|
-
|
|
21
|
+
`Use subagent only when delegation is needed. Before executing, call { action: "list" } and run only executable, non-disabled agents. ${AGENT_CAPABILITY_GUIDANCE}`,
|
|
16
22
|
"Omit action for execution. Use { agent, task? } only for one child; use workflowScript for multi-step or parallel work.",
|
|
17
23
|
"workflowScript means exactly one top-level subagent tool call with async:true. Inside it, use runs.run/runs.all to launch children; do not make another top-level subagent call for those children.",
|
|
24
|
+
WORKFLOW_SCRIPT_PORTABILITY_GUIDANCE,
|
|
25
|
+
WORKFLOW_LANES_GUIDANCE,
|
|
26
|
+
WORKFLOW_HOST_GUIDANCE,
|
|
27
|
+
WORKFLOW_RESUME_KEY_GUIDANCE,
|
|
28
|
+
WORKFLOW_OUTPUT_BINDING_GUIDANCE,
|
|
18
29
|
"For ordinary parallel work, use await runs.all([{key,agent,task}, ...]); it resolves to an ordered array, not a key map, so use results[0], destructuring, or results.map(...), not results.<key>. Do not read .output from unawaited runs.run launches. Stored runs.run promises are only for advanced rolling fanout and each must later be observed with direct await, Promise.race, or Promise.all.",
|
|
19
30
|
"Keep one writer per cwd/worktree unless writers run in isolated worktrees.",
|
|
20
|
-
"To pass an explicit model to a child, first call { action: \"models\" } and copy an exact provider/id (e.g.
|
|
31
|
+
"To pass an explicit model to a child, first call { action: \"models\" } and copy an exact provider/id (e.g. provider/model-id); bare ids resolve only when unique in the registry, and agent names (gpt-pro, advisor) are not model ids. Set per-run thinking with a suffix on the model string (e.g. provider/model-id:high; off/minimal/low/medium/high/xhigh/max); the suffix wins over the agent's thinking default. The thinking field only applies to action='watchdog.configure' and is ignored on dispatch.",
|
|
21
32
|
EXTERNAL_CLI_RUNNER_GUIDANCE,
|
|
22
33
|
"Use guide or the pi-subagents skill for advanced scheduling, missions, steering, and retention.",
|
|
23
34
|
];
|
|
@@ -26,6 +37,9 @@ export const SUBAGENT_SAFETY_GUIDANCE = `SAFETY-CRITICAL SUBAGENT GUIDANCE:
|
|
|
26
37
|
• Use { action: "list" } before execution and only run executable/non-disabled agents.
|
|
27
38
|
• Keep execution and management separate: omit action for structured single-child or workflowScript execution; use action only for management/control.
|
|
28
39
|
• Async/background runs are the normal default unless config sets asyncByDefault:false; set async:true explicitly when async behavior matters. Use async:false only when the parent must block until completion. Async mode still shows progress. Final reviews and gate checks stay async; needing a result is not a blocking reason. After an async launch, continue independent work only until its next dependency barrier; consume the result before work that depends on it. Do not sleep or poll status just to wait; use subagent_wait only when the current request must finish in this turn.
|
|
40
|
+
• ${WORKFLOW_RESUME_KEY_GUIDANCE}
|
|
41
|
+
• ${WORKFLOW_OUTPUT_BINDING_GUIDANCE}
|
|
42
|
+
• ${WORKFLOW_HOST_GUIDANCE}
|
|
29
43
|
• Ordinary child subagents are not orchestrators. Only explicitly configured fanout children may use the child-safe subagent tool, still bounded by depth/session limits.
|
|
30
44
|
• Oracle/advisor consultations should use supervisor dialogue for material unknowns when available; request one-shot only when desired.
|
|
31
45
|
• Keep one writer for the same cwd/worktree. Use fresh-context read-only reviewers for independent review, then have the parent synthesize and apply fixes.
|
|
@@ -39,6 +53,7 @@ EXECUTION:
|
|
|
39
53
|
• When passing an explicit model to a child (on the call or a runs.run/runs.all item), first call { action: "models" } and copy an exact provider/id; bare ids resolve only when unique in the registry, and agent names (e.g. gpt-pro, advisor) are not model ids. Set per-run thinking with a suffix on the model string (e.g. provider/id:high; off/minimal/low/medium/high/xhigh/max); the suffix wins over the agent's thinking default. The thinking field only applies to action='watchdog.configure' and is ignored on dispatch.
|
|
40
54
|
• SINGLE CHILD: { agent:"worker", task:"..." }. This structured form starts exactly one direct child. Fields such as model, context, cwd, worktree, output, budgets, acceptance, and async apply to that child. Do not combine agent/task with action, workflowScript, or workflowScriptPath.
|
|
41
55
|
• WORKFLOW SCRIPT: { workflowScript: "return runs.run('main', {agent:'worker', task:'...'})" }. Use stable-key runs.run for one child and await runs.all([{key,agent,task}, ...]) for ordinary parallel children. runs.all resolves to an ordered array, not a key map, so use results[0], array destructuring, or results.map((result) => result.output), not results.<key>. Do not read .output from unawaited runs.run launches. Stored runs.run promises are only for advanced rolling fanout and each must later be observed with direct await, Promise.race, or Promise.all. Ordinary JavaScript provides sequence, branching, filtering, retries, and aggregation. workflowScript is an ordinary JavaScript statement body, so use an explicit return for a useful result. Use top-level await, plain helper functions, or explicit Promise chains; nested async function, arrow, and method helpers are rejected. For task text with Markdown fences or shell blocks, build quoted lines instead of nesting raw template literals: \`const task=["Run:","\`\`\`bash","npm test","\`\`\`"].join("\\n")\`. Scripts normally start async unless config sets asyncByDefault:false; set async:true explicitly when async behavior matters. Pass async:false only when the parent must block until completion, never for final reviews or gates. Same-repo blocking workflows default to a live in-chat card; explicit live-card requires same-repository async:false, so async workflows should omit chatProgress or use auto/off. Workflow-level child controls default onto each runs.run launch, and explicit child fields override them. Use {action:"children.list"} to list recent retained workflow children with resumable/not-resumable reasons. Resume only rows reported resumable. For a simple follow-up or implementation challenge, use {action:"resume", id:"run-id", message:"..."}. Resume keeps the stored agent/model/tool contract. If no resumable child is listed, launch a same-role fallback challenge and label it as fallback. Inside workflowScript, continue one with runs.run(key, {resume:"run-id", task:"follow-up"}); workflow resumes wait for completed output, and loops must continue from each latest returned runId. Await runs.steer(key, message, {mode?, index?, ackTimeoutMs?}) to guide a prior keyed child without exposing its run id; receipts are queued, delivered, missed, or failed. Always await or return runs.steer. For repository mutation lanes, set worktree:true on the workflow or individual runs.run/runs.all item for managed isolation; each parallel child gets a separate worktree and handoff artifact. A workflow usageBudget is enforced once across the workflow. Available globals are runs.run, runs.all, runs.steer, runs.status, runs.ref/refs, emit, console, and standard JavaScript only. Workflows get async state.get(key) and state.set(key, JSONValue) through their automatic or explicit mission; mission:false workflows do not have a state global. Scripts cannot access filesystem, shell, arbitrary Pi tools, or host globals.
|
|
56
|
+
• ${WORKFLOW_LANES_GUIDANCE}
|
|
42
57
|
• FILE SCRIPT: { workflowScriptPath:"workflows/review.js" }. Relative paths resolve against the request cwd. The host reads the file before the filesystem-free workflow sandbox starts. Do not combine this field with workflowScript.
|
|
43
58
|
• Sequential example: { workflowScript: "const a = await runs.run('analyze', {agent:'agent-a', task:'Analyze the request'}); return (await runs.run('plan', {agent:'agent-b', task:'Plan from: '+a.output})).output" }
|
|
44
59
|
• Parallel example: { workflowScript: "const [a,b] = await runs.all([{key:'correctness',agent:'agent-a',task:'Review correctness'},{key:'tests',agent:'agent-b',task:'Review tests'}]); return {correctness:a.output,tests:b.output}" }
|
|
@@ -46,7 +61,7 @@ EXECUTION:
|
|
|
46
61
|
• Durable mission attachment is automatic by default. Use missionId to attach an existing mission, mission:{...} to override auto-create, or mission:false for ephemeral work. A mission object needs exactly one non-empty title or summary; objective and labels are optional. goal may only be true and requires budget:{tokens}.
|
|
47
62
|
|
|
48
63
|
MANAGEMENT / CONTROL (use action; omit execution fields):
|
|
49
|
-
• validate checks workflowScript or workflowScriptPath syntax and statically decidable structure without launching children. list, get, models, guide, children.list, create, update, delete, eject, disable, enable, reset, status, debug.run, doctor, grant-spawn-budget, worktree.discard, refine/refine.show/refine.rollback, mission.create/list/show/update/resolve-decision/attach-run/close, inspector.open/status/close, project.open/status/close, and watchdog actions remain available. Use {action:"guide", topic:"overview"} for packaged current-version help; topics are overview, workflows, agents, missions, observability, tool-reference, configuration, models, watchdog, and extension-api.
|
|
64
|
+
• validate checks workflowScript or workflowScriptPath syntax and statically decidable structure without launching children. list, get, models, guide, children.list, create, update, delete, eject, disable, enable, reset, status, debug.run, doctor, grant-spawn-budget, worktree.discard, worktree.cleanup (plan-only), lane.status, lane.recordMerge, lane.recordSupersession, refine/refine.show/refine.rollback, mission.create/list/show/update/resolve-decision/attach-run/close, inspector.open/status/close, project.open/status/close, and watchdog actions remain available. Use {action:"guide", topic:"overview"} for packaged current-version help; topics are overview, workflows, agents, missions, observability, tool-reference, configuration, models, watchdog, and extension-api.
|
|
50
65
|
• status, interrupt, stop, resume, and steer manage live or persisted runs. Use status view:"fleet" for an overview or view:"transcript" with id and optional index to tail output.
|
|
51
66
|
• Create durable project schedules with { action:"schedule.create", id?, name?, at:"+10m" | ISO, workflowScript:"return runs.run('main', {agent:'worker', task:'...'})" }, or use workflowScriptPath instead. Manage them with schedule.list/show/history/pause/resume/run/run-due/delete. This first slice supports fixed intervals; calendar schedules and schedule mission attachment are deferred.
|
|
52
67
|
|
|
@@ -60,16 +75,20 @@ EXECUTE:
|
|
|
60
75
|
• Passing an explicit model? Call {action:"models"} first and copy an exact provider/id; bare ids resolve only when unique in the registry; agent names (e.g. gpt-pro, advisor) are not model ids. Per-run thinking is a suffix on the model string (provider/id:high; off/minimal/low/medium/high/xhigh/max), and the suffix wins over the agent's thinking default; the thinking field only applies to action='watchdog.configure' and is ignored on dispatch.
|
|
61
76
|
• SINGLE {agent:"worker",task:"..."} starts exactly one direct child. Fields apply to that child. Do not combine agent/task with action, workflowScript, or workflowScriptPath.
|
|
62
77
|
• SCRIPT {workflowScript:"return runs.run('main', {agent:'worker', task:'...'})"}. Use stable-key runs.run for one child and await runs.all([{key,agent,task}, ...]) for ordinary parallel work. runs.all resolves to an ordered array, not a key map; use results[0], destructuring, or results.map(...), not results.<key>. Do not read .output from unawaited runs.run launches. Stored runs.run promises are only for advanced rolling fanout and each must later be observed with direct await, Promise.race, or Promise.all. Await runs.steer(key,message,options?) to guide a prior keyed child; it returns queued, delivered, missed, or failed and never accepts a raw run id. Always await or return steering calls. Use {action:"children.list"} for recent retained workflow children and resume only rows reported resumable. Use {action:"resume",id:"run-id",message:"..."} for a simple follow-up or challenge; resume keeps the stored agent/model/tool contract. If none is resumable, launch a same-role fallback challenge and label it as fallback. Inside workflowScript use runs.run(key,{resume:"run-id",task:"follow-up"}) when the script must wait for completion and continue from the latest returned runId. Workflows get async state.get/state.set through their automatic or explicit mission; mission:false does not. Scripts are ordinary JavaScript statement bodies; use explicit return for a useful result. Use top-level await, plain helper functions, or explicit Promise chains; nested async function, arrow, and method helpers are rejected. For task text with Markdown fences or shell blocks, build quoted lines instead of nesting raw template literals: \`const task=["Run:","\`\`\`bash","npm test","\`\`\`"].join("\\n")\`. Use JavaScript for sequence, branching, retries, and aggregation. For repository mutation lanes, use worktree:true on the workflow or runs.run/runs.all item for managed isolation. Scripts normally start async unless config sets asyncByDefault:false; set async:true explicitly when async behavior matters. async:false blocks the parent until completion and auto-enables a same-repo live chat card unless chatProgress is off; explicit live-card requires same-repository async:false, so async workflows should omit chatProgress or use auto/off.
|
|
78
|
+
• ${WORKFLOW_LANES_GUIDANCE}
|
|
63
79
|
• FILE SCRIPT {workflowScriptPath:"workflows/review.js"} loads the script on the host relative to the request cwd before sandbox execution. Do not combine it with workflowScript.
|
|
64
80
|
• Example: {workflowScript:"const [a,b]=await runs.all([{key:'a',agent:'agent-a',task:'Implement A',worktree:true},{key:'b',agent:'agent-b',task:'Implement B',worktree:true}]); return [a.output,b.output]"}
|
|
65
81
|
• context can be fresh, fork, or profile. profile requires the selected agent's declared defaultContext and ignores defaultSubagentContext. Explicit fresh/fork wins; omitted context follows defaultSubagentContext before agent defaultContext. Config forkContext can summarize transcript overflow with stable recovery refs before spawn without adding another public context value. timeoutMs/maxRuntimeMs apply to foreground and async workflows; foreground workflows default to 30 minutes and async workflows have no default timeout. Omit acceptance for reviewer/read-only calls.
|
|
66
82
|
|
|
67
83
|
MANAGE / CONTROL:
|
|
68
|
-
• Use action without execution fields for list/get/models/guide/authoring, refine/refine.show/refine.rollback, mission, watchdog, status, interrupt, stop, resume, steer, script-only scheduling, diagnostics, and other management actions. guide reads shipped current-version docs by topic.
|
|
84
|
+
• Use action without execution fields for list/get/models/guide/authoring, refine/refine.show/refine.rollback, mission, watchdog, status, interrupt, stop, resume, steer, worktree.cleanup (mode:'plan' only), script-only scheduling, diagnostics, and other management actions. guide reads shipped current-version docs by topic.
|
|
69
85
|
• A mission object needs exactly one non-empty title or summary; objective and labels are optional. goal may only be true and requires budget:{tokens}.
|
|
70
86
|
|
|
71
87
|
ASYNC / SAFETY:
|
|
72
88
|
• Omitted async follows asyncByDefault config; set async:true explicitly when async behavior matters. Continue independent work only until its next dependency barrier; consume the result before work that depends on it. Do not sleep or poll merely to wait; use subagent_wait only when this turn must receive results.
|
|
89
|
+
• ${WORKFLOW_RESUME_KEY_GUIDANCE}
|
|
90
|
+
• ${WORKFLOW_OUTPUT_BINDING_GUIDANCE}
|
|
91
|
+
• ${WORKFLOW_HOST_GUIDANCE}
|
|
73
92
|
• Ordinary children are not orchestrators. Keep one writer per cwd/worktree and use fresh read-only reviewers for independent checks.
|
|
74
93
|
• Oracle/advisor consultations use available supervisor dialogue for material unknowns; request one-shot when desired.
|
|
75
94
|
• Status and artifacts live under asyncId/asyncDir with status.json, events.jsonl, output logs, and {action:"status",id:"..."}.`;
|
|
@@ -104,6 +104,7 @@ function compactNestedRun(run: NestedRunSummary | PublicNestedRunSummary, depth
|
|
|
104
104
|
})),
|
|
105
105
|
...(run.asyncDir ? { asyncDir: run.asyncDir } : {}),
|
|
106
106
|
...(run.sessionId ? { sessionId: run.sessionId } : {}),
|
|
107
|
+
...(run.sessionName ? { sessionName: run.sessionName } : {}),
|
|
107
108
|
...(run.sessionFile ? { sessionFile: run.sessionFile } : {}),
|
|
108
109
|
...(run.intercomTarget ? { intercomTarget: run.intercomTarget } : {}),
|
|
109
110
|
...(run.ownerIntercomTarget ? { ownerIntercomTarget: run.ownerIntercomTarget } : {}),
|
|
@@ -132,6 +133,7 @@ function compactNestedRun(run: NestedRunSummary | PublicNestedRunSummary, depth
|
|
|
132
133
|
...(run.error ? { error: run.error } : {}),
|
|
133
134
|
...(run.steps?.length ? { steps: run.steps.slice(0, 12).map((step) => ({
|
|
134
135
|
agent: step.agent,
|
|
136
|
+
...(step.sessionName ? { sessionName: step.sessionName } : {}),
|
|
135
137
|
status: step.status,
|
|
136
138
|
...(step.model ? { model: step.model } : {}),
|
|
137
139
|
...(step.thinking ? { thinking: step.thinking } : {}),
|
package/src/profiles/profiles.ts
CHANGED
|
@@ -335,7 +335,6 @@ function resolveProbeStatus(text: string, timedOut: boolean): ProbeStatus {
|
|
|
335
335
|
|
|
336
336
|
async function probeModel(
|
|
337
337
|
pi: Pick<ExtensionAPI, "exec"> | { exec?: ExtensionAPI["exec"] },
|
|
338
|
-
ctx: Pick<ExtensionContext, "cwd">,
|
|
339
338
|
fullId: string,
|
|
340
339
|
): Promise<{ status: ProbeStatus; message?: string }> {
|
|
341
340
|
if (typeof pi.exec !== "function") {
|
|
@@ -401,7 +400,7 @@ function filterDominatedModels(models: ProviderModelCatalogModel[]): ProviderMod
|
|
|
401
400
|
return models.filter((candidate, index) => !models.some((other, otherIndex) => otherIndex !== index && dominatesModel(other, candidate)));
|
|
402
401
|
}
|
|
403
402
|
|
|
404
|
-
function buildProfileFile(
|
|
403
|
+
function buildProfileFile(models: { cheap: string; medium: string; strong: string }): SubagentProfileFile {
|
|
405
404
|
return {
|
|
406
405
|
subagents: {
|
|
407
406
|
agentOverrides: {
|
|
@@ -544,7 +543,7 @@ export async function refreshProviderModelCatalog(
|
|
|
544
543
|
const fullId = `${modelRecord.provider}/${modelRecord.id}`;
|
|
545
544
|
const probe = options.probe === false
|
|
546
545
|
? { status: "skipped" as const, message: "Live probing disabled." }
|
|
547
|
-
: await probeModel(pi,
|
|
546
|
+
: await probeModel(pi, fullId);
|
|
548
547
|
observedModels.push({ rawModel, modelRecord, fullId, probe });
|
|
549
548
|
}
|
|
550
549
|
const classificationContext = buildClassificationContext(observedModels.map(({ modelRecord }) => ({
|
|
@@ -624,8 +623,8 @@ export async function generateProfilesForProvider(
|
|
|
624
623
|
const dir = ensureSubagentProfilesDir();
|
|
625
624
|
const quotaPath = path.join(dir, `${normalizedProvider}.quota.json`);
|
|
626
625
|
const qualityPath = path.join(dir, `${normalizedProvider}.quality.json`);
|
|
627
|
-
writeJsonFile(quotaPath, buildProfileFile(
|
|
628
|
-
writeJsonFile(qualityPath, buildProfileFile(
|
|
626
|
+
writeJsonFile(quotaPath, buildProfileFile(quotaModels));
|
|
627
|
+
writeJsonFile(qualityPath, buildProfileFile(qualityModels));
|
|
629
628
|
const selectedModels = new Set([...Object.values(quotaModels), ...Object.values(qualityModels)]);
|
|
630
629
|
const selectedHeuristicFallbackCount = profileModels.filter((model) => selectedModels.has(model.fullId) && modelUsesHeuristicClassification(model)).length;
|
|
631
630
|
return { quotaPath, qualityPath, catalogPath, quotaModels, qualityModels, heuristicFallbackCount, selectedHeuristicFallbackCount };
|
|
@@ -649,7 +648,7 @@ export async function checkSubagentProfile(
|
|
|
649
648
|
const probeModelId = modelInfo ? `${modelInfo.fullId}${thinkingSuffix}` : entry.model;
|
|
650
649
|
let probe = probeCache.get(probeModelId);
|
|
651
650
|
if (!probe) {
|
|
652
|
-
probe = await probeModel(pi,
|
|
651
|
+
probe = await probeModel(pi, probeModelId);
|
|
653
652
|
probeCache.set(probeModelId, probe);
|
|
654
653
|
}
|
|
655
654
|
results.push({
|
|
@@ -230,10 +230,10 @@ function runnerReleaseVerdict(owner: ActiveAsyncCapacityOwnerV1, status: AsyncSt
|
|
|
230
230
|
&& proof.runId === owner.runId
|
|
231
231
|
&& proof.runnerProcessInstanceId === owner.runnerProcessInstanceId
|
|
232
232
|
? { state: "releasable", reason: "matching observed process-terminal proof is present" }
|
|
233
|
-
: abandonedRunnerReleaseVerdict(
|
|
233
|
+
: abandonedRunnerReleaseVerdict(status, proof?.state ?? "missing", options);
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
function abandonedRunnerReleaseVerdict(
|
|
236
|
+
function abandonedRunnerReleaseVerdict(status: AsyncStatus, proofState: string, options: CapacityOptions): ActiveAsyncCapacityReleaseVerdict {
|
|
237
237
|
const proofReason = `process-terminal proof is ${proofState}`;
|
|
238
238
|
const thresholdMs = resolveAbandonedSlotReleaseAfterMs(options.abandonedSlotReleaseAfterMs);
|
|
239
239
|
if (thresholdMs === false) return { state: "retained", reason: `${proofReason}; abandoned-timeout policy is disabled` };
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
7
|
import * as fs from "node:fs";
|
|
8
|
-
import * as os from "node:os";
|
|
9
8
|
import * as path from "node:path";
|
|
10
9
|
import { fileURLToPath } from "node:url";
|
|
11
10
|
import { createRequire } from "node:module";
|
|
@@ -14,18 +13,20 @@ import { discoverAgents, formatUnknownAgentError, unknownAgentDiagnosticContext,
|
|
|
14
13
|
import { appendAgentRefinementOverlay } from "../../agents/agent-refinements.ts";
|
|
15
14
|
import { writePrivateAtomicJson } from "../../shared/atomic-json.ts";
|
|
16
15
|
import { currentCompletionOwnerId } from "../../shared/completion-owner.ts";
|
|
16
|
+
import { planChildLaunch, resolveStepBehavior, suppressProgressForReadOnlyTask, type ResolvedStepBehavior } from "../shared/child-launch-plan.ts";
|
|
17
17
|
import { applyThinkingSuffix, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan } from "../shared/pi-args.ts";
|
|
18
18
|
import { injectOutputPathSystemPrompt, injectSingleOutputInstruction, normalizeSingleOutputOverride, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.ts";
|
|
19
|
-
import { buildChainInstructions, isDynamicParallelStep, isParallelStep,
|
|
19
|
+
import { buildChainInstructions, isDynamicParallelStep, isParallelStep, resolveExistingReadPaths, writeInitialProgressFile, type ChainStep, type SequentialStep, type StepOverrides } from "../../shared/settings.ts";
|
|
20
20
|
import type { RunnerStep } from "../shared/parallel-utils.ts";
|
|
21
21
|
import type { ContextMode } from "../shared/context-mode.ts";
|
|
22
22
|
import { resolvePiPackageRoot } from "../shared/pi-spawn.ts";
|
|
23
23
|
import { preflightLaunchCwd } from "../shared/launch-cwd.ts";
|
|
24
24
|
import { resolveNodeExecutable } from "../../shared/node-executable.ts";
|
|
25
|
+
import { backgroundProcessOptions } from "../shared/background-process-options.ts";
|
|
25
26
|
import { buildSkillInjection, normalizeSkillInput, resolveSkillsWithFallback } from "../../agents/skills.ts";
|
|
26
27
|
import { buildAgentMemoryInjection } from "../../agents/agent-memory.ts";
|
|
27
28
|
import { PI_CODING_AGENT_PACKAGE_ROOT_ENV, PROMPT_REDACTED, resolveChildCwd } from "../../shared/utils.ts";
|
|
28
|
-
import { buildModelCandidates, inheritsParentModel, resolveEffectiveSubagentModel,
|
|
29
|
+
import { buildModelCandidates, inheritsParentModel, resolveEffectiveSubagentModel, resolveSubagentModelOverride, type AvailableModelInfo, type ParentModel } from "../shared/model-fallback.ts";
|
|
29
30
|
import { resolveToolTimeoutMs, toolTimeoutFromEnv } from "../shared/tool-timeout.ts";
|
|
30
31
|
import { resolveModelScopesForAgent, type ModelScopeConfig } from "../shared/model-scope.ts";
|
|
31
32
|
import { findModelInfo, resolveEffectiveThinking } from "../../shared/model-info.ts";
|
|
@@ -49,12 +50,12 @@ import {
|
|
|
49
50
|
type MaxOutputConfig,
|
|
50
51
|
type NestedRouteInfo,
|
|
51
52
|
type ResolvedControlConfig,
|
|
52
|
-
type ResolvedTurnBudget,
|
|
53
53
|
type ResolvedToolBudget,
|
|
54
54
|
type RunFanoutBudgetDescriptor,
|
|
55
55
|
type ToolBudgetConfig,
|
|
56
56
|
type SubagentRunMode,
|
|
57
57
|
type SteeringRecoveryDescriptor,
|
|
58
|
+
type WorkflowLaneMetadata,
|
|
58
59
|
type UsageBudgetConfig,
|
|
59
60
|
DIRS,
|
|
60
61
|
SUBAGENT_ASYNC_STARTED_EVENT,
|
|
@@ -65,7 +66,6 @@ import {
|
|
|
65
66
|
} from "../../shared/types.ts";
|
|
66
67
|
import { nestedResultsPath, nestedSummaryFromAsyncStatus, resolveInheritedNestedRouteFromEnv, resolveNestedParentAddressFromEnv, writeNestedEvent } from "../shared/nested-events.ts";
|
|
67
68
|
import { resultFilePath } from "./result-files.ts";
|
|
68
|
-
import { appendTurnBudgetSystemPrompt, initialTurnBudgetState } from "../shared/turn-budget.ts";
|
|
69
69
|
import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
|
|
70
70
|
import { usageBudgetState } from "../shared/usage-budget.ts";
|
|
71
71
|
import type { ImportedAsyncRoot } from "./chain-root-attachment.ts";
|
|
@@ -78,6 +78,7 @@ import { assertAgentAllowedByCapabilityCeiling, decodeSubagentCapabilityCeiling,
|
|
|
78
78
|
import { agentDefinitionDigest, launchBindingDigest } from "../../shared/launch-contract.ts";
|
|
79
79
|
import { resolvePermissionRules, type PermissionConfig } from "../shared/permissions.ts";
|
|
80
80
|
import { normalizeExtensionBindings, omitExtensionBindingsEnv, type ExtensionBindings } from "../shared/extension-bindings.ts";
|
|
81
|
+
import { assertWorkflowLaneKey, normalizeWorkflowLaneMetadata } from "../shared/lane-metadata.ts";
|
|
81
82
|
|
|
82
83
|
const require = createRequire(import.meta.url);
|
|
83
84
|
const piPackageRoot = resolvePiPackageRoot();
|
|
@@ -173,6 +174,7 @@ interface AsyncChainParams {
|
|
|
173
174
|
dynamicFanoutMaxItems?: number;
|
|
174
175
|
maxSubagentDepth: number;
|
|
175
176
|
waitToolEnabled?: boolean;
|
|
177
|
+
waitToolDefaultTimeoutMs?: number;
|
|
176
178
|
worktreeSetupHook?: string;
|
|
177
179
|
worktreeSetupHookTimeoutMs?: number;
|
|
178
180
|
worktreeBaseDir?: string;
|
|
@@ -183,7 +185,6 @@ interface AsyncChainParams {
|
|
|
183
185
|
acceptance?: AcceptanceInput;
|
|
184
186
|
fast?: boolean;
|
|
185
187
|
timeoutMs?: number;
|
|
186
|
-
turnBudget?: ResolvedTurnBudget;
|
|
187
188
|
toolBudget?: ResolvedToolBudget;
|
|
188
189
|
usageBudget?: UsageBudgetConfig;
|
|
189
190
|
configToolBudget?: ResolvedToolBudget;
|
|
@@ -200,6 +201,7 @@ interface AsyncChainParams {
|
|
|
200
201
|
runFanoutBudget?: RunFanoutBudgetDescriptor;
|
|
201
202
|
parentWorkflowRunId?: string;
|
|
202
203
|
workflowKey?: string;
|
|
204
|
+
lane?: WorkflowLaneMetadata;
|
|
203
205
|
activeAsyncCapacity?: ActiveAsyncCapacityHandle;
|
|
204
206
|
}
|
|
205
207
|
|
|
@@ -228,6 +230,7 @@ interface AsyncSingleParams {
|
|
|
228
230
|
reads?: string[] | false;
|
|
229
231
|
outputMode?: "inline" | "file-only";
|
|
230
232
|
outputBaseDir?: string;
|
|
233
|
+
outputClaimPath?: string;
|
|
231
234
|
agentContract?: AgentContract;
|
|
232
235
|
structuredOutputSchema?: JsonSchemaObject;
|
|
233
236
|
modelOverride?: string;
|
|
@@ -237,6 +240,7 @@ interface AsyncSingleParams {
|
|
|
237
240
|
availableModels?: AvailableModelInfo[];
|
|
238
241
|
maxSubagentDepth: number;
|
|
239
242
|
waitToolEnabled?: boolean;
|
|
243
|
+
waitToolDefaultTimeoutMs?: number;
|
|
240
244
|
worktreeSetupHook?: string;
|
|
241
245
|
worktreeSetupHookTimeoutMs?: number;
|
|
242
246
|
worktreeBaseDir?: string;
|
|
@@ -251,7 +255,6 @@ interface AsyncSingleParams {
|
|
|
251
255
|
absoluteDeadlineAt?: number;
|
|
252
256
|
/** Optional per-call hard toolTimeoutMs override (highest precedence). */
|
|
253
257
|
toolTimeoutMs?: number;
|
|
254
|
-
turnBudget?: { maxTurns: number; graceTurns?: number };
|
|
255
258
|
toolBudget?: ResolvedToolBudget | ToolBudgetConfig;
|
|
256
259
|
usageBudget?: UsageBudgetConfig;
|
|
257
260
|
configToolBudget?: ResolvedToolBudget;
|
|
@@ -265,6 +268,7 @@ interface AsyncSingleParams {
|
|
|
265
268
|
runFanoutBudget?: RunFanoutBudgetDescriptor;
|
|
266
269
|
parentWorkflowRunId?: string;
|
|
267
270
|
workflowKey?: string;
|
|
271
|
+
lane?: WorkflowLaneMetadata;
|
|
268
272
|
workflowAwaitAsync?: boolean;
|
|
269
273
|
activeAsyncCapacity?: ActiveAsyncCapacityHandle;
|
|
270
274
|
externalJobFollowUp?: {
|
|
@@ -303,6 +307,7 @@ export interface AsyncRunnerStepBuildParams {
|
|
|
303
307
|
dynamicFanoutMaxItems?: number;
|
|
304
308
|
maxSubagentDepth: number;
|
|
305
309
|
waitToolEnabled?: boolean;
|
|
310
|
+
waitToolDefaultTimeoutMs?: number;
|
|
306
311
|
worktreeBaseDir?: string;
|
|
307
312
|
asyncDir: string;
|
|
308
313
|
outputBaseDir?: string;
|
|
@@ -558,9 +563,8 @@ function spawnRunner(cfg: object, suffix: string, cwd: string, initialStatus: Om
|
|
|
558
563
|
}
|
|
559
564
|
const proc = spawn(nodeCommand, [jitiCliPath, runner, cfgPath], {
|
|
560
565
|
cwd,
|
|
561
|
-
|
|
566
|
+
...backgroundProcessOptions(),
|
|
562
567
|
stdio: ["ignore", stdoutFd ?? "ignore", stderrFd ?? "ignore"],
|
|
563
|
-
windowsHide: true,
|
|
564
568
|
env: {
|
|
565
569
|
...omitExtensionBindingsEnv(process.env),
|
|
566
570
|
...(piPackageRoot ? { [PI_CODING_AGENT_PACKAGE_ROOT_ENV]: piPackageRoot } : {}),
|
|
@@ -804,19 +808,21 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
804
808
|
envValue: params.toolTimeoutMsEnv ?? toolTimeoutFromEnv(),
|
|
805
809
|
});
|
|
806
810
|
if (resolvedToolTimeout.error) throw new AsyncStartValidationError(resolvedToolTimeout.error);
|
|
807
|
-
const
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
811
|
+
const launchPlan = planChildLaunch({
|
|
812
|
+
agentConfig: a,
|
|
813
|
+
stepOverrides: buildStepOverrides(s),
|
|
814
|
+
task: s.task,
|
|
815
|
+
originalTask,
|
|
816
|
+
runnerCwd,
|
|
817
|
+
runtimeCwd: ctx.cwd,
|
|
818
|
+
stepCwdInput: s.cwd,
|
|
819
|
+
behaviorCwd,
|
|
820
|
+
chainSkills,
|
|
821
|
+
outputBaseDir,
|
|
822
|
+
parallelOutputNamespace,
|
|
823
|
+
resolvedBehavior,
|
|
824
|
+
});
|
|
825
|
+
const { stepCwd, instructionCwd, readExistenceCwd, behavior, namespaceOutputPath, outputPath, skillNames } = launchPlan;
|
|
820
826
|
const { resolved: resolvedSkills, missing: missingSkills } = resolveSkillsWithFallback(
|
|
821
827
|
skillNames,
|
|
822
828
|
stepCwd,
|
|
@@ -841,7 +847,6 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
841
847
|
const isFirstProgressAgent = behavior.progress && !progressPrecreated && !progressInstructionCreated;
|
|
842
848
|
if (behavior.progress) progressInstructionCreated = true;
|
|
843
849
|
const progressInstructions = buildChainInstructions({ ...behavior, output: false, reads: false }, progressDir, isFirstProgressAgent);
|
|
844
|
-
const outputPath = resolveSingleOutputPath(behavior.output, ctx.cwd, instructionCwd, outputBaseDir);
|
|
845
850
|
if (!namespaceOutputPath) systemPrompt = injectOutputPathSystemPrompt(systemPrompt, outputPath, a);
|
|
846
851
|
const validationError = validateFileOnlyOutputMode(behavior.outputMode, outputPath, `Async step (${s.agent})`);
|
|
847
852
|
if (validationError) throw new AsyncStartValidationError(validationError);
|
|
@@ -896,6 +901,7 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
896
901
|
const fast = s.fast ?? params.fast ?? a.fast;
|
|
897
902
|
const toolPlan = resolvePiLaunchToolPlan({
|
|
898
903
|
tools: a.tools,
|
|
904
|
+
allowNestedSubagents: a.allowNestedSubagents,
|
|
899
905
|
extensions: a.extensions,
|
|
900
906
|
subagentOnlyExtensions: a.subagentOnlyExtensions,
|
|
901
907
|
mcpDirectTools: a.mcpDirectTools,
|
|
@@ -957,6 +963,7 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
957
963
|
...(primaryModelFromParent ? { skipPrimaryModelVerification: true } : {}),
|
|
958
964
|
...(availableModels && availableModels.length > 0 ? { modelVerificationRegistry: availableModels } : {}),
|
|
959
965
|
tools: a.tools,
|
|
966
|
+
allowNestedSubagents: a.allowNestedSubagents,
|
|
960
967
|
extensions: a.extensions,
|
|
961
968
|
subagentOnlyExtensions: a.subagentOnlyExtensions,
|
|
962
969
|
mcpDirectTools: a.mcpDirectTools,
|
|
@@ -976,6 +983,7 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
976
983
|
timeoutMs: a.defaultTimeoutMs ?? DEFAULT_ASYNC_TIMEOUT_MS,
|
|
977
984
|
toolTimeoutMs: resolvedToolTimeout.toolTimeoutMs,
|
|
978
985
|
waitToolEnabled: params.waitToolEnabled,
|
|
986
|
+
waitToolDefaultTimeoutMs: params.waitToolDefaultTimeoutMs,
|
|
979
987
|
effectiveAcceptance: resolveEffectiveAcceptance({
|
|
980
988
|
explicit: s.acceptance,
|
|
981
989
|
agentName: s.agent,
|
|
@@ -1203,6 +1211,7 @@ export function executeAsyncChain(
|
|
|
1203
1211
|
dynamicFanoutMaxItems: params.dynamicFanoutMaxItems,
|
|
1204
1212
|
maxSubagentDepth,
|
|
1205
1213
|
waitToolEnabled: params.waitToolEnabled,
|
|
1214
|
+
waitToolDefaultTimeoutMs: params.waitToolDefaultTimeoutMs,
|
|
1206
1215
|
worktreeBaseDir,
|
|
1207
1216
|
asyncDir,
|
|
1208
1217
|
fast: params.fast,
|
|
@@ -1224,7 +1233,6 @@ export function executeAsyncChain(
|
|
|
1224
1233
|
}
|
|
1225
1234
|
const { steps, runnerCwd, workflowGraph, eventChain } = built;
|
|
1226
1235
|
const deadlineAt = params.timeoutMs !== undefined ? Date.now() + params.timeoutMs : undefined;
|
|
1227
|
-
const initialTurnBudget = params.turnBudget ? initialTurnBudgetState(params.turnBudget) : undefined;
|
|
1228
1236
|
const initialUsageBudget = usageBudgetState(params.usageBudget, undefined);
|
|
1229
1237
|
let childTargetIndex = 0;
|
|
1230
1238
|
const childIntercomTargets = childIntercomTarget ? steps.flatMap((step) => {
|
|
@@ -1281,7 +1289,6 @@ export function executeAsyncChain(
|
|
|
1281
1289
|
worktreeSetupHookTimeoutMs,
|
|
1282
1290
|
worktreeBaseDir,
|
|
1283
1291
|
controlConfig,
|
|
1284
|
-
turnBudget: params.turnBudget,
|
|
1285
1292
|
toolBudget: params.toolBudget,
|
|
1286
1293
|
usageBudget: params.usageBudget,
|
|
1287
1294
|
controlIntercomTarget,
|
|
@@ -1400,7 +1407,6 @@ export function executeAsyncChain(
|
|
|
1400
1407
|
chainStepCount: eventChain.length,
|
|
1401
1408
|
parallelGroups,
|
|
1402
1409
|
...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}),
|
|
1403
|
-
...(initialTurnBudget ? { turnBudget: initialTurnBudget } : {}),
|
|
1404
1410
|
startedAt: now,
|
|
1405
1411
|
lastUpdate: now,
|
|
1406
1412
|
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
@@ -1431,7 +1437,6 @@ export function executeAsyncChain(
|
|
|
1431
1437
|
asyncDir,
|
|
1432
1438
|
...(sessionRoot ? { sessionRoot } : {}),
|
|
1433
1439
|
...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}),
|
|
1434
|
-
...(initialTurnBudget ? { turnBudget: initialTurnBudget } : {}),
|
|
1435
1440
|
...(initialUsageBudget ? { usageBudget: initialUsageBudget } : {}),
|
|
1436
1441
|
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
1437
1442
|
...(params.parentWorkflowRunId ? { parentWorkflowRunId: params.parentWorkflowRunId } : {}),
|
|
@@ -1448,7 +1453,7 @@ export function executeAsyncChain(
|
|
|
1448
1453
|
|
|
1449
1454
|
return {
|
|
1450
1455
|
content: [{ type: "text", text: formatAsyncStartedMessage(`Async ${resultMode}: ${chainDesc} [${id}]`, ctx.interactive === true) }],
|
|
1451
|
-
details: { mode: resultMode, runId: id, results: [], asyncId: id, asyncDir, workflowGraph, ...(capabilityCeiling ? { capabilityCeiling } : {}), ...(params.parentWorkflowRunId ? { parentWorkflowRunId: params.parentWorkflowRunId } : {}), ...(params.workflowKey ? { workflowKey: params.workflowKey } : {}), ...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}), ...(params.
|
|
1456
|
+
details: { mode: resultMode, runId: id, results: [], asyncId: id, asyncDir, workflowGraph, ...(capabilityCeiling ? { capabilityCeiling } : {}), ...(params.parentWorkflowRunId ? { parentWorkflowRunId: params.parentWorkflowRunId } : {}), ...(params.workflowKey ? { workflowKey: params.workflowKey } : {}), ...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}), ...(params.toolBudget ? { toolBudget: params.toolBudget } : {}), ...(initialUsageBudget ? { usageBudget: initialUsageBudget } : {}) },
|
|
1452
1457
|
};
|
|
1453
1458
|
}
|
|
1454
1459
|
|
|
@@ -1483,6 +1488,13 @@ export function executeAsyncSingle(
|
|
|
1483
1488
|
childIntercomTarget,
|
|
1484
1489
|
nestedRoute,
|
|
1485
1490
|
} = params;
|
|
1491
|
+
let lane: WorkflowLaneMetadata | undefined;
|
|
1492
|
+
try {
|
|
1493
|
+
lane = normalizeWorkflowLaneMetadata(params.lane, "lane");
|
|
1494
|
+
assertWorkflowLaneKey(lane, params.workflowKey, "lane");
|
|
1495
|
+
} catch (error) {
|
|
1496
|
+
return formatAsyncStartError("single", error instanceof Error ? error.message : String(error));
|
|
1497
|
+
}
|
|
1486
1498
|
const task = params.task ?? "";
|
|
1487
1499
|
let extensionBindings: ExtensionBindings | undefined;
|
|
1488
1500
|
try {
|
|
@@ -1616,7 +1628,6 @@ export function executeAsyncSingle(
|
|
|
1616
1628
|
});
|
|
1617
1629
|
if (resolvedToolTimeout.error) return formatAsyncStartError("single", resolvedToolTimeout.error);
|
|
1618
1630
|
const toolTimeoutMs = resolvedToolTimeout.toolTimeoutMs;
|
|
1619
|
-
const initialTurnBudget = params.turnBudget ? initialTurnBudgetState(params.turnBudget) : undefined;
|
|
1620
1631
|
const initialUsageBudget = usageBudgetState(params.usageBudget, undefined);
|
|
1621
1632
|
const resolvedSessionDir = params.sessionDir ?? (sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined);
|
|
1622
1633
|
const structuredOutput = params.structuredOutputSchema
|
|
@@ -1639,9 +1650,9 @@ export function executeAsyncSingle(
|
|
|
1639
1650
|
return formatAsyncStartError("single", error instanceof Error ? error.message : String(error));
|
|
1640
1651
|
}
|
|
1641
1652
|
}
|
|
1642
|
-
const effectiveSystemPrompt = appendTurnBudgetSystemPrompt(systemPrompt, params.turnBudget);
|
|
1643
1653
|
const toolPlan = resolvePiLaunchToolPlan({
|
|
1644
1654
|
tools: agentConfig.tools,
|
|
1655
|
+
allowNestedSubagents: agentConfig.allowNestedSubagents,
|
|
1645
1656
|
extensions: agentConfig.extensions,
|
|
1646
1657
|
subagentOnlyExtensions: agentConfig.subagentOnlyExtensions,
|
|
1647
1658
|
mcpDirectTools: agentConfig.mcpDirectTools,
|
|
@@ -1680,7 +1691,7 @@ export function executeAsyncSingle(
|
|
|
1680
1691
|
...((params.fast ?? agentConfig.fast) !== undefined ? { fast: params.fast ?? agentConfig.fast } : {}),
|
|
1681
1692
|
...(resolveEffectiveThinking(model, effectiveThinking) ? { thinking: resolveEffectiveThinking(model, effectiveThinking) } : {}),
|
|
1682
1693
|
...(thinkingCeiling ? { thinkingCeiling } : {}),
|
|
1683
|
-
systemPrompt
|
|
1694
|
+
systemPrompt,
|
|
1684
1695
|
systemPromptMode: agentConfig.systemPromptMode,
|
|
1685
1696
|
inheritProjectContext: agentConfig.inheritProjectContext,
|
|
1686
1697
|
inheritGlobalContext: agentConfig.inheritGlobalContext,
|
|
@@ -1706,6 +1717,7 @@ export function executeAsyncSingle(
|
|
|
1706
1717
|
const recoveryAgentConfig = params.recoveryAgentConfig ?? agentConfig;
|
|
1707
1718
|
const recoveryDescriptor: SteeringRecoveryDescriptor = {
|
|
1708
1719
|
version: 1,
|
|
1720
|
+
...(lane ? { lane } : {}),
|
|
1709
1721
|
launchContractDigest,
|
|
1710
1722
|
...(extensionBindings ? { extensionBindings } : {}),
|
|
1711
1723
|
runFanoutBudget,
|
|
@@ -1723,6 +1735,7 @@ export function executeAsyncSingle(
|
|
|
1723
1735
|
...(effectiveThinking ? { thinking: resolveEffectiveThinking(model, effectiveThinking) } : {}),
|
|
1724
1736
|
...(thinkingCeiling ? { thinkingCeiling } : {}),
|
|
1725
1737
|
...(recoveryAgentConfig.tools ? { tools: [...recoveryAgentConfig.tools] } : {}),
|
|
1738
|
+
...(recoveryAgentConfig.allowNestedSubagents !== undefined ? { allowNestedSubagents: recoveryAgentConfig.allowNestedSubagents } : {}),
|
|
1726
1739
|
...(recoveryAgentConfig.extensions ? { extensions: [...recoveryAgentConfig.extensions] } : {}),
|
|
1727
1740
|
...(recoveryAgentConfig.subagentOnlyExtensions ? { subagentOnlyExtensions: [...recoveryAgentConfig.subagentOnlyExtensions] } : {}),
|
|
1728
1741
|
...(recoveryAgentConfig.mcpDirectTools ? { mcpDirectTools: [...recoveryAgentConfig.mcpDirectTools] } : {}),
|
|
@@ -1745,7 +1758,6 @@ export function executeAsyncSingle(
|
|
|
1745
1758
|
...(params.context ? { context: params.context } : {}),
|
|
1746
1759
|
...(params.intercomBridge !== undefined ? { intercomBridge: params.intercomBridge } : {}),
|
|
1747
1760
|
...(deadlineAt !== undefined ? { absoluteDeadlineAt: deadlineAt } : {}),
|
|
1748
|
-
...(initialTurnBudget ? { initialTurnBudget: { maxTurns: initialTurnBudget.maxTurns, graceTurns: initialTurnBudget.graceTurns } } : {}),
|
|
1749
1761
|
...(resolvedToolBudget.budget ? { initialToolBudget: resolvedToolBudget.budget } : {}),
|
|
1750
1762
|
maxSubagentDepth: resolveChildMaxSubagentDepth(maxSubagentDepth, recoveryAgentConfig.maxSubagentDepth),
|
|
1751
1763
|
...(maxOutput ? { maxOutput } : {}),
|
|
@@ -1790,6 +1802,7 @@ export function executeAsyncSingle(
|
|
|
1790
1802
|
...(params.modelOverrideFromParent ? { skipPrimaryModelVerification: true } : {}),
|
|
1791
1803
|
...(availableModels && availableModels.length > 0 ? { modelVerificationRegistry: availableModels } : {}),
|
|
1792
1804
|
tools: agentConfig.tools,
|
|
1805
|
+
allowNestedSubagents: agentConfig.allowNestedSubagents,
|
|
1793
1806
|
extensions: agentConfig.extensions,
|
|
1794
1807
|
subagentOnlyExtensions: agentConfig.subagentOnlyExtensions,
|
|
1795
1808
|
mcpDirectTools: agentConfig.mcpDirectTools,
|
|
@@ -1804,10 +1817,12 @@ export function executeAsyncSingle(
|
|
|
1804
1817
|
inheritSkills: agentConfig.inheritSkills,
|
|
1805
1818
|
skills: resolvedSkills.map((r) => r.name),
|
|
1806
1819
|
outputPath,
|
|
1820
|
+
...(params.outputClaimPath ? { outputClaimPath: params.outputClaimPath } : {}),
|
|
1807
1821
|
outputMode,
|
|
1808
1822
|
...(!externalRunner && sessionFile ? { sessionFile } : {}),
|
|
1809
1823
|
maxSubagentDepth: resolveChildMaxSubagentDepth(maxSubagentDepth, agentConfig.maxSubagentDepth),
|
|
1810
1824
|
waitToolEnabled: params.waitToolEnabled,
|
|
1825
|
+
waitToolDefaultTimeoutMs: params.waitToolDefaultTimeoutMs,
|
|
1811
1826
|
...(params.agentContract ? { agentContract: params.agentContract } : {}),
|
|
1812
1827
|
definitionDigest: agentDefinitionDigest(agentConfig),
|
|
1813
1828
|
launchBindingTask: task,
|
|
@@ -1819,6 +1834,7 @@ export function executeAsyncSingle(
|
|
|
1819
1834
|
...(params.structuredOutputSchema ? { structuredOutputSchema: params.structuredOutputSchema } : {}),
|
|
1820
1835
|
...(resolvedToolBudget.budget ? { toolBudget: resolvedToolBudget.budget } : {}),
|
|
1821
1836
|
...(params.worktree === true ? { worktree: true } : {}),
|
|
1837
|
+
...(lane ? { lane } : {}),
|
|
1822
1838
|
},
|
|
1823
1839
|
],
|
|
1824
1840
|
resultPath: params.parentWorkflowRunId !== undefined && (params.revivalLease !== undefined || params.workflowAwaitAsync === true)
|
|
@@ -1844,7 +1860,6 @@ export function executeAsyncSingle(
|
|
|
1844
1860
|
timeoutMs,
|
|
1845
1861
|
deadlineAt,
|
|
1846
1862
|
toolTimeoutMs,
|
|
1847
|
-
turnBudget: params.turnBudget,
|
|
1848
1863
|
toolBudget: params.toolBudget,
|
|
1849
1864
|
usageBudget: params.usageBudget,
|
|
1850
1865
|
controlIntercomTarget,
|
|
@@ -1855,6 +1870,7 @@ export function executeAsyncSingle(
|
|
|
1855
1870
|
runFanoutBudget,
|
|
1856
1871
|
...(params.parentWorkflowRunId ? { parentWorkflowRunId: params.parentWorkflowRunId } : {}),
|
|
1857
1872
|
...(params.workflowKey ? { workflowKey: params.workflowKey } : {}),
|
|
1873
|
+
...(lane ? { lane } : {}),
|
|
1858
1874
|
...(params.revivalLease ? { revivalLease: params.revivalLease } : {}),
|
|
1859
1875
|
nestedRoute: nestedRoute ?? inheritedNestedRoute,
|
|
1860
1876
|
nestedSelf: inheritedNestedRoute && nestedAddress ? {
|
|
@@ -1877,7 +1893,8 @@ export function executeAsyncSingle(
|
|
|
1877
1893
|
lastUpdate: initialStatusAt,
|
|
1878
1894
|
currentStep: 0,
|
|
1879
1895
|
chainStepCount: 1,
|
|
1880
|
-
|
|
1896
|
+
...(lane ? { lane } : {}),
|
|
1897
|
+
steps: [{ agent, status: "pending", ...(lane ? { lane } : {}), ...(model ? { model } : {}), ...(contextLimit !== undefined ? { contextLimit } : {}) }],
|
|
1881
1898
|
},
|
|
1882
1899
|
path.join(asyncDir, "status.json"),
|
|
1883
1900
|
(proof) => emitProcessTerminalEvent(ctx, proof),
|
|
@@ -1927,7 +1944,6 @@ export function executeAsyncSingle(
|
|
|
1927
1944
|
agents: [agent],
|
|
1928
1945
|
chainStepCount: 1,
|
|
1929
1946
|
...(timeoutMs !== undefined ? { timeoutMs, deadlineAt } : {}),
|
|
1930
|
-
...(initialTurnBudget ? { turnBudget: initialTurnBudget } : {}),
|
|
1931
1947
|
startedAt: now,
|
|
1932
1948
|
lastUpdate: now,
|
|
1933
1949
|
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
@@ -1955,7 +1971,6 @@ export function executeAsyncSingle(
|
|
|
1955
1971
|
...(params.parentWorkflowRunId ? { parentWorkflowRunId: params.parentWorkflowRunId } : {}),
|
|
1956
1972
|
...(params.workflowKey ? { workflowKey: params.workflowKey } : {}),
|
|
1957
1973
|
...(timeoutMs !== undefined ? { timeoutMs, deadlineAt } : {}),
|
|
1958
|
-
...(initialTurnBudget ? { turnBudget: initialTurnBudget } : {}),
|
|
1959
1974
|
...(initialUsageBudget ? { usageBudget: initialUsageBudget } : {}),
|
|
1960
1975
|
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
1961
1976
|
nestedRoute,
|
|
@@ -1964,6 +1979,6 @@ export function executeAsyncSingle(
|
|
|
1964
1979
|
|
|
1965
1980
|
return {
|
|
1966
1981
|
content: [{ type: "text", text: formatAsyncStartedMessage(`Async: ${agent} [${id}]`, ctx.interactive === true) }],
|
|
1967
|
-
details: { mode: "single", runId: id, results: [], asyncId: id, asyncDir, launchContractDigest, launchResolvedExtensions, ...(capabilityCeiling ? { capabilityCeiling } : {}), ...(params.context ? { context: params.context } : {}), ...(timeoutMs !== undefined ? { timeoutMs, deadlineAt } : {}), ...(params.
|
|
1982
|
+
details: { mode: "single", runId: id, results: [], asyncId: id, asyncDir, launchContractDigest, launchResolvedExtensions, ...(capabilityCeiling ? { capabilityCeiling } : {}), ...(params.context ? { context: params.context } : {}), ...(timeoutMs !== undefined ? { timeoutMs, deadlineAt } : {}), ...(params.toolBudget ? { toolBudget: resolvedToolBudget.budget ?? params.toolBudget } : {}), ...(initialUsageBudget ? { usageBudget: initialUsageBudget } : {}) } as Details,
|
|
1968
1983
|
};
|
|
1969
1984
|
}
|