pi-subagents 0.55.0 → 0.56.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 +28 -3
- package/docs/models.md +6 -0
- package/package.json +1 -1
- package/src/agents/agent-serializer.ts +2 -0
- package/src/agents/agents.ts +23 -1
- package/src/api/preflight.ts +20 -1
- package/src/extension/schemas.ts +5 -0
- package/src/runs/background/async-execution.ts +48 -18
- package/src/runs/background/async-resume.ts +3 -0
- package/src/runs/background/subagent-runner.ts +83 -11
- package/src/runs/foreground/execution.ts +35 -6
- package/src/runs/foreground/foreground-history.ts +3 -2
- package/src/runs/foreground/subagent-executor.ts +59 -8
- package/src/runs/foreground/workflow-detach-reconcile.ts +15 -6
- package/src/runs/shared/acceptance.ts +10 -5
- package/src/runs/shared/agent-contract.ts +1 -1
- package/src/runs/shared/completion-guard.ts +3 -2
- package/src/runs/shared/dynamic-fanout.ts +1 -1
- package/src/runs/shared/extension-bindings.ts +78 -0
- package/src/runs/shared/external-cli-runner.ts +2 -0
- package/src/runs/shared/fast-mode-extension.ts +10 -0
- package/src/runs/shared/model-exclusions.ts +2 -1
- package/src/runs/shared/model-fallback.ts +2 -7
- package/src/runs/shared/mutation-evidence.ts +145 -0
- package/src/runs/shared/parallel-utils.ts +3 -0
- package/src/runs/shared/pi-args.ts +47 -0
- package/src/runs/shared/structured-output.ts +18 -4
- package/src/runs/shared/subagent-prompt-runtime.ts +9 -5
- package/src/shared/launch-contract.ts +6 -0
- package/src/shared/settings.ts +6 -1
- package/src/shared/types.ts +48 -0
- package/src/workflows/scripted-workflow.ts +50 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [0.56.0] - 2026-08-23
|
|
6
|
+
|
|
7
|
+
### Highlights
|
|
8
|
+
- Run allowlisted OpenAI-Codex subagents with opt-in `fast` mode when you want priority service tier.
|
|
9
|
+
- Pass bounded extension metadata into native child launches without leaking that authority to external runners.
|
|
10
|
+
- Workflow scripts are easier to read when child results are stringified or returned.
|
|
11
|
+
- Completion guards now use safer tracked-file evidence, including large dirty files and interrupted runs.
|
|
12
|
+
- Model verification is less fragile for provider-qualified and variant-tagged model ids.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- Add opt-in `fast: true` launches for allowlisted native OpenAI-Codex subagents, using OpenAI's priority service tier.
|
|
16
|
+
- Add bounded namespaced extension bindings to child launch contracts. Thanks to [@FL03](https://github.com/FL03) for #1410.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- Render workflow child results as useful text when scripts stringify `runs.all` or awaited `runs.run` result objects.
|
|
20
|
+
- Keep checked acceptance compatible with strict workflow child `outputSchema` results. Thanks to [@rtbe](https://github.com/rtbe) for #1406.
|
|
21
|
+
- Use bounded tracked-file mutation evidence for implementation completion guards, including files that were already dirty when the child started. Thanks to [@rtbe](https://github.com/rtbe) for #1407.
|
|
22
|
+
- Bind fast mode into launch contract provenance and keep large tracked-file mutation evidence precise.
|
|
23
|
+
- Add timeout recovery summaries with changed tracked files, active child state, and session/artifact paths. Thanks to [@rtbe](https://github.com/rtbe) for #1409.
|
|
24
|
+
- Fail closed when reviewer runs are interrupted or detached workflow children settle without persisted top-level continuation proof. Thanks to [@rtbe](https://github.com/rtbe) for #1408.
|
|
25
|
+
- Stop flagging awaited `.then()` workflow chains as unawaited when a handler returns another child launch.
|
|
26
|
+
- Preserve variant-tagged model ids during verification and fallback exclusion parsing. Thanks to [@rafafortes](https://github.com/rafafortes) for #1420.
|
|
27
|
+
|
|
3
28
|
## [0.55.0] - 2026-08-23
|
|
4
29
|
|
|
5
30
|
### Highlights
|
|
6
31
|
- Stop a single stuck child in an async workflow without stopping the whole run.
|
|
7
|
-
- Continue finished external jobs, like
|
|
32
|
+
- Continue finished external jobs, like `gpt-pro` from [Surf](https://github.com/nicobailon/surf-cli/), with follow-up requests through `resume`.
|
|
8
33
|
- Cap child thinking with `subagents.maxThinking` and set a preferred default provider for bare model ids.
|
|
9
34
|
- Scripted workflow outputs now land in the run's managed artifact directory instead of the repository root.
|
|
10
35
|
- Child launches fail fast with clear reasons when requested models or write tools are unavailable.
|
|
@@ -31,10 +56,10 @@
|
|
|
31
56
|
- Fail child launch attempts when the runtime lacks requested core write tools or an implementation worker has only read-only launch tools, including workflow children that inherit a read-only capability ceiling.
|
|
32
57
|
- Let read-only reviewer acceptance rely on the parent-side staged-file check instead of requiring child-reported `noStagedFiles` evidence.
|
|
33
58
|
- Run public single-child launches directly instead of wrapping them in a workflow, so async external-job agents do not show a completed workflow before the real provider job finishes.
|
|
34
|
-
- Start omitted-`async` public external-runner single-child launches in the supported background mode, so package agents such as
|
|
59
|
+
- Start omitted-`async` public external-runner single-child launches in the supported background mode, so package agents such as `gpt-pro` from [Surf](https://github.com/nicobailon/surf-cli/) do not fail as foreground requests.
|
|
35
60
|
- Let workflow scripts await omitted-`async` external-runner children by launching them in the background internally and returning their terminal result.
|
|
36
61
|
- Report helpful workflow errors when `runs.all(...)` results are read as keyed objects instead of ordered arrays. Thanks to [@ravshansbox](https://github.com/ravshansbox) for #1351.
|
|
37
|
-
- Clarify that Council Mode can include installed external-runner advisors such as
|
|
62
|
+
- Clarify that Council Mode can include installed external-runner advisors such as `gpt-pro` from [Surf](https://github.com/nicobailon/surf-cli/) when the `surf-cli` Pi extension has registered `surf-oracle`, with text JSON reports instead of `outputSchema`.
|
|
38
63
|
|
|
39
64
|
## [0.54.0] - 2026-08-21
|
|
40
65
|
|
package/docs/models.md
CHANGED
|
@@ -60,6 +60,12 @@ For a persistent role override with a backup model for provider failures:
|
|
|
60
60
|
|
|
61
61
|
`subagents.defaultModel` and `subagents.defaultProvider` apply to builtin, package, user, and project agents. `defaultModel` fills only agents that do not set `model` in frontmatter. `defaultProvider` is also applied to frontmatter and override models so bare ids resolve against the intended provider. Per-run model overrides and `agentOverrides.<name>.model` still win, and explicit agent frontmatter still wins over the global default. The same `agentOverrides` block can change `tools`, `skills`, inherited context, prompt text, or disable a builtin (see [agents.md](agents.md)). Matching user and project agents also receive override fields that their frontmatter leaves unset, so a shared project config agent can keep the persona while local settings choose the model or provider.
|
|
62
62
|
|
|
63
|
+
## Fast mode
|
|
64
|
+
|
|
65
|
+
Set `fast: true` on a run, in agent frontmatter, or in `subagents.agentOverrides.<name>.fast` to request the OpenAI priority service tier for supported native OpenAI-Codex children. This can use a higher quota tier or cost more. It is off by default.
|
|
66
|
+
|
|
67
|
+
Fast mode fails before launch unless every resolved model candidate is on the allowlist. The current allowlist is `openai-codex/gpt-5.6-luna` and `openai-codex/gpt-5.6-sol`. External runners, Anthropic models, and other providers do not use fast mode.
|
|
68
|
+
|
|
63
69
|
## Recommended model tiering (optional)
|
|
64
70
|
|
|
65
71
|
A setup that works well in practice: route agents by task shape instead of running everything on one model. Four tiers:
|
package/package.json
CHANGED
|
@@ -11,6 +11,7 @@ export const KNOWN_FIELDS = new Set([
|
|
|
11
11
|
"tools",
|
|
12
12
|
"model",
|
|
13
13
|
"fallbackModels",
|
|
14
|
+
"fast",
|
|
14
15
|
"thinking",
|
|
15
16
|
"systemPromptMode",
|
|
16
17
|
"inheritProjectContext",
|
|
@@ -71,6 +72,7 @@ export function serializeAgent(config: AgentConfig, options: SerializeAgentOptio
|
|
|
71
72
|
if (config.model || preserve("model")) lines.push(`model: ${config.model ?? ""}`);
|
|
72
73
|
const fallbackModelsValue = joinComma(config.fallbackModels);
|
|
73
74
|
if (fallbackModelsValue || preserve("fallbackModels")) lines.push(`fallbackModels: ${fallbackModelsValue ?? ""}`);
|
|
75
|
+
if (config.fast === true || preserve("fast")) lines.push(`fast: ${config.fast === undefined ? "" : config.fast ? "true" : "false"}`);
|
|
74
76
|
if ((config.thinking && (config.thinking !== "off" || preserve("thinking"))) || (!config.thinking && preserve("thinking"))) {
|
|
75
77
|
lines.push(`thinking: ${config.thinking ?? ""}`);
|
|
76
78
|
}
|
package/src/agents/agents.ts
CHANGED
|
@@ -57,6 +57,7 @@ export interface BuiltinAgentOverrideBase {
|
|
|
57
57
|
model?: string;
|
|
58
58
|
modelProvider?: string;
|
|
59
59
|
fallbackModels?: string[];
|
|
60
|
+
fast?: boolean;
|
|
60
61
|
thinking?: string | false;
|
|
61
62
|
systemPromptMode: SystemPromptMode;
|
|
62
63
|
inheritProjectContext: boolean;
|
|
@@ -83,6 +84,7 @@ interface BuiltinAgentOverrideConfig {
|
|
|
83
84
|
model?: string | false;
|
|
84
85
|
defaultProvider?: string | false;
|
|
85
86
|
fallbackModels?: string[] | false;
|
|
87
|
+
fast?: boolean;
|
|
86
88
|
thinking?: string | false;
|
|
87
89
|
systemPromptMode?: SystemPromptMode;
|
|
88
90
|
inheritProjectContext?: boolean;
|
|
@@ -128,6 +130,7 @@ export interface AgentConfig {
|
|
|
128
130
|
model?: string;
|
|
129
131
|
modelProvider?: string;
|
|
130
132
|
fallbackModels?: string[];
|
|
133
|
+
fast?: boolean;
|
|
131
134
|
thinking?: string | false;
|
|
132
135
|
systemPromptMode: SystemPromptMode;
|
|
133
136
|
inheritProjectContext: boolean;
|
|
@@ -640,6 +643,7 @@ function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
|
|
|
640
643
|
...(agent.model !== undefined ? { model: agent.model } : {}),
|
|
641
644
|
...(agent.modelProvider !== undefined ? { modelProvider: agent.modelProvider } : {}),
|
|
642
645
|
...(agent.fallbackModels ? { fallbackModels: [...agent.fallbackModels] } : {}),
|
|
646
|
+
...(agent.fast !== undefined ? { fast: agent.fast } : {}),
|
|
643
647
|
...(agent.thinking !== undefined ? { thinking: agent.thinking } : {}),
|
|
644
648
|
systemPromptMode: agent.systemPromptMode,
|
|
645
649
|
inheritProjectContext: agent.inheritProjectContext,
|
|
@@ -670,6 +674,7 @@ function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentO
|
|
|
670
674
|
...(override.fallbackModels !== undefined
|
|
671
675
|
? { fallbackModels: override.fallbackModels === false ? false : [...override.fallbackModels] }
|
|
672
676
|
: {}),
|
|
677
|
+
...(override.fast !== undefined ? { fast: override.fast } : {}),
|
|
673
678
|
...(override.thinking !== undefined ? { thinking: override.thinking } : {}),
|
|
674
679
|
...(override.systemPromptMode !== undefined ? { systemPromptMode: override.systemPromptMode } : {}),
|
|
675
680
|
...(override.inheritProjectContext !== undefined ? { inheritProjectContext: override.inheritProjectContext } : {}),
|
|
@@ -864,6 +869,11 @@ function parseBuiltinOverrideEntry(
|
|
|
864
869
|
else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'model'; expected a string or false.`);
|
|
865
870
|
}
|
|
866
871
|
|
|
872
|
+
if ("fast" in input) {
|
|
873
|
+
if (typeof input.fast === "boolean") override.fast = input.fast;
|
|
874
|
+
else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'fast'; expected a boolean.`);
|
|
875
|
+
}
|
|
876
|
+
|
|
867
877
|
if ("thinking" in input) {
|
|
868
878
|
if (typeof input.thinking === "string" || input.thinking === false) override.thinking = input.thinking;
|
|
869
879
|
else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'thinking'; expected a string or false.`);
|
|
@@ -1195,6 +1205,7 @@ function applyBuiltinOverride(
|
|
|
1195
1205
|
else next.modelProvider = override.defaultProvider;
|
|
1196
1206
|
}
|
|
1197
1207
|
if (override.fallbackModels !== undefined) { if (override.fallbackModels === false) delete next.fallbackModels; else next.fallbackModels = [...override.fallbackModels]; }
|
|
1208
|
+
if (override.fast !== undefined) next.fast = override.fast;
|
|
1198
1209
|
if (override.thinking !== undefined) { if (override.thinking === false) delete next.thinking; else next.thinking = override.thinking; }
|
|
1199
1210
|
if (override.systemPromptMode !== undefined) next.systemPromptMode = override.systemPromptMode;
|
|
1200
1211
|
if (override.inheritProjectContext !== undefined) next.inheritProjectContext = override.inheritProjectContext;
|
|
@@ -1332,6 +1343,9 @@ function applyCustomAgentOverride(
|
|
|
1332
1343
|
override.fallbackModels === false ? undefined : [...override.fallbackModels],
|
|
1333
1344
|
);
|
|
1334
1345
|
}
|
|
1346
|
+
if (override.fast !== undefined) {
|
|
1347
|
+
fill("fast", ["fast"], override.fast);
|
|
1348
|
+
}
|
|
1335
1349
|
if (override.thinking !== undefined) {
|
|
1336
1350
|
fill("thinking", ["thinking"], override.thinking === false ? undefined : override.thinking);
|
|
1337
1351
|
}
|
|
@@ -1411,7 +1425,7 @@ function applyCustomAgentOverrides(
|
|
|
1411
1425
|
|
|
1412
1426
|
export function buildBuiltinOverrideConfig(
|
|
1413
1427
|
base: BuiltinAgentOverrideBase,
|
|
1414
|
-
draft: Pick<AgentConfig, "model" | "modelProvider" | "fallbackModels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "extensions" | "subagentOnlyExtensions" | "completionGuard" | "toolBudget"> & Partial<Pick<AgentConfig, "description" | "output" | "outputMode" | "defaultReads">>,
|
|
1428
|
+
draft: Pick<AgentConfig, "model" | "modelProvider" | "fallbackModels" | "fast" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "extensions" | "subagentOnlyExtensions" | "completionGuard" | "toolBudget"> & Partial<Pick<AgentConfig, "description" | "output" | "outputMode" | "defaultReads">>,
|
|
1415
1429
|
): BuiltinAgentOverrideConfig | undefined {
|
|
1416
1430
|
const override: BuiltinAgentOverrideConfig = {};
|
|
1417
1431
|
|
|
@@ -1425,6 +1439,7 @@ export function buildBuiltinOverrideConfig(
|
|
|
1425
1439
|
if (draft.model !== base.model) override.model = draft.model ?? false;
|
|
1426
1440
|
if (draft.modelProvider !== base.modelProvider) override.defaultProvider = draft.modelProvider ?? false;
|
|
1427
1441
|
if (!arraysEqual(draft.fallbackModels, base.fallbackModels)) override.fallbackModels = draft.fallbackModels ? [...draft.fallbackModels] : false;
|
|
1442
|
+
if (draft.fast !== base.fast) override.fast = draft.fast === true;
|
|
1428
1443
|
if (draft.thinking !== base.thinking) override.thinking = draft.thinking ?? false;
|
|
1429
1444
|
if (draft.systemPromptMode !== base.systemPromptMode) override.systemPromptMode = draft.systemPromptMode;
|
|
1430
1445
|
if (draft.inheritProjectContext !== base.inheritProjectContext) override.inheritProjectContext = draft.inheritProjectContext;
|
|
@@ -1835,6 +1850,12 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
|
|
|
1835
1850
|
|
|
1836
1851
|
const extensions = resolveAgentRelativeExtensionPaths(parseFrontmatterList(frontmatter.extensions), filePath);
|
|
1837
1852
|
const subagentOnlyExtensions = resolveAgentRelativeExtensionPaths(parseFrontmatterList(frontmatter.subagentOnlyExtensions), filePath);
|
|
1853
|
+
let fast: boolean | undefined;
|
|
1854
|
+
if (frontmatter.fast !== undefined) {
|
|
1855
|
+
if (frontmatter.fast === "true") fast = true;
|
|
1856
|
+
else if (frontmatter.fast === "false") fast = false;
|
|
1857
|
+
else throw new Error(`Agent '${localName}' has invalid fast frontmatter; expected true or false.`);
|
|
1858
|
+
}
|
|
1838
1859
|
|
|
1839
1860
|
const extraFields: Record<string, string> = {};
|
|
1840
1861
|
for (const [key, value] of Object.entries(frontmatter)) {
|
|
@@ -1881,6 +1902,7 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
|
|
|
1881
1902
|
...(mcpDirectTools.length > 0 ? { mcpDirectTools } : {}),
|
|
1882
1903
|
...(frontmatter.model !== undefined ? { model: frontmatter.model } : {}),
|
|
1883
1904
|
...(fallbackModels?.length ? { fallbackModels } : {}),
|
|
1905
|
+
...(fast !== undefined ? { fast } : {}),
|
|
1884
1906
|
...(frontmatter.thinking !== undefined ? { thinking: frontmatter.thinking === "false" ? false : frontmatter.thinking } : {}),
|
|
1885
1907
|
systemPromptMode,
|
|
1886
1908
|
inheritProjectContext,
|
package/src/api/preflight.ts
CHANGED
|
@@ -26,6 +26,7 @@ import { DIRS, TEMP_ROOT_DIR } from "../shared/types.ts";
|
|
|
26
26
|
import { processTerminalCandidatePath, processTerminalPath } from "../runs/background/process-terminal.ts";
|
|
27
27
|
import { resultFilePath } from "../runs/background/result-files.ts";
|
|
28
28
|
import { nestedResultsPath } from "../runs/shared/nested-events.ts";
|
|
29
|
+
import { normalizeExtensionBindings, type ExtensionBindings } from "../runs/shared/extension-bindings.ts";
|
|
29
30
|
|
|
30
31
|
export const SUBAGENT_LAUNCH_CONTRACT_VERSION = 2 as const;
|
|
31
32
|
|
|
@@ -38,7 +39,8 @@ export type SubagentLaunchContractReasonCode =
|
|
|
38
39
|
| "invalid_cwd"
|
|
39
40
|
| "unsupported_mode"
|
|
40
41
|
| "restricted_agent"
|
|
41
|
-
| "thinking_ceiling"
|
|
42
|
+
| "thinking_ceiling"
|
|
43
|
+
| "invalid_extension_bindings";
|
|
42
44
|
|
|
43
45
|
export interface SubagentLaunchContractDiagnostic {
|
|
44
46
|
code: SubagentLaunchContractReasonCode | "host_required" | "snapshot_warning";
|
|
@@ -53,6 +55,7 @@ export interface SubagentLaunchContractInput {
|
|
|
53
55
|
agentScope?: AgentScope;
|
|
54
56
|
context?: "fresh" | "fork";
|
|
55
57
|
model?: string;
|
|
58
|
+
fast?: boolean;
|
|
56
59
|
thinking?: string | false;
|
|
57
60
|
thinkingCeiling?: ThinkingLevel;
|
|
58
61
|
inheritedThinkingCeiling?: ThinkingLevel;
|
|
@@ -63,6 +66,7 @@ export interface SubagentLaunchContractInput {
|
|
|
63
66
|
output?: string | boolean;
|
|
64
67
|
outputMode?: OutputMode;
|
|
65
68
|
outputSchema?: JsonSchemaObject;
|
|
69
|
+
extensionBindings?: ExtensionBindings;
|
|
66
70
|
turnBudget?: ResolvedTurnBudget;
|
|
67
71
|
artifacts?: boolean;
|
|
68
72
|
artifactDir?: ArtifactDirPreference;
|
|
@@ -250,6 +254,15 @@ export async function resolveSubagentLaunchContract(input: SubagentLaunchContrac
|
|
|
250
254
|
return { ok: false, code: "missing_agent", message: `Unknown agent: ${input.agent}`, diagnostics };
|
|
251
255
|
}
|
|
252
256
|
const agent = resolvedAgent.agent;
|
|
257
|
+
let extensionBindings: ExtensionBindings | undefined;
|
|
258
|
+
try {
|
|
259
|
+
extensionBindings = normalizeExtensionBindings(input.extensionBindings)?.value;
|
|
260
|
+
} catch (error) {
|
|
261
|
+
return { ok: false, code: "invalid_extension_bindings", message: error instanceof Error ? error.message : String(error), diagnostics };
|
|
262
|
+
}
|
|
263
|
+
if (extensionBindings !== undefined && (agent.runner?.type === "external-cli" || agent.runner?.type === "external-job")) {
|
|
264
|
+
return { ok: false, code: "unsupported_mode", message: `extensionBindings is not supported for runner.type='${agent.runner.type}'.`, diagnostics };
|
|
265
|
+
}
|
|
253
266
|
const context = resolveLaunchContractContext(input, agent);
|
|
254
267
|
if (context === "fork") {
|
|
255
268
|
diagnostics.push({ code: "host_required", severity: "host-required", message: "Exact fork session branching and fork-thinking downgrade checks require Pi host session and model-registry snapshots." });
|
|
@@ -313,6 +326,7 @@ export async function resolveSubagentLaunchContract(input: SubagentLaunchContrac
|
|
|
313
326
|
}
|
|
314
327
|
let toolPlan: PiLaunchToolPlan;
|
|
315
328
|
const permissionRules = resolvePermissionRules(loadConfig().permissions, agent.permissions);
|
|
329
|
+
const fast = input.fast ?? agent.fast;
|
|
316
330
|
try {
|
|
317
331
|
toolPlan = resolvePiLaunchToolPlan({
|
|
318
332
|
tools: agent.tools,
|
|
@@ -322,6 +336,9 @@ export async function resolveSubagentLaunchContract(input: SubagentLaunchContrac
|
|
|
322
336
|
cwd: effectiveCwd,
|
|
323
337
|
requireReadTool: resolvedSkills.resolved.length > 0,
|
|
324
338
|
structuredOutput: Boolean(input.outputSchema),
|
|
339
|
+
fast,
|
|
340
|
+
model,
|
|
341
|
+
modelCandidates,
|
|
325
342
|
capabilityCeiling: effectiveCapabilityCeiling,
|
|
326
343
|
agentName: agent.name,
|
|
327
344
|
permissionRules,
|
|
@@ -433,6 +450,7 @@ export async function resolveSubagentLaunchContract(input: SubagentLaunchContrac
|
|
|
433
450
|
definitionDigest,
|
|
434
451
|
...(model ? { model } : {}),
|
|
435
452
|
modelCandidates,
|
|
453
|
+
...(fast !== undefined ? { fast } : {}),
|
|
436
454
|
...(resolveEffectiveThinking(model, effectiveThinkingConfig) ? { thinking: resolveEffectiveThinking(model, effectiveThinkingConfig) } : {}),
|
|
437
455
|
systemPrompt: effectiveSystemPrompt,
|
|
438
456
|
systemPromptMode: agent.systemPromptMode,
|
|
@@ -445,6 +463,7 @@ export async function resolveSubagentLaunchContract(input: SubagentLaunchContrac
|
|
|
445
463
|
...(outputPath ? { outputPath } : {}),
|
|
446
464
|
outputMode: behavior.outputMode,
|
|
447
465
|
...(input.outputSchema ? { structuredOutputSchema: input.outputSchema } : {}),
|
|
466
|
+
...(extensionBindings ? { extensionBindings } : {}),
|
|
448
467
|
}),
|
|
449
468
|
};
|
|
450
469
|
return { ok: true, contract: { ...contractBase, digest: digestContract(contractBase) } };
|
package/src/extension/schemas.ts
CHANGED
|
@@ -145,6 +145,7 @@ export const ParallelTaskSchema = Type.Object({
|
|
|
145
145
|
progress: Type.Optional(Type.Boolean({ description: "Enable progress.md tracking in {chain_dir}" })),
|
|
146
146
|
skill: Type.Optional(SkillOverride),
|
|
147
147
|
model: Type.Optional(Type.String({ description: "Override model for this task" })),
|
|
148
|
+
fast: Type.Optional(Type.Boolean({ description: "Opt into priority service tier for supported native OpenAI-Codex child models. This can increase quota or cost." })),
|
|
148
149
|
toolBudget: Type.Optional(ToolBudgetOverride),
|
|
149
150
|
acceptance: Type.Optional(AcceptanceOverride),
|
|
150
151
|
agentContract: Type.Optional(AgentContractOverride),
|
|
@@ -175,6 +176,7 @@ export const DynamicParallelTemplateSchema = Type.Object({
|
|
|
175
176
|
progress: Type.Optional(Type.Boolean({ description: "Enable progress.md tracking in {chain_dir}" })),
|
|
176
177
|
skill: Type.Optional(SkillOverride),
|
|
177
178
|
model: Type.Optional(Type.String({ description: "Override model for this task" })),
|
|
179
|
+
fast: Type.Optional(Type.Boolean({ description: "Opt into priority service tier for supported native OpenAI-Codex child models. This can increase quota or cost." })),
|
|
178
180
|
toolBudget: Type.Optional(ToolBudgetOverride),
|
|
179
181
|
acceptance: Type.Optional(AcceptanceOverride),
|
|
180
182
|
agentContract: Type.Optional(AgentContractOverride),
|
|
@@ -203,6 +205,7 @@ export const ChainItem = Type.Object({
|
|
|
203
205
|
progress: Type.Optional(Type.Boolean({ description: "Enable progress.md tracking in {chain_dir}" })),
|
|
204
206
|
skill: Type.Optional(SkillOverride),
|
|
205
207
|
model: Type.Optional(Type.String({ description: "Override model for this step" })),
|
|
208
|
+
fast: Type.Optional(Type.Boolean({ description: "Opt into priority service tier for supported native OpenAI-Codex child models. This can increase quota or cost." })),
|
|
206
209
|
toolBudget: Type.Optional(ToolBudgetOverride),
|
|
207
210
|
acceptance: Type.Optional(AcceptanceOverride),
|
|
208
211
|
agentContract: Type.Optional(AgentContractOverride),
|
|
@@ -255,6 +258,7 @@ const ControlOverrides = Type.Object({
|
|
|
255
258
|
const SubagentParamProperties = {
|
|
256
259
|
agent: Type.Optional(Type.String({ description: "Agent for one-child execution, or target for agent management actions." })),
|
|
257
260
|
task: Type.Optional(Type.String({ description: "Optional one-child task. Requires agent; cannot combine with action or workflowScript." })),
|
|
261
|
+
extensionBindings: Type.Optional(Type.Unsafe({ type: "object", maxProperties: 16, additionalProperties: true, description: "Namespaced, bounded plain-JSON metadata delivered only to the child runtime. Namespace keys use package.name/1 syntax." })),
|
|
258
262
|
// Management action (when present, tool operates in management mode)
|
|
259
263
|
action: Type.Optional(Type.String({ minLength: 1,
|
|
260
264
|
description: "Optional management/control action. Omit this field for structured single-child or workflowScript execution; use it only for management/control actions."
|
|
@@ -343,6 +347,7 @@ const SubagentParamProperties = {
|
|
|
343
347
|
outputMode: Type.Optional(OutputModeOverride),
|
|
344
348
|
skill: Type.Optional(SkillOverride),
|
|
345
349
|
model: Type.Optional(Type.String({ description: "Default child model override. Full provider/id values are accepted; bare ids resolve from the active registry." })),
|
|
350
|
+
fast: Type.Optional(Type.Boolean({ description: "Opt into priority service tier for supported native OpenAI-Codex child models. Default false. This can increase quota or cost." })),
|
|
346
351
|
outputSchema: Type.Optional(JsonSchemaObject),
|
|
347
352
|
agentContract: Type.Optional(AgentContractOverride),
|
|
348
353
|
acceptance: Type.Optional(AcceptanceOverride),
|
|
@@ -74,6 +74,7 @@ import { SUBAGENT_PROCESS_TERMINAL_EVENT } from "../../shared/types.ts";
|
|
|
74
74
|
import { assertAgentAllowedByCapabilityCeiling, decodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV, type ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
|
|
75
75
|
import { agentDefinitionDigest, launchBindingDigest } from "../../shared/launch-contract.ts";
|
|
76
76
|
import { resolvePermissionRules, type PermissionConfig } from "../shared/permissions.ts";
|
|
77
|
+
import { normalizeExtensionBindings, omitExtensionBindingsEnv, type ExtensionBindings } from "../shared/extension-bindings.ts";
|
|
77
78
|
|
|
78
79
|
const require = createRequire(import.meta.url);
|
|
79
80
|
const piPackageRoot = resolvePiPackageRoot();
|
|
@@ -175,6 +176,7 @@ interface AsyncChainParams {
|
|
|
175
176
|
childIntercomTarget?: (agent: string, index: number) => string | undefined;
|
|
176
177
|
nestedRoute?: NestedRouteInfo;
|
|
177
178
|
acceptance?: AcceptanceInput;
|
|
179
|
+
fast?: boolean;
|
|
178
180
|
timeoutMs?: number;
|
|
179
181
|
turnBudget?: ResolvedTurnBudget;
|
|
180
182
|
toolBudget?: ResolvedToolBudget;
|
|
@@ -224,6 +226,7 @@ interface AsyncSingleParams {
|
|
|
224
226
|
structuredOutputSchema?: JsonSchemaObject;
|
|
225
227
|
modelOverride?: string;
|
|
226
228
|
modelOverrideFromParent?: boolean;
|
|
229
|
+
fast?: boolean;
|
|
227
230
|
thinkingOverride?: AgentConfig["thinking"];
|
|
228
231
|
availableModels?: AvailableModelInfo[];
|
|
229
232
|
maxSubagentDepth: number;
|
|
@@ -265,6 +268,7 @@ interface AsyncSingleParams {
|
|
|
265
268
|
requestId: string;
|
|
266
269
|
requestDigest: string;
|
|
267
270
|
};
|
|
271
|
+
extensionBindings?: ExtensionBindings;
|
|
268
272
|
}
|
|
269
273
|
|
|
270
274
|
interface AsyncExecutionResult {
|
|
@@ -295,6 +299,7 @@ export interface AsyncRunnerStepBuildParams {
|
|
|
295
299
|
asyncDir: string;
|
|
296
300
|
outputBaseDir?: string;
|
|
297
301
|
validateOutputBindings?: boolean;
|
|
302
|
+
fast?: boolean;
|
|
298
303
|
toolBudget?: ResolvedToolBudget;
|
|
299
304
|
configToolBudget?: ResolvedToolBudget;
|
|
300
305
|
/** Optional per-call hard toolTimeoutMs override from the subagent invocation. */
|
|
@@ -506,7 +511,7 @@ function spawnRunner(cfg: object, suffix: string, cwd: string, onProcessTerminal
|
|
|
506
511
|
const cfgPath = getAsyncConfigPath(suffix);
|
|
507
512
|
const runnerProcessInstanceId = randomUUID();
|
|
508
513
|
const launchConfig = { ...cfg, runnerProcessInstanceId };
|
|
509
|
-
|
|
514
|
+
writePrivateAtomicJson(cfgPath, launchConfig);
|
|
510
515
|
const runner = path.join(path.dirname(fileURLToPath(import.meta.url)), "subagent-runner.ts");
|
|
511
516
|
const nodeCommand = resolveNodeExecutable();
|
|
512
517
|
const launchForStartup = launchConfig as typeof launchConfig & { asyncDir?: unknown; id?: unknown; sessionId?: unknown; completionOwnerId?: unknown; revivalLease?: unknown };
|
|
@@ -538,7 +543,7 @@ function spawnRunner(cfg: object, suffix: string, cwd: string, onProcessTerminal
|
|
|
538
543
|
stdio: ["ignore", stdoutFd ?? "ignore", stderrFd ?? "ignore"],
|
|
539
544
|
windowsHide: true,
|
|
540
545
|
env: {
|
|
541
|
-
...process.env,
|
|
546
|
+
...omitExtensionBindingsEnv(process.env),
|
|
542
547
|
...(piPackageRoot ? { [PI_CODING_AGENT_PACKAGE_ROOT_ENV]: piPackageRoot } : {}),
|
|
543
548
|
},
|
|
544
549
|
});
|
|
@@ -727,6 +732,7 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
727
732
|
...(s.progress !== undefined ? { progress: s.progress } : {}),
|
|
728
733
|
...(stepSkillInput !== undefined ? { skills: stepSkillInput } : {}),
|
|
729
734
|
...(s.model !== undefined ? { model: s.model } : {}),
|
|
735
|
+
...(s.fast !== undefined ? { fast: s.fast } : {}),
|
|
730
736
|
};
|
|
731
737
|
};
|
|
732
738
|
const buildSeqStep = (s: SequentialStep, sessionFile?: string, behaviorCwd?: string, progressPrecreated = false, resolvedBehavior?: ResolvedStepBehavior, flatIndex?: number, parallelOutputNamespace?: { stepIndex: number; taskIndex?: number }, runFanoutPath?: string) => {
|
|
@@ -739,6 +745,7 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
739
745
|
if (s.outputSchema !== undefined) unsupported.push("structured output");
|
|
740
746
|
if (s.acceptance !== undefined || params.agentContract !== undefined || s.agentContract !== undefined) unsupported.push("acceptance/agent contract");
|
|
741
747
|
if (s.toolBudget !== undefined || params.toolBudget !== undefined || a.toolBudget !== undefined || params.configToolBudget !== undefined) unsupported.push("tool budget");
|
|
748
|
+
if ((s.fast ?? params.fast ?? a.fast) === true) unsupported.push("fast mode");
|
|
742
749
|
if (params.contextForAgent?.(s.agent) === "fork") unsupported.push("fork context");
|
|
743
750
|
if (unsupported.length > 0) throw new AsyncStartValidationError(`Agent '${a.name}' uses runner.type='${externalRunnerType}' and does not support: ${unsupported.join(", ")}.`);
|
|
744
751
|
}
|
|
@@ -831,6 +838,21 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
831
838
|
}
|
|
832
839
|
const agentContract = s.agentContract ?? params.agentContract;
|
|
833
840
|
const permissionRules = resolvePermissionRules(ctx.permissions, a.permissions);
|
|
841
|
+
const modelCandidates = externalRunner ? [] : buildModelCandidates(primaryModel, a.fallbackModels, availableModels, a.modelProvider ?? ctx.currentModelProvider, {
|
|
842
|
+
scope: modelScopes,
|
|
843
|
+
primaryModelFromParent,
|
|
844
|
+
}).flatMap((candidate) => {
|
|
845
|
+
const resolved = applyThinkingSuffix(candidate, effectiveThinking, thinkingOverride !== undefined);
|
|
846
|
+
return resolved ? [resolved] : [];
|
|
847
|
+
});
|
|
848
|
+
if (!externalRunner) {
|
|
849
|
+
try {
|
|
850
|
+
for (const candidate of modelCandidates) assertThinkingWithinCeiling({ model: candidate, configThinking: effectiveThinking, ceiling: thinkingCeiling, agent: a.name, runId: id });
|
|
851
|
+
} catch (error) {
|
|
852
|
+
throw new AsyncStartValidationError(error instanceof Error ? error.message : String(error));
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
const fast = s.fast ?? params.fast ?? a.fast;
|
|
834
856
|
const toolPlan = resolvePiLaunchToolPlan({
|
|
835
857
|
tools: a.tools,
|
|
836
858
|
extensions: a.extensions,
|
|
@@ -839,6 +861,9 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
839
861
|
cwd: stepCwd,
|
|
840
862
|
requireReadTool: Boolean(resolvedSkills.length),
|
|
841
863
|
structuredOutput: Boolean(s.outputSchema),
|
|
864
|
+
fast,
|
|
865
|
+
model,
|
|
866
|
+
modelCandidates,
|
|
842
867
|
capabilityCeiling: params.capabilityCeiling,
|
|
843
868
|
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
844
869
|
agentName: a.name,
|
|
@@ -862,20 +887,6 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
862
887
|
});
|
|
863
888
|
if (contractError) throw new AsyncStartValidationError(contractError);
|
|
864
889
|
}
|
|
865
|
-
const modelCandidates = externalRunner ? [] : buildModelCandidates(primaryModel, a.fallbackModels, availableModels, a.modelProvider ?? ctx.currentModelProvider, {
|
|
866
|
-
scope: modelScopes,
|
|
867
|
-
primaryModelFromParent,
|
|
868
|
-
}).flatMap((candidate) => {
|
|
869
|
-
const resolved = applyThinkingSuffix(candidate, effectiveThinking, thinkingOverride !== undefined);
|
|
870
|
-
return resolved ? [resolved] : [];
|
|
871
|
-
});
|
|
872
|
-
if (!externalRunner) {
|
|
873
|
-
try {
|
|
874
|
-
for (const candidate of modelCandidates) assertThinkingWithinCeiling({ model: candidate, configThinking: effectiveThinking, ceiling: thinkingCeiling, agent: a.name, runId: id });
|
|
875
|
-
} catch (error) {
|
|
876
|
-
throw new AsyncStartValidationError(error instanceof Error ? error.message : String(error));
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
890
|
return {
|
|
880
891
|
parentSessionId: ctx.parentSessionId ?? ctx.currentSessionId,
|
|
881
892
|
permissionRules,
|
|
@@ -892,6 +903,7 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
892
903
|
structured: Boolean(s.outputSchema),
|
|
893
904
|
cwd: stepCwd,
|
|
894
905
|
model,
|
|
906
|
+
...(fast !== undefined ? { fast } : {}),
|
|
895
907
|
thinking: resolveEffectiveThinking(model, effectiveThinking),
|
|
896
908
|
...(thinkingCeiling ? { thinkingCeiling } : {}),
|
|
897
909
|
launchResolvedExtensions,
|
|
@@ -930,7 +942,7 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
930
942
|
acceptanceRole: a.acceptanceRole,
|
|
931
943
|
...(s.gateOn ? { gateOn: s.gateOn } : {}),
|
|
932
944
|
...(s.outputSchema ? { structuredOutputSchema: s.outputSchema } : {}),
|
|
933
|
-
...(s.outputSchema ? { structuredOutput: createStructuredOutputRuntime(s.outputSchema, path.join(asyncDir, "structured-output")) } : {}),
|
|
945
|
+
...(s.outputSchema ? { structuredOutput: createStructuredOutputRuntime(s.outputSchema, path.join(asyncDir, "structured-output"), { captureAcceptanceReport: s.acceptance !== false }) } : {}),
|
|
934
946
|
...(resolvedToolBudget.budget ? { toolBudget: resolvedToolBudget.budget } : {}),
|
|
935
947
|
...(s.worktree ? { worktree: true } : {}),
|
|
936
948
|
};
|
|
@@ -1143,6 +1155,7 @@ export function executeAsyncChain(
|
|
|
1143
1155
|
waitToolEnabled: params.waitToolEnabled,
|
|
1144
1156
|
worktreeBaseDir,
|
|
1145
1157
|
asyncDir,
|
|
1158
|
+
fast: params.fast,
|
|
1146
1159
|
toolBudget: params.toolBudget,
|
|
1147
1160
|
configToolBudget: params.configToolBudget,
|
|
1148
1161
|
callToolTimeoutMs: params.callToolTimeoutMs,
|
|
@@ -1391,6 +1404,12 @@ export function executeAsyncSingle(
|
|
|
1391
1404
|
nestedRoute,
|
|
1392
1405
|
} = params;
|
|
1393
1406
|
const task = params.task ?? "";
|
|
1407
|
+
let extensionBindings: ExtensionBindings | undefined;
|
|
1408
|
+
try {
|
|
1409
|
+
extensionBindings = normalizeExtensionBindings(params.extensionBindings)?.value;
|
|
1410
|
+
} catch (error) {
|
|
1411
|
+
return formatAsyncStartError("single", error instanceof Error ? error.message : String(error));
|
|
1412
|
+
}
|
|
1394
1413
|
const acceptanceErrors = validateAcceptanceInput(params.acceptance);
|
|
1395
1414
|
if (acceptanceErrors.length > 0) return formatAsyncStartError("single", acceptanceErrors.join(" "));
|
|
1396
1415
|
const externalRunner = agentConfig.runner?.type === "external-cli" || agentConfig.runner?.type === "external-job";
|
|
@@ -1399,6 +1418,7 @@ export function executeAsyncSingle(
|
|
|
1399
1418
|
if (externalRunner) {
|
|
1400
1419
|
const unsupported: string[] = [];
|
|
1401
1420
|
if (params.modelOverride !== undefined) unsupported.push("model override");
|
|
1421
|
+
if ((params.fast ?? agentConfig.fast) === true) unsupported.push("fast mode");
|
|
1402
1422
|
if (params.thinkingOverride !== undefined) unsupported.push("thinking override");
|
|
1403
1423
|
if (params.structuredOutputSchema !== undefined) unsupported.push("structured output");
|
|
1404
1424
|
if (params.acceptance !== undefined || params.agentContract !== undefined) unsupported.push("acceptance/agent contract");
|
|
@@ -1406,6 +1426,7 @@ export function executeAsyncSingle(
|
|
|
1406
1426
|
if (params.context === "fork") unsupported.push("fork context");
|
|
1407
1427
|
if ((params.skills?.length ?? 0) > 0) unsupported.push("skills");
|
|
1408
1428
|
if (permissionRules) unsupported.push("native Pi child permissions");
|
|
1429
|
+
if (extensionBindings !== undefined) unsupported.push("extension bindings");
|
|
1409
1430
|
if (unsupported.length > 0) return formatAsyncStartError("single", `Agent '${agentConfig.name}' uses runner.type='${externalRunnerType}' and does not support: ${unsupported.join(", ")}.`);
|
|
1410
1431
|
}
|
|
1411
1432
|
const capabilityCeiling = intersectSubagentCapabilityCeilings(params.capabilityCeiling ?? resolveCurrentSubagentCapabilityCeiling(ctx.currentSessionId), decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]));
|
|
@@ -1518,7 +1539,7 @@ export function executeAsyncSingle(
|
|
|
1518
1539
|
const initialUsageBudget = usageBudgetState(params.usageBudget, undefined);
|
|
1519
1540
|
const resolvedSessionDir = params.sessionDir ?? (sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined);
|
|
1520
1541
|
const structuredOutput = params.structuredOutputSchema
|
|
1521
|
-
? createStructuredOutputRuntime(params.structuredOutputSchema, path.join(asyncDir, "structured-output"))
|
|
1542
|
+
? createStructuredOutputRuntime(params.structuredOutputSchema, path.join(asyncDir, "structured-output"), { captureAcceptanceReport: params.acceptance !== false })
|
|
1522
1543
|
: undefined;
|
|
1523
1544
|
const modelCandidates = externalRunner
|
|
1524
1545
|
? []
|
|
@@ -1546,6 +1567,9 @@ export function executeAsyncSingle(
|
|
|
1546
1567
|
cwd: runnerCwd,
|
|
1547
1568
|
requireReadTool: Boolean(resolvedSkills.length),
|
|
1548
1569
|
structuredOutput: Boolean(params.structuredOutputSchema),
|
|
1570
|
+
fast: params.fast ?? agentConfig.fast,
|
|
1571
|
+
model,
|
|
1572
|
+
modelCandidates,
|
|
1549
1573
|
capabilityCeiling,
|
|
1550
1574
|
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
1551
1575
|
agentName: agentConfig.name,
|
|
@@ -1571,6 +1595,7 @@ export function executeAsyncSingle(
|
|
|
1571
1595
|
task,
|
|
1572
1596
|
...(model ? { model } : {}),
|
|
1573
1597
|
modelCandidates,
|
|
1598
|
+
...((params.fast ?? agentConfig.fast) !== undefined ? { fast: params.fast ?? agentConfig.fast } : {}),
|
|
1574
1599
|
...(resolveEffectiveThinking(model, effectiveThinking) ? { thinking: resolveEffectiveThinking(model, effectiveThinking) } : {}),
|
|
1575
1600
|
...(thinkingCeiling ? { thinkingCeiling } : {}),
|
|
1576
1601
|
systemPrompt: effectiveSystemPrompt,
|
|
@@ -1584,6 +1609,7 @@ export function executeAsyncSingle(
|
|
|
1584
1609
|
...(outputPath ? { outputPath } : {}),
|
|
1585
1610
|
outputMode,
|
|
1586
1611
|
...(params.structuredOutputSchema ? { structuredOutputSchema: params.structuredOutputSchema } : {}),
|
|
1612
|
+
...(extensionBindings ? { extensionBindings } : {}),
|
|
1587
1613
|
});
|
|
1588
1614
|
const resolvedAcceptance = resolveEffectiveAcceptance({
|
|
1589
1615
|
explicit: params.acceptance,
|
|
@@ -1598,6 +1624,7 @@ export function executeAsyncSingle(
|
|
|
1598
1624
|
const recoveryDescriptor: SteeringRecoveryDescriptor = {
|
|
1599
1625
|
version: 1,
|
|
1600
1626
|
launchContractDigest,
|
|
1627
|
+
...(extensionBindings ? { extensionBindings } : {}),
|
|
1601
1628
|
runFanoutBudget,
|
|
1602
1629
|
sourceRunId: id,
|
|
1603
1630
|
...(params.agentContract ? { agentContract: params.agentContract } : {}),
|
|
@@ -1606,6 +1633,7 @@ export function executeAsyncSingle(
|
|
|
1606
1633
|
...(sessionFile ? { sessionFile } : {}),
|
|
1607
1634
|
cwd: runnerCwd,
|
|
1608
1635
|
...(model ? { model } : {}),
|
|
1636
|
+
...(params.fast ?? recoveryAgentConfig.fast ? { fast: params.fast ?? recoveryAgentConfig.fast } : {}),
|
|
1609
1637
|
...(recoveryAgentConfig.modelProvider ? { modelProvider: recoveryAgentConfig.modelProvider } : {}),
|
|
1610
1638
|
...(params.modelOverrideFromParent ? { modelOverrideFromParent: true } : {}),
|
|
1611
1639
|
...(recoveryAgentConfig.fallbackModels ? { fallbackModels: [...recoveryAgentConfig.fallbackModels] } : {}),
|
|
@@ -1666,6 +1694,7 @@ export function executeAsyncSingle(
|
|
|
1666
1694
|
...(params.context ? { context: params.context } : {}),
|
|
1667
1695
|
cwd: runnerCwd,
|
|
1668
1696
|
model,
|
|
1697
|
+
...(params.fast ?? agentConfig.fast ? { fast: params.fast ?? agentConfig.fast } : {}),
|
|
1669
1698
|
thinking: resolveEffectiveThinking(model, effectiveThinking),
|
|
1670
1699
|
...(thinkingCeiling ? { thinkingCeiling } : {}),
|
|
1671
1700
|
modelCandidates,
|
|
@@ -1690,6 +1719,7 @@ export function executeAsyncSingle(
|
|
|
1690
1719
|
definitionDigest: agentDefinitionDigest(agentConfig),
|
|
1691
1720
|
launchBindingTask: task,
|
|
1692
1721
|
launchContractDigest,
|
|
1722
|
+
...(extensionBindings ? { extensionBindings } : {}),
|
|
1693
1723
|
launchResolvedExtensions,
|
|
1694
1724
|
effectiveAcceptance: resolvedAcceptance,
|
|
1695
1725
|
...(structuredOutput ? { structuredOutput } : {}),
|
|
@@ -2,6 +2,7 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { DIRS, type AcceptanceInput, type AsyncStatus, type ResolvedTurnBudget, type SteeringRecoveryDescriptor, type SubagentRunMode } from "../../shared/types.ts";
|
|
4
4
|
import type { AgentConfig } from "../../agents/agents.ts";
|
|
5
|
+
import { normalizeExtensionBindings } from "../shared/extension-bindings.ts";
|
|
5
6
|
import { validateAcceptanceInput } from "../shared/acceptance.ts";
|
|
6
7
|
import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
|
|
7
8
|
import { intersectSubagentCapabilityCeilings, parseSubagentCapabilityCeiling, type ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
|
|
@@ -328,6 +329,7 @@ export function readAsyncRecoveryDescriptor(asyncDir: string | undefined): Steer
|
|
|
328
329
|
"skillPath", "agentFilePath", "completionGuard", "memory", "outputPath", "outputMode", "structuredOutputSchema", "acceptance", "sessionDir", "artifactConfig",
|
|
329
330
|
"artifactsDir", "maxOutput", "controlConfig", "context", "intercomBridge", "absoluteDeadlineAt", "initialTurnBudget", "initialToolBudget", "maxSubagentDepth", "share", "capabilityCeiling",
|
|
330
331
|
"launchResolvedExtensions", "runFanoutBudget",
|
|
332
|
+
"extensionBindings",
|
|
331
333
|
]);
|
|
332
334
|
for (const field of Object.keys(parsed)) {
|
|
333
335
|
if (!allowedFields.has(field)) throw new Error(`Invalid async recovery descriptor '${descriptorPath}': unknown field '${field}'.`);
|
|
@@ -344,6 +346,7 @@ export function readAsyncRecoveryDescriptor(asyncDir: string | undefined): Steer
|
|
|
344
346
|
}
|
|
345
347
|
if (parsed.capabilityCeiling !== undefined) parsed.capabilityCeiling = parseSubagentCapabilityCeiling(parsed.capabilityCeiling, `async recovery descriptor '${descriptorPath}' capabilityCeiling`);
|
|
346
348
|
if (parsed.thinkingCeiling !== undefined) parsed.thinkingCeiling = parseThinkingLevel(parsed.thinkingCeiling, `async recovery descriptor '${descriptorPath}' thinkingCeiling`);
|
|
349
|
+
if (parsed.extensionBindings !== undefined) parsed.extensionBindings = normalizeExtensionBindings(parsed.extensionBindings)!.value;
|
|
347
350
|
if (parsed.agentContract !== undefined) {
|
|
348
351
|
if (!parsed.agentContract || typeof parsed.agentContract !== "object" || Array.isArray(parsed.agentContract)) throw new Error(`Invalid async recovery descriptor '${descriptorPath}': agentContract must be an object.`);
|
|
349
352
|
const contract = parsed.agentContract as Record<string, unknown>;
|