pi-subagents 0.66.0 → 0.68.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 +138 -0
- package/README.md +5 -4
- package/agents/evidence-auditor.md +34 -0
- package/agents/reviewer.md +3 -2
- package/docs/agents.md +43 -15
- package/docs/configuration.md +67 -23
- package/docs/extension-api.md +38 -19
- package/docs/missions.md +10 -2
- package/docs/models.md +11 -79
- package/docs/observability.md +22 -12
- package/docs/standalone-background.md +59 -0
- package/docs/tool-reference.md +33 -20
- package/docs/watchdog.md +39 -10
- package/docs/workflows.md +37 -13
- package/index.ts +5 -2
- package/inspector-runner.mjs +2 -2
- package/package.json +4 -2
- package/prompts/parallel-review.md +1 -1
- package/runner-peer-loader.mjs +24 -0
- package/runner-peer-preload.mjs +32 -0
- package/skills/pi-subagents/SKILL.md +32 -21
- package/skills/pi-subagents/references/constraints-and-recipes.md +3 -2
- package/skills/pi-subagents/references/execution-controls.md +11 -9
- package/skills/pi-subagents/references/management-authoring-rpc.md +0 -1
- package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +17 -13
- package/skills/pi-subagents/references/review-and-validation.md +3 -3
- package/src/agents/advertised-agent-prompt.ts +34 -3
- package/src/agents/agent-management.ts +57 -58
- package/src/agents/agent-serializer.ts +4 -3
- package/src/agents/agents.ts +190 -71
- package/src/agents/builtin-names.ts +1 -0
- package/src/agents/chain-serializer.ts +5 -0
- package/src/agents/runtime-agent-registry.ts +7 -6
- package/src/api/delegation.ts +4 -0
- package/src/api/preflight.ts +94 -59
- package/src/api/required-child-extensions.ts +6 -0
- package/src/api/shared-types.ts +2 -0
- package/src/extension/config.ts +10 -37
- package/src/extension/fanout-child.ts +66 -4
- package/src/extension/herdr-pi-bridge.ts +160 -0
- package/src/extension/index.ts +62 -39
- package/src/extension/public-execution.ts +7 -5
- package/src/extension/rpc.ts +4 -0
- package/src/extension/schemas.ts +81 -81
- package/src/extension/tool-description.ts +30 -82
- package/src/inspectors/actions.ts +148 -0
- package/src/inspectors/ghostty/actions.ts +74 -0
- package/src/inspectors/ghostty/plugin.ts +17 -0
- package/src/inspectors/herdr/actions.ts +99 -179
- package/src/inspectors/herdr/plugin.ts +20 -0
- package/src/inspectors/herdr/project-panes.ts +1 -1
- package/src/inspectors/{herdr/inspector-runner.ts → inspector-runner.ts} +12 -12
- package/src/inspectors/plugins.ts +8 -0
- package/src/inspectors/{herdr/session-roots-codec.ts → session-roots-codec.ts} +3 -14
- package/src/inspectors/types.ts +51 -0
- package/src/intercom/intercom-bridge.ts +50 -8
- package/src/intercom/native-supervisor-channel.ts +44 -31
- package/src/policy/authority.ts +4 -0
- package/src/profiles/profiles.ts +12 -6
- package/src/runs/background/active-async-capacity.ts +4 -0
- package/src/runs/background/active-run-index.ts +17 -1
- package/src/runs/background/async-execution.ts +348 -176
- package/src/runs/background/async-job-tracker.ts +8 -6
- package/src/runs/background/async-resume.ts +17 -12
- package/src/runs/background/async-status.ts +15 -4
- package/src/runs/background/auto-drain.ts +23 -10
- package/src/runs/background/binary-bootstrap.ts +38 -0
- package/src/runs/background/chain-append.ts +1 -1
- package/src/runs/background/chain-root-attachment.ts +14 -33
- package/src/runs/background/fleet-view.ts +30 -2
- package/src/runs/background/notify.ts +105 -7
- package/src/runs/background/owned-process-tree.ts +29 -2
- package/src/runs/background/result-files.ts +8 -4
- package/src/runs/background/result-watcher.ts +19 -2
- package/src/runs/background/run-child-session.ts +81 -33
- package/src/runs/background/run-status.ts +3 -0
- package/src/runs/background/runner-aliases.ts +12 -33
- package/src/runs/background/runner-child-launch.ts +6 -1
- package/src/runs/background/runner-child-sessions.ts +5 -4
- package/src/runs/background/runner-http-dispatcher.ts +119 -0
- package/src/runs/background/scheduled-runs.ts +51 -18
- package/src/runs/background/stale-run-reconciler.ts +35 -11
- package/src/runs/background/steering.ts +20 -2
- package/src/runs/background/subagent-runner.ts +441 -304
- package/src/runs/background/subagent-wait.ts +176 -28
- package/src/runs/background/wait-completions.ts +75 -27
- package/src/runs/background/wait-subscriptions.ts +9 -3
- package/src/runs/background/wait-tool.ts +5 -3
- package/src/runs/foreground/async-steering-action.ts +18 -7
- package/src/runs/foreground/async-stop-action.ts +93 -3
- package/src/runs/foreground/execution.ts +134 -248
- package/src/runs/foreground/foreground-history.ts +2 -1
- package/src/runs/foreground/prompt-audit.ts +3 -1
- package/src/runs/foreground/subagent-executor.ts +374 -178
- package/src/runs/foreground/workflow-detach-reconcile.ts +2 -0
- package/src/runs/foreground/workflow-foreground-steering.ts +2 -1
- package/src/runs/shared/acceptance.ts +38 -11
- package/src/runs/shared/async-status-projection.ts +127 -33
- package/src/runs/shared/capability-ceiling.ts +2 -0
- package/src/runs/shared/child-hooks.ts +25 -10
- package/src/runs/shared/child-launch-plan.ts +15 -3
- package/src/runs/shared/child-launch.ts +28 -5
- package/src/runs/shared/child-lifecycle.ts +6 -3
- package/src/runs/shared/child-runtime-config.ts +8 -1
- package/src/runs/shared/child-session.ts +127 -52
- package/src/runs/shared/child-tool-plan.ts +142 -11
- package/src/runs/shared/completion-guard.ts +5 -3
- package/src/runs/shared/dynamic-fanout.ts +2 -2
- package/src/runs/shared/effective-system-prompt.ts +33 -0
- package/src/runs/shared/external-cli-contract.ts +11 -1
- package/src/runs/shared/external-cli-preflight.ts +6 -2
- package/src/runs/shared/external-cli-runner.ts +9 -7
- package/src/runs/shared/herdr-connection.ts +134 -0
- package/src/runs/shared/herdr-external-adapters.ts +169 -0
- package/src/runs/shared/herdr-machine.ts +279 -0
- package/src/runs/shared/herdr-pi-protocol.ts +59 -0
- package/src/runs/shared/herdr-placed-run.ts +263 -0
- package/src/runs/shared/llm-intent-arbiter.ts +12 -3
- package/src/runs/shared/model-resolution-diagnostic.ts +76 -0
- package/src/runs/shared/{model-fallback.ts → model-resolution.ts} +22 -235
- package/src/runs/shared/model-scope.ts +1 -1
- package/src/runs/shared/nested-events.ts +11 -2
- package/src/runs/shared/orca-progress-tabs.ts +1 -1
- package/src/runs/shared/parallel-utils.ts +7 -2
- package/src/runs/shared/pi-spawn.ts +10 -0
- package/src/runs/shared/subagent-prompt-runtime.ts +12 -4
- package/src/runs/shared/task-intent.ts +46 -13
- package/src/runs/shared/workflow-async-child-guidance.ts +18 -0
- package/src/runs/shared/worktree-setup-command.ts +27 -4
- package/src/runs/shared/worktree.ts +45 -15
- package/src/shared/child-cache-retention.ts +43 -0
- package/src/shared/fork-context.ts +15 -72
- package/src/shared/launch-contract.ts +68 -8
- package/src/shared/opencode-session-headers.ts +30 -0
- package/src/shared/pruned-fork.ts +1 -1
- package/src/shared/required-child-extensions.ts +81 -0
- package/src/shared/settings.ts +5 -2
- package/src/shared/shortcuts.ts +0 -4
- package/src/shared/types.ts +74 -30
- package/src/slash/delegation-adapters.ts +3 -1
- package/src/slash/delegation-request.ts +14 -0
- package/src/slash/slash-commands.ts +2 -7
- package/src/slash/subagents-admin.ts +24 -13
- package/src/tui/fleet-status.ts +164 -19
- package/src/tui/fleet.ts +16 -14
- package/src/tui/render.ts +168 -37
- package/src/watchdog/child-status.ts +28 -28
- package/src/watchdog/lsp-diagnostics.ts +1 -1
- package/src/watchdog/model-selection.ts +21 -1
- package/src/watchdog/permission-arbiter.ts +3 -1
- package/src/watchdog/register-child.ts +10 -2
- package/src/watchdog/register-main.ts +39 -35
- package/src/watchdog/render.ts +1 -1
- package/src/watchdog/review.ts +123 -74
- package/src/watchdog/rules.ts +1 -1
- package/src/watchdog/runtime.ts +100 -27
- package/src/watchdog/scope.ts +1 -1
- package/src/watchdog/settings.ts +3 -0
- package/src/watchdog/tool-actions.ts +13 -12
- package/src/watchdog/turn-delta.ts +23 -0
- package/src/watchdog/types.ts +5 -3
- package/src/watchdog/warning-format.ts +1 -1
- package/src/workflows/scripted-workflow.ts +279 -10
- package/src/workflows/workflow-checklist.ts +2 -2
- package/src/workflows/workflow-receipt.ts +21 -3
- package/src/workflows/workflow-resources.ts +13 -2
- package/runner-server-preload.mjs +0 -13
- package/src/runs/shared/model-exclusions.ts +0 -374
- package/src/runs/shared/readonly-model-continuation.ts +0 -69
- package/src/runs/shared/readonly-session-evidence.ts +0 -307
- /package/src/inspectors/{herdr/shell-command.ts → shell-command.ts} +0 -0
|
@@ -6,8 +6,8 @@ import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
import type { Message } from "@earendil-works/pi-ai";
|
|
8
8
|
import { discoverAgents, formatUnknownAgentError, unknownAgentDiagnosticContext, type AgentConfig } from "../../agents/agents.ts";
|
|
9
|
-
import { appendAgentRefinementOverlay } from "../../agents/agent-refinements.ts";
|
|
10
9
|
import { alignForkedSessionCwd } from "../../shared/fork-session-cwd.ts";
|
|
10
|
+
import { buildEffectiveSystemPrompt } from "../shared/effective-system-prompt.ts";
|
|
11
11
|
import {
|
|
12
12
|
ensureArtifactsDir,
|
|
13
13
|
formatOutputArtifactContent,
|
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
type AgentProgress,
|
|
21
21
|
type ArtifactPaths,
|
|
22
22
|
type ControlEvent,
|
|
23
|
-
type ModelAttempt,
|
|
24
23
|
type RunSyncOptions,
|
|
25
24
|
type SingleResult,
|
|
26
25
|
type Usage,
|
|
@@ -52,15 +51,10 @@ import {
|
|
|
52
51
|
boundStreamedRecentOutput,
|
|
53
52
|
boundStreamedToolCalls,
|
|
54
53
|
} from "../../shared/utils.ts";
|
|
55
|
-
import {
|
|
56
|
-
import { buildAgentMemoryInjection } from "../../agents/agent-memory.ts";
|
|
54
|
+
import { resolveSkillsWithFallback } from "../../agents/skills.ts";
|
|
57
55
|
import { effectiveToolTimeoutMs, formatToolTimeoutMessage, resolveToolTimeoutMs, toolTimeoutCallKey, toolTimeoutFromEnv } from "../shared/tool-timeout.ts";
|
|
58
56
|
import { evaluateCompletionMutationGuard, expectsImplementationMutation, hasMutationToolCapability, validateImplementationToolContract } from "../shared/completion-guard.ts";
|
|
59
57
|
import { planCompletionEvidence } from "../shared/completion-evidence.ts";
|
|
60
|
-
import { planAbortRecovery } from "../shared/abort-recovery.ts";
|
|
61
|
-
import { planReadonlyModelContinuation, type LogicalRecoveryState } from "../shared/readonly-model-continuation.ts";
|
|
62
|
-
import { getReadonlySessionEvidence, requestReadonlySessionEvidence, type SettledReadonlyEvidence } from "../shared/readonly-session-evidence.ts";
|
|
63
|
-
import { getReadonlyChildModels } from "../shared/child-session.ts";
|
|
64
58
|
import { arbitrateCompletionGuardRescue } from "../shared/llm-intent-arbiter.ts";
|
|
65
59
|
import { preflightLaunchCwd } from "../shared/launch-cwd.ts";
|
|
66
60
|
import { createJsonlWriter } from "../../shared/jsonl-writer.ts";
|
|
@@ -74,16 +68,15 @@ import { assertThinkingWithinCeiling, intersectThinkingCeilings } from "../../sh
|
|
|
74
68
|
import { MISSING_STRUCTURED_ACCEPTANCE_REPORT_ERROR, MISSING_STRUCTURED_OUTPUT_CALL_ERROR } from "../shared/structured-output.ts";
|
|
75
69
|
import { formatMidToolExitError, isOrdinaryToolForMidToolExit } from "../shared/process-signal.ts";
|
|
76
70
|
import { formatChildToolDiagnostic } from "../shared/tool-availability.ts";
|
|
71
|
+
import { formatChildModelResolutionDiagnostic, isChildModelResolutionFailure } from "../shared/model-resolution-diagnostic.ts";
|
|
72
|
+
import { planAbortRecovery } from "../shared/abort-recovery.ts";
|
|
77
73
|
import { buildTimeoutRecoverySummary, collectTrackedMutationEvidence, snapshotTrackedMutations } from "../shared/mutation-evidence.ts";
|
|
78
|
-
import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, hasSingleOutputChangedSinceSnapshot,
|
|
74
|
+
import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, hasSingleOutputChangedSinceSnapshot, resolveSingleOutput, validateFileOnlyOutputMode, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
79
75
|
import {
|
|
80
|
-
buildModelCandidates,
|
|
81
76
|
formatSubagentModelVerificationError,
|
|
82
|
-
formatModelAttemptNote,
|
|
83
77
|
isContextOverflow,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
} from "../shared/model-fallback.ts";
|
|
78
|
+
resolveModelSelection,
|
|
79
|
+
} from "../shared/model-resolution.ts";
|
|
87
80
|
import {
|
|
88
81
|
createMutatingFailureState,
|
|
89
82
|
didMutatingToolFail,
|
|
@@ -100,7 +93,7 @@ import { PROMPT_REDACTED } from "../../shared/utils.ts";
|
|
|
100
93
|
import { attachContractProjections, isAgentContract } from "../shared/agent-contract.ts";
|
|
101
94
|
import { initialToolBudgetState, toolBudgetState } from "../shared/tool-budget.ts";
|
|
102
95
|
import { resolveWatchdogConfig } from "../../watchdog/settings.ts";
|
|
103
|
-
import {
|
|
96
|
+
import { resolveLaunchBinding } from "../../shared/launch-contract.ts";
|
|
104
97
|
import { consumeWorkflowChildPermit } from "../../shared/workflow-child-permit.ts";
|
|
105
98
|
import { projectChildLifecycle, type ChildLifecycleAction, type ChildLifecycleState } from "../shared/child-lifecycle.ts";
|
|
106
99
|
import {
|
|
@@ -113,7 +106,7 @@ import {
|
|
|
113
106
|
type ChildWatchdogStatusEvent,
|
|
114
107
|
} from "../../watchdog/child-status.ts";
|
|
115
108
|
import { buildInProcessChildLaunch, createReportedChildSessionInput } from "../shared/child-launch.ts";
|
|
116
|
-
import { childSessionFactory, projectChildSessionEventForJson, type ChildSession, type ChildSessionEvent } from "../shared/child-session.ts";
|
|
109
|
+
import { childSessionFactory, childSessionHasQueuedMessages, projectChildSessionEventForJson, type ChildSession, type ChildSessionEvent } from "../shared/child-session.ts";
|
|
117
110
|
|
|
118
111
|
const artifactOutputByResult = new WeakMap<SingleResult, string>();
|
|
119
112
|
const acceptanceOutputByResult = new WeakMap<SingleResult, string>();
|
|
@@ -161,8 +154,7 @@ function persistSingleResultMetadata(input: {
|
|
|
161
154
|
processSignal: target.processSignal,
|
|
162
155
|
usage: target.usage,
|
|
163
156
|
model: target.model,
|
|
164
|
-
|
|
165
|
-
modelAttempts: target.modelAttempts,
|
|
157
|
+
requestedModel: target.requestedModel,
|
|
166
158
|
durationMs: target.progressSummary?.durationMs,
|
|
167
159
|
toolCount: target.progressSummary?.toolCount,
|
|
168
160
|
error: target.error,
|
|
@@ -262,13 +254,6 @@ function snapshotResult(result: SingleResult, progress: AgentProgress): SingleRe
|
|
|
262
254
|
messages: result.outputMode === "file-only" && result.savedOutputPath ? undefined : result.messages ? [...result.messages] : undefined,
|
|
263
255
|
usage: { ...result.usage },
|
|
264
256
|
skills: result.skills ? [...result.skills] : undefined,
|
|
265
|
-
attemptedModels: result.attemptedModels ? [...result.attemptedModels] : undefined,
|
|
266
|
-
modelAttempts: result.modelAttempts
|
|
267
|
-
? result.modelAttempts.map((attempt) => ({
|
|
268
|
-
...attempt,
|
|
269
|
-
usage: attempt.usage ? { ...attempt.usage } : undefined,
|
|
270
|
-
}))
|
|
271
|
-
: undefined,
|
|
272
257
|
controlEvents: result.controlEvents ? result.controlEvents.map((event) => ({ ...event })) : undefined,
|
|
273
258
|
progress,
|
|
274
259
|
progressSummary: result.progressSummary ? { ...result.progressSummary } : undefined,
|
|
@@ -341,11 +326,10 @@ function structuredDelegationProgressChanged(
|
|
|
341
326
|
return false;
|
|
342
327
|
}
|
|
343
328
|
|
|
344
|
-
const AFTER_COMPACTION_SETTLEMENT = Symbol("afterCompactionSettlement");
|
|
345
|
-
type AbortRecoverySingleResult = SingleResult & { [AFTER_COMPACTION_SETTLEMENT]?: true };
|
|
346
|
-
const settledReadonlySource = new WeakMap<SingleResult, ChildSession>();
|
|
347
329
|
|
|
348
330
|
const STOPPED_BEFORE_COMPLETION_ERROR = "Subagent stopped before completion.";
|
|
331
|
+
const AFTER_COMPACTION_SETTLEMENT = Symbol("afterCompactionSettlement");
|
|
332
|
+
type AbortRecoverySingleResult = SingleResult & { [AFTER_COMPACTION_SETTLEMENT]?: true };
|
|
349
333
|
|
|
350
334
|
|
|
351
335
|
async function runSingleAttempt(
|
|
@@ -359,7 +343,6 @@ async function runSingleAttempt(
|
|
|
359
343
|
systemPrompt: string;
|
|
360
344
|
acceptancePrompt: string;
|
|
361
345
|
resolvedSkillNames?: string[];
|
|
362
|
-
modelCandidates?: string[];
|
|
363
346
|
skillsWarning?: string;
|
|
364
347
|
jsonlPath?: string;
|
|
365
348
|
artifactPaths?: ArtifactPaths;
|
|
@@ -370,9 +353,6 @@ async function runSingleAttempt(
|
|
|
370
353
|
orcaProgressTab?: OrcaProgressTab;
|
|
371
354
|
launchWarnings: { emitted: boolean };
|
|
372
355
|
verifyModel: boolean;
|
|
373
|
-
readonlyExpected?: SettledReadonlyEvidence;
|
|
374
|
-
readonlyModel?: string;
|
|
375
|
-
readonlyHandoffAllowed?: () => boolean;
|
|
376
356
|
},
|
|
377
357
|
): Promise<SingleResult> {
|
|
378
358
|
const effectiveThinking = options.thinkingOverride ?? agent.thinking;
|
|
@@ -399,6 +379,11 @@ async function runSingleAttempt(
|
|
|
399
379
|
: undefined;
|
|
400
380
|
let onWatchdogStatus: ((event: ChildWatchdogStatusEvent) => void) | undefined;
|
|
401
381
|
const launch = buildInProcessChildLaunch({
|
|
382
|
+
machine: options.machine,
|
|
383
|
+
remoteSkillNames: options.skills ?? agent.skills,
|
|
384
|
+
remoteReads: options.remoteReads,
|
|
385
|
+
extensionBindings: options.extensionBindings,
|
|
386
|
+
requiredExtensions: options.requiredExtensions,
|
|
402
387
|
sessionEnabled: shared.sessionEnabled,
|
|
403
388
|
sessionDir: options.sessionDir,
|
|
404
389
|
sessionFile: options.sessionFile,
|
|
@@ -429,7 +414,6 @@ async function runSingleAttempt(
|
|
|
429
414
|
forkCacheKey: options.context === "fork" ? deriveForkPromptCacheKey(options.parentSessionId) : undefined,
|
|
430
415
|
structuredOutput: options.structuredOutput,
|
|
431
416
|
fast: options.fast ?? agent.fast,
|
|
432
|
-
modelCandidates: shared.modelCandidates,
|
|
433
417
|
toolBudget: options.toolBudget,
|
|
434
418
|
permissionRules,
|
|
435
419
|
permissionAuditPath,
|
|
@@ -442,9 +426,11 @@ async function runSingleAttempt(
|
|
|
442
426
|
thinkingCeiling: options.thinkingCeiling,
|
|
443
427
|
maxSubagentDepth: options.maxSubagentDepth,
|
|
444
428
|
runtimeSnapshotHost: options.runtimeSnapshotHost,
|
|
429
|
+
hostAvailableBuiltins: options.hostAvailableBuiltins,
|
|
445
430
|
inherited: options.childRuntime,
|
|
446
431
|
host: "parent",
|
|
447
432
|
});
|
|
433
|
+
if (!options.machine && options.parentProviderRegistry) launch.session.parentProviderRegistry = options.parentProviderRegistry;
|
|
448
434
|
const { toolPlan, capabilityAudit, warnings, launchResolvedExtensions, capture } = launch;
|
|
449
435
|
if (!shared.launchWarnings.emitted && warnings.length > 0) {
|
|
450
436
|
for (const warning of warnings) console.warn(`[pi-subagents] ${warning}`);
|
|
@@ -475,31 +461,21 @@ async function runSingleAttempt(
|
|
|
475
461
|
error: contractError,
|
|
476
462
|
usage: emptyUsage(),
|
|
477
463
|
model: modelArg,
|
|
478
|
-
modelAttempts: [],
|
|
479
|
-
attemptedModels: [],
|
|
480
464
|
progressSummary: { status: "failed", toolCount: 0, tokens: 0, durationMs: 0 },
|
|
481
465
|
...(toolPlan.capabilityCeiling ? { capabilityCeiling: toolPlan.capabilityCeiling } : {}),
|
|
482
466
|
...(toolPlan.capabilityAudit ? { capabilityAudit: toolPlan.capabilityAudit } : {}),
|
|
483
467
|
};
|
|
484
468
|
}
|
|
485
|
-
const
|
|
486
|
-
|
|
469
|
+
const fast = options.fast ?? agent.fast;
|
|
470
|
+
const { launchContractDigest } = resolveLaunchBinding({
|
|
471
|
+
agent,
|
|
487
472
|
task: shared.originalTask ?? task,
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
...((options.fast ?? agent.fast) !== undefined ? { fast: options.fast ?? agent.fast } : {}),
|
|
473
|
+
model: modelArg,
|
|
474
|
+
...(fast !== undefined ? { fast } : {}),
|
|
491
475
|
...(resolvedThinking ? { thinking: resolvedThinking } : {}),
|
|
492
|
-
...(options.thinkingCeiling ? { thinkingCeiling: options.thinkingCeiling } : {}),
|
|
493
476
|
systemPrompt: effectiveSystemPrompt,
|
|
494
|
-
systemPromptMode: agent.systemPromptMode,
|
|
495
|
-
inheritProjectContext: agent.inheritProjectContext,
|
|
496
|
-
inheritGlobalContext: agent.inheritGlobalContext,
|
|
497
|
-
inheritSkills: agent.inheritSkills,
|
|
498
477
|
skills: shared.resolvedSkillNames ?? [],
|
|
499
|
-
|
|
500
|
-
...(toolPlan.excludeTools.length > 0 ? { excludeTools: toolPlan.excludeTools } : {}),
|
|
501
|
-
extensions: toolPlan.extensionArgs,
|
|
502
|
-
mcpDirectTools: toolPlan.effectiveMcpTools,
|
|
478
|
+
toolPlan,
|
|
503
479
|
...(options.outputPath ? { outputPath: options.outputPath } : {}),
|
|
504
480
|
outputMode: options.outputMode ?? "inline",
|
|
505
481
|
...(options.structuredOutput ? { structuredOutputSchema: options.structuredOutput.schema } : {}),
|
|
@@ -575,12 +551,13 @@ async function runSingleAttempt(
|
|
|
575
551
|
};
|
|
576
552
|
return result;
|
|
577
553
|
}
|
|
578
|
-
const mutationSnapshot = snapshotTrackedMutations(options.cwd ?? runtimeCwd);
|
|
554
|
+
const mutationSnapshot = options.machine ? { source: "tracked-files" as const, trackedOnly: true as const, cwd: options.cwd ?? runtimeCwd, dirtyFiles: [], fingerprints: {}, unavailable: "Local Git evidence is not authoritative for a pane-native remote run." } : snapshotTrackedMutations(options.cwd ?? runtimeCwd);
|
|
579
555
|
let observedMutationAttempt = false;
|
|
580
556
|
let structuredOutputToolInvoked = false;
|
|
581
557
|
let structuredOutputMessageStartIndex: number | undefined;
|
|
582
558
|
let toolAvailabilityError: string | undefined;
|
|
583
559
|
let abortedBySignal = options.signal?.aborted === true;
|
|
560
|
+
let afterCompactionSettlement = false;
|
|
584
561
|
|
|
585
562
|
if (options.workflowChildPermitLaunch) {
|
|
586
563
|
const permitError = consumeWorkflowChildPermit(options.workflowChildPermitLaunch.permit, {
|
|
@@ -601,7 +578,6 @@ async function runSingleAttempt(
|
|
|
601
578
|
}
|
|
602
579
|
}
|
|
603
580
|
const childSessions = options.childSessionFactory ?? childSessionFactory();
|
|
604
|
-
let afterCompactionSettlement = false;
|
|
605
581
|
const exitCode = await new Promise<number>((resolve) => {
|
|
606
582
|
const jsonlWriter = createJsonlWriter(shared.jsonlPath, { pause() {}, resume() {} });
|
|
607
583
|
let session: ChildSession | undefined;
|
|
@@ -681,6 +657,7 @@ async function runSingleAttempt(
|
|
|
681
657
|
let forcedTermination = false;
|
|
682
658
|
let cleanTerminalAssistantStopReceived = false;
|
|
683
659
|
let agentSettledReceived = false;
|
|
660
|
+
let queuedDrainHold = false;
|
|
684
661
|
let compactionStartedReceived = false;
|
|
685
662
|
let finalDrainTimer: NodeJS.Timeout | undefined;
|
|
686
663
|
let finalHardFinishTimer: NodeJS.Timeout | undefined;
|
|
@@ -707,14 +684,28 @@ async function runSingleAttempt(
|
|
|
707
684
|
finalHardFinishTimer = undefined;
|
|
708
685
|
}
|
|
709
686
|
};
|
|
687
|
+
const observeQueuedDrainHold = (): boolean => {
|
|
688
|
+
if (childSessionHasQueuedMessages(session)) queuedDrainHold = true;
|
|
689
|
+
return queuedDrainHold;
|
|
690
|
+
};
|
|
710
691
|
const startFinalDrain = () => {
|
|
711
692
|
if (childWatchdogIsActive(childWatchdogState)) {
|
|
712
693
|
armWatchdogTail();
|
|
713
694
|
return;
|
|
714
695
|
}
|
|
696
|
+
if (sessionSettled || finalDrainTimer || lifecycleFinished) return;
|
|
697
|
+
if (observeQueuedDrainHold()) return;
|
|
698
|
+
armFinalDrainTimer();
|
|
699
|
+
};
|
|
700
|
+
const armFinalDrainTimer = () => {
|
|
715
701
|
if (sessionSettled || finalDrainTimer || lifecycleFinished) return;
|
|
716
702
|
finalDrainTimer = setTimeout(() => {
|
|
717
703
|
if (lifecycleFinished || sessionSettled) return;
|
|
704
|
+
if (capture.finalDrainHeld() || observeQueuedDrainHold()) {
|
|
705
|
+
finalDrainTimer = undefined;
|
|
706
|
+
armFinalDrainTimer();
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
718
709
|
forcedTermination = true;
|
|
719
710
|
if (!cleanTerminalAssistantStopReceived && !agentSettledReceived && !assistantError) {
|
|
720
711
|
result.error = result.error ?? `Subagent session did not settle within ${FINAL_STOP_GRACE_MS}ms after its terminal event. Aborting it.`;
|
|
@@ -746,6 +737,8 @@ async function runSingleAttempt(
|
|
|
746
737
|
}
|
|
747
738
|
const applyChildLifecycle = (action: ChildLifecycleAction): void => {
|
|
748
739
|
if (action === "cancel-drain") {
|
|
740
|
+
cleanTerminalAssistantStopReceived = false;
|
|
741
|
+
agentSettledReceived = false;
|
|
749
742
|
clearFinalDrainTimers();
|
|
750
743
|
clearWatchdogTailTimer();
|
|
751
744
|
return;
|
|
@@ -791,7 +784,6 @@ async function runSingleAttempt(
|
|
|
791
784
|
});
|
|
792
785
|
// Report the run only after the child's extensions have shut down.
|
|
793
786
|
void Promise.resolve().then(() => session?.dispose()).catch(() => undefined).then(() => {
|
|
794
|
-
if (session && getReadonlySessionEvidence(session)) settledReadonlySource.set(result, session);
|
|
795
787
|
resolve(code);
|
|
796
788
|
});
|
|
797
789
|
};
|
|
@@ -992,6 +984,9 @@ async function runSingleAttempt(
|
|
|
992
984
|
compactionStartedReceived = false;
|
|
993
985
|
afterCompactionSettlement = false;
|
|
994
986
|
}
|
|
987
|
+
if (evt.type === "turn_start" || evt.type === "agent_start" || evt.type === "auto_retry_start") {
|
|
988
|
+
queuedDrainHold = false;
|
|
989
|
+
}
|
|
995
990
|
if (evt.type === "agent_start" || evt.type === "auto_retry_start") {
|
|
996
991
|
compactionStartedReceived = false;
|
|
997
992
|
afterCompactionSettlement = false;
|
|
@@ -1295,9 +1290,23 @@ async function runSingleAttempt(
|
|
|
1295
1290
|
const toolDiagnosticError = diagnostic ? formatChildToolDiagnostic(diagnostic, { host: "parent" }) : undefined;
|
|
1296
1291
|
toolAvailabilityError = toolDiagnosticError;
|
|
1297
1292
|
result.runtimeAcknowledgedExtensions = capture.runtimeAcknowledgedExtensions();
|
|
1293
|
+
if (session?.machineEvidence) result.nativeMachine = { provider: "herdr", machineId: session.machineEvidence.machineId, ...(session.machineEvidence.initial ? { initialGit: session.machineEvidence.initial } : {}), ...(session.machineEvidence.final ? { finalGit: session.machineEvidence.final } : {}) };
|
|
1298
1294
|
let closeError = result.error ?? toolDiagnosticError ?? assistantError;
|
|
1299
|
-
|
|
1300
|
-
|
|
1295
|
+
const promptErrorMessage = promptError === undefined ? undefined : promptError instanceof Error ? promptError.message : String(promptError);
|
|
1296
|
+
if (!closeError && promptErrorMessage !== undefined) {
|
|
1297
|
+
closeError = promptErrorMessage;
|
|
1298
|
+
}
|
|
1299
|
+
// A foreground child never loads the parent's ambient extensions, so a
|
|
1300
|
+
// provider one registers resolves as "not found" before the child starts.
|
|
1301
|
+
// Annotate only a creation/prompt failure that produced no turn; keep the
|
|
1302
|
+
// core error and add the host rule and both remedies after it.
|
|
1303
|
+
if (promptErrorMessage !== undefined
|
|
1304
|
+
&& closeError === promptErrorMessage
|
|
1305
|
+
&& isChildModelResolutionFailure(promptErrorMessage)
|
|
1306
|
+
&& (result.messages?.length ?? 0) === 0
|
|
1307
|
+
&& result.usage.turns === 0
|
|
1308
|
+
&& !launch.session.ambientExtensions) {
|
|
1309
|
+
closeError = `${promptErrorMessage}\n\n${formatChildModelResolutionDiagnostic({ agent: agent.name, model: launch.session.model, host: "parent", capabilityCeiling: launch.toolPlan.capabilityCeiling })}`;
|
|
1301
1310
|
}
|
|
1302
1311
|
const forcedDrainAfterFinalSuccess = (forced || forcedTermination) && (cleanTerminalAssistantStopReceived || agentSettledReceived) && !closeError;
|
|
1303
1312
|
const forcedDrainAfterEmptyTerminal = forcedDrainAfterFinalSuccess && hasEmptyTerminalAssistantResponse(result.messages ?? []);
|
|
@@ -1370,24 +1379,28 @@ async function runSingleAttempt(
|
|
|
1370
1379
|
void (async () => {
|
|
1371
1380
|
try {
|
|
1372
1381
|
const input = createReportedChildSessionInput(launch, shared.transcriptWriter);
|
|
1373
|
-
requestReadonlySessionEvidence(input, shared.readonlyExpected);
|
|
1374
|
-
if (shared.readonlyHandoffAllowed && !shared.readonlyHandoffAllowed()) throw new Error("Read-only continuation handoff vetoed.");
|
|
1375
1382
|
const created = await childSessions.create(input);
|
|
1376
1383
|
if (lifecycleFinished) {
|
|
1377
1384
|
void created.dispose();
|
|
1378
1385
|
return;
|
|
1379
1386
|
}
|
|
1380
1387
|
session = created;
|
|
1388
|
+
const steer = created.steer.bind(created);
|
|
1389
|
+
const followUp = created.followUp.bind(created);
|
|
1390
|
+
created.steer = async (text) => {
|
|
1391
|
+
if (cleanTerminalAssistantStopReceived || agentSettledReceived) queuedDrainHold = true;
|
|
1392
|
+
return steer(text);
|
|
1393
|
+
};
|
|
1394
|
+
created.followUp = async (text) => {
|
|
1395
|
+
if (cleanTerminalAssistantStopReceived || agentSettledReceived) queuedDrainHold = true;
|
|
1396
|
+
return followUp(text);
|
|
1397
|
+
};
|
|
1381
1398
|
created.detached = detached;
|
|
1382
1399
|
unsubscribe = created.subscribe((event) => processEvent(event as Parameters<typeof processEvent>[0]));
|
|
1383
1400
|
if (abortedBySignal || interruptedByControl || result.timedOut) {
|
|
1384
1401
|
abortChild();
|
|
1385
1402
|
}
|
|
1386
1403
|
options.onChildSession?.({ steer: (text) => created.steer(text), followUp: (text) => created.followUp(text) });
|
|
1387
|
-
const actualReadonlyModel = shared.readonlyExpected && getReadonlyChildModels(created)?.current;
|
|
1388
|
-
if (shared.readonlyExpected && (!actualReadonlyModel || actualReadonlyModel.fullId !== shared.readonlyModel
|
|
1389
|
-
|| actualReadonlyModel.api !== shared.readonlyExpected.api || created.modelId !== shared.readonlyModel || abortedBySignal || interruptedByControl || result.timedOut
|
|
1390
|
-
|| !shared.readonlyHandoffAllowed?.())) throw new Error("Read-only continuation handoff vetoed.");
|
|
1391
1404
|
await created.prompt(`Task: ${task}`);
|
|
1392
1405
|
settle(undefined);
|
|
1393
1406
|
} catch (error) {
|
|
@@ -1486,7 +1499,8 @@ async function runSingleAttempt(
|
|
|
1486
1499
|
tokens: progress.tokens,
|
|
1487
1500
|
durationMs: progress.durationMs,
|
|
1488
1501
|
};
|
|
1489
|
-
const
|
|
1502
|
+
const remoteGitChanged = result.nativeMachine?.initialGit && result.nativeMachine.finalGit ? result.nativeMachine.initialGit.head !== result.nativeMachine.finalGit.head || result.nativeMachine.initialGit.dirty !== result.nativeMachine.finalGit.dirty : undefined;
|
|
1503
|
+
const mutationEvidence = result.nativeMachine ? { source: "tracked-files" as const, trackedOnly: true as const, changedFiles: [], attemptedMutation: remoteGitChanged === true, ...(remoteGitChanged === undefined ? { unavailable: "Remote Git before/after evidence was incomplete." } : {}) } : collectTrackedMutationEvidence(mutationSnapshot, options.cwd ?? runtimeCwd);
|
|
1490
1504
|
|
|
1491
1505
|
const acceptanceOutput = getFinalOutput(result.messages ?? []);
|
|
1492
1506
|
let fullOutput = stripAcceptanceReport(acceptanceOutput);
|
|
@@ -1779,21 +1793,10 @@ async function runSyncCompletionInner(
|
|
|
1779
1793
|
error: "Skills not found: pi-subagents",
|
|
1780
1794
|
}, options.context));
|
|
1781
1795
|
}
|
|
1782
|
-
|
|
1783
|
-
if (resolvedSkills.length > 0) {
|
|
1784
|
-
const skillInjection = buildSkillInjection(resolvedSkills);
|
|
1785
|
-
systemPrompt = systemPrompt ? `${systemPrompt}\n\n${skillInjection}` : skillInjection;
|
|
1786
|
-
}
|
|
1787
|
-
const memoryInjection = buildAgentMemoryInjection(agent, skillCwd);
|
|
1788
|
-
if (memoryInjection) {
|
|
1789
|
-
systemPrompt = systemPrompt ? `${systemPrompt}\n\n${memoryInjection}` : memoryInjection;
|
|
1790
|
-
}
|
|
1791
|
-
systemPrompt = appendAgentRefinementOverlay(systemPrompt, { cwd: skillCwd, agentName });
|
|
1792
|
-
systemPrompt = injectOutputPathSystemPrompt(systemPrompt, options.outputPath, agent);
|
|
1796
|
+
const systemPrompt = buildEffectiveSystemPrompt({ agent, resolvedSkills, cwd: skillCwd, ...(options.outputPath ? { outputPath: options.outputPath } : {}) });
|
|
1793
1797
|
|
|
1794
|
-
const
|
|
1798
|
+
const { model: selectedModel, requestedModel } = resolveModelSelection(
|
|
1795
1799
|
options.modelOverride ?? agent.model,
|
|
1796
|
-
agent.fallbackModels,
|
|
1797
1800
|
options.availableModels,
|
|
1798
1801
|
agent.modelProvider ?? options.preferredModelProvider,
|
|
1799
1802
|
{
|
|
@@ -1802,23 +1805,9 @@ async function runSyncCompletionInner(
|
|
|
1802
1805
|
origin: options.modelOrigin ?? (options.modelOverrideFromParent ? "inherited" : "configured"),
|
|
1803
1806
|
},
|
|
1804
1807
|
);
|
|
1805
|
-
if (options.workflowChildPermitLaunch && candidates.length > 1) {
|
|
1806
|
-
const error = "Workflow child permit does not support model fallback.";
|
|
1807
|
-
return redactResultPrompt(withRunContext({
|
|
1808
|
-
index: options.index ?? 0,
|
|
1809
|
-
agent: agent.name,
|
|
1810
|
-
task,
|
|
1811
|
-
exitCode: 1,
|
|
1812
|
-
messages: [],
|
|
1813
|
-
usage: emptyUsage(),
|
|
1814
|
-
error,
|
|
1815
|
-
}, options.context));
|
|
1816
|
-
}
|
|
1817
1808
|
try {
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
assertThinkingWithinCeiling({ model, configThinking: options.thinkingOverride ?? agent.thinking, ceiling: options.thinkingCeiling, agent: agent.name, runId: options.runId });
|
|
1821
|
-
}
|
|
1809
|
+
const model = applyThinkingSuffix(selectedModel, options.thinkingOverride ?? agent.thinking, options.thinkingOverride !== undefined);
|
|
1810
|
+
assertThinkingWithinCeiling({ model, configThinking: options.thinkingOverride ?? agent.thinking, ceiling: options.thinkingCeiling, agent: agent.name, runId: options.runId });
|
|
1822
1811
|
} catch (error) {
|
|
1823
1812
|
return redactResultPrompt(withRunContext({
|
|
1824
1813
|
index: options.index ?? 0,
|
|
@@ -1830,8 +1819,6 @@ async function runSyncCompletionInner(
|
|
|
1830
1819
|
error: error instanceof Error ? error.message : String(error),
|
|
1831
1820
|
}, options.context));
|
|
1832
1821
|
}
|
|
1833
|
-
const attemptedModels: string[] = [];
|
|
1834
|
-
const modelAttempts: ModelAttempt[] = [];
|
|
1835
1822
|
const aggregateUsage = emptyUsage();
|
|
1836
1823
|
const attemptNotes: string[] = [];
|
|
1837
1824
|
const launchWarnings = { emitted: false };
|
|
@@ -1882,10 +1869,11 @@ async function runSyncCompletionInner(
|
|
|
1882
1869
|
});
|
|
1883
1870
|
};
|
|
1884
1871
|
|
|
1885
|
-
let intercomDetached = false;
|
|
1886
1872
|
let detachedReason: string | undefined;
|
|
1873
|
+
const logicalDeadline = options.deadlineAt ?? (options.timeoutMs === undefined ? undefined : Date.now() + options.timeoutMs);
|
|
1887
1874
|
const attemptOptions: RunSyncOptions = {
|
|
1888
1875
|
...options,
|
|
1876
|
+
deadlineAt: logicalDeadline,
|
|
1889
1877
|
onDetachReceipt: (receipt) => {
|
|
1890
1878
|
receipt.acceptance = buildPendingAcceptanceLedger(effectiveAcceptance);
|
|
1891
1879
|
try {
|
|
@@ -1896,165 +1884,65 @@ async function runSyncCompletionInner(
|
|
|
1896
1884
|
const accepted = options.onDetachReceipt?.(receipt) === true;
|
|
1897
1885
|
if (accepted) {
|
|
1898
1886
|
detachedReason = receipt.detachedReason;
|
|
1899
|
-
if (receipt.detachedReason === "intercom coordination") intercomDetached = true;
|
|
1900
1887
|
}
|
|
1901
1888
|
return accepted;
|
|
1902
1889
|
},
|
|
1903
1890
|
};
|
|
1891
|
+
const candidate = selectedModel;
|
|
1892
|
+
const verifyModel = Boolean(candidate) && !options.modelOverrideFromParent;
|
|
1904
1893
|
let lastResult: SingleResult | undefined;
|
|
1905
|
-
|
|
1906
|
-
let
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
if (!recoveringAbort) {
|
|
1953
|
-
if (result.model) attemptedModels.push(result.model);
|
|
1954
|
-
else if (candidate) attemptedModels.push(candidate);
|
|
1955
|
-
}
|
|
1956
|
-
sumUsage(aggregateUsage, result.usage);
|
|
1957
|
-
totalToolCount += result.progressSummary?.toolCount ?? 0;
|
|
1958
|
-
totalDurationMs += result.progressSummary?.durationMs ?? 0;
|
|
1959
|
-
const attemptSucceeded = result.exitCode === 0 && !result.error;
|
|
1960
|
-
const attempt: ModelAttempt = {
|
|
1961
|
-
model: result.model ?? candidate ?? agent.model ?? "default",
|
|
1962
|
-
success: attemptSucceeded,
|
|
1963
|
-
exitCode: result.exitCode,
|
|
1964
|
-
error: result.error,
|
|
1965
|
-
usage: { ...result.usage },
|
|
1966
|
-
};
|
|
1967
|
-
modelAttempts.push(attempt);
|
|
1968
|
-
// A consumed retained continuation is terminal even on a startup error or abort.
|
|
1969
|
-
if (recoveryState === "readonly-continuation") break modelAttemptsLoop;
|
|
1970
|
-
const source = settledReadonlySource.get(result);
|
|
1971
|
-
const evidence = source && getReadonlySessionEvidence(source);
|
|
1972
|
-
const models = source && getReadonlyChildModels(source);
|
|
1973
|
-
// Deny non-text retained inputs, including unknown blocks. Count bytes once,
|
|
1974
|
-
// not restored usage (the latter belongs to earlier attempts/runs).
|
|
1975
|
-
const textOnly = evidence && (JSON.parse(evidence.contextJson) as Array<{ role: string; content: unknown }>).every((message) =>
|
|
1976
|
-
typeof message.content === "string" || Array.isArray(message.content) && message.content.every((block) =>
|
|
1977
|
-
block?.type === "text" || message.role === "assistant" && block?.type === "toolCall"));
|
|
1978
|
-
const retainedBytes = evidence && models ? Buffer.byteLength(evidence.contextJson) + models.requestBytes : Infinity;
|
|
1979
|
-
const resolvedCandidates = modelsToTry.map((reference, index) => index === modelIndex ? models?.current : reference ? models?.resolve(reference) : undefined);
|
|
1980
|
-
const continuation = planReadonlyModelContinuation({
|
|
1981
|
-
source, recoveryState, currentIndex: modelIndex,
|
|
1982
|
-
candidates: resolvedCandidates.map((resolved, index) => {
|
|
1983
|
-
// A conservative byte ceiling includes serialized history, actual system
|
|
1984
|
-
// prompt/tools, framing/continuation headroom and full output allowance.
|
|
1985
|
-
const required = resolved?.maxTokens ? retainedBytes + 4096 + resolved.maxTokens : Infinity;
|
|
1986
|
-
return {
|
|
1987
|
-
resolved: resolved?.api ? { provider: resolved.provider, model: resolved.id, api: resolved.api } : undefined,
|
|
1988
|
-
tried: index <= modelIndex,
|
|
1989
|
-
compatibility: textOnly && resolved?.input?.includes("text") && (resolved.contextWindow ?? 0) >= required ? "compatible" as const : "unknown" as const,
|
|
1990
|
-
};
|
|
1991
|
-
}),
|
|
1992
|
-
lifecycleAllowsContinuation: !attemptSucceeded && readonlyHandoffAllowed() && !result.stopped && !result.detached && !result.interrupted && !result.timedOut,
|
|
1993
|
-
effectsAllowContinuation: !result.structuredOutputFailed && !result.toolBudgetBlocked && !result.progress?.currentTool
|
|
1994
|
-
&& !result.outputSaveError && (!result.effects?.fileMutation || result.effects.fileMutation.status === "not-applicable"),
|
|
1995
|
-
budget: options.toolBudget ? "tool-budget-configured" : options.usageBudget ? "unknown" : "unconfigured",
|
|
1996
|
-
knownContextOverflow: Boolean(result.contextOverflow || isContextOverflow(result.error)),
|
|
1997
|
-
});
|
|
1998
|
-
if (continuation.kind === "continue") {
|
|
1999
|
-
recoveryState = continuation.recoveryState; // consume BEFORE any sibling creation
|
|
2000
|
-
readonlyExpected = continuation.expected;
|
|
2001
|
-
readonlySource = source;
|
|
2002
|
-
readonlyModel = resolvedCandidates[continuation.candidateIndex]?.fullId;
|
|
2003
|
-
nextAttemptTask = continuation.prompt;
|
|
2004
|
-
attemptNotes.push(`[readonly-continuation] ${attempt.model} failed with HTTP 429 after read-only progress; continuing retained session once with ${readonlyModel}.`);
|
|
2005
|
-
modelIndex = continuation.candidateIndex - 1;
|
|
2006
|
-
continue modelAttemptsLoop;
|
|
2007
|
-
}
|
|
2008
|
-
if (!attemptSucceeded) {
|
|
2009
|
-
const afterCompactionSettlement = (result as AbortRecoverySingleResult)[AFTER_COMPACTION_SETTLEMENT];
|
|
2010
|
-
const abortRecovery = planAbortRecovery({
|
|
2011
|
-
messages: result.messages ?? [],
|
|
2012
|
-
error: result.error,
|
|
2013
|
-
processSignal: result.processSignal,
|
|
2014
|
-
sessionAvailable: Boolean(options.sessionFile && existsSync(options.sessionFile)),
|
|
2015
|
-
alreadyResumed: recoveryState !== "unused",
|
|
2016
|
-
stopped: result.stopped || result.detached || options.signal?.aborted,
|
|
2017
|
-
interrupted: result.interrupted || intercomDetached || options.interruptSignal?.aborted,
|
|
2018
|
-
timedOut: result.timedOut,
|
|
2019
|
-
toolBudgetExhausted: result.toolBudgetBlocked,
|
|
2020
|
-
usageBudgetExhausted: false,
|
|
2021
|
-
structuredOutputFailed: result.structuredOutputFailed,
|
|
2022
|
-
acceptanceFailed: false,
|
|
2023
|
-
currentTool: result.progress?.currentTool,
|
|
2024
|
-
afterCompactionSettlement,
|
|
2025
|
-
});
|
|
2026
|
-
if (abortRecovery.action === "resume") {
|
|
2027
|
-
recoveryState = "abort-recovery";
|
|
2028
|
-
nextAttemptTask = abortRecovery.prompt;
|
|
2029
|
-
attemptNotes.push("[abort-recovery] provider/transport abort after useful progress; resuming the retained child session once.");
|
|
2030
|
-
continue;
|
|
2031
|
-
}
|
|
2032
|
-
if (abortRecovery.diagnostic) {
|
|
2033
|
-
result.error = result.error ? `${result.error}\n${abortRecovery.diagnostic}` : abortRecovery.diagnostic;
|
|
2034
|
-
attempt.error = result.error;
|
|
2035
|
-
break modelAttemptsLoop;
|
|
2036
|
-
}
|
|
2037
|
-
}
|
|
2038
|
-
if (recoveringAbort && !attemptSucceeded) break modelAttemptsLoop;
|
|
2039
|
-
if (options.workflowChildPermitLaunch && !attemptSucceeded) break modelAttemptsLoop;
|
|
2040
|
-
// Preserve the legacy intercom handoff contract: once this logical run has
|
|
2041
|
-
// been handed to a supervisor, terminating that attempt must not launch a
|
|
2042
|
-
// model fallback. Explicit user detach retains fallback.
|
|
2043
|
-
if (intercomDetached || result.timedOut) break modelAttemptsLoop;
|
|
2044
|
-
if (attemptSucceeded) break modelAttemptsLoop;
|
|
2045
|
-
|
|
2046
|
-
const retryableModelFailure = isRetryableModelFailureAttempt({ error: result.error, messages: result.messages, toolCount: result.progressSummary?.toolCount });
|
|
2047
|
-
if (retryableModelFailure) recordRetryableModelFailure(result.model ?? candidate, result.error);
|
|
2048
|
-
if (isContextOverflow(result.error)) {
|
|
2049
|
-
result.contextOverflow = true;
|
|
2050
|
-
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.`);
|
|
2051
|
-
break modelAttemptsLoop;
|
|
2052
|
-
}
|
|
2053
|
-
if (!retryableModelFailure || modelIndex === modelsToTry.length - 1) break modelAttemptsLoop;
|
|
2054
|
-
attemptNotes.push(formatModelAttemptNote(attempt, modelsToTry[modelIndex + 1]));
|
|
2055
|
-
break;
|
|
1894
|
+
let recoveryPrompt = task;
|
|
1895
|
+
for (let attemptIndex = 0; attemptIndex < 2; attemptIndex++) {
|
|
1896
|
+
const outputSnapshot = captureSingleOutputSnapshot(options.outputPath);
|
|
1897
|
+
const attemptResult = await runSingleAttempt(runtimeCwd, agent, recoveryPrompt, candidate, attemptOptions, {
|
|
1898
|
+
sessionEnabled,
|
|
1899
|
+
systemPrompt,
|
|
1900
|
+
acceptancePrompt,
|
|
1901
|
+
resolvedSkillNames: resolvedSkills.length > 0 ? resolvedSkills.map((skill) => skill.name) : undefined,
|
|
1902
|
+
skillsWarning: missingSkills.length > 0 ? `Skills not found: ${missingSkills.join(", ")}` : undefined,
|
|
1903
|
+
jsonlPath,
|
|
1904
|
+
artifactPaths: artifactPathsResult,
|
|
1905
|
+
transcriptWriter,
|
|
1906
|
+
attemptNotes,
|
|
1907
|
+
outputSnapshot,
|
|
1908
|
+
originalTask: task,
|
|
1909
|
+
orcaProgressTab,
|
|
1910
|
+
launchWarnings,
|
|
1911
|
+
verifyModel,
|
|
1912
|
+
});
|
|
1913
|
+
lastResult = attemptResult;
|
|
1914
|
+
sumUsage(aggregateUsage, attemptResult.usage);
|
|
1915
|
+
totalToolCount += attemptResult.progressSummary?.toolCount ?? 0;
|
|
1916
|
+
totalDurationMs += attemptResult.progressSummary?.durationMs ?? 0;
|
|
1917
|
+
if (attemptResult.exitCode === 0 && !attemptResult.error) break;
|
|
1918
|
+
const recovery = planAbortRecovery({
|
|
1919
|
+
messages: attemptResult.messages ?? [],
|
|
1920
|
+
error: attemptResult.error,
|
|
1921
|
+
processSignal: attemptResult.processSignal,
|
|
1922
|
+
sessionAvailable: Boolean(options.sessionFile && existsSync(options.sessionFile)),
|
|
1923
|
+
alreadyResumed: attemptIndex > 0,
|
|
1924
|
+
stopped: attemptResult.stopped || attemptResult.detached || Boolean(detachedReason) || Boolean(options.workflowChildPermitLaunch) || options.signal?.aborted,
|
|
1925
|
+
interrupted: attemptResult.interrupted || options.interruptSignal?.aborted,
|
|
1926
|
+
timedOut: attemptResult.timedOut,
|
|
1927
|
+
toolBudgetExhausted: attemptResult.toolBudgetBlocked,
|
|
1928
|
+
usageBudgetExhausted: false,
|
|
1929
|
+
structuredOutputFailed: attemptResult.structuredOutputFailed,
|
|
1930
|
+
acceptanceFailed: false,
|
|
1931
|
+
currentTool: attemptResult.progress?.currentTool,
|
|
1932
|
+
afterCompactionSettlement: (attemptResult as AbortRecoverySingleResult)[AFTER_COMPACTION_SETTLEMENT],
|
|
1933
|
+
});
|
|
1934
|
+
if (recovery.action === "resume") {
|
|
1935
|
+
recoveryPrompt = recovery.prompt;
|
|
1936
|
+
attemptNotes.push("[abort-recovery] compaction abort after useful progress; resuming the retained child session once on the same model.");
|
|
1937
|
+
continue;
|
|
1938
|
+
}
|
|
1939
|
+
if (recovery.diagnostic) {
|
|
1940
|
+
attemptResult.error = attemptResult.error ? `${attemptResult.error}\n${recovery.diagnostic}` : recovery.diagnostic;
|
|
2056
1941
|
}
|
|
1942
|
+
break;
|
|
2057
1943
|
}
|
|
1944
|
+
if (!lastResult) throw new Error("Subagent did not produce a result.");
|
|
1945
|
+
if (isContextOverflow(lastResult.error)) lastResult.contextOverflow = true;
|
|
2058
1946
|
|
|
2059
1947
|
const result = withRunContext(lastResult ?? {
|
|
2060
1948
|
index: options.index ?? 0,
|
|
@@ -2068,8 +1956,7 @@ async function runSyncCompletionInner(
|
|
|
2068
1956
|
result.task = task;
|
|
2069
1957
|
|
|
2070
1958
|
result.usage = aggregateUsage;
|
|
2071
|
-
result.
|
|
2072
|
-
result.modelAttempts = modelAttempts.length > 0 ? modelAttempts : undefined;
|
|
1959
|
+
result.requestedModel = requestedModel;
|
|
2073
1960
|
result.progressSummary = {
|
|
2074
1961
|
...(childSessionName ? { sessionName: childSessionName } : {}),
|
|
2075
1962
|
toolCount: totalToolCount,
|
|
@@ -2159,7 +2046,6 @@ async function runSyncCompletionInner(
|
|
|
2159
2046
|
savedPath: result.savedOutputPath,
|
|
2160
2047
|
outputReference: result.outputReference,
|
|
2161
2048
|
}).displayOutput;
|
|
2162
|
-
artifactOutputByResult.set(result, result.finalOutput);
|
|
2163
2049
|
}
|
|
2164
2050
|
result.error = result.error ? `${result.error}\n${acceptanceFailure}` : acceptanceFailure;
|
|
2165
2051
|
if (artifactPathsResult && options.artifactConfig?.enabled !== false && options.artifactConfig?.includeOutput !== false) {
|