@claudexor/orchestrator 4.1.0 → 4.2.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/dist/account-pool.d.ts +11 -0
- package/dist/account-pool.d.ts.map +1 -1
- package/dist/account-pool.js +9 -0
- package/dist/account-pool.js.map +1 -1
- package/dist/account-resolution.d.ts +3 -0
- package/dist/account-resolution.d.ts.map +1 -1
- package/dist/account-resolution.js +1 -0
- package/dist/account-resolution.js.map +1 -1
- package/dist/attemptTelemetry.d.ts +4 -6
- package/dist/attemptTelemetry.d.ts.map +1 -1
- package/dist/attemptTelemetry.js +1 -1
- package/dist/attemptTelemetry.js.map +1 -1
- package/dist/budgetFailure.d.ts +4 -1
- package/dist/budgetFailure.d.ts.map +1 -1
- package/dist/budgetFailure.js +4 -2
- package/dist/budgetFailure.js.map +1 -1
- package/dist/candidateEvidence.d.ts.map +1 -1
- package/dist/candidateEvidence.js +7 -2
- package/dist/candidateEvidence.js.map +1 -1
- package/dist/candidateOutputs.d.ts.map +1 -1
- package/dist/candidateOutputs.js +6 -0
- package/dist/candidateOutputs.js.map +1 -1
- package/dist/candidateReview.d.ts +3 -1
- package/dist/candidateReview.d.ts.map +1 -1
- package/dist/candidateReview.js +6 -1
- package/dist/candidateReview.js.map +1 -1
- package/dist/candidateTerminals.d.ts +12 -1
- package/dist/candidateTerminals.d.ts.map +1 -1
- package/dist/candidateTerminals.js +51 -21
- package/dist/candidateTerminals.js.map +1 -1
- package/dist/captureRefusal.d.ts +28 -0
- package/dist/captureRefusal.d.ts.map +1 -0
- package/dist/captureRefusal.js +54 -0
- package/dist/captureRefusal.js.map +1 -0
- package/dist/continuity-terminal.d.ts +3 -1
- package/dist/continuity-terminal.d.ts.map +1 -1
- package/dist/continuity-terminal.js.map +1 -1
- package/dist/contract-gates.d.ts +10 -2
- package/dist/contract-gates.d.ts.map +1 -1
- package/dist/contract-gates.js +14 -1
- package/dist/contract-gates.js.map +1 -1
- package/dist/credential-profile-rotation.js +2 -3
- package/dist/credential-profile-rotation.js.map +1 -1
- package/dist/delegationFailure.d.ts +104 -7
- package/dist/delegationFailure.d.ts.map +1 -1
- package/dist/delegationFailure.js +47 -31
- package/dist/delegationFailure.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/inrun-continuity-types.d.ts +13 -1
- package/dist/inrun-continuity-types.d.ts.map +1 -1
- package/dist/inrun-continuity.d.ts +9 -2
- package/dist/inrun-continuity.d.ts.map +1 -1
- package/dist/inrun-continuity.js +43 -23
- package/dist/inrun-continuity.js.map +1 -1
- package/dist/inrun-continuity.test-support.d.ts +6 -2
- package/dist/inrun-continuity.test-support.d.ts.map +1 -1
- package/dist/inrun-continuity.test-support.js +4 -1
- package/dist/inrun-continuity.test-support.js.map +1 -1
- package/dist/orchestrator-credentials.d.ts +5 -4
- package/dist/orchestrator-credentials.d.ts.map +1 -1
- package/dist/orchestrator-credentials.js +7 -4
- package/dist/orchestrator-credentials.js.map +1 -1
- package/dist/orchestrator.d.ts +11 -3
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +341 -414
- package/dist/orchestrator.js.map +1 -1
- package/dist/persistedPatch.js +2 -2
- package/dist/persistedPatch.js.map +1 -1
- package/dist/pool-attempt-evidence.d.ts +62 -0
- package/dist/pool-attempt-evidence.d.ts.map +1 -0
- package/dist/pool-attempt-evidence.js +153 -0
- package/dist/pool-attempt-evidence.js.map +1 -0
- package/dist/pre-progress-refusal.d.ts +43 -6
- package/dist/pre-progress-refusal.d.ts.map +1 -1
- package/dist/pre-progress-refusal.js +53 -8
- package/dist/pre-progress-refusal.js.map +1 -1
- package/dist/readonlyTerminals.d.ts +55 -0
- package/dist/readonlyTerminals.d.ts.map +1 -0
- package/dist/readonlyTerminals.js +205 -0
- package/dist/readonlyTerminals.js.map +1 -0
- package/dist/reviewEvidence.d.ts +4 -0
- package/dist/reviewEvidence.d.ts.map +1 -0
- package/dist/reviewEvidence.js +46 -0
- package/dist/reviewEvidence.js.map +1 -0
- package/dist/rotation-predicate.d.ts +7 -23
- package/dist/rotation-predicate.d.ts.map +1 -1
- package/dist/rotation-predicate.js +45 -0
- package/dist/rotation-predicate.js.map +1 -1
- package/dist/runEventLog.d.ts +1 -0
- package/dist/runEventLog.d.ts.map +1 -1
- package/dist/runEventLog.js +3 -2
- package/dist/runEventLog.js.map +1 -1
- package/dist/runScope.d.ts +86 -0
- package/dist/runScope.d.ts.map +1 -0
- package/dist/runScope.js +181 -0
- package/dist/runScope.js.map +1 -0
- package/dist/runTerminalContext.d.ts +4 -0
- package/dist/runTerminalContext.d.ts.map +1 -1
- package/dist/runTerminalContext.js.map +1 -1
- package/dist/runTerminalHelpers.d.ts +50 -0
- package/dist/runTerminalHelpers.d.ts.map +1 -0
- package/dist/runTerminalHelpers.js +200 -0
- package/dist/runTerminalHelpers.js.map +1 -0
- package/dist/runTerminalResults.d.ts +25 -3
- package/dist/runTerminalResults.d.ts.map +1 -1
- package/dist/runTerminalResults.js +61 -29
- package/dist/runTerminalResults.js.map +1 -1
- package/dist/runTerminals.d.ts +1 -12
- package/dist/runTerminals.d.ts.map +1 -1
- package/dist/runTerminals.js +113 -140
- package/dist/runTerminals.js.map +1 -1
- package/dist/secretDiff.d.ts +14 -11
- package/dist/secretDiff.d.ts.map +1 -1
- package/dist/secretDiff.js +21 -28
- package/dist/secretDiff.js.map +1 -1
- package/dist/terminalOutcome.d.ts +24 -4
- package/dist/terminalOutcome.d.ts.map +1 -1
- package/dist/terminalOutcome.js +32 -5
- package/dist/terminalOutcome.js.map +1 -1
- package/package.json +17 -17
|
@@ -4,6 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import { cancelReasonFromSignalToken } from "./runTerminals.js";
|
|
5
5
|
import { RunFailure, RunFailureCode, HarnessRequestRefusal, } from "@claudexor/schema";
|
|
6
6
|
import { redactSecrets } from "@claudexor/util";
|
|
7
|
+
import { poolFailure, redactVendorFailure } from "./pool-attempt-evidence.js";
|
|
7
8
|
import { resumableTerminal } from "./continuity-terminal.js";
|
|
8
9
|
import { terminalOutcomeFacts } from "./terminalOutcome.js";
|
|
9
10
|
export function writeFailure(store, paths, failure) {
|
|
@@ -28,24 +29,32 @@ export function writeFailure(store, paths, failure) {
|
|
|
28
29
|
runDir: failure.runDir ?? paths.root,
|
|
29
30
|
resetsAt: failure.resetsAt ?? null,
|
|
30
31
|
...(failure.requestRefusal ? { requestRefusal: failure.requestRefusal } : {}),
|
|
32
|
+
...(failure.captureFailure ? { captureFailure: failure.captureFailure } : {}),
|
|
31
33
|
// Vendor text was redacted at event ingress; redact again like safeMessage (INV-062).
|
|
32
|
-
vendorFailure: vendor &&
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
vendorFailure: vendor && redactVendorFailure(vendor),
|
|
35
|
+
poolAttempts: (failure.poolAttempts ?? []).map((row) => ({
|
|
36
|
+
...row,
|
|
37
|
+
profileDisplayName: row.profileDisplayName && redactSecrets(row.profileDisplayName),
|
|
38
|
+
error: redactSecrets(row.error),
|
|
39
|
+
vendorFailure: row.vendorFailure && redactVendorFailure(row.vendorFailure),
|
|
40
|
+
})),
|
|
41
|
+
nextActions: [
|
|
42
|
+
...new Set([
|
|
43
|
+
...(failure.code === "input_too_large"
|
|
44
|
+
? [
|
|
45
|
+
"Fit the input to the reported transport limit or supply source references",
|
|
46
|
+
"Choose another compatible harness if the complete input must remain inline",
|
|
47
|
+
]
|
|
48
|
+
: failure.code === "vendor_cli_too_old"
|
|
49
|
+
? [
|
|
50
|
+
`Update the Claude Code CLI${installation ? ` at ${installation}` : ""}`,
|
|
51
|
+
"Use the update method for that installation, then retry the requested model",
|
|
52
|
+
"Open diagnostics",
|
|
53
|
+
]
|
|
54
|
+
: (failure.nextActions ?? [])),
|
|
55
|
+
...(failure.captureFailure ? (failure.nextActions ?? []) : []),
|
|
56
|
+
]),
|
|
57
|
+
],
|
|
49
58
|
});
|
|
50
59
|
}
|
|
51
60
|
export function requestRefusalFailure(requestRefusal) {
|
|
@@ -86,6 +95,25 @@ export function declaredFailure(err) {
|
|
|
86
95
|
...(refusal.success ? { requestRefusal: refusal.data } : {}),
|
|
87
96
|
};
|
|
88
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* The one statement of a cancellation, shared by every cancelled terminal: the
|
|
100
|
+
* cancel first (a STRING abort reason, e.g. the maxSeconds deadline, is named),
|
|
101
|
+
* then the run's earlier failed tries; `markdown` is its summary.md.
|
|
102
|
+
*/
|
|
103
|
+
export function cancellationStatement(runId, mode, cancelSignal, attempts) {
|
|
104
|
+
const cancelReason = typeof cancelSignal?.reason === "string" && cancelSignal.reason
|
|
105
|
+
? cancelSignal.reason
|
|
106
|
+
: undefined;
|
|
107
|
+
const { message, poolAttempts } = poolFailure(cancelReason === "wall_clock_exceeded"
|
|
108
|
+
? "run cancelled: wall-clock deadline (maxSeconds) exceeded"
|
|
109
|
+
: "run cancelled", attempts);
|
|
110
|
+
return {
|
|
111
|
+
...(cancelReason ? { cancelReason } : {}),
|
|
112
|
+
summary: message,
|
|
113
|
+
markdown: `# Run ${runId} (${mode})\n\n- Lifecycle: cancelled\n${cancelReason ? `- Reason: ${cancelReason}\n` : ""}\n${message}\n`,
|
|
114
|
+
poolAttempts,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
89
117
|
/**
|
|
90
118
|
* Terminal result for a cancelled run: emits run.failed with status
|
|
91
119
|
* "cancelled" so every mode ends consistently. `writeTelemetry` carries the
|
|
@@ -104,7 +132,10 @@ store,
|
|
|
104
132
|
* when cancellation wins during the Delegate terminal barrier. */
|
|
105
133
|
priorFacts,
|
|
106
134
|
/** The attempt's continuation facts (cause wall_clock/cancelled, carriers), when any. */
|
|
107
|
-
resumable
|
|
135
|
+
resumable,
|
|
136
|
+
/** The run's attempts: their earlier failed tries stay diagnostic history
|
|
137
|
+
* beside the cancellation (a cancelled try has no row; no failure record). */
|
|
138
|
+
attempts) {
|
|
108
139
|
if (writeTelemetry) {
|
|
109
140
|
try {
|
|
110
141
|
writeTelemetry();
|
|
@@ -113,19 +144,14 @@ resumable) {
|
|
|
113
144
|
/* partial telemetry is best-effort on the cancel path */
|
|
114
145
|
}
|
|
115
146
|
}
|
|
116
|
-
const cancelReason =
|
|
117
|
-
? cancelSignal.reason
|
|
118
|
-
: undefined;
|
|
119
|
-
const summaryText = cancelReason === "wall_clock_exceeded"
|
|
120
|
-
? "run cancelled: wall-clock deadline (maxSeconds) exceeded"
|
|
121
|
-
: "run cancelled";
|
|
147
|
+
const { cancelReason, summary: summaryText, markdown, poolAttempts, } = cancellationStatement(runId, mode, cancelSignal, attempts ?? []);
|
|
122
148
|
// Materialize the diagnostic summary BEFORE announcing it — output.ready must
|
|
123
149
|
// point at a file that exists (partial-output honesty), and it must precede
|
|
124
150
|
// the terminal in every mode (INV-116).
|
|
125
151
|
let summaryWritten = false;
|
|
126
152
|
if (store) {
|
|
127
153
|
try {
|
|
128
|
-
store.writeText(join(runDir, "final", "summary.md"),
|
|
154
|
+
store.writeText(join(runDir, "final", "summary.md"), markdown);
|
|
129
155
|
summaryWritten = true;
|
|
130
156
|
}
|
|
131
157
|
catch {
|
|
@@ -146,6 +172,7 @@ resumable) {
|
|
|
146
172
|
facts: cancelFacts,
|
|
147
173
|
reason: cancelFacts.reason,
|
|
148
174
|
...(cancelReason ? { cancel_reason: cancelReason } : {}),
|
|
175
|
+
...(attempts ? { pool_attempts: poolAttempts } : {}),
|
|
149
176
|
...(resumable ? { resumable } : {}),
|
|
150
177
|
});
|
|
151
178
|
return {
|
|
@@ -173,9 +200,9 @@ export function failTerminally(log, store, paths, runId, taskId, mode, phase, er
|
|
|
173
200
|
: null;
|
|
174
201
|
if (budget)
|
|
175
202
|
phase = budget.phase;
|
|
176
|
-
const message = budget?.safeMessage ?? redactSecrets(err instanceof Error ? err.message : String(err));
|
|
203
|
+
const { message, poolAttempts } = poolFailure(budget?.safeMessage ?? redactSecrets(err instanceof Error ? err.message : String(err)), failureMeta.attempts ?? failureMeta.continuity ?? []);
|
|
177
204
|
const declared = declaredFailure(err);
|
|
178
|
-
const failFacts = terminalOutcomeFacts(failureMeta.priorFacts, "failed", budget?.reason ?? "harness_failed");
|
|
205
|
+
const failFacts = terminalOutcomeFacts(failureMeta.priorFacts, "failed", budget?.reason ?? (phase === "workspace" ? "workspace_unavailable" : "harness_failed"));
|
|
179
206
|
store.writeText(join(paths.finalDir, "summary.md"), `# Run ${runId} (${mode})\n\n- Lifecycle: failed\n- Phase: ${phase}\n\n${message}\n`);
|
|
180
207
|
writeFailure(store, paths, {
|
|
181
208
|
phase,
|
|
@@ -185,11 +212,15 @@ export function failTerminally(log, store, paths, runId, taskId, mode, phase, er
|
|
|
185
212
|
attemptId: budget?.attemptId ?? failureMeta.attemptId,
|
|
186
213
|
safeMessage: message,
|
|
187
214
|
rawDetailRef: failureMeta.rawDetailRef,
|
|
215
|
+
captureFailure: failureMeta.captureFailure,
|
|
188
216
|
runDir: paths.root,
|
|
189
217
|
resetsAt: declared.resetsAt,
|
|
190
218
|
requestRefusal: declared.requestRefusal,
|
|
191
|
-
|
|
192
|
-
|
|
219
|
+
poolAttempts,
|
|
220
|
+
nextActions: [
|
|
221
|
+
...(budget?.nextActions ?? failureMeta.nextActions ?? ["Open diagnostics", "Retry the run"]),
|
|
222
|
+
...(failureMeta.followUps ?? []),
|
|
223
|
+
],
|
|
193
224
|
});
|
|
194
225
|
log.emit("output.ready", { kind: "summary", path: "final/summary.md", state: "diagnostic" });
|
|
195
226
|
log.emit("run.failed", {
|
|
@@ -198,6 +229,7 @@ export function failTerminally(log, store, paths, runId, taskId, mode, phase, er
|
|
|
198
229
|
reason: failFacts.reason,
|
|
199
230
|
phase,
|
|
200
231
|
error: message,
|
|
232
|
+
pool_attempts: poolAttempts,
|
|
201
233
|
failure_ref: "final/failure.yaml",
|
|
202
234
|
...resumableTerminal(store, paths, failureMeta.continuity ?? [], true),
|
|
203
235
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runTerminalResults.js","sourceRoot":"","sources":["../src/runTerminalResults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AAGhE,OAAO,EACL,UAAU,EACV,cAAc,
|
|
1
|
+
{"version":3,"file":"runTerminalResults.js","sourceRoot":"","sources":["../src/runTerminalResults.ts"],"names":[],"mappings":"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"}
|
package/dist/runTerminals.d.ts
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
import { type CancelReasonCode } from "@claudexor/schema";
|
|
2
1
|
import type { OrchestratorResult } from "./orchestrator.js";
|
|
3
2
|
import type { AnnouncedRunContext } from "./runTerminalContext.js";
|
|
4
3
|
import { cancelledResult, declaredFailure, failTerminally, writeFailure } from "./runTerminalResults.js";
|
|
5
4
|
export type { AnnouncedRunContext } from "./runTerminalContext.js";
|
|
6
5
|
export { cancelledResult, declaredFailure, failTerminally, writeFailure };
|
|
7
|
-
export {
|
|
8
|
-
/** Map an abort-signal reason token to its typed terminal RunReason. The
|
|
9
|
-
* abort reason is the ONE channel a cancel's provenance survives on — before
|
|
10
|
-
* this mapping every host-initiated cancel coerced to user_cancelled (the
|
|
11
|
-
* daemon's own ctrl-c relay and the MCP host teardown included). The client
|
|
12
|
-
* vocabulary is read from CANCEL_REASON_CODES so a future member cannot be
|
|
13
|
-
* silently coerced away here while the HTTP boundary already admits it;
|
|
14
|
-
* wall_clock_exceeded stays daemon-internal (deliberately NOT in the client
|
|
15
|
-
* enum — unforgeable). Unknown tokens keep the user_cancelled coercion for
|
|
16
|
-
* wire compatibility. */
|
|
17
|
-
export declare function cancelReasonFromSignalToken(reason: unknown): "wall_clock_exceeded" | CancelReasonCode;
|
|
6
|
+
export { cancelReasonFromSignalToken } from "./runTerminalHelpers.js";
|
|
18
7
|
/**
|
|
19
8
|
* Whole-strategy terminal net: run `body`; if it throws AFTER announcing,
|
|
20
9
|
* stamp terminal artifacts instead of orphaning the run. Pre-announce throws
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runTerminals.d.ts","sourceRoot":"","sources":["../src/runTerminals.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runTerminals.d.ts","sourceRoot":"","sources":["../src/runTerminals.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAGnE,OAAO,EAEL,eAAe,EACf,eAAe,EACf,cAAc,EACd,YAAY,EACb,MAAM,yBAAyB,CAAC;AAQjC,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC;AAC1E,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAEtE;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,mBAAmB,KAAK,IAAI,KAAK,OAAO,CAAC,kBAAkB,CAAC;AACjF;6EAC6E;AAC7E,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;AACvE;;;;;GAKG;AACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAClD,OAAO,CAAC,kBAAkB,CAAC,CA0d7B"}
|
package/dist/runTerminals.js
CHANGED
|
@@ -8,142 +8,18 @@
|
|
|
8
8
|
* forever.
|
|
9
9
|
*/
|
|
10
10
|
import { join } from "node:path";
|
|
11
|
-
import { makeOutcomeFacts,
|
|
11
|
+
import { makeOutcomeFacts, RunOutcomeFacts, } from "@claudexor/schema";
|
|
12
12
|
import { readTextSafe, redactSecrets } from "@claudexor/util";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { reconcileDecisionBudget, settledBudgetSnapshot } from "./decisionBudget.js";
|
|
14
|
+
import { cancelReasonFromSignalToken, cancellationFacts, commitCancellation, committedOutcome, committedResult, isTerminalRecoveryRequired, ownsDelegateDrain, postDrainBudgetFailure, settledSpend, terminalEventTypeFor, terminalFactsFailure, terminalOutcomeFromPayload, } from "./runTerminalHelpers.js";
|
|
15
15
|
import { reconcileDecisionTerminal } from "./decisionTerminalReconciliation.js";
|
|
16
16
|
import { prepareRunFactsFailureReceipt, prepareRunFactsReceipt } from "./runFacts.js";
|
|
17
17
|
import { flushContinuationTerminal } from "./continuation-custody.js";
|
|
18
18
|
import { publishRetainedOutput } from "./retainedOutput.js";
|
|
19
|
-
import { cancelledResult, declaredFailure, failTerminally, writeFailure, } from "./runTerminalResults.js";
|
|
20
|
-
import { clearFailureArtifact, reconcileWorkProductTerminal, terminalOutcomeFacts, } from "./terminalOutcome.js";
|
|
19
|
+
import { cancellationStatement, cancelledResult, declaredFailure, failTerminally, writeFailure, } from "./runTerminalResults.js";
|
|
20
|
+
import { clearFailureArtifact, preparedCaptureFacts, reconcileWorkProductTerminal, terminalOutcomeFacts, } from "./terminalOutcome.js";
|
|
21
21
|
export { cancelledResult, declaredFailure, failTerminally, writeFailure };
|
|
22
|
-
export {
|
|
23
|
-
function ownsDelegateDrain(context) {
|
|
24
|
-
try {
|
|
25
|
-
return context.recheckBudgetAfterBarrier?.() === true;
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
// Reconciliation is an extra authority granted only to a proven Delegate
|
|
29
|
-
// drain owner. An unreadable ownership predicate must fail closed instead
|
|
30
|
-
// of touching an ordinary Agent's already-terminal artifacts.
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
function postDrainBudgetFailure(context, terminal, budget, prior) {
|
|
35
|
-
const mapping = classifyBudgetFailure({ denial: null, terminal });
|
|
36
|
-
const facts = terminalOutcomeFacts(prior.facts, "failed", mapping.reason);
|
|
37
|
-
reconcileDecisionBudget(context, budget, { facts, why: mapping.safeMessage });
|
|
38
|
-
reconcileWorkProductTerminal(context, facts);
|
|
39
|
-
context.store.writeText(join(context.paths.finalDir, "summary.md"), `# Run ${context.runId} (${context.mode})\n\n- Lifecycle: failed (${mapping.reason})\n- Phase: budget\n\n${mapping.safeMessage}\n`);
|
|
40
|
-
writeFailure(context.store, context.paths, budgetFailureRecord(mapping, { runDir: context.paths.root }));
|
|
41
|
-
context.log.emit("output.ready", {
|
|
42
|
-
kind: "summary",
|
|
43
|
-
path: "final/summary.md",
|
|
44
|
-
state: "diagnostic",
|
|
45
|
-
});
|
|
46
|
-
context.log.emit("run.failed", {
|
|
47
|
-
lifecycle: "failed",
|
|
48
|
-
facts,
|
|
49
|
-
reason: mapping.reason,
|
|
50
|
-
phase: "budget",
|
|
51
|
-
error: mapping.safeMessage,
|
|
52
|
-
failure_ref: "final/failure.yaml",
|
|
53
|
-
});
|
|
54
|
-
return {
|
|
55
|
-
...prior,
|
|
56
|
-
lifecycle: "failed",
|
|
57
|
-
facts,
|
|
58
|
-
summary: mapping.safeMessage,
|
|
59
|
-
spendUsd: budget.spendUsd,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
function terminalEventTypeFor(_originalType, outcome) {
|
|
63
|
-
if (outcome.lifecycle !== "succeeded")
|
|
64
|
-
return "run.failed";
|
|
65
|
-
if (needsOperatorAttention(outcome, false))
|
|
66
|
-
return "run.blocked";
|
|
67
|
-
// The canonical axes own terminal type. Preserving a producer-authored
|
|
68
|
-
// run.blocked with clean axes creates an unexplainable block (no reason or
|
|
69
|
-
// required action), so it is normalized to completed.
|
|
70
|
-
return "run.completed";
|
|
71
|
-
}
|
|
72
|
-
/** Map an abort-signal reason token to its typed terminal RunReason. The
|
|
73
|
-
* abort reason is the ONE channel a cancel's provenance survives on — before
|
|
74
|
-
* this mapping every host-initiated cancel coerced to user_cancelled (the
|
|
75
|
-
* daemon's own ctrl-c relay and the MCP host teardown included). The client
|
|
76
|
-
* vocabulary is read from CANCEL_REASON_CODES so a future member cannot be
|
|
77
|
-
* silently coerced away here while the HTTP boundary already admits it;
|
|
78
|
-
* wall_clock_exceeded stays daemon-internal (deliberately NOT in the client
|
|
79
|
-
* enum — unforgeable). Unknown tokens keep the user_cancelled coercion for
|
|
80
|
-
* wire compatibility. */
|
|
81
|
-
export function cancelReasonFromSignalToken(reason) {
|
|
82
|
-
if (reason === "wall_clock_exceeded")
|
|
83
|
-
return "wall_clock_exceeded";
|
|
84
|
-
return normalizeCancelReasonCode(reason) ?? "user_cancelled";
|
|
85
|
-
}
|
|
86
|
-
function cancellationFacts(signal, prior) {
|
|
87
|
-
return terminalOutcomeFacts(prior, "cancelled", cancelReasonFromSignalToken(signal.reason));
|
|
88
|
-
}
|
|
89
|
-
function terminalOutcomeFromPayload(payload) {
|
|
90
|
-
const parsed = RunOutcomeFacts.safeParse(payload["facts"]);
|
|
91
|
-
if (parsed.success)
|
|
92
|
-
return parsed.data;
|
|
93
|
-
// Older in-process terminal producers (including the Delegate drain
|
|
94
|
-
// contract) supplied only lifecycle. Keep that compatible while treating an
|
|
95
|
-
// explicitly malformed facts object as a contradiction that must fail
|
|
96
|
-
// closed through the terminal-facts path below.
|
|
97
|
-
if (!Object.prototype.hasOwnProperty.call(payload, "facts")) {
|
|
98
|
-
const lifecycle = payload["lifecycle"];
|
|
99
|
-
if (lifecycle === "succeeded" ||
|
|
100
|
-
lifecycle === "failed" ||
|
|
101
|
-
lifecycle === "cancelled" ||
|
|
102
|
-
lifecycle === "interrupted") {
|
|
103
|
-
return makeOutcomeFacts(lifecycle);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return RunOutcomeFacts.parse(payload["facts"]);
|
|
107
|
-
}
|
|
108
|
-
function settledSpend(a) {
|
|
109
|
-
try {
|
|
110
|
-
return a.spend ? a.spend() : null;
|
|
111
|
-
}
|
|
112
|
-
catch {
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
function isTerminalRecoveryRequired(error) {
|
|
117
|
-
return (!!error &&
|
|
118
|
-
typeof error === "object" &&
|
|
119
|
-
"code" in error &&
|
|
120
|
-
error.code === "terminal_recovery_required");
|
|
121
|
-
}
|
|
122
|
-
function committedOutcome(a) {
|
|
123
|
-
const terminal = [...a.log.readAll().events]
|
|
124
|
-
.reverse()
|
|
125
|
-
.find((event) => event.type === "run.completed" ||
|
|
126
|
-
event.type === "run.blocked" ||
|
|
127
|
-
event.type === "run.failed");
|
|
128
|
-
const parsed = RunOutcomeFacts.safeParse(terminal?.payload["facts"]);
|
|
129
|
-
return parsed.success ? parsed.data : null;
|
|
130
|
-
}
|
|
131
|
-
function committedResult(a, outcome, spendUsd) {
|
|
132
|
-
const summary = readTextSafe(join(a.paths.finalDir, "summary.md"))?.trim().slice(0, 400) ??
|
|
133
|
-
`run terminal committed with lifecycle ${outcome.lifecycle}`;
|
|
134
|
-
return {
|
|
135
|
-
runId: a.runId,
|
|
136
|
-
taskId: a.taskId,
|
|
137
|
-
mode: a.mode,
|
|
138
|
-
lifecycle: outcome.lifecycle,
|
|
139
|
-
facts: outcome,
|
|
140
|
-
winner: null,
|
|
141
|
-
runDir: a.paths.root,
|
|
142
|
-
summary,
|
|
143
|
-
candidates: [],
|
|
144
|
-
spendUsd,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
22
|
+
export { cancelReasonFromSignalToken } from "./runTerminalHelpers.js";
|
|
147
23
|
/**
|
|
148
24
|
* Whole-strategy terminal net: run `body`; if it throws AFTER announcing,
|
|
149
25
|
* stamp terminal artifacts instead of orphaning the run. Pre-announce throws
|
|
@@ -165,9 +41,16 @@ onSettled) {
|
|
|
165
41
|
let announced = null;
|
|
166
42
|
let preparedResult = null;
|
|
167
43
|
let canonicalOutcome = null;
|
|
44
|
+
let committedCancel = null;
|
|
168
45
|
let terminalPreparationError = null;
|
|
169
46
|
let barrierAttempted = false;
|
|
170
47
|
let barrierFailed = false;
|
|
48
|
+
// The cancellation decision is frozen the moment the strategy's terminal is
|
|
49
|
+
// held (the strategy returned): a host cancel or wall-clock abort that
|
|
50
|
+
// arrives DURING the settlement barrier must not turn a completed run into
|
|
51
|
+
// a cancelled one. Null until the strategy has returned.
|
|
52
|
+
let abortedAtStrategyEnd = null;
|
|
53
|
+
const cancellationDecided = () => abortedAtStrategyEnd !== null ? abortedAtStrategyEnd : signal?.aborted === true;
|
|
171
54
|
const runBarrier = async (context) => {
|
|
172
55
|
if (barrierAttempted)
|
|
173
56
|
return;
|
|
@@ -180,6 +63,30 @@ onSettled) {
|
|
|
180
63
|
throw error;
|
|
181
64
|
}
|
|
182
65
|
};
|
|
66
|
+
/** The barrier for a HELD terminal: true when it (already) succeeded. */
|
|
67
|
+
let heldBarrierError = null;
|
|
68
|
+
const barrierHeld = async (context) => {
|
|
69
|
+
try {
|
|
70
|
+
await runBarrier(context);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
heldBarrierError = error;
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* The held-terminal RECOVERY path (the strategy held its terminal, then
|
|
80
|
+
* threw): for an ordinary run the cancellation decision is frozen NOW,
|
|
81
|
+
* before its barrier, exactly as on the normal return — the verdict was
|
|
82
|
+
* reached before any abort that lands during settlement. Delegate parents
|
|
83
|
+
* keep the live signal through their child drain (the drain is their work).
|
|
84
|
+
*/
|
|
85
|
+
const heldVerdictBarrier = async (context) => {
|
|
86
|
+
if (!ownsDelegateDrain(context))
|
|
87
|
+
abortedAtStrategyEnd = signal?.aborted === true;
|
|
88
|
+
return barrierHeld(context);
|
|
89
|
+
};
|
|
183
90
|
try {
|
|
184
91
|
let result;
|
|
185
92
|
try {
|
|
@@ -190,15 +97,23 @@ onSettled) {
|
|
|
190
97
|
// Cancellation wins only until the synchronous terminal commit
|
|
191
98
|
// starts. A later abort cannot rewrite an already-durable success.
|
|
192
99
|
const payloadOutcome = terminalOutcomeFromPayload(payload);
|
|
193
|
-
const terminalOutcome = signal
|
|
100
|
+
const terminalOutcome = cancellationDecided() && signal
|
|
194
101
|
? cancellationFacts(signal, payloadOutcome)
|
|
195
102
|
: payloadOutcome;
|
|
196
103
|
const prepared = prepareRunFactsReceipt(a, terminalOutcome);
|
|
197
104
|
canonicalOutcome = prepared.facts.outcome;
|
|
105
|
+
// A cancellation chosen here replaces the strategy's own verdict,
|
|
106
|
+
// so the terminal states that cancellation instead.
|
|
107
|
+
committedCancel =
|
|
108
|
+
signal &&
|
|
109
|
+
payloadOutcome.lifecycle !== "cancelled" &&
|
|
110
|
+
prepared.facts.outcome.lifecycle === "cancelled"
|
|
111
|
+
? commitCancellation(a, signal, payload)
|
|
112
|
+
: null;
|
|
198
113
|
return {
|
|
199
114
|
type: terminalEventTypeFor(originalType, prepared.facts.outcome),
|
|
200
115
|
payload: {
|
|
201
|
-
...payload,
|
|
116
|
+
...(committedCancel?.payload ?? payload),
|
|
202
117
|
lifecycle: prepared.facts.outcome.lifecycle,
|
|
203
118
|
facts: prepared.facts.outcome,
|
|
204
119
|
reason: prepared.facts.outcome.reason,
|
|
@@ -209,14 +124,17 @@ onSettled) {
|
|
|
209
124
|
rollback: () => {
|
|
210
125
|
prepared.rollback();
|
|
211
126
|
canonicalOutcome = null;
|
|
127
|
+
committedCancel = null;
|
|
212
128
|
},
|
|
213
129
|
};
|
|
214
130
|
}
|
|
215
131
|
catch (error) {
|
|
132
|
+
committedCancel = null;
|
|
216
133
|
// A contradictory terminal projection must fail the run, not throw
|
|
217
134
|
// out of the hook and retry the same contradiction forever.
|
|
218
135
|
const detail = redactSecrets(error instanceof Error ? error.message : String(error));
|
|
219
|
-
|
|
136
|
+
const history = terminalFactsFailure(a, detail);
|
|
137
|
+
terminalPreparationError = history.message;
|
|
220
138
|
const failureOutcome = makeOutcomeFacts("failed", {
|
|
221
139
|
reason: "harness_failed",
|
|
222
140
|
});
|
|
@@ -227,6 +145,7 @@ onSettled) {
|
|
|
227
145
|
phase: "terminal_facts",
|
|
228
146
|
category: "internal",
|
|
229
147
|
safeMessage: terminalPreparationError,
|
|
148
|
+
poolAttempts: history.poolAttempts,
|
|
230
149
|
runDir: a.paths.root,
|
|
231
150
|
nextActions: [
|
|
232
151
|
"Open diagnostics",
|
|
@@ -251,6 +170,7 @@ onSettled) {
|
|
|
251
170
|
run_facts: prepared.facts,
|
|
252
171
|
phase: "terminal_facts",
|
|
253
172
|
error: terminalPreparationError,
|
|
173
|
+
pool_attempts: history.poolAttempts,
|
|
254
174
|
...(failureRefWritten ? { failure_ref: "final/failure.yaml" } : {}),
|
|
255
175
|
},
|
|
256
176
|
commit: prepared.commit,
|
|
@@ -273,27 +193,38 @@ onSettled) {
|
|
|
273
193
|
reason: failureOutcome.reason,
|
|
274
194
|
phase: "terminal_facts",
|
|
275
195
|
error: terminalPreparationError,
|
|
196
|
+
pool_attempts: history.poolAttempts,
|
|
276
197
|
...(failureRefWritten ? { failure_ref: "final/failure.yaml" } : {}),
|
|
277
198
|
},
|
|
278
199
|
};
|
|
279
200
|
}
|
|
280
201
|
}
|
|
281
|
-
}, (_type, payload) => publishRetainedOutput(a, !
|
|
202
|
+
}, (_type, payload) => publishRetainedOutput(a, !cancellationDecided() &&
|
|
282
203
|
(RunOutcomeFacts.safeParse(payload["facts"]).data?.lifecycle ??
|
|
283
204
|
payload["lifecycle"]) === "succeeded"));
|
|
284
205
|
});
|
|
285
206
|
preparedResult = result;
|
|
207
|
+
abortedAtStrategyEnd = signal?.aborted === true;
|
|
286
208
|
const context = announced;
|
|
287
209
|
if (context) {
|
|
288
210
|
await runBarrier(context);
|
|
289
211
|
const budget = settledBudgetSnapshot(context);
|
|
290
212
|
const delegateBarrierArmed = ownsDelegateDrain(context);
|
|
213
|
+
// Delegate parents keep their explicit cancel branch on the LIVE
|
|
214
|
+
// signal: a cancel that arrives while the child drain is still running
|
|
215
|
+
// wins there (the drain is part of their work). The frozen decision
|
|
216
|
+
// applies only to an ordinary run's held terminal.
|
|
291
217
|
if (delegateBarrierArmed && signal?.aborted) {
|
|
292
218
|
context.log.clearDeferredTerminal();
|
|
293
219
|
const cancelFacts = terminalOutcomeFacts(result.facts, "cancelled", cancelReasonFromSignalToken(signal.reason));
|
|
294
220
|
const cancelSummary = signal.reason === "wall_clock_exceeded"
|
|
295
221
|
? "run cancelled: wall-clock deadline (maxSeconds) exceeded"
|
|
296
222
|
: "run cancelled";
|
|
223
|
+
const attempts = context.attempts?.();
|
|
224
|
+
// A kept capture-bearing record is re-labelled with the same
|
|
225
|
+
// statement the cancelled terminal below makes (cancel, then the
|
|
226
|
+
// run's earlier failed tries).
|
|
227
|
+
const statement = cancellationStatement(context.runId, context.mode, signal, attempts ?? []);
|
|
297
228
|
let reconciledCancelFacts = cancelFacts;
|
|
298
229
|
try {
|
|
299
230
|
reconcileDecisionBudget(context, budget);
|
|
@@ -303,12 +234,12 @@ onSettled) {
|
|
|
303
234
|
preparedFacts: result.facts,
|
|
304
235
|
});
|
|
305
236
|
reconcileWorkProductTerminal(context, reconciledCancelFacts);
|
|
306
|
-
clearFailureArtifact(context);
|
|
237
|
+
clearFailureArtifact(context, { summary: statement.summary });
|
|
307
238
|
}
|
|
308
239
|
catch {
|
|
309
240
|
/* the cancellation terminal below remains authoritative */
|
|
310
241
|
}
|
|
311
|
-
const cancelled = cancelledResult(context.log, context.runId, context.taskId, context.mode, context.paths.root, result.candidates, undefined, budget.spendUsd, signal, context.store, reconciledCancelFacts);
|
|
242
|
+
const cancelled = cancelledResult(context.log, context.runId, context.taskId, context.mode, context.paths.root, result.candidates, undefined, budget.spendUsd, signal, context.store, reconciledCancelFacts, undefined, attempts);
|
|
312
243
|
await flushContinuationTerminal(context, cancelled.facts);
|
|
313
244
|
result = {
|
|
314
245
|
...result,
|
|
@@ -360,9 +291,34 @@ onSettled) {
|
|
|
360
291
|
}
|
|
361
292
|
: committedResult(a, outcome, spendUsd);
|
|
362
293
|
}
|
|
294
|
+
else if (a.log.deferredTerminalPending() &&
|
|
295
|
+
!signal?.aborted &&
|
|
296
|
+
!barrierFailed &&
|
|
297
|
+
(await heldVerdictBarrier(a))) {
|
|
298
|
+
// The strategy already produced its terminal — held for the barrier
|
|
299
|
+
// (INV-144: custody settles before the terminal is published) — and
|
|
300
|
+
// then threw. Exactly like a committed terminal, its verdict stands
|
|
301
|
+
// once the barrier itself succeeded: publish the held terminal and
|
|
302
|
+
// keep its outcome. A FAILED barrier (a child drain that timed out)
|
|
303
|
+
// falls through to the typed failure below, as before.
|
|
304
|
+
const pending = a.log.deferredTerminalPending();
|
|
305
|
+
await flushContinuationTerminal(a, terminalOutcomeFromPayload(pending.payload));
|
|
306
|
+
const outcome = canonicalOutcome ?? committedOutcome(a);
|
|
307
|
+
if (!outcome)
|
|
308
|
+
throw err;
|
|
309
|
+
const spendUsd = settledSpend(a);
|
|
310
|
+
result = preparedResult
|
|
311
|
+
? {
|
|
312
|
+
...preparedResult,
|
|
313
|
+
lifecycle: outcome.lifecycle,
|
|
314
|
+
facts: outcome,
|
|
315
|
+
...(spendUsd !== null ? { spendUsd } : {}),
|
|
316
|
+
}
|
|
317
|
+
: committedResult(a, outcome, spendUsd);
|
|
318
|
+
}
|
|
363
319
|
else {
|
|
364
320
|
a.log.clearDeferredTerminal();
|
|
365
|
-
let terminalError = err;
|
|
321
|
+
let terminalError = heldBarrierError ?? err;
|
|
366
322
|
try {
|
|
367
323
|
await runBarrier(a);
|
|
368
324
|
}
|
|
@@ -381,6 +337,10 @@ onSettled) {
|
|
|
381
337
|
const cancelSummary = signal.reason === "wall_clock_exceeded"
|
|
382
338
|
? "run cancelled: wall-clock deadline (maxSeconds) exceeded"
|
|
383
339
|
: "run cancelled";
|
|
340
|
+
const attempts = a.attempts?.();
|
|
341
|
+
// As above: a kept capture-bearing record carries the cancelled
|
|
342
|
+
// terminal's own statement.
|
|
343
|
+
const statement = cancellationStatement(a.runId, a.mode, signal, attempts ?? []);
|
|
384
344
|
let reconciledCancelFacts = cancelFacts;
|
|
385
345
|
try {
|
|
386
346
|
if (delegateBarrierArmed)
|
|
@@ -391,7 +351,7 @@ onSettled) {
|
|
|
391
351
|
...(preparedResult ? { preparedFacts: preparedResult.facts } : {}),
|
|
392
352
|
});
|
|
393
353
|
reconcileWorkProductTerminal(a, reconciledCancelFacts);
|
|
394
|
-
clearFailureArtifact(a);
|
|
354
|
+
clearFailureArtifact(a, { summary: statement.summary });
|
|
395
355
|
}
|
|
396
356
|
catch {
|
|
397
357
|
/* the cancellation terminal below remains authoritative */
|
|
@@ -399,7 +359,7 @@ onSettled) {
|
|
|
399
359
|
const cancelled = cancelledResult(a.log, a.runId, a.taskId, a.mode, a.paths.root, preparedResult?.candidates ?? [], undefined, spendUsd,
|
|
400
360
|
// A wall-clock abort surfaced as a throw must keep its reason and
|
|
401
361
|
// materialize the diagnostic summary, exactly like the checkpoint paths.
|
|
402
|
-
signal, a.store, reconciledCancelFacts);
|
|
362
|
+
signal, a.store, reconciledCancelFacts, undefined, attempts);
|
|
403
363
|
await flushContinuationTerminal(a, cancelled.facts);
|
|
404
364
|
result = preparedResult
|
|
405
365
|
? {
|
|
@@ -430,7 +390,13 @@ onSettled) {
|
|
|
430
390
|
catch {
|
|
431
391
|
/* the failure terminal below remains authoritative */
|
|
432
392
|
}
|
|
433
|
-
const failed = failTerminally(a.log, a.store, a.paths, a.runId, a.taskId, a.mode, barrierFailed ? "delegation_drain" : a.phase, terminalError, spendUsd,
|
|
393
|
+
const failed = failTerminally(a.log, a.store, a.paths, a.runId, a.taskId, a.mode, barrierFailed ? "delegation_drain" : a.phase, terminalError, spendUsd,
|
|
394
|
+
// Read before this terminal replaces the prepared record.
|
|
395
|
+
{
|
|
396
|
+
priorFacts: reconciledFailureFacts,
|
|
397
|
+
...preparedCaptureFacts(a),
|
|
398
|
+
attempts: a.attempts?.(),
|
|
399
|
+
});
|
|
434
400
|
await flushContinuationTerminal(a, failed.facts);
|
|
435
401
|
result = preparedResult
|
|
436
402
|
? {
|
|
@@ -478,12 +444,19 @@ onSettled) {
|
|
|
478
444
|
}
|
|
479
445
|
// TS cannot see assignments performed inside EventLog's hook closure.
|
|
480
446
|
const settledOutcome = canonicalOutcome;
|
|
447
|
+
const settledCancel = committedCancel;
|
|
481
448
|
if (settledOutcome) {
|
|
482
449
|
result = {
|
|
483
450
|
...result,
|
|
484
451
|
lifecycle: settledOutcome.lifecycle,
|
|
485
452
|
facts: settledOutcome,
|
|
486
453
|
...(terminalPreparationError ? { winner: null, summary: terminalPreparationError } : {}),
|
|
454
|
+
...(settledCancel
|
|
455
|
+
? {
|
|
456
|
+
summary: settledCancel.summary,
|
|
457
|
+
...(settledCancel.cancelReason ? { cancelReason: settledCancel.cancelReason } : {}),
|
|
458
|
+
}
|
|
459
|
+
: {}),
|
|
487
460
|
};
|
|
488
461
|
}
|
|
489
462
|
return result;
|