pi-subagents 0.53.0 → 0.55.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 +66 -5
- package/README.md +1 -1
- package/agents/reviewer.md +12 -2
- package/docs/agents.md +4 -4
- package/docs/configuration.md +6 -6
- package/docs/extension-api.md +14 -4
- package/docs/models.md +41 -6
- package/docs/observability.md +14 -3
- package/docs/tool-reference.md +21 -6
- package/docs/workflows.md +7 -1
- package/index.ts +10 -1
- package/package.json +1 -1
- package/prompts/council.md +19 -7
- package/prompts/parallel-review.md +5 -1
- package/prompts/review-loop.md +9 -5
- package/skills/council-mode/SKILL.md +50 -26
- package/skills/pi-subagents/SKILL.md +5 -1
- package/skills/pi-subagents/references/constraints-and-recipes.md +16 -1
- package/skills/pi-subagents/references/execution-controls.md +13 -4
- package/skills/pi-subagents/references/multi-lane-orchestration.md +3 -3
- package/skills/pi-subagents/references/prompting-and-roles.md +14 -7
- package/src/agents/agent-management.ts +115 -14
- package/src/agents/agent-serializer.ts +2 -2
- package/src/agents/agents.ts +195 -47
- package/src/api/external-job-provider.ts +10 -1
- package/src/api/preflight.ts +33 -19
- package/src/api/project-panes.ts +2 -0
- package/src/extension/doctor.ts +10 -0
- package/src/extension/fanout-child.ts +3 -2
- package/src/extension/index.ts +24 -4
- package/src/extension/public-execution.ts +12 -9
- package/src/extension/rpc.ts +77 -3
- package/src/extension/schemas.ts +2 -1
- package/src/extension/tool-description.ts +9 -6
- package/src/extension/tool-result.ts +19 -0
- package/src/inspectors/herdr/client.ts +3 -3
- package/src/inspectors/herdr/focus.ts +55 -0
- package/src/inspectors/herdr/project-panes.ts +228 -44
- package/src/integrations/herdr-status.ts +26 -4
- package/src/runs/background/async-execution.ts +112 -13
- package/src/runs/background/async-job-tracker.ts +33 -14
- package/src/runs/background/async-resume.ts +20 -2
- package/src/runs/background/async-retention.ts +1 -1
- package/src/runs/background/async-status.ts +10 -0
- package/src/runs/background/chain-root-attachment.ts +5 -0
- package/src/runs/background/control-channel.ts +98 -10
- package/src/runs/background/notify.ts +62 -1
- package/src/runs/background/result-watcher.ts +4 -3
- package/src/runs/background/run-status.ts +15 -1
- package/src/runs/background/stale-run-reconciler.ts +3 -0
- package/src/runs/background/subagent-runner.ts +251 -38
- package/src/runs/background/wait-completions.ts +2 -0
- package/src/runs/background/wait-tool.ts +4 -3
- package/src/runs/foreground/async-stop-action.ts +23 -2
- package/src/runs/foreground/execution.ts +110 -8
- package/src/runs/foreground/subagent-executor.ts +361 -45
- package/src/runs/foreground/workflow-detach-reconcile.ts +3 -0
- package/src/runs/shared/acceptance.ts +1 -0
- package/src/runs/shared/child-identity.ts +36 -0
- package/src/runs/shared/completion-guard.ts +50 -1
- package/src/runs/shared/external-job-bridge.ts +53 -37
- package/src/runs/shared/external-job-runner.ts +126 -23
- package/src/runs/shared/model-fallback.ts +46 -15
- package/src/runs/shared/model-scope.ts +106 -39
- package/src/runs/shared/orca-progress-tabs.ts +71 -9
- package/src/runs/shared/parallel-utils.ts +12 -0
- package/src/runs/shared/pi-args.ts +31 -1
- package/src/runs/shared/subagent-prompt-runtime.ts +39 -10
- package/src/runs/shared/tool-availability.ts +1 -3
- package/src/shared/launch-contract.ts +6 -5
- package/src/shared/thinking-ceiling.ts +52 -0
- package/src/shared/types.ts +72 -5
- package/src/tui/fleet-status.ts +66 -13
- package/src/tui/render.ts +5 -4
- package/src/watchdog/permission-arbiter.ts +59 -51
- package/src/workflows/scripted-workflow.ts +107 -10
|
@@ -26,14 +26,16 @@ import { buildAgentMemoryInjection } from "../../agents/agent-memory.ts";
|
|
|
26
26
|
import { PI_CODING_AGENT_PACKAGE_ROOT_ENV, PROMPT_REDACTED, resolveChildCwd } from "../../shared/utils.ts";
|
|
27
27
|
import { buildModelCandidates, inheritsParentModel, resolveEffectiveSubagentModel, resolveModelCandidate, resolveSubagentModelOverride, type AvailableModelInfo, type ParentModel } from "../shared/model-fallback.ts";
|
|
28
28
|
import { resolveToolTimeoutMs, toolTimeoutFromEnv } from "../shared/tool-timeout.ts";
|
|
29
|
-
import type
|
|
29
|
+
import { resolveModelScopesForAgent, type ModelScopeConfig } from "../shared/model-scope.ts";
|
|
30
30
|
import { resolveEffectiveThinking } from "../../shared/model-info.ts";
|
|
31
|
+
import { assertThinkingWithinCeiling, decodeThinkingCeiling, intersectThinkingCeilings, SUBAGENT_THINKING_CEILING_ENV, type ThinkingLevel } from "../../shared/thinking-ceiling.ts";
|
|
31
32
|
import { resolveExpectedWorktreeAgentCwd } from "../shared/worktree.ts";
|
|
32
33
|
import { buildWorkflowGraphSnapshot } from "../shared/workflow-graph.ts";
|
|
33
34
|
import { ChainOutputValidationError, validateChainOutputBindings } from "../shared/chain-outputs.ts";
|
|
34
35
|
import { createStructuredOutputRuntime } from "../shared/structured-output.ts";
|
|
35
36
|
import { resolveEffectiveAcceptance, validateAcceptanceInput, validateExecutionAcceptance } from "../shared/acceptance.ts";
|
|
36
37
|
import { createRunFanoutBudget, writeRunFanoutBudgetDescriptor } from "../shared/run-fanout-budget.ts";
|
|
38
|
+
import { validateImplementationToolContract } from "../shared/completion-guard.ts";
|
|
37
39
|
import {
|
|
38
40
|
type AcceptanceInput,
|
|
39
41
|
type AgentContract,
|
|
@@ -187,6 +189,7 @@ interface AsyncChainParams {
|
|
|
187
189
|
/** Global cap on simultaneously-running subagent tasks within the async run. */
|
|
188
190
|
globalConcurrencyLimit?: number;
|
|
189
191
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
192
|
+
thinkingCeiling?: ThinkingLevel;
|
|
190
193
|
runFanoutBudget?: RunFanoutBudgetDescriptor;
|
|
191
194
|
parentWorkflowRunId?: string;
|
|
192
195
|
workflowKey?: string;
|
|
@@ -249,10 +252,19 @@ interface AsyncSingleParams {
|
|
|
249
252
|
toolTimeoutMsEnv?: string | undefined;
|
|
250
253
|
allowZeroToolBudget?: boolean;
|
|
251
254
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
255
|
+
thinkingCeiling?: ThinkingLevel;
|
|
252
256
|
runFanoutBudget?: RunFanoutBudgetDescriptor;
|
|
253
257
|
parentWorkflowRunId?: string;
|
|
254
258
|
workflowKey?: string;
|
|
259
|
+
workflowAwaitAsync?: boolean;
|
|
255
260
|
activeAsyncCapacity?: ActiveAsyncCapacityHandle;
|
|
261
|
+
externalJobFollowUp?: {
|
|
262
|
+
sourceRunId: string;
|
|
263
|
+
sourceStepIndex: number;
|
|
264
|
+
parentProviderJobId: string;
|
|
265
|
+
requestId: string;
|
|
266
|
+
requestDigest: string;
|
|
267
|
+
};
|
|
256
268
|
}
|
|
257
269
|
|
|
258
270
|
interface AsyncExecutionResult {
|
|
@@ -292,6 +304,7 @@ export interface AsyncRunnerStepBuildParams {
|
|
|
292
304
|
/** PI_SUBAGENT_TOOL_TIMEOUT_MS override (lowest precedence). */
|
|
293
305
|
toolTimeoutMsEnv?: string | undefined;
|
|
294
306
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
307
|
+
thinkingCeiling?: ThinkingLevel;
|
|
295
308
|
}
|
|
296
309
|
|
|
297
310
|
export type AsyncRunnerStepBuildResult =
|
|
@@ -791,18 +804,33 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
791
804
|
const taskText = `${readInstructions.prefix}${taskTemplate}${progressInstructions.suffix}`;
|
|
792
805
|
const task = namespaceOutputPath ? taskText : injectSingleOutputInstruction(taskText, outputPath, a);
|
|
793
806
|
|
|
807
|
+
const modelScopes = resolveModelScopesForAgent(ctx.modelScope, a.name, ctx.currentModel);
|
|
808
|
+
const primaryModelFromParent = inheritsParentModel(s.model, a.model, ctx.currentModel);
|
|
794
809
|
const primaryModel = externalRunner ? undefined : resolveEffectiveSubagentModel(
|
|
795
810
|
s.model,
|
|
796
811
|
a.model,
|
|
797
812
|
ctx.currentModel,
|
|
798
813
|
availableModels,
|
|
799
|
-
ctx.currentModelProvider,
|
|
800
|
-
{ scope:
|
|
814
|
+
a.modelProvider ?? ctx.currentModelProvider,
|
|
815
|
+
{ scope: modelScopes },
|
|
801
816
|
);
|
|
802
817
|
const thinkingOverride = flatIndex === undefined ? undefined : thinkingOverridesByFlatIndex?.[flatIndex];
|
|
803
818
|
const effectiveThinking = externalRunner ? undefined : thinkingOverride ?? a.thinking;
|
|
804
819
|
const model = externalRunner ? undefined : applyThinkingSuffix(primaryModel, effectiveThinking, thinkingOverride !== undefined);
|
|
820
|
+
const thinkingCeiling = externalRunner ? undefined : intersectThinkingCeilings(
|
|
821
|
+
params.thinkingCeiling,
|
|
822
|
+
a.maxThinking,
|
|
823
|
+
decodeThinkingCeiling(process.env[SUBAGENT_THINKING_CEILING_ENV]),
|
|
824
|
+
);
|
|
825
|
+
if (!externalRunner) {
|
|
826
|
+
try {
|
|
827
|
+
assertThinkingWithinCeiling({ model, configThinking: effectiveThinking, ceiling: thinkingCeiling, agent: a.name, runId: id });
|
|
828
|
+
} catch (error) {
|
|
829
|
+
throw new AsyncStartValidationError(error instanceof Error ? error.message : String(error));
|
|
830
|
+
}
|
|
831
|
+
}
|
|
805
832
|
const agentContract = s.agentContract ?? params.agentContract;
|
|
833
|
+
const permissionRules = resolvePermissionRules(ctx.permissions, a.permissions);
|
|
806
834
|
const toolPlan = resolvePiLaunchToolPlan({
|
|
807
835
|
tools: a.tools,
|
|
808
836
|
extensions: a.extensions,
|
|
@@ -814,12 +842,40 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
814
842
|
capabilityCeiling: params.capabilityCeiling,
|
|
815
843
|
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
816
844
|
agentName: a.name,
|
|
845
|
+
permissionRules,
|
|
817
846
|
});
|
|
818
847
|
const launchResolvedExtensions = externalRunner ? undefined : projectLaunchResolvedChildExtensions(toolPlan);
|
|
819
|
-
const permissionRules = resolvePermissionRules(ctx.permissions, a.permissions);
|
|
820
848
|
if (externalRunner && permissionRules) {
|
|
821
849
|
throw new AsyncStartValidationError(`Agent '${a.name}' uses runner.type='${externalRunnerType}', which cannot enforce native Pi child permission rules.`);
|
|
822
850
|
}
|
|
851
|
+
if (!externalRunner) {
|
|
852
|
+
const contractTools = toolPlan.explicitToolAllowlist ? toolPlan.effectiveToolAllowlist : undefined;
|
|
853
|
+
const contractError = validateImplementationToolContract({
|
|
854
|
+
agent: a.name,
|
|
855
|
+
task,
|
|
856
|
+
tools: contractTools,
|
|
857
|
+
mcpDirectTools: toolPlan.effectiveMcpTools,
|
|
858
|
+
configuredExtensions: toolPlan.configuredExtensions,
|
|
859
|
+
requestedTools: toolPlan.requestedBuiltinTools,
|
|
860
|
+
acceptanceRole: a.acceptanceRole,
|
|
861
|
+
completionGuard: a.completionGuard,
|
|
862
|
+
});
|
|
863
|
+
if (contractError) throw new AsyncStartValidationError(contractError);
|
|
864
|
+
}
|
|
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
|
+
}
|
|
823
879
|
return {
|
|
824
880
|
parentSessionId: ctx.parentSessionId ?? ctx.currentSessionId,
|
|
825
881
|
permissionRules,
|
|
@@ -837,13 +893,11 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
837
893
|
cwd: stepCwd,
|
|
838
894
|
model,
|
|
839
895
|
thinking: resolveEffectiveThinking(model, effectiveThinking),
|
|
896
|
+
...(thinkingCeiling ? { thinkingCeiling } : {}),
|
|
840
897
|
launchResolvedExtensions,
|
|
841
|
-
modelCandidates: externalRunner ? undefined :
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
}).map((candidate) =>
|
|
845
|
-
applyThinkingSuffix(candidate, effectiveThinking, thinkingOverride !== undefined),
|
|
846
|
-
),
|
|
898
|
+
modelCandidates: externalRunner ? undefined : modelCandidates,
|
|
899
|
+
...(primaryModelFromParent ? { skipPrimaryModelVerification: true } : {}),
|
|
900
|
+
...(availableModels && availableModels.length > 0 ? { modelVerificationRegistry: availableModels } : {}),
|
|
847
901
|
tools: a.tools,
|
|
848
902
|
extensions: a.extensions,
|
|
849
903
|
subagentOnlyExtensions: a.subagentOnlyExtensions,
|
|
@@ -960,6 +1014,7 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
960
1014
|
acceptanceRole: agent.acceptanceRole,
|
|
961
1015
|
...(s.agentContract ?? params.agentContract ? { agentContract: s.agentContract ?? params.agentContract } : {}),
|
|
962
1016
|
...(s.gateOn ? { gateOn: s.gateOn } : {}),
|
|
1017
|
+
...(parallel.thinkingCeiling ? { thinkingCeiling: parallel.thinkingCeiling } : {}),
|
|
963
1018
|
};
|
|
964
1019
|
}
|
|
965
1020
|
const sequential = s as SequentialStep;
|
|
@@ -1094,6 +1149,7 @@ export function executeAsyncChain(
|
|
|
1094
1149
|
configToolTimeoutMs: params.configToolTimeoutMs,
|
|
1095
1150
|
toolTimeoutMsEnv: params.toolTimeoutMsEnv ?? toolTimeoutFromEnv(),
|
|
1096
1151
|
capabilityCeiling,
|
|
1152
|
+
thinkingCeiling: params.thinkingCeiling,
|
|
1097
1153
|
});
|
|
1098
1154
|
if ("error" in built) {
|
|
1099
1155
|
try {
|
|
@@ -1418,6 +1474,7 @@ export function executeAsyncSingle(
|
|
|
1418
1474
|
? `[Read from: ${readPaths.join(", ")}]\n\n`
|
|
1419
1475
|
: "";
|
|
1420
1476
|
const taskText = readsInstruction + taskWithOutputInstruction;
|
|
1477
|
+
const modelScopes = resolveModelScopesForAgent(ctx.modelScope, agentConfig.name, ctx.currentModel);
|
|
1421
1478
|
const primaryModel = externalRunner ? undefined : params.modelOverrideFromParent
|
|
1422
1479
|
? params.modelOverride
|
|
1423
1480
|
: resolveSubagentModelOverride(
|
|
@@ -1425,9 +1482,22 @@ export function executeAsyncSingle(
|
|
|
1425
1482
|
ctx.currentModel,
|
|
1426
1483
|
availableModels,
|
|
1427
1484
|
ctx.currentModelProvider,
|
|
1485
|
+
{ scope: modelScopes },
|
|
1428
1486
|
);
|
|
1429
1487
|
const effectiveThinking = externalRunner ? undefined : params.thinkingOverride ?? agentConfig.thinking;
|
|
1430
1488
|
const model = externalRunner ? undefined : applyThinkingSuffix(primaryModel, effectiveThinking, params.thinkingOverride !== undefined);
|
|
1489
|
+
const thinkingCeiling = externalRunner ? undefined : intersectThinkingCeilings(
|
|
1490
|
+
params.thinkingCeiling,
|
|
1491
|
+
agentConfig.maxThinking,
|
|
1492
|
+
decodeThinkingCeiling(process.env[SUBAGENT_THINKING_CEILING_ENV]),
|
|
1493
|
+
);
|
|
1494
|
+
if (!externalRunner) {
|
|
1495
|
+
try {
|
|
1496
|
+
assertThinkingWithinCeiling({ model, configThinking: effectiveThinking, ceiling: thinkingCeiling, agent: agentConfig.name, runId: id });
|
|
1497
|
+
} catch (error) {
|
|
1498
|
+
return formatAsyncStartError("single", error instanceof Error ? error.message : String(error));
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1431
1501
|
const toolBudgetInput = params.toolBudget ?? agentConfig.toolBudget ?? params.configToolBudget;
|
|
1432
1502
|
const resolvedToolBudget = validateToolBudgetConfig(toolBudgetInput, params.toolBudget ? "toolBudget" : agentConfig.toolBudget ? "agent.toolBudget" : "config.toolBudget");
|
|
1433
1503
|
if (resolvedToolBudget.error) return formatAsyncStartError("single", resolvedToolBudget.error);
|
|
@@ -1452,14 +1522,21 @@ export function executeAsyncSingle(
|
|
|
1452
1522
|
: undefined;
|
|
1453
1523
|
const modelCandidates = externalRunner
|
|
1454
1524
|
? []
|
|
1455
|
-
: buildModelCandidates(primaryModel, agentConfig.fallbackModels, availableModels, ctx.currentModelProvider, {
|
|
1456
|
-
scope:
|
|
1525
|
+
: buildModelCandidates(primaryModel, agentConfig.fallbackModels, availableModels, agentConfig.modelProvider ?? ctx.currentModelProvider, {
|
|
1526
|
+
scope: modelScopes,
|
|
1457
1527
|
primaryModelFromParent: params.modelOverrideFromParent,
|
|
1458
1528
|
})
|
|
1459
1529
|
.flatMap((candidate) => {
|
|
1460
1530
|
const resolved = applyThinkingSuffix(candidate, effectiveThinking, params.thinkingOverride !== undefined);
|
|
1461
1531
|
return resolved ? [resolved] : [];
|
|
1462
1532
|
});
|
|
1533
|
+
if (!externalRunner) {
|
|
1534
|
+
try {
|
|
1535
|
+
for (const candidate of modelCandidates) assertThinkingWithinCeiling({ model: candidate, configThinking: effectiveThinking, ceiling: thinkingCeiling, agent: agentConfig.name, runId: id });
|
|
1536
|
+
} catch (error) {
|
|
1537
|
+
return formatAsyncStartError("single", error instanceof Error ? error.message : String(error));
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1463
1540
|
const effectiveSystemPrompt = appendTurnBudgetSystemPrompt(systemPrompt, params.turnBudget);
|
|
1464
1541
|
const toolPlan = resolvePiLaunchToolPlan({
|
|
1465
1542
|
tools: agentConfig.tools,
|
|
@@ -1472,14 +1549,30 @@ export function executeAsyncSingle(
|
|
|
1472
1549
|
capabilityCeiling,
|
|
1473
1550
|
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
1474
1551
|
agentName: agentConfig.name,
|
|
1552
|
+
permissionRules: resolvePermissionRules(ctx.permissions, agentConfig.permissions),
|
|
1475
1553
|
});
|
|
1476
1554
|
const launchResolvedExtensions = externalRunner ? undefined : projectLaunchResolvedChildExtensions(toolPlan);
|
|
1555
|
+
if (!externalRunner) {
|
|
1556
|
+
const contractTools = toolPlan.explicitToolAllowlist ? toolPlan.effectiveToolAllowlist : undefined;
|
|
1557
|
+
const contractError = validateImplementationToolContract({
|
|
1558
|
+
agent: agentConfig.name,
|
|
1559
|
+
task: taskText,
|
|
1560
|
+
tools: contractTools,
|
|
1561
|
+
mcpDirectTools: toolPlan.effectiveMcpTools,
|
|
1562
|
+
configuredExtensions: toolPlan.configuredExtensions,
|
|
1563
|
+
requestedTools: toolPlan.requestedBuiltinTools,
|
|
1564
|
+
acceptanceRole: agentConfig.acceptanceRole,
|
|
1565
|
+
completionGuard: agentConfig.completionGuard,
|
|
1566
|
+
});
|
|
1567
|
+
if (contractError) return formatAsyncStartError("single", contractError);
|
|
1568
|
+
}
|
|
1477
1569
|
const launchContractDigest = launchBindingDigest({
|
|
1478
1570
|
definitionDigest: agentDefinitionDigest(agentConfig),
|
|
1479
1571
|
task,
|
|
1480
1572
|
...(model ? { model } : {}),
|
|
1481
1573
|
modelCandidates,
|
|
1482
1574
|
...(resolveEffectiveThinking(model, effectiveThinking) ? { thinking: resolveEffectiveThinking(model, effectiveThinking) } : {}),
|
|
1575
|
+
...(thinkingCeiling ? { thinkingCeiling } : {}),
|
|
1483
1576
|
systemPrompt: effectiveSystemPrompt,
|
|
1484
1577
|
systemPromptMode: agentConfig.systemPromptMode,
|
|
1485
1578
|
inheritProjectContext: agentConfig.inheritProjectContext,
|
|
@@ -1513,9 +1606,11 @@ export function executeAsyncSingle(
|
|
|
1513
1606
|
...(sessionFile ? { sessionFile } : {}),
|
|
1514
1607
|
cwd: runnerCwd,
|
|
1515
1608
|
...(model ? { model } : {}),
|
|
1609
|
+
...(recoveryAgentConfig.modelProvider ? { modelProvider: recoveryAgentConfig.modelProvider } : {}),
|
|
1516
1610
|
...(params.modelOverrideFromParent ? { modelOverrideFromParent: true } : {}),
|
|
1517
1611
|
...(recoveryAgentConfig.fallbackModels ? { fallbackModels: [...recoveryAgentConfig.fallbackModels] } : {}),
|
|
1518
1612
|
...(effectiveThinking ? { thinking: resolveEffectiveThinking(model, effectiveThinking) } : {}),
|
|
1613
|
+
...(thinkingCeiling ? { thinkingCeiling } : {}),
|
|
1519
1614
|
...(recoveryAgentConfig.tools ? { tools: [...recoveryAgentConfig.tools] } : {}),
|
|
1520
1615
|
...(recoveryAgentConfig.extensions ? { extensions: [...recoveryAgentConfig.extensions] } : {}),
|
|
1521
1616
|
...(recoveryAgentConfig.subagentOnlyExtensions ? { subagentOnlyExtensions: [...recoveryAgentConfig.subagentOnlyExtensions] } : {}),
|
|
@@ -1567,11 +1662,15 @@ export function executeAsyncSingle(
|
|
|
1567
1662
|
agent,
|
|
1568
1663
|
task: taskText,
|
|
1569
1664
|
...(agentConfig.runner ? { runner: agentConfig.runner } : {}),
|
|
1665
|
+
...(params.externalJobFollowUp ? { externalJobFollowUp: params.externalJobFollowUp } : {}),
|
|
1570
1666
|
...(params.context ? { context: params.context } : {}),
|
|
1571
1667
|
cwd: runnerCwd,
|
|
1572
1668
|
model,
|
|
1573
1669
|
thinking: resolveEffectiveThinking(model, effectiveThinking),
|
|
1670
|
+
...(thinkingCeiling ? { thinkingCeiling } : {}),
|
|
1574
1671
|
modelCandidates,
|
|
1672
|
+
...(params.modelOverrideFromParent ? { skipPrimaryModelVerification: true } : {}),
|
|
1673
|
+
...(availableModels && availableModels.length > 0 ? { modelVerificationRegistry: availableModels } : {}),
|
|
1575
1674
|
tools: agentConfig.tools,
|
|
1576
1675
|
extensions: agentConfig.extensions,
|
|
1577
1676
|
subagentOnlyExtensions: agentConfig.subagentOnlyExtensions,
|
|
@@ -1599,7 +1698,7 @@ export function executeAsyncSingle(
|
|
|
1599
1698
|
...(params.worktree === true ? { worktree: true } : {}),
|
|
1600
1699
|
},
|
|
1601
1700
|
],
|
|
1602
|
-
resultPath: params.parentWorkflowRunId !== undefined && params.revivalLease !== undefined
|
|
1701
|
+
resultPath: params.parentWorkflowRunId !== undefined && (params.revivalLease !== undefined || params.workflowAwaitAsync === true)
|
|
1603
1702
|
? workflowAwaitedAsyncResultPath(asyncDir)
|
|
1604
1703
|
: inheritedNestedRoute ? nestedResultsPath(inheritedNestedRoute.rootRunId, id) : resultFilePath(DIRS.results, id),
|
|
1605
1704
|
cwd: runnerCwd,
|
|
@@ -8,12 +8,14 @@ import {
|
|
|
8
8
|
type AsyncStartedEvent,
|
|
9
9
|
type ControlEvent,
|
|
10
10
|
type SteeringNotice,
|
|
11
|
+
type SubagentChildStatusEvent,
|
|
11
12
|
type SubagentState,
|
|
12
|
-
POLL_INTERVAL_MS,
|
|
13
13
|
DIRS,
|
|
14
|
+
SUBAGENT_CHILD_STATUS_EVENT,
|
|
14
15
|
SUBAGENT_CONTROL_EVENT,
|
|
15
16
|
SUBAGENT_CONTROL_INTERCOM_EVENT,
|
|
16
17
|
SUBAGENT_STEERING_NOTICE_EVENT,
|
|
18
|
+
WIDGET_ANIMATION_INTERVAL_MS,
|
|
17
19
|
} from "../../shared/types.ts";
|
|
18
20
|
import { readStatus, resolveWatchPath } from "../../shared/utils.ts";
|
|
19
21
|
import { normalizeParallelGroups } from "./parallel-groups.ts";
|
|
@@ -71,6 +73,7 @@ export function createAsyncJobTracker(pi: Pick<ExtensionAPI, "events">, state: S
|
|
|
71
73
|
const runningJobIds = new Set<string>();
|
|
72
74
|
let rootWatcher: fs.FSWatcher | undefined;
|
|
73
75
|
let nextLivenessAt = Date.now() + livenessIntervalMs;
|
|
76
|
+
let nextWidgetAnimationAt = Date.now() + WIDGET_ANIMATION_INTERVAL_MS;
|
|
74
77
|
const watch = options.watch ?? fs.watch;
|
|
75
78
|
const useNativeWatcher = () => shouldUseNativeFsWatch("async-job-tracker", options.platform);
|
|
76
79
|
const terminalStatus = (status: string) => status === "complete" || status === "failed" || status === "paused" || status === "stopped";
|
|
@@ -93,17 +96,8 @@ export function createAsyncJobTracker(pi: Pick<ExtensionAPI, "events">, state: S
|
|
|
93
96
|
}
|
|
94
97
|
};
|
|
95
98
|
const requestLastWidgetRender = () => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
if (ctx.hasUI) (ctx.ui as { requestRender?: () => void }).requestRender?.();
|
|
100
|
-
} catch (error) {
|
|
101
|
-
if (error instanceof Error && error.message.includes("extension ctx is stale")) {
|
|
102
|
-
state.lastUiContext = null;
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
throw error;
|
|
106
|
-
}
|
|
99
|
+
if (options.widgetEnabled === false) return;
|
|
100
|
+
rerenderLastWidget();
|
|
107
101
|
};
|
|
108
102
|
const refreshWidget = (ctx: ExtensionContext) => rerenderWidget(ctx);
|
|
109
103
|
const restoredControlEventCursor = (asyncDir: string) => {
|
|
@@ -227,6 +221,28 @@ export function createAsyncJobTracker(pi: Pick<ExtensionAPI, "events">, state: S
|
|
|
227
221
|
return;
|
|
228
222
|
}
|
|
229
223
|
if (!parsed || typeof parsed !== "object") return;
|
|
224
|
+
if ((parsed as { type?: unknown }).type === "subagent.child-status") {
|
|
225
|
+
const event = parsed as Partial<SubagentChildStatusEvent>;
|
|
226
|
+
if (event.version !== 1 || typeof event.runId !== "string" || typeof event.childId !== "string" || (event.status !== "stopping" && event.status !== "stopped") || typeof event.ts !== "number") return;
|
|
227
|
+
pi.events.emit(SUBAGENT_CHILD_STATUS_EVENT, {
|
|
228
|
+
type: "subagent.child-status",
|
|
229
|
+
version: 1,
|
|
230
|
+
runId: event.runId,
|
|
231
|
+
childId: event.childId,
|
|
232
|
+
status: event.status,
|
|
233
|
+
ts: event.ts,
|
|
234
|
+
...(typeof event.reason === "string" ? { reason: event.reason } : {}),
|
|
235
|
+
source: event.source === "rpc" ? "rpc" : "async",
|
|
236
|
+
asyncDir: job.asyncDir,
|
|
237
|
+
...(typeof event.stepIndex === "number" ? { stepIndex: event.stepIndex } : {}),
|
|
238
|
+
...(typeof event.agent === "string" ? { agent: event.agent } : {}),
|
|
239
|
+
...(typeof event.childRunId === "string" ? { childRunId: event.childRunId } : {}),
|
|
240
|
+
...(typeof event.workflowKey === "string" ? { workflowKey: event.workflowKey } : {}),
|
|
241
|
+
...(typeof event.phase === "string" ? { phase: event.phase } : {}),
|
|
242
|
+
...(typeof event.label === "string" ? { label: event.label } : {}),
|
|
243
|
+
} satisfies SubagentChildStatusEvent);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
230
246
|
if ((parsed as { type?: unknown }).type === "subagent.steering.notice") {
|
|
231
247
|
const notice = parsed as Partial<SteeringNotice>;
|
|
232
248
|
if (typeof notice.requestId !== "string" || typeof notice.runId !== "string" || (notice.state !== "failed" && notice.state !== "partial" && notice.state !== "recovered") || typeof notice.message !== "string") return;
|
|
@@ -556,8 +572,11 @@ export function createAsyncJobTracker(pi: Pick<ExtensionAPI, "events">, state: S
|
|
|
556
572
|
}
|
|
557
573
|
if (widgetChanged) rerenderLastWidget();
|
|
558
574
|
}
|
|
559
|
-
if (runningJobIds.size > 0)
|
|
560
|
-
|
|
575
|
+
if (runningJobIds.size > 0 && now >= nextWidgetAnimationAt) {
|
|
576
|
+
nextWidgetAnimationAt = now + WIDGET_ANIMATION_INTERVAL_MS;
|
|
577
|
+
requestLastWidgetRender();
|
|
578
|
+
}
|
|
579
|
+
}, Math.min(WIDGET_ANIMATION_INTERVAL_MS, livenessIntervalMs));
|
|
561
580
|
state.poller.unref?.();
|
|
562
581
|
};
|
|
563
582
|
|
|
@@ -11,6 +11,7 @@ import { reconcileAsyncRun } from "./stale-run-reconciler.ts";
|
|
|
11
11
|
import { resultFilePath, resultPayloadPathForIndexedRun } from "./result-files.ts";
|
|
12
12
|
import { canScanAsyncRunPrefix, MIN_SAFE_ASYNC_RUN_PREFIX_LENGTH } from "./run-id-query.ts";
|
|
13
13
|
import { parallelHandoffPath, resolveRetainedWorktreeCwd } from "../shared/parallel-handoff.ts";
|
|
14
|
+
import { intersectThinkingCeilings, parseThinkingLevel, type ThinkingLevel } from "../../shared/thinking-ceiling.ts";
|
|
14
15
|
|
|
15
16
|
export interface AsyncResumeParams {
|
|
16
17
|
id?: string;
|
|
@@ -43,9 +44,12 @@ export type AsyncResumeTarget = {
|
|
|
43
44
|
sessionFile?: string;
|
|
44
45
|
model?: string;
|
|
45
46
|
thinking?: string;
|
|
47
|
+
thinkingCeiling?: ThinkingLevel;
|
|
46
48
|
recoveryDescriptor?: SteeringRecoveryDescriptor;
|
|
47
49
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
48
50
|
launchContractDigest?: string;
|
|
51
|
+
runner?: NonNullable<AsyncStatus["steps"]>[number]["runner"];
|
|
52
|
+
externalJob?: NonNullable<AsyncStatus["steps"]>[number]["externalJob"];
|
|
49
53
|
};
|
|
50
54
|
|
|
51
55
|
interface AsyncResultFile {
|
|
@@ -265,6 +269,7 @@ function validateStatusForResume(status: AsyncStatus | null, source: string): vo
|
|
|
265
269
|
if (stepRecord.sessionFile !== undefined && typeof stepRecord.sessionFile !== "string") throw new Error(`Invalid async status '${source}': steps[${index}].sessionFile must be a string.`);
|
|
266
270
|
if (stepRecord.model !== undefined && typeof stepRecord.model !== "string") throw new Error(`Invalid async status '${source}': steps[${index}].model must be a string.`);
|
|
267
271
|
if (stepRecord.thinking !== undefined && typeof stepRecord.thinking !== "string") throw new Error(`Invalid async status '${source}': steps[${index}].thinking must be a string.`);
|
|
272
|
+
if (stepRecord.thinkingCeiling !== undefined) stepRecord.thinkingCeiling = parseThinkingLevel(stepRecord.thinkingCeiling, `async status '${source}' steps[${index}].thinkingCeiling`);
|
|
268
273
|
if (stepRecord.launchContractDigest !== undefined && typeof stepRecord.launchContractDigest !== "string") throw new Error(`Invalid async status '${source}': steps[${index}].launchContractDigest must be a string.`);
|
|
269
274
|
if (stepRecord.capabilityCeiling !== undefined) stepRecord.capabilityCeiling = parseSubagentCapabilityCeiling(stepRecord.capabilityCeiling, `async status '${source}' steps[${index}].capabilityCeiling`);
|
|
270
275
|
});
|
|
@@ -318,7 +323,7 @@ export function readAsyncRecoveryDescriptor(asyncDir: string | undefined): Steer
|
|
|
318
323
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`Invalid async recovery descriptor '${descriptorPath}': expected an object.`);
|
|
319
324
|
const parsed = value as Record<string, unknown>;
|
|
320
325
|
const allowedFields = new Set([
|
|
321
|
-
"version", "launchContractDigest", "sourceRunId", "agentContract", "agent", "sessionFile", "cwd", "model", "modelOverrideFromParent", "fallbackModels", "thinking", "tools", "extensions",
|
|
326
|
+
"version", "launchContractDigest", "sourceRunId", "agentContract", "agent", "sessionFile", "cwd", "model", "modelProvider", "modelOverrideFromParent", "fallbackModels", "thinking", "thinkingCeiling", "tools", "extensions",
|
|
322
327
|
"subagentOnlyExtensions", "mcpDirectTools", "systemPrompt", "systemPromptMode", "inheritProjectContext", "inheritSkills", "skills",
|
|
323
328
|
"skillPath", "agentFilePath", "completionGuard", "memory", "outputPath", "outputMode", "structuredOutputSchema", "acceptance", "sessionDir", "artifactConfig",
|
|
324
329
|
"artifactsDir", "maxOutput", "controlConfig", "context", "intercomBridge", "absoluteDeadlineAt", "initialTurnBudget", "initialToolBudget", "maxSubagentDepth", "share", "capabilityCeiling",
|
|
@@ -338,6 +343,7 @@ export function readAsyncRecoveryDescriptor(asyncDir: string | undefined): Steer
|
|
|
338
343
|
throw new Error(`Invalid async recovery descriptor '${descriptorPath}': ${error instanceof Error ? error.message : String(error)}`);
|
|
339
344
|
}
|
|
340
345
|
if (parsed.capabilityCeiling !== undefined) parsed.capabilityCeiling = parseSubagentCapabilityCeiling(parsed.capabilityCeiling, `async recovery descriptor '${descriptorPath}' capabilityCeiling`);
|
|
346
|
+
if (parsed.thinkingCeiling !== undefined) parsed.thinkingCeiling = parseThinkingLevel(parsed.thinkingCeiling, `async recovery descriptor '${descriptorPath}' thinkingCeiling`);
|
|
341
347
|
if (parsed.agentContract !== undefined) {
|
|
342
348
|
if (!parsed.agentContract || typeof parsed.agentContract !== "object" || Array.isArray(parsed.agentContract)) throw new Error(`Invalid async recovery descriptor '${descriptorPath}': agentContract must be an object.`);
|
|
343
349
|
const contract = parsed.agentContract as Record<string, unknown>;
|
|
@@ -356,7 +362,7 @@ export function readAsyncRecoveryDescriptor(asyncDir: string | undefined): Steer
|
|
|
356
362
|
if (item !== undefined && (!Array.isArray(item) || item.some((entry) => typeof entry !== "string" || !entry.trim()))) throw new Error(`Invalid async recovery descriptor '${descriptorPath}': ${field} must contain non-empty strings.`);
|
|
357
363
|
}
|
|
358
364
|
if (parsed.systemPrompt !== undefined && typeof parsed.systemPrompt !== "string") throw new Error(`Invalid async recovery descriptor '${descriptorPath}': systemPrompt must be a string.`);
|
|
359
|
-
for (const field of ["launchContractDigest", "sessionFile", "model", "thinking", "agentFilePath", "outputPath", "sessionDir", "artifactsDir"] as const) {
|
|
365
|
+
for (const field of ["launchContractDigest", "sessionFile", "model", "modelProvider", "thinking", "agentFilePath", "outputPath", "sessionDir", "artifactsDir"] as const) {
|
|
360
366
|
if (parsed[field] !== undefined && (typeof parsed[field] !== "string" || !(parsed[field] as string).trim())) throw new Error(`Invalid async recovery descriptor '${descriptorPath}': ${field} must be a non-empty string.`);
|
|
361
367
|
}
|
|
362
368
|
if (parsed.completionGuard !== undefined && typeof parsed.completionGuard !== "boolean") throw new Error(`Invalid async recovery descriptor '${descriptorPath}': completionGuard must be a boolean.`);
|
|
@@ -487,7 +493,10 @@ export function resolveAsyncResumeTarget(params: AsyncResumeParams, deps: AsyncR
|
|
|
487
493
|
model: selectedStep.model,
|
|
488
494
|
thinking: selectedStep.thinking,
|
|
489
495
|
launchContractDigest: selectedStep.launchContractDigest ?? result?.results?.[requestedIndex]?.launchContractDigest ?? result?.launchContractDigest ?? recoveryDescriptor?.launchContractDigest,
|
|
496
|
+
...(selectedStep.runner ? { runner: selectedStep.runner } : {}),
|
|
497
|
+
...(selectedStep.externalJob ? { externalJob: selectedStep.externalJob } : {}),
|
|
490
498
|
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
499
|
+
...(selectedStep.thinkingCeiling ? { thinkingCeiling: selectedStep.thinkingCeiling } : {}),
|
|
491
500
|
...(recoveryDescriptor ? { recoveryDescriptor } : {}),
|
|
492
501
|
};
|
|
493
502
|
}
|
|
@@ -515,7 +524,10 @@ export function resolveAsyncResumeTarget(params: AsyncResumeParams, deps: AsyncR
|
|
|
515
524
|
model: selected.step.model,
|
|
516
525
|
thinking: selected.step.thinking,
|
|
517
526
|
launchContractDigest: selected.step.launchContractDigest ?? result?.results?.[selected.index]?.launchContractDigest ?? result?.launchContractDigest ?? recoveryDescriptor?.launchContractDigest,
|
|
527
|
+
...(selected.step.runner ? { runner: selected.step.runner } : {}),
|
|
528
|
+
...(selected.step.externalJob ? { externalJob: selected.step.externalJob } : {}),
|
|
518
529
|
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
530
|
+
...(selected.step.thinkingCeiling ? { thinkingCeiling: selected.step.thinkingCeiling } : {}),
|
|
519
531
|
...(recoveryDescriptor ? { recoveryDescriptor } : {}),
|
|
520
532
|
};
|
|
521
533
|
}
|
|
@@ -537,6 +549,7 @@ export function resolveAsyncResumeTarget(params: AsyncResumeParams, deps: AsyncR
|
|
|
537
549
|
const resolvedSessionFile = sessionFile ? validateResumeSessionFile(runId, sessionFile) : undefined;
|
|
538
550
|
const stepModel = statusSteps[index]?.model ?? resultSteps[index]?.model ?? (stepCount === 1 ? result?.model : undefined);
|
|
539
551
|
const stepThinking = statusSteps[index]?.thinking ?? resultSteps[index]?.thinking ?? (stepCount === 1 ? result?.thinking : undefined);
|
|
552
|
+
const thinkingCeiling = statusSteps[index]?.thinkingCeiling ?? (stepCount === 1 ? recoveryDescriptor?.thinkingCeiling : undefined);
|
|
540
553
|
const capabilityCeiling = intersectSubagentCapabilityCeilings(status?.capabilityCeiling, statusSteps[index]?.capabilityCeiling, result?.capabilityCeiling, resultSteps[index]?.capabilityCeiling);
|
|
541
554
|
const managedWorktreeCwd = location.asyncDir
|
|
542
555
|
? resolveRetainedWorktreeCwd(parallelHandoffPath(location.asyncDir), runId, index)
|
|
@@ -556,7 +569,10 @@ export function resolveAsyncResumeTarget(params: AsyncResumeParams, deps: AsyncR
|
|
|
556
569
|
...(stepModel ? { model: stepModel } : {}),
|
|
557
570
|
...(stepThinking ? { thinking: stepThinking } : {}),
|
|
558
571
|
launchContractDigest: statusSteps[index]?.launchContractDigest ?? resultSteps[index]?.launchContractDigest ?? result?.launchContractDigest ?? recoveryDescriptor?.launchContractDigest,
|
|
572
|
+
...(statusSteps[index]?.runner ? { runner: statusSteps[index]!.runner } : {}),
|
|
573
|
+
...(statusSteps[index]?.externalJob ? { externalJob: statusSteps[index]!.externalJob } : {}),
|
|
559
574
|
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
575
|
+
...(thinkingCeiling ? { thinkingCeiling } : {}),
|
|
560
576
|
...(recoveryDescriptor ? { recoveryDescriptor } : {}),
|
|
561
577
|
};
|
|
562
578
|
}
|
|
@@ -565,8 +581,10 @@ export function applySteeringRecoveryAgentConfig(agentConfig: AgentConfig, descr
|
|
|
565
581
|
return {
|
|
566
582
|
...agentConfig,
|
|
567
583
|
model: descriptor.model,
|
|
584
|
+
modelProvider: descriptor.modelProvider,
|
|
568
585
|
fallbackModels: descriptor.fallbackModels ? [...descriptor.fallbackModels] : undefined,
|
|
569
586
|
thinking: descriptor.thinking,
|
|
587
|
+
maxThinking: intersectThinkingCeilings(descriptor.thinkingCeiling, agentConfig.maxThinking),
|
|
570
588
|
tools: descriptor.tools ? [...descriptor.tools] : undefined,
|
|
571
589
|
extensions: descriptor.extensions ? [...descriptor.extensions] : undefined,
|
|
572
590
|
subagentOnlyExtensions: descriptor.subagentOnlyExtensions ? [...descriptor.subagentOnlyExtensions] : undefined,
|
|
@@ -600,7 +600,7 @@ function runRetentionDiscovery(input: {
|
|
|
600
600
|
};
|
|
601
601
|
const onAbort = (): void => fail(new RetentionCancelledError("Retention discovery was cancelled."));
|
|
602
602
|
input.signal?.addEventListener("abort", onAbort, { once: true });
|
|
603
|
-
worker.once("error", (error) => fail(error));
|
|
603
|
+
worker.once("error", (error) => fail(error instanceof Error ? error : new Error(String(error))));
|
|
604
604
|
worker.once("exit", (code) => {
|
|
605
605
|
if (!settled) fail(new Error(`Retention discovery worker exited before replying (${code}).`));
|
|
606
606
|
});
|
|
@@ -15,14 +15,18 @@ import { readProcessTerminal, sanitizeProcessTerminal } from "./process-terminal
|
|
|
15
15
|
import { ACTIVE_RUN_INDEX_DIR, DEFAULT_STALE_TERMINAL_ACTIVE_MARKER_MS, activeRunMarkerAgeMs, isActiveAsyncState, readActiveRunIndex, releaseActiveRunIndex, updateActiveRunIndex } from "./active-run-index.ts";
|
|
16
16
|
import { readRecentTerminalRunIndex, TERMINAL_RUN_INDEX_DIR } from "./terminal-run-index.ts";
|
|
17
17
|
import { canScanAsyncRunPrefix } from "./run-id-query.ts";
|
|
18
|
+
import { asyncStatusChildIdentity } from "../shared/child-identity.ts";
|
|
18
19
|
|
|
19
20
|
interface AsyncRunStepSummary {
|
|
20
21
|
index: number;
|
|
22
|
+
childId?: string;
|
|
21
23
|
agent: string;
|
|
22
24
|
context?: ContextMode;
|
|
23
25
|
label?: string;
|
|
24
26
|
description?: string;
|
|
25
27
|
phase?: string;
|
|
28
|
+
workflowKey?: string;
|
|
29
|
+
runId?: string;
|
|
26
30
|
outputName?: string;
|
|
27
31
|
structured?: boolean;
|
|
28
32
|
status: AsyncJobStep["status"];
|
|
@@ -251,11 +255,14 @@ function statusToSummary(asyncDir: string, status: AsyncStatus & { cwd?: string
|
|
|
251
255
|
const stepLastActivityAt = step.lastActivityAt;
|
|
252
256
|
return {
|
|
253
257
|
index,
|
|
258
|
+
childId: asyncStatusChildIdentity(step, index),
|
|
254
259
|
agent: step.agent,
|
|
255
260
|
...(step.context ? { context: step.context } : {}),
|
|
256
261
|
...(step.label ? { label: step.label } : {}),
|
|
257
262
|
...(step.description ? { description: step.description } : {}),
|
|
258
263
|
...(step.phase ? { phase: step.phase } : {}),
|
|
264
|
+
...(step.workflowKey ? { workflowKey: step.workflowKey } : {}),
|
|
265
|
+
...(step.runId ? { runId: step.runId } : {}),
|
|
259
266
|
...(step.outputName ? { outputName: step.outputName } : {}),
|
|
260
267
|
...(step.structured ? { structured: step.structured } : {}),
|
|
261
268
|
status: step.status,
|
|
@@ -277,12 +284,15 @@ function statusToSummary(asyncDir: string, status: AsyncStatus & { cwd?: string
|
|
|
277
284
|
...(step.skills ? { skills: step.skills } : {}),
|
|
278
285
|
...(step.model ? { model: step.model } : {}),
|
|
279
286
|
...(step.thinking ? { thinking: step.thinking } : {}),
|
|
287
|
+
...(step.thinkingCeiling ? { thinkingCeiling: step.thinkingCeiling } : {}),
|
|
280
288
|
...(step.attemptedModels ? { attemptedModels: step.attemptedModels } : {}),
|
|
281
289
|
...(step.sessionFile ? { sessionFile: step.sessionFile } : {}),
|
|
282
290
|
...(step.transcriptPath ? { transcriptPath: step.transcriptPath } : {}),
|
|
283
291
|
...(step.error ? { error: step.error } : {}),
|
|
284
292
|
...(step.timedOut !== undefined ? { timedOut: step.timedOut } : {}),
|
|
285
293
|
...(step.stopped !== undefined ? { stopped: step.stopped } : {}),
|
|
294
|
+
...(step.stopRequested !== undefined ? { stopRequested: step.stopRequested } : {}),
|
|
295
|
+
...(step.stopRequestedAt !== undefined ? { stopRequestedAt: step.stopRequestedAt } : {}),
|
|
286
296
|
...(step.turnBudget ? { turnBudget: step.turnBudget } : {}),
|
|
287
297
|
...(step.turnBudgetExceeded !== undefined ? { turnBudgetExceeded: step.turnBudgetExceeded } : {}),
|
|
288
298
|
...(step.wrapUpRequested !== undefined ? { wrapUpRequested: step.wrapUpRequested } : {}),
|
|
@@ -21,6 +21,7 @@ export interface ImportedAsyncRootResult {
|
|
|
21
21
|
model?: string;
|
|
22
22
|
attemptedModels?: string[];
|
|
23
23
|
modelAttempts?: ModelAttempt[];
|
|
24
|
+
contextOverflow?: boolean;
|
|
24
25
|
totalCost?: CostSummary;
|
|
25
26
|
structuredOutput?: unknown;
|
|
26
27
|
structuredOutputPath?: string;
|
|
@@ -49,6 +50,7 @@ interface AsyncResultFile {
|
|
|
49
50
|
model?: string;
|
|
50
51
|
attemptedModels?: string[];
|
|
51
52
|
modelAttempts?: ModelAttempt[];
|
|
53
|
+
contextOverflow?: boolean;
|
|
52
54
|
totalCost?: CostSummary;
|
|
53
55
|
structuredOutput?: unknown;
|
|
54
56
|
structuredOutputPath?: string;
|
|
@@ -110,6 +112,7 @@ function outputFromTerminalStatus(root: ImportedAsyncRoot, status: AsyncStatus,
|
|
|
110
112
|
...(step?.model ? { model: step.model } : {}),
|
|
111
113
|
...(step?.attemptedModels ? { attemptedModels: step.attemptedModels } : {}),
|
|
112
114
|
...(step?.modelAttempts ? { modelAttempts: step.modelAttempts } : {}),
|
|
115
|
+
...(step?.contextOverflow ? { contextOverflow: true } : {}),
|
|
113
116
|
...(step?.totalCost ? { totalCost: step.totalCost } : {}),
|
|
114
117
|
...(step?.structuredOutput !== undefined ? { structuredOutput: step.structuredOutput } : {}),
|
|
115
118
|
...(step?.structuredOutputPath ? { structuredOutputPath: step.structuredOutputPath } : {}),
|
|
@@ -131,6 +134,7 @@ function outputFromTimeout(root: ImportedAsyncRoot, status: AsyncStatus | null,
|
|
|
131
134
|
...(step?.model ? { model: step.model } : {}),
|
|
132
135
|
...(step?.attemptedModels ? { attemptedModels: step.attemptedModels } : {}),
|
|
133
136
|
...(step?.modelAttempts ? { modelAttempts: step.modelAttempts } : {}),
|
|
137
|
+
...(step?.contextOverflow ? { contextOverflow: true } : {}),
|
|
134
138
|
...(step?.totalCost ? { totalCost: step.totalCost } : {}),
|
|
135
139
|
};
|
|
136
140
|
}
|
|
@@ -158,6 +162,7 @@ function buildImportedResult(root: ImportedAsyncRoot, status: AsyncStatus | null
|
|
|
158
162
|
...(child?.model ?? step?.model ? { model: child?.model ?? step?.model } : {}),
|
|
159
163
|
...(child?.attemptedModels ?? step?.attemptedModels ? { attemptedModels: child?.attemptedModels ?? step?.attemptedModels } : {}),
|
|
160
164
|
...(child?.modelAttempts ?? step?.modelAttempts ? { modelAttempts: child?.modelAttempts ?? step?.modelAttempts } : {}),
|
|
165
|
+
...(child?.contextOverflow || step?.contextOverflow ? { contextOverflow: true } : {}),
|
|
161
166
|
...(child?.totalCost ?? step?.totalCost ? { totalCost: child?.totalCost ?? step?.totalCost } : {}),
|
|
162
167
|
...(child?.structuredOutput !== undefined ? { structuredOutput: child.structuredOutput } : step?.structuredOutput !== undefined ? { structuredOutput: step.structuredOutput } : {}),
|
|
163
168
|
...(child?.structuredOutputPath ?? step?.structuredOutputPath ? { structuredOutputPath: child?.structuredOutputPath ?? step?.structuredOutputPath } : {}),
|