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
|
@@ -11,7 +11,7 @@ import { createCapacityResilientJsonWriter } from "../../shared/capacity-resilie
|
|
|
11
11
|
import { isStorageCapacityError } from "../../shared/file-system-retry.ts";
|
|
12
12
|
import { updateActiveRunIndex } from "./active-run-index.ts";
|
|
13
13
|
import { createChildTranscriptWriter, type ChildTranscriptWriter } from "../../shared/child-transcript.ts";
|
|
14
|
-
import { closeSteerInbox, consumeInterruptRequest, consumeSteerRequests, deliverInterruptRequest, deliverStopRequest, deliverTimeoutRequest, enqueueStepSteer, steerAcksDir, steerCapabilityPath, stepSteerInboxDir, watchAsyncControlInbox, type SteerAck, type SteerCapability, type SteerRequest } from "./control-channel.ts";
|
|
14
|
+
import { closeSteerInbox, consumeInterruptRequest, consumeSteerRequests, deliverInterruptRequest, deliverStopRequest, deliverTimeoutRequest, enqueueStepSteer, steerAcksDir, steerCapabilityPath, stepSteerInboxDir, watchAsyncControlInbox, type SteerAck, type SteerCapability, type SteerRequest, type StopRequest } from "./control-channel.ts";
|
|
15
15
|
import { appendJsonl as appendRawJsonl, formatOutputArtifactContent, getArtifactPaths, writeArtifact, writeMetadata } from "../../shared/artifacts.ts";
|
|
16
16
|
import { PI_CODING_AGENT_PACKAGE, getPiSpawnCommand, resolveInstalledPiPackageRoot } from "../shared/pi-spawn.ts";
|
|
17
17
|
import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, injectOutputPathSystemPrompt, injectSingleOutputInstruction, resolveSingleOutput, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
type SteeringStatus,
|
|
49
49
|
type SteeringTargetState,
|
|
50
50
|
type SteeringTargetStatus,
|
|
51
|
+
type SubagentChildStatusEvent,
|
|
51
52
|
DEFAULT_MAX_OUTPUT,
|
|
52
53
|
type MaxOutputConfig,
|
|
53
54
|
SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
@@ -85,7 +86,7 @@ import { readChildToolDiagnosticError } from "../shared/tool-availability.ts";
|
|
|
85
86
|
import { collectDynamicResults, DynamicFanoutError, materializeDynamicParallelStep, validateDynamicCollection } from "../shared/dynamic-fanout.ts";
|
|
86
87
|
import { claimRunFanoutBatch, getRunFanoutBudgetSnapshot } from "../shared/run-fanout-budget.ts";
|
|
87
88
|
import { nestedSummaryFromAsyncStatus, projectNestedEvents, resolveNestedAsyncDir, writeNestedEvent } from "../shared/nested-events.ts";
|
|
88
|
-
import { formatModelAttemptNote, isRetryableModelFailure, recordRetryableModelFailure } from "../shared/model-fallback.ts";
|
|
89
|
+
import { formatModelAttemptNote, formatSubagentModelVerificationError, isContextOverflow, isRetryableModelFailure, recordRetryableModelFailure } from "../shared/model-fallback.ts";
|
|
89
90
|
import {
|
|
90
91
|
SUBAGENT_STARTUP_RETRY_DELAYS_MS,
|
|
91
92
|
formatSubagentExtensionConflictError,
|
|
@@ -99,7 +100,7 @@ import { createOwnedProcessTreeController, type OwnedProcessTreeController } fro
|
|
|
99
100
|
import { createSteeringStatus, recordSteeringRequest, steeringStatus, terminalSteeringNoticeState, updateSteeringTarget } from "./steering.ts";
|
|
100
101
|
import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
|
|
101
102
|
import { PROMPT_REDACTED, detectSubagentError, extractTextFromContent, extractToolArgsPreview, getFinalOutput, hasEmptyTerminalAssistantResponse, readStatus } from "../../shared/utils.ts";
|
|
102
|
-
import { evaluateCompletionMutationGuard } from "../shared/completion-guard.ts";
|
|
103
|
+
import { evaluateCompletionMutationGuard, validateImplementationToolContract } from "../shared/completion-guard.ts";
|
|
103
104
|
import {
|
|
104
105
|
createMutatingFailureState,
|
|
105
106
|
didMutatingToolFail,
|
|
@@ -123,6 +124,7 @@ import {
|
|
|
123
124
|
type WorktreeSetup,
|
|
124
125
|
} from "../shared/worktree.ts";
|
|
125
126
|
import { resolveEffectiveThinking } from "../../shared/model-info.ts";
|
|
127
|
+
import { assertThinkingWithinCeiling, decodeThinkingCeiling, SUBAGENT_THINKING_CEILING_ENV } from "../../shared/thinking-ceiling.ts";
|
|
126
128
|
import { launchBindingDigest } from "../../shared/launch-contract.ts";
|
|
127
129
|
import { writeInitialProgressFile } from "../../shared/settings.ts";
|
|
128
130
|
import { resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.ts";
|
|
@@ -130,6 +132,7 @@ import { acceptanceFailureMessage, aggregateAcceptanceReport, buildSkippedAccept
|
|
|
130
132
|
import { attachContractProjections, isAgentContractV1 } from "../shared/agent-contract.ts";
|
|
131
133
|
import { waitForImportedAsyncRoot } from "./chain-root-attachment.ts";
|
|
132
134
|
import { appendRunnerStepsToStatus, consumeChainAppendRequests, countPendingChainAppendRequests, statusStepDescription } from "./chain-append.ts";
|
|
135
|
+
import { asyncStatusChildIdentity } from "../shared/child-identity.ts";
|
|
133
136
|
import { appendTurnBudgetSystemPrompt, formatTurnBudgetOutput, initialTurnBudgetState, turnBudgetDecision, turnBudgetDeferredNote, turnBudgetDeferredState, turnBudgetExceededMessage, turnBudgetSoftNote, turnBudgetState } from "../shared/turn-budget.ts";
|
|
134
137
|
import { initialToolBudgetState, toolBudgetState } from "../shared/tool-budget.ts";
|
|
135
138
|
import { effectiveToolTimeoutMs, formatToolTimeoutMessage, toolTimeoutCallKey } from "../shared/tool-timeout.ts";
|
|
@@ -236,6 +239,8 @@ interface StepResult {
|
|
|
236
239
|
model?: string;
|
|
237
240
|
attemptedModels?: string[];
|
|
238
241
|
modelAttempts?: ModelAttempt[];
|
|
242
|
+
/** True when the dispatch failed because the input exceeded the model's context window. */
|
|
243
|
+
contextOverflow?: boolean;
|
|
239
244
|
totalCost?: CostSummary;
|
|
240
245
|
artifactPaths?: ArtifactPaths;
|
|
241
246
|
outputSaveError?: string;
|
|
@@ -558,6 +563,8 @@ function runPiStreaming(
|
|
|
558
563
|
toolTimeoutMs?: number,
|
|
559
564
|
runDeadlineAt?: number,
|
|
560
565
|
orcaProgressTab?: OrcaProgressTab,
|
|
566
|
+
expectedModelForVerification?: string,
|
|
567
|
+
modelVerificationRegistry?: Array<{ provider: string; id: string; fullId: string }>,
|
|
561
568
|
): Promise<RunPiStreamingResult> {
|
|
562
569
|
return new Promise((resolve) => {
|
|
563
570
|
const startedAt = Date.now();
|
|
@@ -716,7 +723,14 @@ function runPiStreaming(
|
|
|
716
723
|
if (text) writeOutputText(text);
|
|
717
724
|
|
|
718
725
|
if (event.type !== "message_end" || event.message.role !== "assistant") return;
|
|
719
|
-
|
|
726
|
+
const hasToolCall = assistantStartsToolCall(event.message);
|
|
727
|
+
if (event.message.model) {
|
|
728
|
+
model = event.message.model;
|
|
729
|
+
if (expectedModelForVerification && !hasToolCall) {
|
|
730
|
+
const modelVerificationError = formatSubagentModelVerificationError(expectedModelForVerification, event.message.model, modelVerificationRegistry);
|
|
731
|
+
if (modelVerificationError && !error) error = modelVerificationError;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
720
734
|
if (event.message.errorMessage) assistantError = event.message.errorMessage;
|
|
721
735
|
const eventUsage = event.message.usage;
|
|
722
736
|
if (eventUsage) {
|
|
@@ -1257,6 +1271,7 @@ async function runSingleStepInner(
|
|
|
1257
1271
|
model: imported.model,
|
|
1258
1272
|
attemptedModels: imported.attemptedModels,
|
|
1259
1273
|
modelAttempts: imported.modelAttempts,
|
|
1274
|
+
contextOverflow: imported.contextOverflow,
|
|
1260
1275
|
totalCost: imported.totalCost,
|
|
1261
1276
|
structuredOutput: timedOut || stopped ? undefined : imported.structuredOutput,
|
|
1262
1277
|
structuredOutputPath: timedOut || stopped ? undefined : imported.structuredOutputPath,
|
|
@@ -1276,6 +1291,43 @@ async function runSingleStepInner(
|
|
|
1276
1291
|
let task = step.task.replace(placeholderRegex, () => ctx.previousOutput);
|
|
1277
1292
|
if (ctx.outputs) task = resolveOutputReferences(task, ctx.outputs);
|
|
1278
1293
|
const taskForCompletionGuard = task;
|
|
1294
|
+
let resolvedTaskToolPlan: ReturnType<typeof resolvePiLaunchToolPlan> | undefined;
|
|
1295
|
+
if (!step.runner) {
|
|
1296
|
+
resolvedTaskToolPlan = resolvePiLaunchToolPlan(omitUndefinedProperties({
|
|
1297
|
+
tools: step.tools,
|
|
1298
|
+
extensions: step.extensions,
|
|
1299
|
+
subagentOnlyExtensions: step.subagentOnlyExtensions,
|
|
1300
|
+
mcpDirectTools: step.mcpDirectTools,
|
|
1301
|
+
cwd: step.cwd ?? ctx.cwd,
|
|
1302
|
+
requireReadTool: Boolean(step.skills?.length),
|
|
1303
|
+
structuredOutput: Boolean(effectiveStructuredOutput),
|
|
1304
|
+
capabilityCeiling: step.capabilityCeiling ?? ctx.capabilityCeiling,
|
|
1305
|
+
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
1306
|
+
permissionRules: step.permissionRules,
|
|
1307
|
+
}));
|
|
1308
|
+
const contractTools = resolvedTaskToolPlan.explicitToolAllowlist ? resolvedTaskToolPlan.effectiveToolAllowlist : undefined;
|
|
1309
|
+
const contractError = validateImplementationToolContract({
|
|
1310
|
+
agent: step.agent,
|
|
1311
|
+
task: taskForCompletionGuard,
|
|
1312
|
+
tools: contractTools,
|
|
1313
|
+
mcpDirectTools: resolvedTaskToolPlan.effectiveMcpTools,
|
|
1314
|
+
configuredExtensions: resolvedTaskToolPlan.configuredExtensions,
|
|
1315
|
+
requestedTools: resolvedTaskToolPlan.requestedBuiltinTools,
|
|
1316
|
+
acceptanceRole: step.acceptanceRole,
|
|
1317
|
+
completionGuard: step.completionGuard,
|
|
1318
|
+
});
|
|
1319
|
+
if (contractError) {
|
|
1320
|
+
return omitUndefinedProperties({
|
|
1321
|
+
agent: step.agent,
|
|
1322
|
+
context: step.context,
|
|
1323
|
+
output: contractError,
|
|
1324
|
+
error: contractError,
|
|
1325
|
+
exitCode: 1,
|
|
1326
|
+
capabilityCeiling: resolvedTaskToolPlan.capabilityCeiling,
|
|
1327
|
+
capabilityAudit: resolvedTaskToolPlan.capabilityAudit,
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1279
1331
|
if (step.effectiveAcceptance) {
|
|
1280
1332
|
const acceptancePrompt = formatAcceptancePrompt(step.effectiveAcceptance, { reportOptional: isAgentContractV1(step.agentContract) });
|
|
1281
1333
|
if (acceptancePrompt) task = `${task}\n${acceptancePrompt}`;
|
|
@@ -1392,6 +1444,7 @@ async function runSingleStepInner(
|
|
|
1392
1444
|
timeoutMessage: ctx.timeoutMessage,
|
|
1393
1445
|
stopMessage: ctx.stopMessage,
|
|
1394
1446
|
onExternalJob: ctx.onExternalJob,
|
|
1447
|
+
followUp: step.externalJobFollowUp,
|
|
1395
1448
|
}));
|
|
1396
1449
|
try { fs.writeFileSync(ctx.outputFile, external.output, "utf-8"); } catch { /* Observability output is best-effort. */ }
|
|
1397
1450
|
const resolvedOutput = step.outputPath && external.exitCode === 0
|
|
@@ -1458,9 +1511,18 @@ async function runSingleStepInner(
|
|
|
1458
1511
|
// Escalated to "file" after an unexplained zero-activity startup failure so
|
|
1459
1512
|
// retries keep the task text out of argv (endpoint pre-exec scans may deny it).
|
|
1460
1513
|
let taskDeliveryOverride: SubagentTaskDelivery | undefined;
|
|
1514
|
+
let contextOverflow = false;
|
|
1515
|
+
let launchWarningsEmitted = false;
|
|
1461
1516
|
modelAttemptsLoop: while (modelIndex < candidates.length) {
|
|
1462
1517
|
if (ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.()) break;
|
|
1463
1518
|
const candidate = candidates[modelIndex];
|
|
1519
|
+
const expectedModelForVerification = candidate && !(step.skipPrimaryModelVerification && modelIndex === 0) ? candidate : undefined;
|
|
1520
|
+
try {
|
|
1521
|
+
assertThinkingWithinCeiling({ model: candidate, configThinking: step.thinking, ceiling: step.thinkingCeiling ?? decodeThinkingCeiling(process.env[SUBAGENT_THINKING_CEILING_ENV]), agent: step.agent, runId: ctx.id });
|
|
1522
|
+
} catch (error) {
|
|
1523
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1524
|
+
return omitUndefinedProperties({ agent: step.agent, output: message, error: message, exitCode: 1, context: step.context, thinkingCeiling: step.thinkingCeiling });
|
|
1525
|
+
}
|
|
1464
1526
|
ctx.onAttemptStart?.(omitUndefinedProperties({ model: candidate, thinking: resolveEffectiveThinking(candidate, step.thinking) }));
|
|
1465
1527
|
const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
|
|
1466
1528
|
if (effectiveStructuredOutput) {
|
|
@@ -1479,7 +1541,7 @@ async function runSingleStepInner(
|
|
|
1479
1541
|
childIndex: ctx.flatIndex,
|
|
1480
1542
|
})
|
|
1481
1543
|
: undefined;
|
|
1482
|
-
const { args, env, tempDir, toolDiagnosticPath, runtimeAcknowledgedExtensionsPath, capabilityAudit: attemptCapabilityAudit } = buildPiArgs(omitUndefinedProperties({
|
|
1544
|
+
const { args, env, tempDir, toolDiagnosticPath, runtimeAcknowledgedExtensionsPath, capabilityAudit: attemptCapabilityAudit, warnings } = buildPiArgs(omitUndefinedProperties({
|
|
1483
1545
|
parentSessionId: step.parentSessionId,
|
|
1484
1546
|
baseArgs: ["--mode", "json", "-p"],
|
|
1485
1547
|
task,
|
|
@@ -1524,9 +1586,14 @@ async function runSingleStepInner(
|
|
|
1524
1586
|
: undefined,
|
|
1525
1587
|
childWatchdog,
|
|
1526
1588
|
waitToolEnabled: step.waitToolEnabled,
|
|
1589
|
+
thinkingCeiling: step.thinkingCeiling,
|
|
1527
1590
|
}));
|
|
1591
|
+
if (!launchWarningsEmitted && warnings.length > 0) {
|
|
1592
|
+
for (const warning of warnings) console.warn(`[pi-subagents] ${warning}`);
|
|
1593
|
+
launchWarningsEmitted = true;
|
|
1594
|
+
}
|
|
1528
1595
|
if (step.definitionDigest) {
|
|
1529
|
-
const toolPlan = resolvePiLaunchToolPlan(omitUndefinedProperties({
|
|
1596
|
+
const toolPlan = resolvedTaskToolPlan ?? resolvePiLaunchToolPlan(omitUndefinedProperties({
|
|
1530
1597
|
tools: step.tools,
|
|
1531
1598
|
extensions: step.extensions,
|
|
1532
1599
|
subagentOnlyExtensions: step.subagentOnlyExtensions,
|
|
@@ -1536,6 +1603,7 @@ async function runSingleStepInner(
|
|
|
1536
1603
|
structuredOutput: Boolean(effectiveStructuredOutput),
|
|
1537
1604
|
capabilityCeiling: step.capabilityCeiling ?? ctx.capabilityCeiling,
|
|
1538
1605
|
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
1606
|
+
permissionRules: step.permissionRules,
|
|
1539
1607
|
}));
|
|
1540
1608
|
launchResolvedExtensions = projectLaunchResolvedChildExtensions(toolPlan);
|
|
1541
1609
|
actualLaunchContractDigest = launchBindingDigest(omitUndefinedProperties({
|
|
@@ -1544,6 +1612,7 @@ async function runSingleStepInner(
|
|
|
1544
1612
|
...(candidate ? { model: candidate } : {}),
|
|
1545
1613
|
modelCandidates: candidates as string[],
|
|
1546
1614
|
...(resolveEffectiveThinking(candidate, step.thinking) ? { thinking: resolveEffectiveThinking(candidate, step.thinking) } : {}),
|
|
1615
|
+
...(step.thinkingCeiling ? { thinkingCeiling: step.thinkingCeiling } : {}),
|
|
1547
1616
|
systemPrompt: appendTurnBudgetSystemPrompt(step.systemPrompt ?? "", ctx.turnBudget),
|
|
1548
1617
|
systemPromptMode: step.systemPromptMode,
|
|
1549
1618
|
inheritProjectContext: step.inheritProjectContext,
|
|
@@ -1580,6 +1649,8 @@ async function runSingleStepInner(
|
|
|
1580
1649
|
ctx.toolTimeoutMs,
|
|
1581
1650
|
ctx.deadlineAt,
|
|
1582
1651
|
ctx.orcaProgressTab,
|
|
1652
|
+
expectedModelForVerification,
|
|
1653
|
+
step.modelVerificationRegistry,
|
|
1583
1654
|
);
|
|
1584
1655
|
if (run.processCloseObservedAt !== undefined) {
|
|
1585
1656
|
writerProcesses.push({
|
|
@@ -1652,21 +1723,25 @@ async function runSingleStepInner(
|
|
|
1652
1723
|
? "Subagent produced no output (possible model cold-start or empty response)."
|
|
1653
1724
|
: undefined;
|
|
1654
1725
|
const completionGuardEnabled = isAgentContractV1(step.agentContract) ? step.completionGuard === true : step.completionGuard !== false;
|
|
1655
|
-
const
|
|
1726
|
+
const completionToolPlan = resolvedTaskToolPlan;
|
|
1727
|
+
const completionGuard = run.exitCode === 0 && !run.error && !structuredError && !hiddenError?.hasError && !emptyOutputError && completionGuardEnabled
|
|
1656
1728
|
? evaluateCompletionMutationGuard(omitUndefinedProperties({
|
|
1657
1729
|
agent: step.agent,
|
|
1658
1730
|
task: taskForCompletionGuard,
|
|
1659
1731
|
messages: run.messages,
|
|
1660
|
-
tools: step.tools,
|
|
1661
|
-
mcpDirectTools: step.mcpDirectTools,
|
|
1732
|
+
tools: completionToolPlan ? (completionToolPlan.explicitToolAllowlist ? completionToolPlan.effectiveToolAllowlist : undefined) : step.tools,
|
|
1733
|
+
mcpDirectTools: completionToolPlan?.effectiveMcpTools ?? step.mcpDirectTools,
|
|
1734
|
+
toolAvailabilityError,
|
|
1662
1735
|
}))
|
|
1663
1736
|
: undefined;
|
|
1664
1737
|
const completionGuardTriggered = completionGuard?.triggered === true && !run.observedMutationAttempt;
|
|
1738
|
+
const completionGuardBlocked = completionGuard?.blocked === true;
|
|
1665
1739
|
const fileMutationEffect = completionGuard
|
|
1666
1740
|
? {
|
|
1667
|
-
status: completionGuard.expectedMutation ? completionGuardTriggered ? "missing" as const : "observed" as const : "not-applicable" as const,
|
|
1741
|
+
status: completionGuardBlocked ? "blocked" as const : completionGuard.expectedMutation ? completionGuardTriggered ? "missing" as const : "observed" as const : "not-applicable" as const,
|
|
1668
1742
|
expected: completionGuard.expectedMutation,
|
|
1669
|
-
attempted: completionGuard.attemptedMutation || run.observedMutationAttempt === true,
|
|
1743
|
+
attempted: completionGuardBlocked ? false : completionGuard.attemptedMutation || run.observedMutationAttempt === true,
|
|
1744
|
+
...(completionGuardBlocked && completionGuard.message ? { message: completionGuard.message } : {}),
|
|
1670
1745
|
...(completionGuardTriggered ? { message: "Subagent completed without making edits for an implementation task." } : {}),
|
|
1671
1746
|
}
|
|
1672
1747
|
: undefined;
|
|
@@ -1771,6 +1846,11 @@ async function runSingleStepInner(
|
|
|
1771
1846
|
}
|
|
1772
1847
|
const retryableModelFailure = isRetryableModelFailure(error);
|
|
1773
1848
|
if (retryableModelFailure) recordRetryableModelFailure(candidate ?? run.model ?? step.model, error);
|
|
1849
|
+
if (isContextOverflow(error)) {
|
|
1850
|
+
contextOverflow = true;
|
|
1851
|
+
attemptNotes.push(`[fallback] ${attempt.model} failed: context overflow — the input exceeds this model's context window. Reduce the task input or use a model with a larger context window.`);
|
|
1852
|
+
break modelAttemptsLoop;
|
|
1853
|
+
}
|
|
1774
1854
|
if (!retryableModelFailure || modelIndex === candidates.length - 1) break modelAttemptsLoop;
|
|
1775
1855
|
attemptNotes.push(formatModelAttemptNote(attempt, candidates[modelIndex + 1]));
|
|
1776
1856
|
modelIndex += 1;
|
|
@@ -1908,6 +1988,7 @@ async function runSingleStepInner(
|
|
|
1908
1988
|
model: finalResult?.model,
|
|
1909
1989
|
attemptedModels: attemptedModels.length > 0 ? attemptedModels : undefined,
|
|
1910
1990
|
modelAttempts,
|
|
1991
|
+
contextOverflow: contextOverflow || undefined,
|
|
1911
1992
|
totalCost: costSummaryFromAttempts(modelAttempts),
|
|
1912
1993
|
artifactPaths,
|
|
1913
1994
|
outputSaveError: artifactErrors.outputSaveError,
|
|
@@ -1943,21 +2024,8 @@ async function runSingleStep(
|
|
|
1943
2024
|
step: SubagentStep,
|
|
1944
2025
|
ctx: SingleStepContext,
|
|
1945
2026
|
): Promise<StepResult & { completionGuardTriggered?: boolean }> {
|
|
1946
|
-
if (step.importAsyncRoot)
|
|
1947
|
-
|
|
1948
|
-
cwd: step.cwd ?? ctx.cwd,
|
|
1949
|
-
runId: ctx.id,
|
|
1950
|
-
agent: step.agent,
|
|
1951
|
-
index: ctx.flatIndex,
|
|
1952
|
-
});
|
|
1953
|
-
try {
|
|
1954
|
-
const result = await runSingleStepInner(step, { ...ctx, orcaProgressTab });
|
|
1955
|
-
orcaProgressTab?.finish(result.stopped ? "stopped" : result.exitCode === 0 && !result.error ? "completed" : "failed", result.sessionFile);
|
|
1956
|
-
return result;
|
|
1957
|
-
} catch (error) {
|
|
1958
|
-
orcaProgressTab?.finish("failed");
|
|
1959
|
-
throw error;
|
|
1960
|
-
}
|
|
2027
|
+
if (!step.importAsyncRoot) ctx.orcaProgressTab?.section({ agent: step.agent, index: ctx.flatIndex, count: ctx.flatStepCount });
|
|
2028
|
+
return runSingleStepInner(step, ctx);
|
|
1961
2029
|
}
|
|
1962
2030
|
|
|
1963
2031
|
type RunnerStatusStep = NonNullable<AsyncStatus["steps"]>[number] & {
|
|
@@ -2226,6 +2294,7 @@ async function runSubagent(
|
|
|
2226
2294
|
const activeChildInterrupts = new Map<number, () => void>();
|
|
2227
2295
|
const activeChildTimeouts = new Map<number, () => void>();
|
|
2228
2296
|
const activeChildStops = new Map<number, () => void>();
|
|
2297
|
+
const childStopRequests = new Map<number, { childId: string; requestedAt: number }>();
|
|
2229
2298
|
const activeChildTurnBudgetAborts = new Map<number, (message: string, state?: TurnBudgetState) => void>();
|
|
2230
2299
|
const pendingStepSteers: SteerRequest[] = [];
|
|
2231
2300
|
const steeringCapabilities = new Map<number, SteerCapability>();
|
|
@@ -2269,6 +2338,7 @@ async function runSubagent(
|
|
|
2269
2338
|
...(task.launchContractDigest ? { launchContractDigest: task.launchContractDigest } : {}),
|
|
2270
2339
|
...(task.launchResolvedExtensions ? { launchResolvedExtensions: task.launchResolvedExtensions } : {}),
|
|
2271
2340
|
...(task.capabilityCeiling ? { capabilityCeiling: task.capabilityCeiling } : {}),
|
|
2341
|
+
...(task.thinkingCeiling ? { thinkingCeiling: task.thinkingCeiling } : {}),
|
|
2272
2342
|
status: "pending",
|
|
2273
2343
|
...(task.toolBudget ? { toolBudget: initialToolBudgetState(task.toolBudget) } : {}),
|
|
2274
2344
|
...(task.sessionFile ? { sessionFile: task.sessionFile } : {}),
|
|
@@ -2294,6 +2364,7 @@ async function runSubagent(
|
|
|
2294
2364
|
structured: Boolean(step.collect.outputSchema),
|
|
2295
2365
|
...(step.agentContract ? { agentContract: step.agentContract } : {}),
|
|
2296
2366
|
...(step.capabilityCeiling ? { capabilityCeiling: step.capabilityCeiling } : {}),
|
|
2367
|
+
...(step.thinkingCeiling ? { thinkingCeiling: step.thinkingCeiling } : {}),
|
|
2297
2368
|
status: "pending",
|
|
2298
2369
|
...(step.parallel.toolBudget ? { toolBudget: initialToolBudgetState(step.parallel.toolBudget) } : {}),
|
|
2299
2370
|
recentTools: [],
|
|
@@ -2316,6 +2387,7 @@ async function runSubagent(
|
|
|
2316
2387
|
...(step.launchContractDigest ? { launchContractDigest: step.launchContractDigest } : {}),
|
|
2317
2388
|
...(step.launchResolvedExtensions ? { launchResolvedExtensions: step.launchResolvedExtensions } : {}),
|
|
2318
2389
|
...(step.capabilityCeiling ? { capabilityCeiling: step.capabilityCeiling } : {}),
|
|
2390
|
+
...(step.thinkingCeiling ? { thinkingCeiling: step.thinkingCeiling } : {}),
|
|
2319
2391
|
status: "pending",
|
|
2320
2392
|
...(step.toolBudget ? { toolBudget: initialToolBudgetState(step.toolBudget) } : {}),
|
|
2321
2393
|
...(step.sessionFile ? { sessionFile: step.sessionFile } : {}),
|
|
@@ -2338,6 +2410,19 @@ async function runSubagent(
|
|
|
2338
2410
|
step.processTerminal = { version: 1, state: "pending", runId: id, runnerProcessInstanceId: config.runnerProcessInstanceId };
|
|
2339
2411
|
}
|
|
2340
2412
|
}
|
|
2413
|
+
const initialAgentLabel = initialStatusSteps.length === 1
|
|
2414
|
+
? initialStatusSteps[0]!.agent
|
|
2415
|
+
: (config.resultMode ?? (flatSteps.length > 1 ? "chain" : "single")) === "parallel"
|
|
2416
|
+
? `parallel:${initialStatusSteps.map((step) => step.agent).join("+")}`
|
|
2417
|
+
: `chain:${initialStatusSteps.map((step) => step.agent).join("->")}`;
|
|
2418
|
+
const orcaProgressTab = flatSteps.every((step) => step.importAsyncRoot) ? undefined : createOrcaProgressTab({
|
|
2419
|
+
cwd,
|
|
2420
|
+
runId: id,
|
|
2421
|
+
agent: initialAgentLabel,
|
|
2422
|
+
index: 0,
|
|
2423
|
+
stepCount: Math.max(initialStatusSteps.length, 1),
|
|
2424
|
+
});
|
|
2425
|
+
|
|
2341
2426
|
const statusPayload: RunnerStatusPayload = omitUndefinedProperties({
|
|
2342
2427
|
lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
2343
2428
|
runId: id,
|
|
@@ -2520,6 +2605,7 @@ async function runSubagent(
|
|
|
2520
2605
|
model: step.model,
|
|
2521
2606
|
attemptedModels: step.attemptedModels,
|
|
2522
2607
|
modelAttempts: step.modelAttempts,
|
|
2608
|
+
contextOverflow: step.contextOverflow,
|
|
2523
2609
|
})),
|
|
2524
2610
|
exitCode: state === "complete" || state === "paused" ? 0 : 1,
|
|
2525
2611
|
timestamp: now,
|
|
@@ -2555,6 +2641,83 @@ async function runSubagent(
|
|
|
2555
2641
|
statusPayload.lastUpdate = Date.now();
|
|
2556
2642
|
writeStatusPayload();
|
|
2557
2643
|
};
|
|
2644
|
+
const childStopTargetId = (index: number): string => asyncStatusChildIdentity(requiredStatusStep(statusPayload, index), index);
|
|
2645
|
+
const appendChildStatusEvent = (index: number, childId: string, status: "stopping" | "stopped", now = Date.now()): void => {
|
|
2646
|
+
const step = requiredStatusStep(statusPayload, index);
|
|
2647
|
+
appendJsonl(eventsPath, JSON.stringify({
|
|
2648
|
+
type: "subagent.child-status",
|
|
2649
|
+
version: 1,
|
|
2650
|
+
ts: now,
|
|
2651
|
+
runId: id,
|
|
2652
|
+
childId,
|
|
2653
|
+
status,
|
|
2654
|
+
reason: "user",
|
|
2655
|
+
source: "async",
|
|
2656
|
+
stepIndex: index,
|
|
2657
|
+
agent: step.agent,
|
|
2658
|
+
...(step.runId ? { childRunId: step.runId } : {}),
|
|
2659
|
+
...(step.workflowKey ? { workflowKey: step.workflowKey } : {}),
|
|
2660
|
+
...(step.phase ? { phase: step.phase } : {}),
|
|
2661
|
+
...(step.label ? { label: step.label } : {}),
|
|
2662
|
+
} satisfies SubagentChildStatusEvent));
|
|
2663
|
+
};
|
|
2664
|
+
const appendTerminalChildStatusEvent = (index: number, now = Date.now()): void => {
|
|
2665
|
+
const request = childStopRequests.get(index);
|
|
2666
|
+
if (request) appendChildStatusEvent(index, request.childId, "stopped", now);
|
|
2667
|
+
};
|
|
2668
|
+
const markChildStopRequested = (index: number, childId: string, now = Date.now()): boolean => {
|
|
2669
|
+
const step = statusPayload.steps[index];
|
|
2670
|
+
if (!step || (step.status !== "pending" && step.status !== "running")) return false;
|
|
2671
|
+
childStopRequests.set(index, { childId, requestedAt: now });
|
|
2672
|
+
step.stopRequested = true;
|
|
2673
|
+
step.stopRequestedAt = now;
|
|
2674
|
+
delete step.activityState;
|
|
2675
|
+
statusPayload.lastUpdate = now;
|
|
2676
|
+
writeStatusPayload();
|
|
2677
|
+
appendJsonl(eventsPath, JSON.stringify({ type: "subagent.step.stop_requested", ts: now, runId: id, stepIndex: index, childId, agent: step.agent }));
|
|
2678
|
+
appendChildStatusEvent(index, childId, "stopping", now);
|
|
2679
|
+
return true;
|
|
2680
|
+
};
|
|
2681
|
+
const markChildStopped = (index: number, now = Date.now()): void => {
|
|
2682
|
+
const step = requiredStatusStep(statusPayload, index);
|
|
2683
|
+
if (step.status === "stopped") return;
|
|
2684
|
+
step.status = "stopped";
|
|
2685
|
+
step.error = stopMessage;
|
|
2686
|
+
step.exitCode = 1;
|
|
2687
|
+
step.stopped = true;
|
|
2688
|
+
step.stopRequested = true;
|
|
2689
|
+
step.stopRequestedAt = childStopRequests.get(index)?.requestedAt ?? step.stopRequestedAt ?? now;
|
|
2690
|
+
delete step.activityState;
|
|
2691
|
+
step.endedAt = now;
|
|
2692
|
+
step.durationMs = step.startedAt ? now - step.startedAt : 0;
|
|
2693
|
+
step.lastActivityAt = now;
|
|
2694
|
+
statusPayload.lastUpdate = now;
|
|
2695
|
+
writeStatusPayload();
|
|
2696
|
+
const childId = childStopRequests.get(index)?.childId ?? childStopTargetId(index);
|
|
2697
|
+
appendJsonl(eventsPath, JSON.stringify({ type: "subagent.step.stopped", ts: now, runId: id, stepIndex: index, childId, agent: step.agent, exitCode: 1, durationMs: step.durationMs }));
|
|
2698
|
+
appendChildStatusEvent(index, childId, "stopped", now);
|
|
2699
|
+
};
|
|
2700
|
+
const childStopResult = (index: number, agent: string, context?: "fresh" | "fork"): SingleStepResult => {
|
|
2701
|
+
markChildStopped(index);
|
|
2702
|
+
return stoppedStepResult(agent, context);
|
|
2703
|
+
};
|
|
2704
|
+
const stopChildStep = (request: StopRequest): void => {
|
|
2705
|
+
if (request.targetIndex === undefined) {
|
|
2706
|
+
stopRunner();
|
|
2707
|
+
return;
|
|
2708
|
+
}
|
|
2709
|
+
const childId = request.childId ?? childStopTargetId(request.targetIndex);
|
|
2710
|
+
const now = Date.now();
|
|
2711
|
+
if (!markChildStopRequested(request.targetIndex, childId, now)) {
|
|
2712
|
+
appendJsonl(eventsPath, JSON.stringify({ type: "subagent.step.stop_failed", ts: now, runId: id, stepIndex: request.targetIndex, childId, message: "Child is not pending or running." }));
|
|
2713
|
+
return;
|
|
2714
|
+
}
|
|
2715
|
+
const stop = activeChildStops.get(request.targetIndex);
|
|
2716
|
+
if (stop) stop();
|
|
2717
|
+
else if (requiredStatusStep(statusPayload, request.targetIndex).status === "pending") {
|
|
2718
|
+
appendJsonl(eventsPath, JSON.stringify({ type: "subagent.step.stop_queued", ts: now, runId: id, stepIndex: request.targetIndex, childId }));
|
|
2719
|
+
}
|
|
2720
|
+
};
|
|
2558
2721
|
const registerStepInterrupt = (flatIndex: number, interrupt: (() => void) | undefined): void => {
|
|
2559
2722
|
if (!interrupt) {
|
|
2560
2723
|
activeChildInterrupts.delete(flatIndex);
|
|
@@ -2577,7 +2740,7 @@ async function runSubagent(
|
|
|
2577
2740
|
return;
|
|
2578
2741
|
}
|
|
2579
2742
|
activeChildStops.set(flatIndex, stop);
|
|
2580
|
-
if (stopped) stop();
|
|
2743
|
+
if (stopped || childStopRequests.has(flatIndex)) stop();
|
|
2581
2744
|
};
|
|
2582
2745
|
const registerStepTurnBudgetAbort = (flatIndex: number, abort: ((message: string, state?: TurnBudgetState) => void) | undefined): void => {
|
|
2583
2746
|
if (!abort) {
|
|
@@ -3482,7 +3645,7 @@ async function runSubagent(
|
|
|
3482
3645
|
const disposeControlInbox = watchAsyncControlInbox(asyncDir, {
|
|
3483
3646
|
onInterrupt: interruptRunner,
|
|
3484
3647
|
onTimeout: timeoutRunner,
|
|
3485
|
-
onStop:
|
|
3648
|
+
onStop: stopChildStep,
|
|
3486
3649
|
onSteer: (request) => {
|
|
3487
3650
|
const targetStep = request.targetIndex !== undefined ? statusPayload.steps[request.targetIndex] : undefined;
|
|
3488
3651
|
if (targetStep?.status === "pending") {
|
|
@@ -3558,6 +3721,19 @@ async function runSubagent(
|
|
|
3558
3721
|
if (materialized.parallel.length > 1 && step.parallel.outputPath && !step.parallel.namespaceOutputPath) {
|
|
3559
3722
|
throw new DynamicFanoutError(`Dynamic chain step ${stepIndex + 1} materialized ${materialized.parallel.length} items that resolve output to the same path: ${step.parallel.outputPath}. Remove the explicit output path or use an inherited relative agent output so each item can be isolated.`);
|
|
3560
3723
|
}
|
|
3724
|
+
for (const [itemIndex] of materialized.parallel.entries()) {
|
|
3725
|
+
const thinkingOverride = step.thinkingOverrides?.[itemIndex];
|
|
3726
|
+
const model = thinkingOverride ? applyThinkingSuffix(step.parallel.model, thinkingOverride, true) : step.parallel.model;
|
|
3727
|
+
const configThinking = thinkingOverride ? thinkingOverride : step.parallel.thinking;
|
|
3728
|
+
const candidates = step.parallel.modelCandidates !== undefined
|
|
3729
|
+
? step.parallel.modelCandidates.length > 0
|
|
3730
|
+
? step.parallel.modelCandidates.map((candidate) => thinkingOverride ? applyThinkingSuffix(candidate, thinkingOverride, true) ?? candidate : candidate)
|
|
3731
|
+
: [undefined]
|
|
3732
|
+
: model ? [model] : [undefined];
|
|
3733
|
+
for (const candidate of candidates) {
|
|
3734
|
+
assertThinkingWithinCeiling({ model: candidate, configThinking, ceiling: step.parallel.thinkingCeiling ?? decodeThinkingCeiling(process.env[SUBAGENT_THINKING_CEILING_ENV]), agent: step.parallel.agent, runId: id });
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3561
3737
|
if (materialized.collectedOnEmpty) await validateDynamicCollection(step.collect.outputSchema, materialized.collectedOnEmpty);
|
|
3562
3738
|
if (!config.runFanoutBudget) throw new Error("Async runner is missing its run fan-out budget identity.");
|
|
3563
3739
|
const runFanoutBudget = claimRunFanoutBatch(config.runFanoutBudget, materialized.parallel.map((_, itemIndex) => `chain[${stepIndex}].expand[${itemIndex}]`));
|
|
@@ -3714,6 +3890,7 @@ async function runSubagent(
|
|
|
3714
3890
|
...(task.skills ? { skills: task.skills } : {}),
|
|
3715
3891
|
...(task.model ? { model: task.model } : {}),
|
|
3716
3892
|
...(task.thinking ? { thinking: task.thinking } : {}),
|
|
3893
|
+
...(task.thinkingCeiling ? { thinkingCeiling: task.thinkingCeiling } : {}),
|
|
3717
3894
|
...(task.modelCandidates && task.modelCandidates.length > 0 ? { attemptedModels: task.modelCandidates } : task.model ? { attemptedModels: [task.model] } : {}),
|
|
3718
3895
|
recentTools: [],
|
|
3719
3896
|
recentOutput: [],
|
|
@@ -3785,6 +3962,7 @@ async function runSubagent(
|
|
|
3785
3962
|
}
|
|
3786
3963
|
if (timedOut) return timedOutStepResult(task.agent, task.context);
|
|
3787
3964
|
if (stopped) return stoppedStepResult(task.agent, task.context);
|
|
3965
|
+
if (childStopRequests.has(fi)) return childStopResult(fi, task.agent, task.context);
|
|
3788
3966
|
if (interrupted) return pausedStepResult(task.agent, task.context);
|
|
3789
3967
|
if (aborted && failFast) {
|
|
3790
3968
|
const skippedAt = Date.now();
|
|
@@ -3844,7 +4022,8 @@ async function runSubagent(
|
|
|
3844
4022
|
onWriterProcess,
|
|
3845
4023
|
onExternalProcess: (process) => updateExternalProcess(fi, process),
|
|
3846
4024
|
onExternalJob: (externalJob) => updateExternalJob(fi, externalJob),
|
|
3847
|
-
skipAcceptance: () => timedOut || stopped,
|
|
4025
|
+
skipAcceptance: () => timedOut || stopped || childStopRequests.has(fi),
|
|
4026
|
+
orcaProgressTab,
|
|
3848
4027
|
}), config.deadlineAt);
|
|
3849
4028
|
const taskEndTime = Date.now();
|
|
3850
4029
|
const childInterrupted = singleResult.interrupted === true;
|
|
@@ -3869,6 +4048,7 @@ async function runSubagent(
|
|
|
3869
4048
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, fi).thinking));
|
|
3870
4049
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "attemptedModels", singleResult.attemptedModels);
|
|
3871
4050
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "modelAttempts", singleResult.modelAttempts);
|
|
4051
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "contextOverflow", singleResult.contextOverflow);
|
|
3872
4052
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "totalCost", singleResult.totalCost);
|
|
3873
4053
|
if (singleResult.totalCost) {
|
|
3874
4054
|
pendingParallelUsageCost = {
|
|
@@ -3900,12 +4080,13 @@ async function runSubagent(
|
|
|
3900
4080
|
statusPayload.lastUpdate = taskEndTime;
|
|
3901
4081
|
writeStatusPayload();
|
|
3902
4082
|
appendCapabilityCeilingAppliedEvent(eventsPath, id, fi, task.agent, singleResult);
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
4083
|
+
appendJsonl(eventsPath, JSON.stringify({
|
|
4084
|
+
type: stopped || childStopped ? "subagent.step.stopped" : timedOut ? "subagent.step.failed" : childInterrupted ? "subagent.step.paused" : singleResult.exitCode === 0 ? "subagent.step.completed" : "subagent.step.failed",
|
|
4085
|
+
ts: taskEndTime, runId: id, stepIndex: fi, agent: task.agent,
|
|
4086
|
+
exitCode: stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode, durationMs: taskEndTime - taskStartTime,
|
|
4087
|
+
}));
|
|
4088
|
+
if (stopped || childStopped) appendTerminalChildStatusEvent(fi, taskEndTime);
|
|
4089
|
+
if (singleResult.exitCode !== 0 && failFast && !childStopped) aborted = true;
|
|
3909
4090
|
return stopped || childStopped ? { ...singleResult, output: stopMessage, error: stopMessage, exitCode: 1, interrupted: false, timedOut: false, stopped: true, skipped: false } : timedOut ? { ...singleResult, output: timeoutMessage ?? "Subagent timed out.", error: timeoutMessage ?? "Subagent timed out.", exitCode: 1, interrupted: false, timedOut: true, skipped: false } : { ...singleResult, skipped: false };
|
|
3910
4091
|
}, globalSemaphore);
|
|
3911
4092
|
|
|
@@ -3938,6 +4119,7 @@ async function runSubagent(
|
|
|
3938
4119
|
model: pr.model,
|
|
3939
4120
|
attemptedModels: pr.attemptedModels,
|
|
3940
4121
|
modelAttempts: pr.modelAttempts,
|
|
4122
|
+
contextOverflow: pr.contextOverflow,
|
|
3941
4123
|
totalCost: pr.totalCost,
|
|
3942
4124
|
artifactPaths: pr.artifactPaths,
|
|
3943
4125
|
transcriptPath: pr.transcriptPath,
|
|
@@ -4157,6 +4339,7 @@ async function runSubagent(
|
|
|
4157
4339
|
}
|
|
4158
4340
|
if (timedOut) return timedOutStepResult(task.agent, task.context);
|
|
4159
4341
|
if (stopped) return stoppedStepResult(task.agent, task.context);
|
|
4342
|
+
if (childStopRequests.has(fi)) return childStopResult(fi, task.agent, task.context);
|
|
4160
4343
|
if (interrupted) return pausedStepResult(task.agent, task.context);
|
|
4161
4344
|
if (aborted && failFast) {
|
|
4162
4345
|
const skippedAt = Date.now();
|
|
@@ -4232,7 +4415,8 @@ async function runSubagent(
|
|
|
4232
4415
|
onWriterProcess,
|
|
4233
4416
|
onExternalProcess: (process) => updateExternalProcess(fi, process),
|
|
4234
4417
|
onExternalJob: (externalJob) => updateExternalJob(fi, externalJob),
|
|
4235
|
-
skipAcceptance: () => timedOut || stopped,
|
|
4418
|
+
skipAcceptance: () => timedOut || stopped || childStopRequests.has(fi),
|
|
4419
|
+
orcaProgressTab,
|
|
4236
4420
|
}), config.deadlineAt);
|
|
4237
4421
|
if (task.sessionFile) {
|
|
4238
4422
|
latestSessionFile = task.sessionFile;
|
|
@@ -4263,6 +4447,7 @@ async function runSubagent(
|
|
|
4263
4447
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, fi).thinking));
|
|
4264
4448
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "attemptedModels", singleResult.attemptedModels);
|
|
4265
4449
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "modelAttempts", singleResult.modelAttempts);
|
|
4450
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "contextOverflow", singleResult.contextOverflow);
|
|
4266
4451
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "totalCost", singleResult.totalCost);
|
|
4267
4452
|
if (singleResult.totalCost) {
|
|
4268
4453
|
pendingParallelUsageCost = {
|
|
@@ -4299,6 +4484,7 @@ async function runSubagent(
|
|
|
4299
4484
|
ts: taskEndTime, runId: id, stepIndex: fi, agent: task.agent,
|
|
4300
4485
|
exitCode: stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode, durationMs: taskDuration,
|
|
4301
4486
|
}));
|
|
4487
|
+
if (stopped || childStopped) appendTerminalChildStatusEvent(fi, taskEndTime);
|
|
4302
4488
|
if (singleResult.completionGuardTriggered) {
|
|
4303
4489
|
const event = buildControlEvent(omitUndefinedProperties({
|
|
4304
4490
|
from: requiredStatusStep(statusPayload, fi).activityState,
|
|
@@ -4313,7 +4499,7 @@ async function runSubagent(
|
|
|
4313
4499
|
appendControlEvent(event);
|
|
4314
4500
|
}
|
|
4315
4501
|
|
|
4316
|
-
if (singleResult.exitCode !== 0 && failFast) aborted = true;
|
|
4502
|
+
if (singleResult.exitCode !== 0 && failFast && !childStopped) aborted = true;
|
|
4317
4503
|
return stopped || childStopped ? { ...singleResult, output: stopMessage, error: stopMessage, exitCode: 1, interrupted: false, timedOut: false, stopped: true, skipped: false } : timedOut ? { ...singleResult, output: timeoutMessage ?? "Subagent timed out.", error: timeoutMessage ?? "Subagent timed out.", exitCode: 1, interrupted: false, timedOut: true, skipped: false } : { ...singleResult, skipped: false };
|
|
4318
4504
|
},
|
|
4319
4505
|
globalSemaphore,
|
|
@@ -4366,6 +4552,7 @@ async function runSubagent(
|
|
|
4366
4552
|
model: pr.model,
|
|
4367
4553
|
attemptedModels: pr.attemptedModels,
|
|
4368
4554
|
modelAttempts: pr.modelAttempts,
|
|
4555
|
+
contextOverflow: pr.contextOverflow,
|
|
4369
4556
|
totalCost: pr.totalCost,
|
|
4370
4557
|
artifactPaths: pr.artifactPaths,
|
|
4371
4558
|
transcriptPath: pr.transcriptPath,
|
|
@@ -4469,6 +4656,26 @@ async function runSubagent(
|
|
|
4469
4656
|
}
|
|
4470
4657
|
} else {
|
|
4471
4658
|
const seqStep = step as SubagentStep;
|
|
4659
|
+
if (timedOut) {
|
|
4660
|
+
results.push(timedOutStepResult(seqStep.agent, seqStep.context));
|
|
4661
|
+
flatIndex++;
|
|
4662
|
+
continue;
|
|
4663
|
+
}
|
|
4664
|
+
if (stopped) {
|
|
4665
|
+
results.push(stoppedStepResult(seqStep.agent, seqStep.context));
|
|
4666
|
+
flatIndex++;
|
|
4667
|
+
continue;
|
|
4668
|
+
}
|
|
4669
|
+
if (childStopRequests.has(flatIndex)) {
|
|
4670
|
+
results.push(childStopResult(flatIndex, seqStep.agent, seqStep.context));
|
|
4671
|
+
flatIndex++;
|
|
4672
|
+
continue;
|
|
4673
|
+
}
|
|
4674
|
+
if (interrupted) {
|
|
4675
|
+
results.push(pausedStepResult(seqStep.agent, seqStep.context));
|
|
4676
|
+
flatIndex++;
|
|
4677
|
+
continue;
|
|
4678
|
+
}
|
|
4472
4679
|
let singleWorktreeSetup: WorktreeSetup | undefined;
|
|
4473
4680
|
if (seqStep.worktree) {
|
|
4474
4681
|
try {
|
|
@@ -4553,7 +4760,8 @@ async function runSubagent(
|
|
|
4553
4760
|
onWriterProcess,
|
|
4554
4761
|
onExternalProcess: (process) => updateExternalProcess(flatIndex, process),
|
|
4555
4762
|
onExternalJob: (externalJob) => updateExternalJob(flatIndex, externalJob),
|
|
4556
|
-
skipAcceptance: () => timedOut || stopped,
|
|
4763
|
+
skipAcceptance: () => timedOut || stopped || childStopRequests.has(flatIndex),
|
|
4764
|
+
orcaProgressTab,
|
|
4557
4765
|
}), config.deadlineAt);
|
|
4558
4766
|
} catch (error) {
|
|
4559
4767
|
if (singleWorktreeSetup) cleanupWorktrees(singleWorktreeSetup);
|
|
@@ -4583,6 +4791,7 @@ async function runSubagent(
|
|
|
4583
4791
|
model: singleResult.model,
|
|
4584
4792
|
attemptedModels: singleResult.attemptedModels,
|
|
4585
4793
|
modelAttempts: singleResult.modelAttempts,
|
|
4794
|
+
contextOverflow: singleResult.contextOverflow,
|
|
4586
4795
|
totalCost: singleResult.totalCost,
|
|
4587
4796
|
artifactPaths: singleResult.artifactPaths,
|
|
4588
4797
|
transcriptPath: singleResult.transcriptPath,
|
|
@@ -4661,6 +4870,7 @@ async function runSubagent(
|
|
|
4661
4870
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, flatIndex).thinking));
|
|
4662
4871
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "attemptedModels", singleResult.attemptedModels);
|
|
4663
4872
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "modelAttempts", singleResult.modelAttempts);
|
|
4873
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "contextOverflow", singleResult.contextOverflow);
|
|
4664
4874
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "totalCost", singleResult.totalCost);
|
|
4665
4875
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "error", stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error);
|
|
4666
4876
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "transcriptPath", singleResult.transcriptPath ?? requiredStatusStep(statusPayload, flatIndex).transcriptPath);
|
|
@@ -4698,6 +4908,7 @@ async function runSubagent(
|
|
|
4698
4908
|
durationMs: stepEndTime - stepStartTime,
|
|
4699
4909
|
tokens: stepTokens,
|
|
4700
4910
|
}));
|
|
4911
|
+
if (stopped || childStopped) appendTerminalChildStatusEvent(flatIndex, stepEndTime);
|
|
4701
4912
|
if (singleWorktreeSetup && !singleResult.detached) {
|
|
4702
4913
|
const diffs = diffWorktrees(singleWorktreeSetup, [seqStep.agent], path.join(asyncDir, "worktree-diffs", `step-${stepIndex}`));
|
|
4703
4914
|
const diffSummary = formatWorktreeDiffSummary(diffs);
|
|
@@ -4935,6 +5146,7 @@ async function runSubagent(
|
|
|
4935
5146
|
model: r.model,
|
|
4936
5147
|
attemptedModels: r.attemptedModels,
|
|
4937
5148
|
modelAttempts: r.modelAttempts,
|
|
5149
|
+
contextOverflow: r.contextOverflow,
|
|
4938
5150
|
totalCost: r.totalCost,
|
|
4939
5151
|
artifactPaths: r.artifactPaths,
|
|
4940
5152
|
outputSaveError: r.outputSaveError,
|
|
@@ -4999,6 +5211,7 @@ async function runSubagent(
|
|
|
4999
5211
|
statusPayload.lastUpdate = Date.now();
|
|
5000
5212
|
}
|
|
5001
5213
|
writeStatusPayload();
|
|
5214
|
+
orcaProgressTab?.finish(statusPayload.state === "complete" ? "completed" : statusPayload.state === "stopped" ? "stopped" : "failed", effectiveSessionFile);
|
|
5002
5215
|
appendJsonl(
|
|
5003
5216
|
eventsPath,
|
|
5004
5217
|
JSON.stringify({
|
|
@@ -44,6 +44,7 @@ export function toWaitCompletion(data: Record<string, unknown>, runId: string):
|
|
|
44
44
|
const childRunId = asNonEmptyString(child.runId);
|
|
45
45
|
const error = asNonEmptyString(child.error);
|
|
46
46
|
const model = asNonEmptyString(child.model);
|
|
47
|
+
const contextOverflow = child.contextOverflow === true;
|
|
47
48
|
return [{
|
|
48
49
|
...(agent ? { agent } : {}),
|
|
49
50
|
...(childRunId ? { runId: childRunId } : {}),
|
|
@@ -51,6 +52,7 @@ export function toWaitCompletion(data: Record<string, unknown>, runId: string):
|
|
|
51
52
|
...(outputState ? { outputState } : {}),
|
|
52
53
|
...(error ? { error } : {}),
|
|
53
54
|
...(model ? { model } : {}),
|
|
55
|
+
...(contextOverflow ? { contextOverflow: true } : {}),
|
|
54
56
|
...(artifactPaths ? { artifactPaths } : {}),
|
|
55
57
|
}];
|
|
56
58
|
})
|