pi-subagents 0.56.0 → 0.58.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 +92 -0
- package/agents/claude-code-writer.md +15 -0
- package/agents/claude-code.md +15 -0
- package/agents/codex-exec-writer.md +15 -0
- package/agents/codex-exec.md +15 -0
- package/agents/cursor-agent-writer.md +14 -0
- package/agents/cursor-agent.md +14 -0
- package/docs/agents.md +124 -21
- package/docs/configuration.md +37 -0
- package/docs/extension-api.md +41 -2
- package/docs/models.md +3 -3
- package/docs/observability.md +8 -7
- package/docs/tool-reference.md +14 -3
- package/docs/workflows.md +44 -0
- package/package.json +1 -1
- package/skills/pi-subagents/SKILL.md +2 -0
- package/skills/pi-subagents/references/execution-controls.md +2 -2
- package/skills/pi-subagents/references/management-authoring-rpc.md +1 -0
- package/skills/pi-subagents/references/prompting-and-roles.md +2 -2
- package/src/agents/agent-management.ts +36 -5
- package/src/agents/agent-refinements.ts +4 -4
- package/src/agents/agent-serializer.ts +5 -0
- package/src/agents/agents.ts +257 -51
- package/src/agents/builtin-names.ts +6 -0
- package/src/agents/runtime-agent-events.ts +70 -0
- package/src/agents/runtime-agent-registry.ts +18 -4
- package/src/api/agents.ts +10 -5
- package/src/api/preflight.ts +28 -3
- package/src/extension/config.ts +70 -0
- package/src/extension/doctor.ts +3 -3
- package/src/extension/index.ts +33 -8
- package/src/extension/public-execution.ts +29 -13
- package/src/extension/rpc.ts +55 -19
- package/src/extension/schemas.ts +6 -5
- package/src/extension/tool-description.ts +18 -12
- package/src/inspectors/herdr/actions.ts +2 -1
- package/src/inspectors/herdr/inspector-runner.ts +2 -10
- package/src/inspectors/herdr/session-roots-codec.ts +42 -0
- package/src/integrations/herdr-status.ts +51 -3
- package/src/runs/background/active-async-capacity.ts +77 -10
- package/src/runs/background/async-execution.ts +127 -19
- package/src/runs/background/async-job-tracker.ts +5 -0
- package/src/runs/background/async-resume.ts +6 -2
- package/src/runs/background/async-retention.ts +20 -3
- package/src/runs/background/async-status.ts +7 -0
- package/src/runs/background/chain-append.ts +2 -0
- package/src/runs/background/chain-root-attachment.ts +15 -1
- package/src/runs/background/fleet-view.ts +16 -10
- package/src/runs/background/inspect-rpc.ts +8 -8
- package/src/runs/background/notify.ts +26 -3
- package/src/runs/background/result-delivery-ownership.ts +45 -0
- package/src/runs/background/result-files.ts +27 -14
- package/src/runs/background/result-watcher.ts +36 -15
- package/src/runs/background/run-status.ts +33 -6
- package/src/runs/background/scheduled-runs.ts +7 -1
- package/src/runs/background/subagent-runner.ts +239 -56
- package/src/runs/background/wait-completions.ts +4 -0
- package/src/runs/foreground/execution.ts +92 -11
- package/src/runs/foreground/foreground-control.ts +6 -0
- package/src/runs/foreground/foreground-history.ts +22 -1
- package/src/runs/foreground/subagent-executor.ts +322 -102
- package/src/runs/foreground/workflow-detach-reconcile.ts +144 -18
- package/src/runs/shared/child-protocol.ts +21 -7
- package/src/runs/shared/claude-code-adapter.ts +129 -0
- package/src/runs/shared/codex-exec-adapter.ts +129 -0
- package/src/runs/shared/completion-guard.ts +4 -3
- package/src/runs/shared/cursor-agent-adapter.ts +114 -0
- package/src/runs/shared/dynamic-fanout.ts +3 -3
- package/src/runs/shared/external-cli-contract.ts +167 -0
- package/src/runs/shared/external-cli-preflight.ts +122 -0
- package/src/runs/shared/external-cli-runner.ts +348 -55
- package/src/runs/shared/fast-mode-extension.ts +5 -5
- package/src/runs/shared/launch-cwd.ts +16 -0
- package/src/runs/shared/long-running-guard.ts +2 -1
- package/src/runs/shared/mcp-config-sources.ts +386 -0
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +155 -42
- package/src/runs/shared/model-exclusions.ts +69 -7
- package/src/runs/shared/model-fallback.ts +39 -5
- package/src/runs/shared/mutation-evidence.ts +7 -2
- package/src/runs/shared/nested-events.ts +3 -1
- package/src/runs/shared/nested-render.ts +2 -2
- package/src/runs/shared/parallel-utils.ts +8 -1
- package/src/runs/shared/pi-args.ts +61 -6
- package/src/runs/shared/process-signal.ts +13 -0
- package/src/runs/shared/run-history.ts +21 -1
- package/src/runs/shared/single-output.ts +17 -0
- package/src/runs/shared/subagent-prompt-runtime.ts +85 -9
- package/src/shared/fork-context.ts +21 -0
- package/src/shared/formatters.ts +13 -1
- package/src/shared/launch-contract.ts +4 -0
- package/src/shared/pruned-fork.ts +450 -0
- package/src/shared/session-file-trust.ts +19 -0
- package/src/shared/session-tokens.ts +14 -3
- package/src/shared/settings.ts +10 -2
- package/src/shared/shortcuts.ts +17 -0
- package/src/shared/types.ts +160 -10
- package/src/shared/utils.ts +6 -29
- package/src/shared/workflow-child-permit.ts +116 -0
- package/src/slash/delegation-adapters.ts +0 -1
- package/src/slash/slash-commands.ts +8 -6
- package/src/slash/subagents-admin.ts +3 -0
- package/src/tui/fleet-status.ts +27 -10
- package/src/tui/fleet-transcript.ts +11 -5
- package/src/tui/fleet.ts +28 -13
- package/src/tui/render.ts +55 -21
- package/src/workflows/scripted-workflow.ts +299 -31
- package/src/workflows/workflow-child-summary.ts +117 -0
- package/src/workflows/workflow-receipt.ts +155 -5
|
@@ -3,6 +3,7 @@ import type { ArtifactPaths, SubagentState, WaitCompletion, WaitCompletionChild
|
|
|
3
3
|
import type { AsyncRunSummary } from "./async-status.ts";
|
|
4
4
|
import { readCompletionReplay, writeCompletionReplay } from "./completion-replay.ts";
|
|
5
5
|
import { fallbackResultPayloadPathForSessionRun, resultFilePath, resultPayloadPathForSessionRun } from "./result-files.ts";
|
|
6
|
+
import { parseWorkflowChildSummary } from "../../workflows/workflow-child-summary.ts";
|
|
6
7
|
|
|
7
8
|
function asNonEmptyString(value: unknown): string | undefined {
|
|
8
9
|
return typeof value === "string" && value ? value : undefined;
|
|
@@ -60,6 +61,8 @@ export function toWaitCompletion(data: Record<string, unknown>, runId: string):
|
|
|
60
61
|
const agent = asNonEmptyString(data.agent);
|
|
61
62
|
const mode = asNonEmptyString(data.mode);
|
|
62
63
|
const state = asNonEmptyString(data.state);
|
|
64
|
+
const workflowChildren = parseWorkflowChildSummary(data.workflowChildren);
|
|
65
|
+
if (workflowChildren && workflowChildren.workflowRunId !== runId) throw new Error("workflowChildren.workflowRunId does not match its completion run id.");
|
|
63
66
|
return {
|
|
64
67
|
runId,
|
|
65
68
|
...(agent ? { agent } : {}),
|
|
@@ -67,6 +70,7 @@ export function toWaitCompletion(data: Record<string, unknown>, runId: string):
|
|
|
67
70
|
...(state ? { state } : {}),
|
|
68
71
|
...(typeof data.success === "boolean" ? { success: data.success } : {}),
|
|
69
72
|
...(results && results.length > 0 ? { results } : {}),
|
|
73
|
+
...(workflowChildren ? { workflowChildren } : {}),
|
|
70
74
|
};
|
|
71
75
|
}
|
|
72
76
|
|
|
@@ -6,7 +6,7 @@ import { spawn } from "node:child_process";
|
|
|
6
6
|
import { existsSync, unlinkSync } from "node:fs";
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import type { Message } from "@earendil-works/pi-ai";
|
|
9
|
-
import type
|
|
9
|
+
import { discoverAgents, formatUnknownAgentError, unknownAgentDiagnosticContext, type AgentConfig } from "../../agents/agents.ts";
|
|
10
10
|
import { appendAgentRefinementOverlay } from "../../agents/agent-refinements.ts";
|
|
11
11
|
import { alignForkedSessionCwd } from "../../shared/fork-context.ts";
|
|
12
12
|
import {
|
|
@@ -58,6 +58,7 @@ import { effectiveToolTimeoutMs, formatToolTimeoutMessage, resolveToolTimeoutMs,
|
|
|
58
58
|
import { evaluateCompletionMutationGuard, validateImplementationToolContract } from "../shared/completion-guard.ts";
|
|
59
59
|
import { arbitrateCompletionGuardRescue } from "../shared/llm-intent-arbiter.ts";
|
|
60
60
|
import { getPiSpawnCommand } from "../shared/pi-spawn.ts";
|
|
61
|
+
import { preflightLaunchCwd } from "../shared/launch-cwd.ts";
|
|
61
62
|
import { createJsonlWriter } from "../../shared/jsonl-writer.ts";
|
|
62
63
|
import { createOrcaProgressTab, type OrcaProgressTab } from "../shared/orca-progress-tabs.ts";
|
|
63
64
|
import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
|
|
@@ -68,7 +69,7 @@ import { assertAgentAllowedByCapabilityCeiling, decodeSubagentCapabilityCeiling,
|
|
|
68
69
|
import { resolveEffectiveThinking } from "../../shared/model-info.ts";
|
|
69
70
|
import { assertThinkingWithinCeiling, decodeThinkingCeiling, intersectThinkingCeilings, SUBAGENT_THINKING_CEILING_ENV } from "../../shared/thinking-ceiling.ts";
|
|
70
71
|
import { MISSING_STRUCTURED_OUTPUT_CALL_ERROR, readStructuredOutput, readStructuredOutputAcceptanceReport } from "../shared/structured-output.ts";
|
|
71
|
-
import { formatProcessSignalError, isUnexplainedProcessSignal } from "../shared/process-signal.ts";
|
|
72
|
+
import { formatMidToolExitError, formatProcessSignalError, isOrdinaryToolForMidToolExit, isUnexplainedProcessSignal } from "../shared/process-signal.ts";
|
|
72
73
|
import { readChildToolDiagnosticError } from "../shared/tool-availability.ts";
|
|
73
74
|
import { buildTimeoutRecoverySummary, collectTrackedMutationEvidence, snapshotTrackedMutations } from "../shared/mutation-evidence.ts";
|
|
74
75
|
import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, injectOutputPathSystemPrompt, resolveSingleOutput, validateFileOnlyOutputMode, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
@@ -77,7 +78,7 @@ import {
|
|
|
77
78
|
formatSubagentModelVerificationError,
|
|
78
79
|
formatModelAttemptNote,
|
|
79
80
|
isContextOverflow,
|
|
80
|
-
|
|
81
|
+
isRetryableModelFailureAttempt,
|
|
81
82
|
recordRetryableModelFailure,
|
|
82
83
|
} from "../shared/model-fallback.ts";
|
|
83
84
|
import {
|
|
@@ -106,7 +107,8 @@ import { appendTurnBudgetSystemPrompt, formatTurnBudgetOutput, initialTurnBudget
|
|
|
106
107
|
import { initialToolBudgetState, toolBudgetState } from "../shared/tool-budget.ts";
|
|
107
108
|
import { resolveWatchdogConfig } from "../../watchdog/settings.ts";
|
|
108
109
|
import { agentDefinitionDigest, launchBindingDigest } from "../../shared/launch-contract.ts";
|
|
109
|
-
import {
|
|
110
|
+
import { consumeWorkflowChildPermit } from "../../shared/workflow-child-permit.ts";
|
|
111
|
+
import { createBoundedByteTail, createBoundedLineReader, formatProtocolOutputLimit, MAX_CHILD_STDERR_BYTES, PI_AGGREGATE_EVENT_PROJECTOR, projectChildLifecycle, type ChildLifecycleAction, type ChildLifecycleState, type ProtocolOutputLimit } from "../shared/child-protocol.ts";
|
|
110
112
|
import {
|
|
111
113
|
acceptChildWatchdogEvent,
|
|
112
114
|
childWatchdogIsActive,
|
|
@@ -345,6 +347,7 @@ async function runSingleAttempt(
|
|
|
345
347
|
thinking: effectiveThinking,
|
|
346
348
|
systemPromptMode: agent.systemPromptMode,
|
|
347
349
|
inheritProjectContext: agent.inheritProjectContext,
|
|
350
|
+
inheritGlobalContext: agent.inheritGlobalContext,
|
|
348
351
|
inheritSkills: agent.inheritSkills,
|
|
349
352
|
requireReadTool: Boolean(shared.resolvedSkillNames?.length),
|
|
350
353
|
tools: agent.tools,
|
|
@@ -380,6 +383,7 @@ async function runSingleAttempt(
|
|
|
380
383
|
capabilityCeiling: options.capabilityCeiling,
|
|
381
384
|
thinkingCeiling: options.thinkingCeiling,
|
|
382
385
|
extensionBindings: options.extensionBindings,
|
|
386
|
+
runtimeSnapshotHost: options.runtimeSnapshotHost,
|
|
383
387
|
});
|
|
384
388
|
if (!shared.launchWarnings.emitted && warnings.length > 0) {
|
|
385
389
|
for (const warning of warnings) console.warn(`[pi-subagents] ${warning}`);
|
|
@@ -402,6 +406,7 @@ async function runSingleAttempt(
|
|
|
402
406
|
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
403
407
|
agentName: agent.name,
|
|
404
408
|
permissionRules,
|
|
409
|
+
runtimeSnapshotHost: options.runtimeSnapshotHost,
|
|
405
410
|
});
|
|
406
411
|
const contractTools = toolPlan.explicitToolAllowlist ? toolPlan.effectiveToolAllowlist : undefined;
|
|
407
412
|
const contractError = validateImplementationToolContract({
|
|
@@ -445,6 +450,7 @@ async function runSingleAttempt(
|
|
|
445
450
|
systemPrompt: effectiveSystemPrompt,
|
|
446
451
|
systemPromptMode: agent.systemPromptMode,
|
|
447
452
|
inheritProjectContext: agent.inheritProjectContext,
|
|
453
|
+
inheritGlobalContext: agent.inheritGlobalContext,
|
|
448
454
|
inheritSkills: agent.inheritSkills,
|
|
449
455
|
skills: shared.resolvedSkillNames ?? [],
|
|
450
456
|
tools: toolPlan.effectiveToolAllowlist,
|
|
@@ -538,9 +544,29 @@ async function runSingleAttempt(
|
|
|
538
544
|
let structuredOutputToolInvoked = false;
|
|
539
545
|
let structuredOutputMessageStartIndex: number | undefined;
|
|
540
546
|
let toolAvailabilityError: string | undefined;
|
|
547
|
+
let abortedBySignal = options.signal?.aborted === true;
|
|
541
548
|
|
|
549
|
+
const spawnSpec = getPiSpawnCommand(args);
|
|
550
|
+
if (options.workflowChildPermitLaunch) {
|
|
551
|
+
const permitError = consumeWorkflowChildPermit(options.workflowChildPermitLaunch.permit, {
|
|
552
|
+
workflowRunId: options.workflowChildPermitLaunch.workflowRunId,
|
|
553
|
+
childKey: options.workflowChildPermitLaunch.childKey,
|
|
554
|
+
agent: agent.name,
|
|
555
|
+
launchContractDigest,
|
|
556
|
+
context: options.context ?? "fresh",
|
|
557
|
+
runner: "pi",
|
|
558
|
+
});
|
|
559
|
+
if (permitError) {
|
|
560
|
+
cleanupTempDir(tempDir);
|
|
561
|
+
result.exitCode = 1;
|
|
562
|
+
result.error = permitError;
|
|
563
|
+
result.finalOutput = permitError;
|
|
564
|
+
progress.status = "failed";
|
|
565
|
+
progress.error = permitError;
|
|
566
|
+
return result;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
542
569
|
const exitCode = await new Promise<number>((resolve) => {
|
|
543
|
-
const spawnSpec = getPiSpawnCommand(args);
|
|
544
570
|
const proc = spawn(spawnSpec.command, spawnSpec.args, {
|
|
545
571
|
cwd: options.cwd ?? runtimeCwd,
|
|
546
572
|
env: spawnEnv,
|
|
@@ -707,6 +733,7 @@ async function runSingleAttempt(
|
|
|
707
733
|
}
|
|
708
734
|
if (action === "start-drain") startFinalDrain();
|
|
709
735
|
};
|
|
736
|
+
const childLifecycleState: ChildLifecycleState = { compactionRetryActive: false };
|
|
710
737
|
|
|
711
738
|
const unsubscribeIntercomDetach = options.intercomEvents?.on?.(INTERCOM_DETACH_REQUEST_EVENT, (payload) => {
|
|
712
739
|
if (!options.allowIntercomDetach || processClosed) return;
|
|
@@ -994,8 +1021,9 @@ async function runSingleAttempt(
|
|
|
994
1021
|
}
|
|
995
1022
|
shared.transcriptWriter?.writeChildEvent(evt);
|
|
996
1023
|
shared.orcaProgressTab?.event(evt);
|
|
997
|
-
|
|
998
|
-
|
|
1024
|
+
const lifecycleAction = projectChildLifecycle(evt, false, childLifecycleState);
|
|
1025
|
+
if (evt.type === "agent_settled" && lifecycleAction === "start-drain") agentSettledReceived = true;
|
|
1026
|
+
applyChildLifecycle(lifecycleAction);
|
|
999
1027
|
|
|
1000
1028
|
if (isChildWatchdogStatusEvent(evt)) {
|
|
1001
1029
|
if (!childWatchdog) return;
|
|
@@ -1041,7 +1069,7 @@ async function runSingleAttempt(
|
|
|
1041
1069
|
if (options.toolBudget) {
|
|
1042
1070
|
result.toolBudget = toolBudgetState(options.toolBudget, progress.toolCount);
|
|
1043
1071
|
}
|
|
1044
|
-
const mutates = isMutatingTool(evt.toolName, toolArgs);
|
|
1072
|
+
const mutates = isMutatingTool(evt.toolName, toolArgs, agent.mutationTools);
|
|
1045
1073
|
observedMutationAttempt = observedMutationAttempt || mutates;
|
|
1046
1074
|
pendingToolResult = { tool: evt.toolName ?? "tool", path: activeTool?.path, mutates, startedAt: now };
|
|
1047
1075
|
fireUpdate();
|
|
@@ -1078,6 +1106,7 @@ async function runSingleAttempt(
|
|
|
1078
1106
|
updateTurnBudget(result.usage.turns, terminalAssistantStop || terminalStructuredOutputCall, hasToolCall || Boolean(progress.currentTool));
|
|
1079
1107
|
const u = evt.message.usage;
|
|
1080
1108
|
if (u) {
|
|
1109
|
+
const window = (u.input || 0) + (u.cacheRead || 0);
|
|
1081
1110
|
result.usage.input += u.input || 0;
|
|
1082
1111
|
result.usage.output += u.output || 0;
|
|
1083
1112
|
result.usage.cacheRead += u.cacheRead || 0;
|
|
@@ -1086,6 +1115,8 @@ async function runSingleAttempt(
|
|
|
1086
1115
|
progress.tokens = result.usage.input + result.usage.output;
|
|
1087
1116
|
progress.inputTokens = result.usage.input;
|
|
1088
1117
|
progress.outputTokens = result.usage.output;
|
|
1118
|
+
progress.window = window;
|
|
1119
|
+
progress.windowPeak = Math.max(progress.windowPeak ?? 0, window);
|
|
1089
1120
|
}
|
|
1090
1121
|
if (evt.message.model) {
|
|
1091
1122
|
progress.model = evt.message.model;
|
|
@@ -1102,7 +1133,11 @@ async function runSingleAttempt(
|
|
|
1102
1133
|
if (terminalAssistantStop) {
|
|
1103
1134
|
if (!evt.message.errorMessage && assistantText.trim()) assistantError = undefined;
|
|
1104
1135
|
cleanTerminalAssistantStopReceived ||= !evt.message.errorMessage;
|
|
1105
|
-
|
|
1136
|
+
clearAllToolTimeouts();
|
|
1137
|
+
activeToolCalls.clear();
|
|
1138
|
+
activeToolKeysByName.clear();
|
|
1139
|
+
refreshCurrentTool();
|
|
1140
|
+
applyChildLifecycle(projectChildLifecycle(evt, true, childLifecycleState));
|
|
1106
1141
|
}
|
|
1107
1142
|
}
|
|
1108
1143
|
updateActivityState(now);
|
|
@@ -1369,6 +1404,7 @@ async function runSingleAttempt(
|
|
|
1369
1404
|
if (options.signal) {
|
|
1370
1405
|
const kill = () => {
|
|
1371
1406
|
if (processClosed || lifecycleFinished) return;
|
|
1407
|
+
abortedBySignal = true;
|
|
1372
1408
|
proc.kill("SIGTERM");
|
|
1373
1409
|
setTimeout(() => !proc.killed && proc.kill("SIGKILL"), 3000);
|
|
1374
1410
|
};
|
|
@@ -1431,6 +1467,22 @@ async function runSingleAttempt(
|
|
|
1431
1467
|
};
|
|
1432
1468
|
return result;
|
|
1433
1469
|
}
|
|
1470
|
+
if (progress.currentTool
|
|
1471
|
+
&& isOrdinaryToolForMidToolExit(progress.currentTool)
|
|
1472
|
+
&& !abortedBySignal
|
|
1473
|
+
&& !result.timedOut
|
|
1474
|
+
&& !result.stopped
|
|
1475
|
+
&& !result.turnBudgetExceeded
|
|
1476
|
+
&& !result.protocolError
|
|
1477
|
+
&& !toolAvailabilityError) {
|
|
1478
|
+
const processExitCode = result.exitCode;
|
|
1479
|
+
result.exitCode = 1;
|
|
1480
|
+
result.error = formatMidToolExitError({
|
|
1481
|
+
toolName: progress.currentTool,
|
|
1482
|
+
exitCode: processExitCode,
|
|
1483
|
+
processSignal: result.processSignal,
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1434
1486
|
result.error = formatSubagentExtensionConflictError(result.error, {
|
|
1435
1487
|
agent: agent.name,
|
|
1436
1488
|
ambientExtensionsEnabled: !launchResolvedExtensions.disableAmbientExtensions,
|
|
@@ -1536,6 +1588,7 @@ async function runSingleAttempt(
|
|
|
1536
1588
|
messages: result.messages ?? [],
|
|
1537
1589
|
tools: contractTools,
|
|
1538
1590
|
mcpDirectTools: toolPlan.effectiveMcpTools,
|
|
1591
|
+
mutationTools: agent.mutationTools,
|
|
1539
1592
|
toolAvailabilityError,
|
|
1540
1593
|
mutationEvidence,
|
|
1541
1594
|
})
|
|
@@ -1641,12 +1694,27 @@ async function runSyncCompletionInner(
|
|
|
1641
1694
|
task: string,
|
|
1642
1695
|
options: RunSyncOptions,
|
|
1643
1696
|
): Promise<SingleResult> {
|
|
1697
|
+
const effectiveCwd = options.cwd ?? runtimeCwd;
|
|
1698
|
+
const cwdError = preflightLaunchCwd(options.requestedCwd ?? effectiveCwd, effectiveCwd);
|
|
1699
|
+
if (cwdError) {
|
|
1700
|
+
return redactResultPrompt(withRunContext({
|
|
1701
|
+
index: options.index ?? 0,
|
|
1702
|
+
agent: agentName,
|
|
1703
|
+
task,
|
|
1704
|
+
exitCode: 1,
|
|
1705
|
+
messages: [],
|
|
1706
|
+
usage: emptyUsage(),
|
|
1707
|
+
error: cwdError,
|
|
1708
|
+
}, options.context));
|
|
1709
|
+
}
|
|
1644
1710
|
options = {
|
|
1645
1711
|
...options,
|
|
1646
1712
|
capabilityCeiling: intersectSubagentCapabilityCeilings(options.capabilityCeiling ?? resolveCurrentSubagentCapabilityCeiling(options.parentSessionId), decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV])),
|
|
1647
1713
|
};
|
|
1648
1714
|
const agent = agents.find((a) => a.name === agentName);
|
|
1649
1715
|
if (!agent) {
|
|
1716
|
+
const diagnosticContext = options.unknownAgentDiagnosticContext
|
|
1717
|
+
?? unknownAgentDiagnosticContext(discoverAgents(path.resolve(options.cwd ?? runtimeCwd), "both"));
|
|
1650
1718
|
return redactResultPrompt(withRunContext({
|
|
1651
1719
|
index: options.index ?? 0,
|
|
1652
1720
|
agent: agentName,
|
|
@@ -1654,7 +1722,7 @@ async function runSyncCompletionInner(
|
|
|
1654
1722
|
exitCode: 1,
|
|
1655
1723
|
messages: [],
|
|
1656
1724
|
usage: emptyUsage(),
|
|
1657
|
-
error:
|
|
1725
|
+
error: formatUnknownAgentError(agentName, diagnosticContext),
|
|
1658
1726
|
}, options.context));
|
|
1659
1727
|
}
|
|
1660
1728
|
options = {
|
|
@@ -1781,6 +1849,18 @@ async function runSyncCompletionInner(
|
|
|
1781
1849
|
agent.modelProvider ?? options.preferredModelProvider,
|
|
1782
1850
|
{ scope: options.modelScope, primaryModelFromParent: options.modelOverrideFromParent },
|
|
1783
1851
|
);
|
|
1852
|
+
if (options.workflowChildPermitLaunch && candidates.length > 1) {
|
|
1853
|
+
const error = "Workflow child permit does not support model fallback.";
|
|
1854
|
+
return redactResultPrompt(withRunContext({
|
|
1855
|
+
index: options.index ?? 0,
|
|
1856
|
+
agent: agent.name,
|
|
1857
|
+
task,
|
|
1858
|
+
exitCode: 1,
|
|
1859
|
+
messages: [],
|
|
1860
|
+
usage: emptyUsage(),
|
|
1861
|
+
error,
|
|
1862
|
+
}, options.context));
|
|
1863
|
+
}
|
|
1784
1864
|
try {
|
|
1785
1865
|
for (const candidate of candidates) {
|
|
1786
1866
|
const model = applyThinkingSuffix(candidate, options.thinkingOverride ?? agent.thinking, options.thinkingOverride !== undefined);
|
|
@@ -1914,6 +1994,7 @@ async function runSyncCompletionInner(
|
|
|
1914
1994
|
usage: { ...result.usage },
|
|
1915
1995
|
};
|
|
1916
1996
|
modelAttempts.push(attempt);
|
|
1997
|
+
if (options.workflowChildPermitLaunch && !attemptSucceeded) break modelAttemptsLoop;
|
|
1917
1998
|
// Preserve the legacy intercom handoff contract: once this logical run has
|
|
1918
1999
|
// been handed to a supervisor, terminating that attempt must not launch a
|
|
1919
2000
|
// startup retry or model fallback. Explicit user detach retains fallback.
|
|
@@ -1986,7 +2067,7 @@ async function runSyncCompletionInner(
|
|
|
1986
2067
|
attempt.error = startupError;
|
|
1987
2068
|
break modelAttemptsLoop;
|
|
1988
2069
|
}
|
|
1989
|
-
const retryableModelFailure =
|
|
2070
|
+
const retryableModelFailure = isRetryableModelFailureAttempt({ error: result.error, messages: result.messages, toolCount: result.progressSummary?.toolCount });
|
|
1990
2071
|
if (retryableModelFailure) recordRetryableModelFailure(result.model ?? candidate, result.error);
|
|
1991
2072
|
if (isContextOverflow(result.error)) {
|
|
1992
2073
|
result.contextOverflow = true;
|
|
@@ -27,6 +27,8 @@ function copyProgress(target: ForegroundChildControl, progress: AgentProgress |
|
|
|
27
27
|
target.tokens = progress.tokens;
|
|
28
28
|
target.inputTokens = progress.inputTokens;
|
|
29
29
|
target.outputTokens = progress.outputTokens;
|
|
30
|
+
target.window = progress.window;
|
|
31
|
+
target.windowPeak = progress.windowPeak;
|
|
30
32
|
target.model = progress.model;
|
|
31
33
|
target.thinking = progress.thinking;
|
|
32
34
|
target.toolCount = progress.toolCount;
|
|
@@ -45,6 +47,8 @@ function syncCurrentChild(control: ForegroundRunControl, child: ForegroundChildC
|
|
|
45
47
|
control.tokens = child.tokens;
|
|
46
48
|
control.inputTokens = child.inputTokens;
|
|
47
49
|
control.outputTokens = child.outputTokens;
|
|
50
|
+
control.window = child.window;
|
|
51
|
+
control.windowPeak = child.windowPeak;
|
|
48
52
|
control.model = child.model;
|
|
49
53
|
control.thinking = child.thinking;
|
|
50
54
|
control.toolCount = child.toolCount;
|
|
@@ -65,6 +69,8 @@ function clearCurrentChild(control: ForegroundRunControl): void {
|
|
|
65
69
|
control.tokens = undefined;
|
|
66
70
|
control.inputTokens = undefined;
|
|
67
71
|
control.outputTokens = undefined;
|
|
72
|
+
control.window = undefined;
|
|
73
|
+
control.windowPeak = undefined;
|
|
68
74
|
control.model = undefined;
|
|
69
75
|
control.thinking = undefined;
|
|
70
76
|
control.toolCount = undefined;
|
|
@@ -4,10 +4,12 @@ import type { ForegroundResumeChild, ForegroundResumeRun, SubagentState } from "
|
|
|
4
4
|
import { DIRS } from "../../shared/types.ts";
|
|
5
5
|
import { writePrivateAtomicJson } from "../../shared/atomic-json.ts";
|
|
6
6
|
import { utf8Tail } from "../../shared/utf8.ts";
|
|
7
|
+
import { validateAcceptanceInput } from "../shared/acceptance.ts";
|
|
7
8
|
|
|
8
9
|
export const MAX_REMEMBERED_FOREGROUND_RUNS = 50;
|
|
9
10
|
const HISTORY_VERSION = 1;
|
|
10
11
|
const MAX_INLINE_OUTPUT_BYTES = 64 * 1024;
|
|
12
|
+
const MAX_RESUME_CONTRACT_BYTES = 64 * 1024;
|
|
11
13
|
|
|
12
14
|
interface ForegroundHistoryIndex {
|
|
13
15
|
version: 1;
|
|
@@ -51,6 +53,7 @@ function compactChild(child: ForegroundResumeChild): ForegroundResumeChild {
|
|
|
51
53
|
...(child.transcriptPath ? { transcriptPath: child.transcriptPath } : {}),
|
|
52
54
|
...(child.transcriptError ? { transcriptError: child.transcriptError } : {}),
|
|
53
55
|
...(child.acceptance ? { acceptance: child.acceptance } : {}),
|
|
56
|
+
...(child.resumeContract ? { resumeContract: child.resumeContract } : {}),
|
|
54
57
|
...(child.launchContractDigest ? { launchContractDigest: child.launchContractDigest } : {}),
|
|
55
58
|
...(child.extensionBindings ? { extensionBindings: child.extensionBindings } : {}),
|
|
56
59
|
...(child.capabilityCeiling ? { capabilityCeiling: child.capabilityCeiling } : {}),
|
|
@@ -62,9 +65,26 @@ function isRestorableForegroundStatus(status: unknown): status is ForegroundResu
|
|
|
62
65
|
return status === "completed" || status === "failed" || status === "paused" || status === "stopped";
|
|
63
66
|
}
|
|
64
67
|
|
|
68
|
+
function isRestorableResumeContract(value: unknown): boolean {
|
|
69
|
+
if (value === undefined) return true;
|
|
70
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
71
|
+
try {
|
|
72
|
+
if (Buffer.byteLength(JSON.stringify(value), "utf8") > MAX_RESUME_CONTRACT_BYTES) return false;
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const contract = value as NonNullable<ForegroundResumeChild["resumeContract"]>;
|
|
77
|
+
if (Object.keys(contract).some((key) => !["outputSchema", "agentContract", "acceptance", "output", "outputMode"].includes(key))) return false;
|
|
78
|
+
if (contract.outputSchema !== undefined && (!contract.outputSchema || typeof contract.outputSchema !== "object" || Array.isArray(contract.outputSchema))) return false;
|
|
79
|
+
if (contract.agentContract !== undefined && (!contract.agentContract || typeof contract.agentContract !== "object" || Array.isArray(contract.agentContract) || contract.agentContract.version !== 1)) return false;
|
|
80
|
+
if (validateAcceptanceInput(contract.acceptance).length > 0) return false;
|
|
81
|
+
if (contract.output !== undefined && typeof contract.output !== "string" && typeof contract.output !== "boolean") return false;
|
|
82
|
+
return contract.outputMode === undefined || contract.outputMode === "inline" || contract.outputMode === "file-only";
|
|
83
|
+
}
|
|
84
|
+
|
|
65
85
|
function compactRun(run: ForegroundResumeRun): ForegroundResumeRun | undefined {
|
|
66
86
|
if (!run.sessionId) return undefined;
|
|
67
|
-
if (run.children.length === 0 || !run.children.every((child) => isRestorableForegroundStatus(child.status))) return undefined;
|
|
87
|
+
if (run.children.length === 0 || !run.children.every((child) => isRestorableForegroundStatus(child.status) && isRestorableResumeContract(child.resumeContract))) return undefined;
|
|
68
88
|
return {
|
|
69
89
|
runId: run.runId,
|
|
70
90
|
mode: run.mode,
|
|
@@ -102,6 +122,7 @@ function isRestorableRun(value: unknown): value is ForegroundResumeRun {
|
|
|
102
122
|
&& run.children.every((child) => Boolean(child && typeof child === "object" && !Array.isArray(child)
|
|
103
123
|
&& typeof (child as Partial<ForegroundResumeChild>).agent === "string"
|
|
104
124
|
&& typeof (child as Partial<ForegroundResumeChild>).index === "number"
|
|
125
|
+
&& isRestorableResumeContract((child as Partial<ForegroundResumeChild>).resumeContract)
|
|
105
126
|
&& isRestorableForegroundStatus((child as Partial<ForegroundResumeChild>).status)));
|
|
106
127
|
}
|
|
107
128
|
|