pi-subagents 0.52.0 → 0.53.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 +58 -0
- package/README.md +4 -0
- package/docs/configuration.md +11 -1
- package/docs/extension-api.md +3 -1
- package/docs/workflows.md +2 -0
- package/package.json +2 -1
- package/prompts/council.md +48 -0
- package/skills/council-mode/SKILL.md +230 -0
- package/skills/pi-subagents/SKILL.md +2 -0
- package/skills/pi-subagents/references/constraints-and-recipes.md +1 -0
- package/skills/pi-subagents/references/execution-controls.md +11 -0
- package/skills/pi-subagents/references/multi-lane-orchestration.md +39 -0
- package/src/agents/agent-management.ts +22 -3
- package/src/agents/agent-serializer.ts +2 -0
- package/src/agents/agents.ts +29 -13
- package/src/agents/builtin-names.ts +9 -0
- package/src/agents/runtime-agent-registry.ts +418 -0
- package/src/api/agents.ts +7 -0
- package/src/api/external-job-provider.ts +3 -2
- package/src/api/preflight.ts +1 -1
- package/src/extension/config.ts +3 -0
- package/src/extension/doctor.ts +1 -0
- package/src/extension/index.ts +17 -2
- package/src/extension/rpc.ts +41 -1
- package/src/extension/schemas.ts +7 -4
- package/src/extension/tool-description.ts +2 -2
- package/src/runs/background/async-execution.ts +2 -1
- package/src/runs/background/async-job-tracker.ts +4 -3
- package/src/runs/background/async-resume.ts +2 -1
- package/src/runs/background/async-status-snapshot.ts +14 -5
- package/src/runs/background/auto-drain.ts +1 -0
- package/src/runs/background/result-watcher.ts +8 -0
- package/src/runs/background/subagent-runner.ts +7 -4
- package/src/runs/background/subagent-wait.ts +9 -5
- package/src/runs/background/terminal-run-index.ts +15 -6
- package/src/runs/background/wait-tool.ts +1 -0
- package/src/runs/foreground/execution.ts +5 -1
- package/src/runs/foreground/subagent-executor.ts +182 -46
- package/src/runs/foreground/workflow-detach-reconcile.ts +83 -15
- package/src/runs/shared/acceptance.ts +44 -1
- package/src/runs/shared/model-exclusions.ts +242 -0
- package/src/runs/shared/model-fallback.ts +55 -2
- package/src/runs/shared/subagent-control.ts +25 -3
- package/src/shared/fork-context.ts +17 -1
- package/src/shared/model-info.ts +20 -0
- package/src/shared/settings.ts +2 -2
- package/src/shared/types.ts +35 -0
- package/src/slash/slash-commands.ts +20 -6
- package/src/slash/slash-live-state.ts +3 -3
- package/src/tui/fleet-status.ts +86 -1
- package/src/tui/fleet.ts +55 -2
- package/src/tui/render.ts +73 -3
- package/src/workflows/scripted-workflow.ts +100 -12
- package/src/workflows/workflow-receipt.ts +140 -0
|
@@ -7,7 +7,7 @@ import { findBlockingAgentDiagnostic, resolveAgentName, type AgentConfig, type A
|
|
|
7
7
|
import { getArtifactsDir, getChainRunsDir, getProjectArtifactPackagingWarning, getProjectSubagentsDir } from "../../shared/artifacts.ts";
|
|
8
8
|
import { writeAtomicJson } from "../../shared/atomic-json.ts";
|
|
9
9
|
import { createCapacityResilientJsonWriter } from "../../shared/capacity-resilient-json.ts";
|
|
10
|
-
import {
|
|
10
|
+
import { isStorageCapacityError } from "../../shared/file-system-retry.ts";
|
|
11
11
|
import { resolveEffectiveThinking, toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
|
|
12
12
|
import {
|
|
13
13
|
beginForegroundChild,
|
|
@@ -118,7 +118,8 @@ import { createMissionWorkflowState } from "../../missions/workflow-state.ts";
|
|
|
118
118
|
import { resolveAuthorityDecision } from "../../policy/authority.ts";
|
|
119
119
|
import { handleHerdrInspectorAction, HERDR_INSPECTOR_ACTIONS } from "../../inspectors/herdr/actions.ts";
|
|
120
120
|
import { handleHerdrProjectPaneAction, HERDR_PROJECT_PANE_ACTIONS } from "../../inspectors/herdr/project-panes.ts";
|
|
121
|
-
import { previewSimpleWorkflowRun, runWorkflowScript, WorkflowScriptError, type WorkflowScriptChildResult, type WorkflowSteerOptions, type WorkflowSteerResult } from "../../workflows/scripted-workflow.ts";
|
|
121
|
+
import { previewSimpleWorkflowRun, runWorkflowScript, WorkflowScriptError, type WorkflowReceiptResumeReference, type WorkflowScriptChildResult, type WorkflowSteerOptions, type WorkflowSteerResult } from "../../workflows/scripted-workflow.ts";
|
|
122
|
+
import { buildWorkflowReceipt, resolveWorkflowReceiptResumeEntry, writeWorkflowReceipt, type WorkflowReceipt, type WorkflowReceiptState } from "../../workflows/workflow-receipt.ts";
|
|
122
123
|
import { resolveWorkflowChatProgress, type WorkflowChatProgressProjection } from "../../workflows/chat-progress.ts";
|
|
123
124
|
import {
|
|
124
125
|
cleanupWorktrees,
|
|
@@ -308,7 +309,7 @@ export interface SubagentParamsLike {
|
|
|
308
309
|
tasks?: TaskParam[];
|
|
309
310
|
concurrency?: number;
|
|
310
311
|
worktree?: boolean;
|
|
311
|
-
context?: "fresh" | "fork";
|
|
312
|
+
context?: "fresh" | "fork" | "profile";
|
|
312
313
|
/** Per-run intercom bridge config. It replaces the global config for this launch only. */
|
|
313
314
|
intercomBridge?: IntercomBridgeConfig;
|
|
314
315
|
async?: boolean;
|
|
@@ -795,12 +796,13 @@ function updateRememberedForegroundChild(state: SubagentState, input: { runId: s
|
|
|
795
796
|
});
|
|
796
797
|
}
|
|
797
798
|
|
|
798
|
-
function resolveForegroundResumeTarget(params: SubagentParamsLike, state: SubagentState): { runId: string; mode: SubagentRunMode; state: "complete"; agent: string; index: number; cwd: string; sessionFile: string; model?: string; thinking?: string; launchContractDigest?: string; capabilityCeiling?: ResolvedSubagentCapabilityCeiling } | undefined {
|
|
799
|
+
function resolveForegroundResumeTarget(params: SubagentParamsLike, state: SubagentState, options: { exactOnly?: boolean } = {}): { runId: string; mode: SubagentRunMode; state: "complete"; agent: string; index: number; cwd: string; sessionFile: string; model?: string; thinking?: string; launchContractDigest?: string; capabilityCeiling?: ResolvedSubagentCapabilityCeiling } | undefined {
|
|
799
800
|
const requested = (params.id ?? params.runId)?.trim();
|
|
800
801
|
if (!requested || !state.foregroundRuns?.size || !state.currentSessionId) return undefined;
|
|
801
|
-
const
|
|
802
|
-
const
|
|
803
|
-
|
|
802
|
+
const direct = state.foregroundRuns.get(requested);
|
|
803
|
+
const matches = direct?.sessionId === state.currentSessionId
|
|
804
|
+
? [direct]
|
|
805
|
+
: options.exactOnly ? [] : [...state.foregroundRuns.values()].filter((run) => run.sessionId === state.currentSessionId && run.runId.startsWith(requested));
|
|
804
806
|
if (matches.length === 0) return undefined;
|
|
805
807
|
if (matches.length > 1) throw new Error(`Ambiguous foreground run id prefix '${requested}' matched: ${matches.map((run) => run.runId).join(", ")}. Provide a longer id.`);
|
|
806
808
|
const run = matches[0]!;
|
|
@@ -868,7 +870,7 @@ function isExactResumeError(error: unknown, source: "async" | "foreground", requ
|
|
|
868
870
|
return new RegExp(`\\b${source} run '${escapeRegExp(requested)}'`, "i").test(error.message);
|
|
869
871
|
}
|
|
870
872
|
|
|
871
|
-
function resolveResumeTarget(params: SubagentParamsLike, state: SubagentState, options: { asyncRequireSessionFile?: boolean } = {}): ResumeSourceTarget {
|
|
873
|
+
function resolveResumeTarget(params: SubagentParamsLike, state: SubagentState, options: { asyncRequireSessionFile?: boolean; exactOnly?: boolean } = {}): ResumeSourceTarget {
|
|
872
874
|
const requested = (params.id ?? params.runId)?.trim() ?? "";
|
|
873
875
|
let foregroundTarget: ForegroundResumeSourceTarget | undefined;
|
|
874
876
|
let foregroundError: unknown;
|
|
@@ -876,15 +878,18 @@ function resolveResumeTarget(params: SubagentParamsLike, state: SubagentState, o
|
|
|
876
878
|
let asyncError: unknown;
|
|
877
879
|
|
|
878
880
|
try {
|
|
879
|
-
const target = resolveForegroundResumeTarget(params, state);
|
|
881
|
+
const target = resolveForegroundResumeTarget(params, state, options);
|
|
880
882
|
if (target) foregroundTarget = { kind: "revive", source: "foreground", ...target };
|
|
881
883
|
} catch (error) {
|
|
882
884
|
foregroundError = error;
|
|
883
885
|
}
|
|
884
886
|
try {
|
|
887
|
+
const asyncParams = options.exactOnly && requested && !params.dir
|
|
888
|
+
? { ...params, dir: path.join(DIRS.async, requested) }
|
|
889
|
+
: params;
|
|
885
890
|
asyncTarget = {
|
|
886
891
|
source: "async",
|
|
887
|
-
...resolveAsyncResumeTarget(
|
|
892
|
+
...resolveAsyncResumeTarget(asyncParams, {}, compactOptional<NonNullable<Parameters<typeof resolveAsyncResumeTarget>[2]>>({
|
|
888
893
|
requireSessionFile: options.asyncRequireSessionFile,
|
|
889
894
|
sessionId: state.currentSessionId ?? undefined,
|
|
890
895
|
})),
|
|
@@ -1566,10 +1571,11 @@ async function resumeAsyncRun(input: {
|
|
|
1566
1571
|
const modelScope = discovered.modelScope;
|
|
1567
1572
|
const sessionName = resolveIntercomSessionTarget(input.deps.pi.getSessionName(), input.ctx.sessionManager.getSessionId());
|
|
1568
1573
|
const recoveryDescriptor = "recoveryDescriptor" in target ? target.recoveryDescriptor : undefined;
|
|
1574
|
+
const recoveryContext = recoveryDescriptor?.context ?? (input.params.context === "profile" ? undefined : input.params.context);
|
|
1569
1575
|
const intercomBridge = resolveIntercomBridge({
|
|
1570
1576
|
config: input.deps.config.intercomBridge,
|
|
1571
1577
|
override: input.params.intercomBridge ?? recoveryDescriptor?.intercomBridge,
|
|
1572
|
-
context:
|
|
1578
|
+
context: recoveryContext,
|
|
1573
1579
|
orchestratorTarget: sessionName,
|
|
1574
1580
|
});
|
|
1575
1581
|
const agents = intercomBridge.active
|
|
@@ -1765,6 +1771,7 @@ async function resumeAsyncRun(input: {
|
|
|
1765
1771
|
sourceRunId: target.runId,
|
|
1766
1772
|
...(input.deps.state.currentSessionId ? { parentSessionId: input.deps.state.currentSessionId } : {}),
|
|
1767
1773
|
},
|
|
1774
|
+
context: recoveryContext,
|
|
1768
1775
|
modelOverride: recoveryDescriptor?.model ?? target.model,
|
|
1769
1776
|
modelOverrideFromParent: recoveryDescriptor?.modelOverrideFromParent,
|
|
1770
1777
|
thinkingOverride: recoveryDescriptor?.thinking ?? target.thinking,
|
|
@@ -1916,9 +1923,12 @@ function formatFailedSingleRunOutput(result: SingleResult, displayOutput: string
|
|
|
1916
1923
|
return lines.join("\n");
|
|
1917
1924
|
}
|
|
1918
1925
|
|
|
1919
|
-
function createForegroundControlNotifier(data: Pick<ExecutionContextData, "controlConfig" | "intercomBridge" | "params">, deps: Pick<ExecutorDeps, "pi" | "state">): (event: ControlEvent) => void {
|
|
1926
|
+
function createForegroundControlNotifier(data: Pick<ExecutionContextData, "controlConfig" | "contextPolicy" | "intercomBridge" | "params">, deps: Pick<ExecutorDeps, "pi" | "state">): (event: ControlEvent) => void {
|
|
1920
1927
|
return (event) => {
|
|
1921
1928
|
applyControlEventToRememberedForegroundRun(deps.state, event);
|
|
1929
|
+
const eventBridge = intercomBridgeAppliesToAgent(data.intercomBridge, data.contextPolicy, event.agent)
|
|
1930
|
+
? data.intercomBridge
|
|
1931
|
+
: { ...data.intercomBridge, active: false };
|
|
1922
1932
|
const parentWorkflowRunId = data.params.workflowParentRunId;
|
|
1923
1933
|
const asyncWorkflow = typeof parentWorkflowRunId === "string" ? deps.state.asyncJobs.get(parentWorkflowRunId) : undefined;
|
|
1924
1934
|
const workflowKey = typeof data.params.workflowKey === "string" && data.params.workflowKey.trim()
|
|
@@ -1930,8 +1940,8 @@ function createForegroundControlNotifier(data: Pick<ExecutionContextData, "contr
|
|
|
1930
1940
|
job: asyncWorkflow,
|
|
1931
1941
|
event: enriched,
|
|
1932
1942
|
controlConfig: data.controlConfig,
|
|
1933
|
-
intercomBridge:
|
|
1934
|
-
childIntercomTarget:
|
|
1943
|
+
intercomBridge: eventBridge,
|
|
1944
|
+
childIntercomTarget: eventBridge.active
|
|
1935
1945
|
? resolveSubagentIntercomTarget(enriched.runId, enriched.agent, enriched.index)
|
|
1936
1946
|
: undefined,
|
|
1937
1947
|
});
|
|
@@ -1939,7 +1949,7 @@ function createForegroundControlNotifier(data: Pick<ExecutionContextData, "contr
|
|
|
1939
1949
|
emitControlNotification({
|
|
1940
1950
|
pi: deps.pi,
|
|
1941
1951
|
controlConfig: data.controlConfig,
|
|
1942
|
-
intercomBridge:
|
|
1952
|
+
intercomBridge: eventBridge,
|
|
1943
1953
|
event: enriched,
|
|
1944
1954
|
source: asyncWorkflow ? "async" : "foreground",
|
|
1945
1955
|
});
|
|
@@ -2243,17 +2253,40 @@ interface AgentDefaultContextPolicy {
|
|
|
2243
2253
|
usesFork: boolean;
|
|
2244
2254
|
}
|
|
2245
2255
|
|
|
2256
|
+
type AgentDefaultContextPolicyResult = AgentDefaultContextPolicy | { error: string };
|
|
2257
|
+
|
|
2246
2258
|
function resolveAgentDefaultContextPolicy(
|
|
2247
2259
|
params: SubagentParamsLike,
|
|
2248
2260
|
agents: AgentConfig[],
|
|
2249
2261
|
defaultSubagentContext: ExtensionConfig["defaultSubagentContext"],
|
|
2250
2262
|
canUseDefaultFork = false,
|
|
2251
|
-
):
|
|
2252
|
-
if (params.context
|
|
2263
|
+
): AgentDefaultContextPolicyResult {
|
|
2264
|
+
if (params.context === "profile") {
|
|
2265
|
+
const byName = new Map(agents.map((agent) => [agent.name, agent]));
|
|
2266
|
+
for (const agentName of collectRequestedAgentNames(params)) {
|
|
2267
|
+
const agent = byName.get(agentName);
|
|
2268
|
+
if (agent && agent.defaultContext === undefined) {
|
|
2269
|
+
return { error: `context: "profile" requires agent '${agentName}' to declare defaultContext.` };
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
const contextForAgent = (agentName: string): ContextMode => {
|
|
2273
|
+
const context = byName.get(agentName)?.defaultContext;
|
|
2274
|
+
if (context === undefined) throw new Error(`context: "profile" requires agent '${agentName}' to declare defaultContext.`);
|
|
2275
|
+
return context;
|
|
2276
|
+
};
|
|
2277
|
+
const contextSummary = summarizeContextModes(collectRequestedAgentNames(params).map(contextForAgent));
|
|
2278
|
+
return {
|
|
2279
|
+
params,
|
|
2280
|
+
contextForAgent,
|
|
2281
|
+
contextSummary,
|
|
2282
|
+
usesFork: contextSummary === "fork" || contextSummary === "mixed",
|
|
2283
|
+
};
|
|
2284
|
+
}
|
|
2285
|
+
if (params.context === "fresh" || params.context === "fork") return resolveExplicitContextPolicy(params);
|
|
2253
2286
|
const byName = new Map(agents.map((agent) => [agent.name, agent]));
|
|
2254
2287
|
const contextForAgent = (agentName: string): ContextMode =>
|
|
2255
2288
|
resolveSubagentLaunchContext({
|
|
2256
|
-
explicitContext:
|
|
2289
|
+
explicitContext: undefined,
|
|
2257
2290
|
agentDefaultContext: byName.get(agentName)?.defaultContext,
|
|
2258
2291
|
defaultSubagentContext,
|
|
2259
2292
|
canUseImplicitFork: canUseDefaultFork,
|
|
@@ -2271,7 +2304,7 @@ function resolveAgentDefaultContextPolicy(
|
|
|
2271
2304
|
|
|
2272
2305
|
function resolveExplicitContextPolicy(params: SubagentParamsLike): AgentDefaultContextPolicy {
|
|
2273
2306
|
const context = resolveSubagentLaunchContext({
|
|
2274
|
-
explicitContext: params.context,
|
|
2307
|
+
explicitContext: params.context === "profile" ? undefined : params.context,
|
|
2275
2308
|
canUseImplicitFork: false,
|
|
2276
2309
|
});
|
|
2277
2310
|
return {
|
|
@@ -2294,6 +2327,31 @@ function shouldForkAgent(contextPolicy: AgentDefaultContextPolicy, agentName: st
|
|
|
2294
2327
|
return contextPolicy.contextForAgent(agentName) === "fork";
|
|
2295
2328
|
}
|
|
2296
2329
|
|
|
2330
|
+
function intercomBridgeAppliesToAgent(bridge: IntercomBridgeState, contextPolicy: AgentDefaultContextPolicy, agentName: string): boolean {
|
|
2331
|
+
if (!bridge.active) return false;
|
|
2332
|
+
return bridge.mode !== "fork-only" || shouldForkAgent(contextPolicy, agentName);
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
function applyScopedIntercomBridgeToAgents(agents: AgentConfig[], bridge: IntercomBridgeState, contextPolicy: AgentDefaultContextPolicy): AgentConfig[] {
|
|
2336
|
+
if (!bridge.active) return agents;
|
|
2337
|
+
return agents.map((agent) => intercomBridgeAppliesToAgent(bridge, contextPolicy, agent.name)
|
|
2338
|
+
? applyIntercomBridgeToAgent(agent, bridge)
|
|
2339
|
+
: agent);
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
function resolveChildIntercomTargetFactory(bridge: IntercomBridgeState, contextPolicy: AgentDefaultContextPolicy, runId: string): ((agent: string, index: number) => string | undefined) | undefined {
|
|
2343
|
+
if (!bridge.active) return undefined;
|
|
2344
|
+
return (agent, index) => intercomBridgeAppliesToAgent(bridge, contextPolicy, agent)
|
|
2345
|
+
? resolveSubagentIntercomTarget(runId, agent, index)
|
|
2346
|
+
: undefined;
|
|
2347
|
+
}
|
|
2348
|
+
|
|
2349
|
+
function resolveRunLevelIntercomTarget(bridge: IntercomBridgeState, contextPolicy: AgentDefaultContextPolicy): string | undefined {
|
|
2350
|
+
if (!bridge.active) return undefined;
|
|
2351
|
+
if (bridge.mode === "fork-only" && contextPolicy.contextSummary === "mixed") return undefined;
|
|
2352
|
+
return bridge.orchestratorTarget;
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2297
2355
|
function summarizeResultContext(details: Details, fallback: ContextSummary | undefined): ContextSummary | undefined {
|
|
2298
2356
|
return summarizeContextModes(details.results.map((result) => result.context)) ?? fallback;
|
|
2299
2357
|
}
|
|
@@ -2305,7 +2363,7 @@ function buildRequestedModeError(params: SubagentParamsLike, message: string): A
|
|
|
2305
2363
|
isError: true,
|
|
2306
2364
|
details: { mode: getRequestedModeLabel(params), results: [] },
|
|
2307
2365
|
},
|
|
2308
|
-
params.context,
|
|
2366
|
+
params.context === "profile" ? undefined : params.context,
|
|
2309
2367
|
);
|
|
2310
2368
|
}
|
|
2311
2369
|
|
|
@@ -2810,8 +2868,8 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2810
2868
|
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
2811
2869
|
const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth);
|
|
2812
2870
|
const currentProvider = parentModel?.provider;
|
|
2813
|
-
const controlIntercomTarget = intercomBridge
|
|
2814
|
-
const childIntercomTarget = intercomBridge
|
|
2871
|
+
const controlIntercomTarget = resolveRunLevelIntercomTarget(intercomBridge, contextPolicy);
|
|
2872
|
+
const childIntercomTarget = resolveChildIntercomTargetFactory(intercomBridge, contextPolicy, id);
|
|
2815
2873
|
|
|
2816
2874
|
|
|
2817
2875
|
if (hasSingle) {
|
|
@@ -2825,7 +2883,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2825
2883
|
}
|
|
2826
2884
|
const rawOutput = params.output !== undefined ? params.output : a.output;
|
|
2827
2885
|
const effectiveOutput = normalizeSingleOutputOverride(rawOutput, a.output);
|
|
2828
|
-
const effectiveOutputMode = params.outputMode ?? "inline";
|
|
2886
|
+
const effectiveOutputMode = params.outputMode ?? a.outputMode ?? "inline";
|
|
2829
2887
|
const normalizedSkills = normalizeSkillInput(params.skill);
|
|
2830
2888
|
const skills = normalizedSkills === false ? [] : normalizedSkills;
|
|
2831
2889
|
const maxSubagentDepth = resolveChildMaxSubagentDepth(currentMaxSubagentDepth, a.maxSubagentDepth);
|
|
@@ -3158,7 +3216,8 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3158
3216
|
contextPolicy,
|
|
3159
3217
|
} = data;
|
|
3160
3218
|
const onControlEvent = createForegroundControlNotifier(data, deps);
|
|
3161
|
-
const
|
|
3219
|
+
const childBridgeActive = intercomBridgeAppliesToAgent(data.intercomBridge, contextPolicy, params.agent!);
|
|
3220
|
+
const childIntercomTarget = childBridgeActive ? resolveSubagentIntercomTarget(runId, params.agent!, 0) : undefined;
|
|
3162
3221
|
const allProgress: AgentProgress[] = [];
|
|
3163
3222
|
const allArtifactPaths: ArtifactPaths[] = [];
|
|
3164
3223
|
const agentConfig = agents.find((a) => a.name === params.agent);
|
|
@@ -3189,7 +3248,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3189
3248
|
let readsOverride: string[] | false | undefined = params.reads;
|
|
3190
3249
|
const rawOutput = params.output !== undefined ? params.output : agentConfig.output;
|
|
3191
3250
|
let effectiveOutput = normalizeSingleOutputOverride(rawOutput, agentConfig.output);
|
|
3192
|
-
const effectiveOutputMode = params.outputMode ?? "inline";
|
|
3251
|
+
const effectiveOutputMode = params.outputMode ?? agentConfig.outputMode ?? "inline";
|
|
3193
3252
|
const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth);
|
|
3194
3253
|
const maxSubagentDepth = resolveChildMaxSubagentDepth(currentMaxSubagentDepth, agentConfig.maxSubagentDepth);
|
|
3195
3254
|
|
|
@@ -3317,7 +3376,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3317
3376
|
controlConfig,
|
|
3318
3377
|
onControlEvent,
|
|
3319
3378
|
intercomSessionName: childIntercomTarget,
|
|
3320
|
-
orchestratorIntercomTarget:
|
|
3379
|
+
orchestratorIntercomTarget: childBridgeActive ? data.intercomBridge.orchestratorTarget : undefined,
|
|
3321
3380
|
nestedRoute: foregroundControl?.nestedRoute,
|
|
3322
3381
|
index: 0,
|
|
3323
3382
|
modelOverride,
|
|
@@ -3579,7 +3638,12 @@ export function bindMissionWorkflowChildAsyncLaunch(
|
|
|
3579
3638
|
return { ...params, workflowChildAsyncId: id };
|
|
3580
3639
|
}
|
|
3581
3640
|
|
|
3582
|
-
function workflowChildResult(
|
|
3641
|
+
function workflowChildResult(
|
|
3642
|
+
key: string,
|
|
3643
|
+
result: AgentToolResult<Details>,
|
|
3644
|
+
childParams: Record<string, unknown> = {},
|
|
3645
|
+
resumeState?: SubagentState,
|
|
3646
|
+
): WorkflowScriptChildResult {
|
|
3583
3647
|
const receiptOutput = result.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n");
|
|
3584
3648
|
const output = result.details.results.length === 1 && result.details.results[0]?.finalOutput !== undefined
|
|
3585
3649
|
? result.details.results[0].finalOutput
|
|
@@ -3596,15 +3660,41 @@ function workflowChildResult(key: string, result: AgentToolResult<Details>): Wor
|
|
|
3596
3660
|
}
|
|
3597
3661
|
const structured = result.details.results.map((child) => child.structuredOutput).filter((value) => value !== undefined);
|
|
3598
3662
|
const resolvedAgents = [...new Set(result.details.results.map((child) => child.agent).filter((agent): agent is string => Boolean(agent)))];
|
|
3663
|
+
const resolvedContexts = [...new Set(result.details.results.map((child) => child.context).filter((context): context is "fresh" | "fork" => context === "fresh" || context === "fork"))];
|
|
3664
|
+
const runId = result.details.runId ?? result.details.asyncId;
|
|
3665
|
+
let resumability: WorkflowScriptChildResult["resumability"];
|
|
3666
|
+
if (!runId || !resumeState) {
|
|
3667
|
+
resumability = { state: "not-resumable", reason: runId ? "resumability was not inspected" : "child produced no run id" };
|
|
3668
|
+
} else {
|
|
3669
|
+
try {
|
|
3670
|
+
const target = resolveResumeTarget({ id: runId }, resumeState, { asyncRequireSessionFile: true, exactOnly: true });
|
|
3671
|
+
resumability = target.kind === "revive"
|
|
3672
|
+
? { state: "resumable" }
|
|
3673
|
+
: { state: "not-resumable", reason: "child is still running" };
|
|
3674
|
+
} catch (error) {
|
|
3675
|
+
resumability = { state: "not-resumable", reason: error instanceof Error ? error.message : String(error) };
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
const requestedContext = childParams.context === "fresh" || childParams.context === "fork" ? childParams.context : undefined;
|
|
3679
|
+
const resolvedContext = result.details.context ?? (resolvedContexts.length === 1 ? resolvedContexts[0] : resolvedContexts.length > 1 ? "mixed" : undefined);
|
|
3680
|
+
const resumeSourceRunId = typeof childParams.resume === "string" && childParams.resume.trim() ? childParams.resume.trim() : undefined;
|
|
3681
|
+
const continuationRunIds = [...new Set([resumeSourceRunId, runId].filter((value): value is string => Boolean(value)))];
|
|
3682
|
+
const outputReference = result.details.results.find((child) => child.savedOutputPath)?.savedOutputPath
|
|
3683
|
+
?? result.details.results.find((child) => child.outputReference?.path)?.outputReference?.path;
|
|
3599
3684
|
return {
|
|
3600
3685
|
key,
|
|
3601
3686
|
ok,
|
|
3602
3687
|
...(resolvedAgents.length === 1 ? { agent: resolvedAgents[0] } : {}),
|
|
3603
|
-
...(
|
|
3688
|
+
...(runId ? { runId } : {}),
|
|
3604
3689
|
output,
|
|
3605
3690
|
...(!ok ? { error: receiptOutput || output || "Child run failed." } : {}),
|
|
3606
3691
|
...(detached ? { detached: true } : {}),
|
|
3607
3692
|
...(structured.length === 1 ? { structuredOutput: structured[0] } : structured.length > 1 ? { structuredOutput: structured } : {}),
|
|
3693
|
+
...(requestedContext ? { requestedContext } : {}),
|
|
3694
|
+
...(resolvedContext ? { resolvedContext } : {}),
|
|
3695
|
+
...(outputReference ? { outputReference } : {}),
|
|
3696
|
+
resumability,
|
|
3697
|
+
continuation: { runIds: continuationRunIds },
|
|
3608
3698
|
artifactPaths: [...artifactPaths],
|
|
3609
3699
|
results: result.details.results,
|
|
3610
3700
|
};
|
|
@@ -3627,6 +3717,31 @@ function workflowSteerReceipt(key: string, result: AgentToolResult<Details>): Wo
|
|
|
3627
3717
|
};
|
|
3628
3718
|
}
|
|
3629
3719
|
|
|
3720
|
+
function resolveKeyedWorkflowResume(
|
|
3721
|
+
reference: WorkflowReceiptResumeReference,
|
|
3722
|
+
state: SubagentState,
|
|
3723
|
+
): { runId: string; runIds: string[] } {
|
|
3724
|
+
const entry = resolveWorkflowReceiptResumeEntry({
|
|
3725
|
+
reference,
|
|
3726
|
+
asyncDirRoot: DIRS.async,
|
|
3727
|
+
assertResumable(runId) {
|
|
3728
|
+
const target = resolveResumeTarget({ id: runId }, state, { asyncRequireSessionFile: true, exactOnly: true });
|
|
3729
|
+
if (target.kind !== "revive") throw new Error(`Workflow receipt child '${reference.key}' latest run '${runId}' is still running.`);
|
|
3730
|
+
},
|
|
3731
|
+
});
|
|
3732
|
+
const runId = entry.latestRunId;
|
|
3733
|
+
if (!runId) throw new Error(`Workflow receipt child '${reference.key}' has no retained run id.`);
|
|
3734
|
+
return { runId, runIds: entry.continuation.runIds };
|
|
3735
|
+
}
|
|
3736
|
+
|
|
3737
|
+
function terminalWorkflowReceipt(
|
|
3738
|
+
workflowRunId: string,
|
|
3739
|
+
state: WorkflowReceiptState,
|
|
3740
|
+
children: WorkflowScriptChildResult[],
|
|
3741
|
+
): WorkflowReceipt {
|
|
3742
|
+
return buildWorkflowReceipt({ workflowRunId, state, children });
|
|
3743
|
+
}
|
|
3744
|
+
|
|
3630
3745
|
export async function steerWorkflowChildByKey(input: {
|
|
3631
3746
|
state: SubagentState;
|
|
3632
3747
|
workflowRunId: string;
|
|
@@ -4018,7 +4133,6 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4018
4133
|
// The event log is a journal, not workflow truth. Callers append from
|
|
4019
4134
|
// inside run-result handling, so losing an entry to a full disk or to a
|
|
4020
4135
|
// transient Windows lock must not fail the run being recorded.
|
|
4021
|
-
if (!isStorageCapacityError(error) && !isRetryableFileSystemError(error)) throw error;
|
|
4022
4136
|
console.error(`Failed to append async workflow event '${eventsPath}':`, error);
|
|
4023
4137
|
}
|
|
4024
4138
|
};
|
|
@@ -4248,9 +4362,9 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4248
4362
|
appendWorkflowEvent({ type: "subagent.workflow.emit", value: emits.at(-1) });
|
|
4249
4363
|
},
|
|
4250
4364
|
launch: async (key, childParams, workflowSignal, admission) => {
|
|
4251
|
-
if (workflowUsageBudget.budget && childParams.async === true) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, "workflow usageBudget does not support async runs.run launches."));
|
|
4365
|
+
if (workflowUsageBudget.budget && childParams.async === true) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, "workflow usageBudget does not support async runs.run launches."), childParams, deps.state);
|
|
4252
4366
|
const budgetState = usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults));
|
|
4253
|
-
if (budgetState?.exhausted) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, usageBudgetExceededMessage(budgetState)));
|
|
4367
|
+
if (budgetState?.exhausted) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, usageBudgetExceededMessage(budgetState)), childParams, deps.state);
|
|
4254
4368
|
const childPhase = typeof childParams.phase === "string" && childParams.phase.trim() ? childParams.phase.trim() : undefined;
|
|
4255
4369
|
const childLabel = typeof childParams.label === "string" && childParams.label.trim() ? childParams.label.trim() : undefined;
|
|
4256
4370
|
recordMissionWorkflowChild(missionBinding, workflowRunId, key, {
|
|
@@ -4307,7 +4421,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4307
4421
|
for (const childResult of result.details.results) {
|
|
4308
4422
|
if (childResult.savedOutputPath) producedChildOutputPaths.add(childResult.savedOutputPath);
|
|
4309
4423
|
}
|
|
4310
|
-
const child = workflowChildResult(key, result);
|
|
4424
|
+
const child = workflowChildResult(key, result, childParams, deps.state);
|
|
4311
4425
|
if (child.runId) workflowChildRunIds.set(key, child.runId);
|
|
4312
4426
|
const step = status.steps?.find((candidate) => candidate.workflowKey === key);
|
|
4313
4427
|
if (step) {
|
|
@@ -4332,6 +4446,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4332
4446
|
return child;
|
|
4333
4447
|
},
|
|
4334
4448
|
status: async (keyOrRunId, workflowSignal) => workflowChildResult(keyOrRunId, await execute(randomUUID(), { action: "status", id: keyOrRunId }, workflowSignal, undefined, ctx, preserveActiveSession)),
|
|
4449
|
+
resolveResume: (reference) => resolveKeyedWorkflowResume(reference, deps.state),
|
|
4335
4450
|
steer: (key, message, options, workflowSignal) => steerWorkflowChildByKey({ state: deps.state, workflowRunId, key, message, options, signal: workflowSignal, resolveRunId: () => workflowChildRunIds.get(key) }),
|
|
4336
4451
|
});
|
|
4337
4452
|
const returnPreview = formatWorkflowValue(workflow.value).slice(0, 1_000);
|
|
@@ -4341,7 +4456,14 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4341
4456
|
const resultSummary = appendWorkflowOutputWarning(summary, outputWarning);
|
|
4342
4457
|
const workflowUsage = sumResultsUsage(workflowResults);
|
|
4343
4458
|
status = { ...status, state: "complete", endedAt: Date.now(), workflow: { value: workflow.value, trace: workflow.trace, emits: workflow.emits, console: workflow.console }, totalTokens: { input: workflowUsage.input, output: workflowUsage.output, total: workflowUsage.input + workflowUsage.output }, totalCost: sumResultsCost(workflowResults) };
|
|
4344
|
-
|
|
4459
|
+
const receipt = terminalWorkflowReceipt(workflowRunId, "complete", workflow.children);
|
|
4460
|
+
let workflowReceipt: { path: string; receipt: WorkflowReceipt } | undefined;
|
|
4461
|
+
try {
|
|
4462
|
+
workflowReceipt = { path: writeWorkflowReceipt(asyncDir, receipt), receipt };
|
|
4463
|
+
} catch (receiptError) {
|
|
4464
|
+
appendWorkflowEvent({ type: "subagent.workflow.receipt_write_failed", error: `Failed to persist async workflow receipt: ${receiptError instanceof Error ? receiptError.message : String(receiptError)}` });
|
|
4465
|
+
}
|
|
4466
|
+
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: true, state: "complete", summary: resultSummary, output: resultSummary, results: workflow.children.map((child) => ({ workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
|
|
4345
4467
|
persist();
|
|
4346
4468
|
persistClosed = true;
|
|
4347
4469
|
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, ...(status.error ? { error: status.error } : {}) });
|
|
@@ -4373,7 +4495,15 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4373
4495
|
: status.error ?? (pauseForDetached ? "Workflow paused." : "Workflow failed.");
|
|
4374
4496
|
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, terminalSummary, producedChildOutputPaths);
|
|
4375
4497
|
const resultSummary = appendWorkflowOutputWarning(terminalSummary, outputWarning);
|
|
4376
|
-
|
|
4498
|
+
const receiptState: WorkflowReceiptState = status.state === "complete" ? "complete" : status.state === "paused" ? "paused" : status.state === "stopped" ? "stopped" : "failed";
|
|
4499
|
+
const receipt = terminalWorkflowReceipt(workflowRunId, receiptState, partial.children);
|
|
4500
|
+
let workflowReceipt: { path: string; receipt: WorkflowReceipt } | undefined;
|
|
4501
|
+
try {
|
|
4502
|
+
workflowReceipt = { path: writeWorkflowReceipt(asyncDir, receipt), receipt };
|
|
4503
|
+
} catch (receiptError) {
|
|
4504
|
+
appendWorkflowEvent({ type: "subagent.workflow.receipt_write_failed", error: `Failed to persist async workflow receipt: ${receiptError instanceof Error ? receiptError.message : String(receiptError)}` });
|
|
4505
|
+
}
|
|
4506
|
+
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: status.state === "complete", state: status.state, summary: resultSummary, error: status.state === "complete" ? undefined : status.error, stopped: status.stopped, activityState: status.activityState, results: partial.children.map((child) => ({ workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.detached && status.state !== "complete" ? { detached: true } : {}), ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
|
|
4377
4507
|
persist();
|
|
4378
4508
|
persistClosed = true;
|
|
4379
4509
|
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, ...(status.error ? { error: status.error } : {}), ...(status.activityState ? { activityState: status.activityState } : {}) });
|
|
@@ -4426,9 +4556,9 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4426
4556
|
sendWorkflowProgress();
|
|
4427
4557
|
},
|
|
4428
4558
|
launch: async (key, childParams, workflowSignal, admission) => {
|
|
4429
|
-
if (workflowUsageBudget.budget && childParams.async === true) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, "workflow usageBudget does not support async runs.run launches."));
|
|
4559
|
+
if (workflowUsageBudget.budget && childParams.async === true) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, "workflow usageBudget does not support async runs.run launches."), childParams, deps.state);
|
|
4430
4560
|
const budgetState = usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults));
|
|
4431
|
-
if (budgetState?.exhausted) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, usageBudgetExceededMessage(budgetState)));
|
|
4561
|
+
if (budgetState?.exhausted) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, usageBudgetExceededMessage(budgetState)), childParams, deps.state);
|
|
4432
4562
|
const childPhase = typeof childParams.phase === "string" && childParams.phase.trim() ? childParams.phase.trim() : undefined;
|
|
4433
4563
|
const childLabel = typeof childParams.label === "string" && childParams.label.trim() ? childParams.label.trim() : undefined;
|
|
4434
4564
|
recordMissionWorkflowChild(missionBinding, _id, key, {
|
|
@@ -4464,7 +4594,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4464
4594
|
if (childResult.savedOutputPath) producedChildOutputPaths.add(childResult.savedOutputPath);
|
|
4465
4595
|
}
|
|
4466
4596
|
if (result.details.asyncDir && missionBinding) writeMissionAsyncBinding(result.details.asyncDir, missionBinding);
|
|
4467
|
-
const child = workflowChildResult(key, result);
|
|
4597
|
+
const child = workflowChildResult(key, result, childParams, deps.state);
|
|
4468
4598
|
if (child.runId) workflowChildRunIds.set(key, child.runId);
|
|
4469
4599
|
const childStatus = missionWorkflowChildStatus(result);
|
|
4470
4600
|
recordMissionWorkflowChild(missionBinding, _id, key, {
|
|
@@ -4479,8 +4609,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4479
4609
|
return child;
|
|
4480
4610
|
},
|
|
4481
4611
|
status: async (keyOrRunId, workflowSignal) => workflowChildResult(keyOrRunId, await execute(randomUUID(), { action: "status", id: keyOrRunId }, workflowSignal, undefined, ctx, preserveActiveSession)),
|
|
4612
|
+
resolveResume: (reference) => resolveKeyedWorkflowResume(reference, deps.state),
|
|
4482
4613
|
steer: (key, message, options, workflowSignal) => steerWorkflowChildByKey({ state: deps.state, workflowRunId: _id, key, message, options, signal: workflowSignal, resolveRunId: () => workflowChildRunIds.get(key) }),
|
|
4483
4614
|
});
|
|
4615
|
+
const receipt = terminalWorkflowReceipt(_id, "complete", workflow.children);
|
|
4484
4616
|
const traceLines = workflow.trace.map((entry) => `- ${entry.operation} ${entry.key}: ${entry.state}${entry.runId ? ` (${entry.runId})` : ""}${entry.durationMs !== undefined ? ` in ${entry.durationMs}ms` : ""}${entry.error ? ` — ${entry.error}` : ""}`);
|
|
4485
4617
|
const sections = ["Workflow completed.", `Return:\n${formatWorkflowValue(workflow.value)}`];
|
|
4486
4618
|
if (workflow.emits.length > 0) sections.push(`Emitted:\n${workflow.emits.map(formatWorkflowValue).join("\n")}`);
|
|
@@ -4491,7 +4623,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4491
4623
|
const displayText = appendWorkflowOutputWarning(workflowText, outputWarning);
|
|
4492
4624
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
4493
4625
|
content: [{ type: "text", text: displayText }],
|
|
4494
|
-
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: workflow.children.flatMap((child) => (child.results ?? []) as SingleResult[]), totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { value: workflow.value, trace: workflow.trace, emits: workflow.emits, console: workflow.console }, chatProgress }),
|
|
4626
|
+
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: workflow.children.flatMap((child) => (child.results ?? []) as SingleResult[]), totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { value: workflow.value, trace: workflow.trace, emits: workflow.emits, console: workflow.console, receipt }, chatProgress }),
|
|
4495
4627
|
}, workflowFanoutBudget));
|
|
4496
4628
|
} catch (error) {
|
|
4497
4629
|
const partial = error instanceof WorkflowScriptError ? error.partial : { trace: [], emits: [], console: [], children: [] };
|
|
@@ -4504,10 +4636,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4504
4636
|
const workflowText = sections.join("\n\n");
|
|
4505
4637
|
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, workflowText, producedChildOutputPaths);
|
|
4506
4638
|
const displayText = appendWorkflowOutputWarning(workflowText, outputWarning);
|
|
4639
|
+
const receipt = terminalWorkflowReceipt(_id, "failed", partial.children);
|
|
4507
4640
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
4508
4641
|
content: [{ type: "text", text: displayText }],
|
|
4509
4642
|
isError: true,
|
|
4510
|
-
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: partial.children.flatMap((child) => (child.results ?? []) as SingleResult[]), totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { trace: partial.trace, emits: partial.emits, console: partial.console }, chatProgress }),
|
|
4643
|
+
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: partial.children.flatMap((child) => (child.results ?? []) as SingleResult[]), totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { trace: partial.trace, emits: partial.emits, console: partial.console, receipt }, chatProgress }),
|
|
4511
4644
|
}, workflowFanoutBudget));
|
|
4512
4645
|
}
|
|
4513
4646
|
}
|
|
@@ -4757,7 +4890,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4757
4890
|
cwd: requestCwd,
|
|
4758
4891
|
config: deps.config,
|
|
4759
4892
|
state: deps.state,
|
|
4760
|
-
context: paramsWithResolvedCwd.context,
|
|
4893
|
+
context: paramsWithResolvedCwd.context === "profile" ? undefined : paramsWithResolvedCwd.context,
|
|
4761
4894
|
requestedSessionDir: paramsWithResolvedCwd.sessionDir,
|
|
4762
4895
|
currentSessionFile,
|
|
4763
4896
|
currentSessionId,
|
|
@@ -5071,6 +5204,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5071
5204
|
cwd: requestCwd,
|
|
5072
5205
|
config: deps.config,
|
|
5073
5206
|
currentSessionId: deps.state.currentSessionId ?? ctx.sessionManager.getSessionId() ?? undefined,
|
|
5207
|
+
runtimeAgentOwner: deps.pi,
|
|
5074
5208
|
});
|
|
5075
5209
|
}
|
|
5076
5210
|
|
|
@@ -5127,23 +5261,25 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5127
5261
|
// Prefer fork only when the parent session is persisted and has a current leaf;
|
|
5128
5262
|
// otherwise use fresh immediately instead of launching a guaranteed-to-fail fork.
|
|
5129
5263
|
// Explicit context:"fork" remains strict.
|
|
5130
|
-
const
|
|
5264
|
+
const contextPolicyResult = resolveAgentDefaultContextPolicy(
|
|
5131
5265
|
effectiveParams,
|
|
5132
5266
|
discoveredAgents,
|
|
5133
5267
|
deps.config.defaultSubagentContext,
|
|
5134
5268
|
canPreferFork(ctx.sessionManager),
|
|
5135
5269
|
);
|
|
5270
|
+
if ("error" in contextPolicyResult) return buildRequestedModeError(effectiveParams, contextPolicyResult.error);
|
|
5271
|
+
const contextPolicy = contextPolicyResult;
|
|
5136
5272
|
effectiveParams = contextPolicy.params;
|
|
5137
5273
|
const sessionName = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
5138
5274
|
const intercomBridge = resolveIntercomBridge({
|
|
5139
5275
|
config: deps.config.intercomBridge,
|
|
5140
5276
|
override: effectiveParams.intercomBridge,
|
|
5141
|
-
context: effectiveParams.context
|
|
5277
|
+
context: effectiveParams.context === "fresh" || effectiveParams.context === "fork"
|
|
5278
|
+
? effectiveParams.context
|
|
5279
|
+
: contextPolicy.usesFork ? "fork" : undefined,
|
|
5142
5280
|
orchestratorTarget: sessionName,
|
|
5143
5281
|
});
|
|
5144
|
-
const agents = intercomBridge
|
|
5145
|
-
? discoveredAgents.map((agent) => applyIntercomBridgeToAgent(agent, intercomBridge))
|
|
5146
|
-
: discoveredAgents;
|
|
5282
|
+
const agents = applyScopedIntercomBridgeToAgents(discoveredAgents, intercomBridge, contextPolicy);
|
|
5147
5283
|
const runId = randomUUID();
|
|
5148
5284
|
const inheritedNestedRoute = resolveInheritedNestedRouteFromEnv();
|
|
5149
5285
|
const nestedParentAddress = inheritedNestedRoute ? resolveNestedParentAddressFromEnv() : undefined;
|
|
@@ -5546,7 +5682,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5546
5682
|
startedLaunches = selectedAgentNames.map((agent) => ({ agent }));
|
|
5547
5683
|
}
|
|
5548
5684
|
const agentsForSummary = startedLaunches.map((launch) => launch.agent);
|
|
5549
|
-
const leafIntercomTarget =
|
|
5685
|
+
const leafIntercomTarget = agentsForSummary[0] && intercomBridgeAppliesToAgent(intercomBridge, contextPolicy, agentsForSummary[0])
|
|
5550
5686
|
? resolveSubagentIntercomTarget(runId, agentsForSummary[0], 0)
|
|
5551
5687
|
: undefined;
|
|
5552
5688
|
try {
|