pi-subagents 0.56.0 → 0.57.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 +53 -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 +111 -15
- package/docs/configuration.md +37 -0
- package/docs/extension-api.md +2 -2
- package/docs/observability.md +8 -7
- package/docs/tool-reference.md +11 -1
- package/docs/workflows.md +20 -0
- package/package.json +1 -1
- package/skills/pi-subagents/references/execution-controls.md +1 -1
- package/src/agents/agent-management.ts +13 -5
- package/src/agents/agent-refinements.ts +4 -4
- package/src/agents/agents.ts +219 -48
- package/src/agents/builtin-names.ts +6 -0
- package/src/agents/runtime-agent-registry.ts +8 -2
- package/src/api/preflight.ts +2 -2
- package/src/extension/config.ts +70 -0
- package/src/extension/doctor.ts +3 -3
- package/src/extension/index.ts +18 -4
- package/src/extension/public-execution.ts +29 -13
- package/src/extension/rpc.ts +20 -5
- package/src/extension/schemas.ts +4 -3
- package/src/extension/tool-description.ts +11 -9
- 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 +46 -3
- package/src/runs/background/active-async-capacity.ts +77 -10
- package/src/runs/background/async-execution.ts +100 -9
- package/src/runs/background/async-job-tracker.ts +5 -0
- package/src/runs/background/async-retention.ts +20 -3
- package/src/runs/background/async-status.ts +5 -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/result-files.ts +27 -14
- package/src/runs/background/result-watcher.ts +9 -5
- 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 +177 -44
- package/src/runs/background/wait-completions.ts +4 -0
- package/src/runs/foreground/execution.ts +72 -10
- 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 +270 -81
- package/src/runs/foreground/workflow-detach-reconcile.ts +16 -1
- 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/cursor-agent-adapter.ts +114 -0
- 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/model-exclusions.ts +57 -7
- package/src/runs/shared/model-fallback.ts +23 -1
- 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/process-signal.ts +13 -0
- package/src/runs/shared/run-history.ts +21 -1
- package/src/shared/fork-context.ts +21 -0
- package/src/shared/formatters.ts +7 -1
- 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 +118 -9
- 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/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 +47 -21
- package/src/workflows/scripted-workflow.ts +248 -27
- package/src/workflows/workflow-child-summary.ts +117 -0
- package/src/workflows/workflow-receipt.ts +119 -4
|
@@ -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 {
|
|
@@ -68,7 +68,7 @@ import { assertAgentAllowedByCapabilityCeiling, decodeSubagentCapabilityCeiling,
|
|
|
68
68
|
import { resolveEffectiveThinking } from "../../shared/model-info.ts";
|
|
69
69
|
import { assertThinkingWithinCeiling, decodeThinkingCeiling, intersectThinkingCeilings, SUBAGENT_THINKING_CEILING_ENV } from "../../shared/thinking-ceiling.ts";
|
|
70
70
|
import { MISSING_STRUCTURED_OUTPUT_CALL_ERROR, readStructuredOutput, readStructuredOutputAcceptanceReport } from "../shared/structured-output.ts";
|
|
71
|
-
import { formatProcessSignalError, isUnexplainedProcessSignal } from "../shared/process-signal.ts";
|
|
71
|
+
import { formatMidToolExitError, formatProcessSignalError, isOrdinaryToolForMidToolExit, isUnexplainedProcessSignal } from "../shared/process-signal.ts";
|
|
72
72
|
import { readChildToolDiagnosticError } from "../shared/tool-availability.ts";
|
|
73
73
|
import { buildTimeoutRecoverySummary, collectTrackedMutationEvidence, snapshotTrackedMutations } from "../shared/mutation-evidence.ts";
|
|
74
74
|
import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, injectOutputPathSystemPrompt, resolveSingleOutput, validateFileOnlyOutputMode, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
@@ -77,7 +77,7 @@ import {
|
|
|
77
77
|
formatSubagentModelVerificationError,
|
|
78
78
|
formatModelAttemptNote,
|
|
79
79
|
isContextOverflow,
|
|
80
|
-
|
|
80
|
+
isRetryableModelFailureAttempt,
|
|
81
81
|
recordRetryableModelFailure,
|
|
82
82
|
} from "../shared/model-fallback.ts";
|
|
83
83
|
import {
|
|
@@ -106,7 +106,8 @@ import { appendTurnBudgetSystemPrompt, formatTurnBudgetOutput, initialTurnBudget
|
|
|
106
106
|
import { initialToolBudgetState, toolBudgetState } from "../shared/tool-budget.ts";
|
|
107
107
|
import { resolveWatchdogConfig } from "../../watchdog/settings.ts";
|
|
108
108
|
import { agentDefinitionDigest, launchBindingDigest } from "../../shared/launch-contract.ts";
|
|
109
|
-
import {
|
|
109
|
+
import { consumeWorkflowChildPermit } from "../../shared/workflow-child-permit.ts";
|
|
110
|
+
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
111
|
import {
|
|
111
112
|
acceptChildWatchdogEvent,
|
|
112
113
|
childWatchdogIsActive,
|
|
@@ -538,9 +539,29 @@ async function runSingleAttempt(
|
|
|
538
539
|
let structuredOutputToolInvoked = false;
|
|
539
540
|
let structuredOutputMessageStartIndex: number | undefined;
|
|
540
541
|
let toolAvailabilityError: string | undefined;
|
|
542
|
+
let abortedBySignal = options.signal?.aborted === true;
|
|
541
543
|
|
|
544
|
+
const spawnSpec = getPiSpawnCommand(args);
|
|
545
|
+
if (options.workflowChildPermitLaunch) {
|
|
546
|
+
const permitError = consumeWorkflowChildPermit(options.workflowChildPermitLaunch.permit, {
|
|
547
|
+
workflowRunId: options.workflowChildPermitLaunch.workflowRunId,
|
|
548
|
+
childKey: options.workflowChildPermitLaunch.childKey,
|
|
549
|
+
agent: agent.name,
|
|
550
|
+
launchContractDigest,
|
|
551
|
+
context: options.context ?? "fresh",
|
|
552
|
+
runner: "pi",
|
|
553
|
+
});
|
|
554
|
+
if (permitError) {
|
|
555
|
+
cleanupTempDir(tempDir);
|
|
556
|
+
result.exitCode = 1;
|
|
557
|
+
result.error = permitError;
|
|
558
|
+
result.finalOutput = permitError;
|
|
559
|
+
progress.status = "failed";
|
|
560
|
+
progress.error = permitError;
|
|
561
|
+
return result;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
542
564
|
const exitCode = await new Promise<number>((resolve) => {
|
|
543
|
-
const spawnSpec = getPiSpawnCommand(args);
|
|
544
565
|
const proc = spawn(spawnSpec.command, spawnSpec.args, {
|
|
545
566
|
cwd: options.cwd ?? runtimeCwd,
|
|
546
567
|
env: spawnEnv,
|
|
@@ -707,6 +728,7 @@ async function runSingleAttempt(
|
|
|
707
728
|
}
|
|
708
729
|
if (action === "start-drain") startFinalDrain();
|
|
709
730
|
};
|
|
731
|
+
const childLifecycleState: ChildLifecycleState = { compactionRetryActive: false };
|
|
710
732
|
|
|
711
733
|
const unsubscribeIntercomDetach = options.intercomEvents?.on?.(INTERCOM_DETACH_REQUEST_EVENT, (payload) => {
|
|
712
734
|
if (!options.allowIntercomDetach || processClosed) return;
|
|
@@ -994,8 +1016,9 @@ async function runSingleAttempt(
|
|
|
994
1016
|
}
|
|
995
1017
|
shared.transcriptWriter?.writeChildEvent(evt);
|
|
996
1018
|
shared.orcaProgressTab?.event(evt);
|
|
997
|
-
|
|
998
|
-
|
|
1019
|
+
const lifecycleAction = projectChildLifecycle(evt, false, childLifecycleState);
|
|
1020
|
+
if (evt.type === "agent_settled" && lifecycleAction === "start-drain") agentSettledReceived = true;
|
|
1021
|
+
applyChildLifecycle(lifecycleAction);
|
|
999
1022
|
|
|
1000
1023
|
if (isChildWatchdogStatusEvent(evt)) {
|
|
1001
1024
|
if (!childWatchdog) return;
|
|
@@ -1078,6 +1101,7 @@ async function runSingleAttempt(
|
|
|
1078
1101
|
updateTurnBudget(result.usage.turns, terminalAssistantStop || terminalStructuredOutputCall, hasToolCall || Boolean(progress.currentTool));
|
|
1079
1102
|
const u = evt.message.usage;
|
|
1080
1103
|
if (u) {
|
|
1104
|
+
const window = (u.input || 0) + (u.cacheRead || 0);
|
|
1081
1105
|
result.usage.input += u.input || 0;
|
|
1082
1106
|
result.usage.output += u.output || 0;
|
|
1083
1107
|
result.usage.cacheRead += u.cacheRead || 0;
|
|
@@ -1086,6 +1110,8 @@ async function runSingleAttempt(
|
|
|
1086
1110
|
progress.tokens = result.usage.input + result.usage.output;
|
|
1087
1111
|
progress.inputTokens = result.usage.input;
|
|
1088
1112
|
progress.outputTokens = result.usage.output;
|
|
1113
|
+
progress.window = window;
|
|
1114
|
+
progress.windowPeak = Math.max(progress.windowPeak ?? 0, window);
|
|
1089
1115
|
}
|
|
1090
1116
|
if (evt.message.model) {
|
|
1091
1117
|
progress.model = evt.message.model;
|
|
@@ -1102,7 +1128,11 @@ async function runSingleAttempt(
|
|
|
1102
1128
|
if (terminalAssistantStop) {
|
|
1103
1129
|
if (!evt.message.errorMessage && assistantText.trim()) assistantError = undefined;
|
|
1104
1130
|
cleanTerminalAssistantStopReceived ||= !evt.message.errorMessage;
|
|
1105
|
-
|
|
1131
|
+
clearAllToolTimeouts();
|
|
1132
|
+
activeToolCalls.clear();
|
|
1133
|
+
activeToolKeysByName.clear();
|
|
1134
|
+
refreshCurrentTool();
|
|
1135
|
+
applyChildLifecycle(projectChildLifecycle(evt, true, childLifecycleState));
|
|
1106
1136
|
}
|
|
1107
1137
|
}
|
|
1108
1138
|
updateActivityState(now);
|
|
@@ -1369,6 +1399,7 @@ async function runSingleAttempt(
|
|
|
1369
1399
|
if (options.signal) {
|
|
1370
1400
|
const kill = () => {
|
|
1371
1401
|
if (processClosed || lifecycleFinished) return;
|
|
1402
|
+
abortedBySignal = true;
|
|
1372
1403
|
proc.kill("SIGTERM");
|
|
1373
1404
|
setTimeout(() => !proc.killed && proc.kill("SIGKILL"), 3000);
|
|
1374
1405
|
};
|
|
@@ -1431,6 +1462,22 @@ async function runSingleAttempt(
|
|
|
1431
1462
|
};
|
|
1432
1463
|
return result;
|
|
1433
1464
|
}
|
|
1465
|
+
if (progress.currentTool
|
|
1466
|
+
&& isOrdinaryToolForMidToolExit(progress.currentTool)
|
|
1467
|
+
&& !abortedBySignal
|
|
1468
|
+
&& !result.timedOut
|
|
1469
|
+
&& !result.stopped
|
|
1470
|
+
&& !result.turnBudgetExceeded
|
|
1471
|
+
&& !result.protocolError
|
|
1472
|
+
&& !toolAvailabilityError) {
|
|
1473
|
+
const processExitCode = result.exitCode;
|
|
1474
|
+
result.exitCode = 1;
|
|
1475
|
+
result.error = formatMidToolExitError({
|
|
1476
|
+
toolName: progress.currentTool,
|
|
1477
|
+
exitCode: processExitCode,
|
|
1478
|
+
processSignal: result.processSignal,
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1434
1481
|
result.error = formatSubagentExtensionConflictError(result.error, {
|
|
1435
1482
|
agent: agent.name,
|
|
1436
1483
|
ambientExtensionsEnabled: !launchResolvedExtensions.disableAmbientExtensions,
|
|
@@ -1647,6 +1694,8 @@ async function runSyncCompletionInner(
|
|
|
1647
1694
|
};
|
|
1648
1695
|
const agent = agents.find((a) => a.name === agentName);
|
|
1649
1696
|
if (!agent) {
|
|
1697
|
+
const diagnosticContext = options.unknownAgentDiagnosticContext
|
|
1698
|
+
?? unknownAgentDiagnosticContext(discoverAgents(path.resolve(options.cwd ?? runtimeCwd), "both"));
|
|
1650
1699
|
return redactResultPrompt(withRunContext({
|
|
1651
1700
|
index: options.index ?? 0,
|
|
1652
1701
|
agent: agentName,
|
|
@@ -1654,7 +1703,7 @@ async function runSyncCompletionInner(
|
|
|
1654
1703
|
exitCode: 1,
|
|
1655
1704
|
messages: [],
|
|
1656
1705
|
usage: emptyUsage(),
|
|
1657
|
-
error:
|
|
1706
|
+
error: formatUnknownAgentError(agentName, diagnosticContext),
|
|
1658
1707
|
}, options.context));
|
|
1659
1708
|
}
|
|
1660
1709
|
options = {
|
|
@@ -1781,6 +1830,18 @@ async function runSyncCompletionInner(
|
|
|
1781
1830
|
agent.modelProvider ?? options.preferredModelProvider,
|
|
1782
1831
|
{ scope: options.modelScope, primaryModelFromParent: options.modelOverrideFromParent },
|
|
1783
1832
|
);
|
|
1833
|
+
if (options.workflowChildPermitLaunch && candidates.length > 1) {
|
|
1834
|
+
const error = "Workflow child permit does not support model fallback.";
|
|
1835
|
+
return redactResultPrompt(withRunContext({
|
|
1836
|
+
index: options.index ?? 0,
|
|
1837
|
+
agent: agent.name,
|
|
1838
|
+
task,
|
|
1839
|
+
exitCode: 1,
|
|
1840
|
+
messages: [],
|
|
1841
|
+
usage: emptyUsage(),
|
|
1842
|
+
error,
|
|
1843
|
+
}, options.context));
|
|
1844
|
+
}
|
|
1784
1845
|
try {
|
|
1785
1846
|
for (const candidate of candidates) {
|
|
1786
1847
|
const model = applyThinkingSuffix(candidate, options.thinkingOverride ?? agent.thinking, options.thinkingOverride !== undefined);
|
|
@@ -1914,6 +1975,7 @@ async function runSyncCompletionInner(
|
|
|
1914
1975
|
usage: { ...result.usage },
|
|
1915
1976
|
};
|
|
1916
1977
|
modelAttempts.push(attempt);
|
|
1978
|
+
if (options.workflowChildPermitLaunch && !attemptSucceeded) break modelAttemptsLoop;
|
|
1917
1979
|
// Preserve the legacy intercom handoff contract: once this logical run has
|
|
1918
1980
|
// been handed to a supervisor, terminating that attempt must not launch a
|
|
1919
1981
|
// startup retry or model fallback. Explicit user detach retains fallback.
|
|
@@ -1986,7 +2048,7 @@ async function runSyncCompletionInner(
|
|
|
1986
2048
|
attempt.error = startupError;
|
|
1987
2049
|
break modelAttemptsLoop;
|
|
1988
2050
|
}
|
|
1989
|
-
const retryableModelFailure =
|
|
2051
|
+
const retryableModelFailure = isRetryableModelFailureAttempt({ error: result.error, messages: result.messages, toolCount: result.progressSummary?.toolCount });
|
|
1990
2052
|
if (retryableModelFailure) recordRetryableModelFailure(result.model ?? candidate, result.error);
|
|
1991
2053
|
if (isContextOverflow(result.error)) {
|
|
1992
2054
|
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
|
|