@sema-agent/core 7.5.2 → 7.6.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 +41 -0
- package/dist/agents/cascade.d.ts +2 -2
- package/dist/agents/cascade.js +12 -10
- package/dist/agents/repair-loop.d.ts +5 -3
- package/dist/agents/repair-loop.js +13 -15
- package/dist/agents/subagent.d.ts +24 -42
- package/dist/agents/subagent.js +119 -105
- package/dist/agents/suspend-guard.d.ts +31 -19
- package/dist/agents/suspend-guard.js +14 -8
- package/dist/agents/teacher.js +9 -9
- package/dist/agents/team.d.ts +4 -3
- package/dist/agents/team.js +10 -8
- package/dist/agents/verify.d.ts +3 -3
- package/dist/agents/verify.js +17 -17
- package/dist/core/a2a.js +2 -1
- package/dist/core/ask-origin.d.ts +60 -7
- package/dist/core/ask-origin.js +26 -1
- package/dist/core/checkpoint-store.d.ts +78 -76
- package/dist/core/checkpoint-store.js +17 -1
- package/dist/core/gate-outcome.d.ts +189 -0
- package/dist/core/gate-outcome.js +70 -0
- package/dist/core/hooks.d.ts +18 -92
- package/dist/core/hooks.js +88 -85
- package/dist/core/mcp-failure.d.ts +104 -0
- package/dist/core/mcp-failure.js +128 -0
- package/dist/core/mcp.d.ts +21 -77
- package/dist/core/mcp.js +76 -150
- package/dist/core/pause-registry.d.ts +131 -0
- package/dist/core/pause-registry.js +27 -0
- package/dist/core/runner/assemble-result.d.ts +32 -41
- package/dist/core/runner/assemble-result.js +55 -74
- package/dist/core/runner/contracts.d.ts +46 -64
- package/dist/core/runner/denial-limit-arms.d.ts +1 -1
- package/dist/core/runner/denial-limit-arms.js +3 -3
- package/dist/core/runner/gate-exit.d.ts +74 -0
- package/dist/core/runner/gate-exit.js +55 -0
- package/dist/core/runner/park-commit.d.ts +17 -23
- package/dist/core/runner/park-commit.js +14 -15
- package/dist/core/runner/prepare-ask-lane.d.ts +0 -3
- package/dist/core/runner/prepare-ask-lane.js +3 -5
- package/dist/core/runner/prepare-boundary-parks.d.ts +3 -6
- package/dist/core/runner/prepare-boundary-parks.js +3 -3
- package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -7
- package/dist/core/runner/prepare-gate-stations.js +29 -54
- package/dist/core/runner/prepare-inherited-gate.js +1 -1
- package/dist/core/runner/prepare-memory.d.ts +44 -26
- package/dist/core/runner/prepare-park-ask.d.ts +2 -4
- package/dist/core/runner/prepare-park-ask.js +5 -5
- package/dist/core/runner/prepare-task.js +8 -9
- package/dist/core/runner/prepare-wiring-manifest.d.ts +7 -15
- package/dist/core/runner/prepare-wiring-manifest.js +9 -10
- package/dist/core/runner/runtask.d.ts +16 -31
- package/dist/core/runner/runtask.js +109 -120
- package/dist/core/runner/terminal-projection.d.ts +22 -0
- package/dist/core/runner/terminal-projection.js +28 -0
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +4 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +8 -2
- package/dist/core/terminal-cause.d.ts +137 -0
- package/dist/core/terminal-cause.js +9 -0
- package/dist/core/tool-policy.d.ts +43 -139
- package/dist/core/tool-policy.js +79 -112
- package/dist/core/types.d.ts +67 -164
- package/dist/core/wiring-manifest.d.ts +6 -3
- package/dist/core/workflow-journal-store.js +3 -4
- package/dist/engine/harness/agent-harness.d.ts +1 -1
- package/dist/index.d.ts +10 -7
- package/dist/index.js +8 -5
- package/dist/orchestration/builtin-workflows.d.ts +2 -2
- package/dist/orchestration/builtin-workflows.js +1 -1
- package/dist/orchestration/goal.js +8 -7
- package/dist/orchestration/run-spec.js +5 -3
- package/dist/orchestration/run-workflow-tool.d.ts +1 -1
- package/dist/orchestration/run-workflow-tool.js +4 -4
- package/dist/orchestration/workflow-governance.d.ts +4 -4
- package/dist/orchestration/workflow-governance.js +4 -2
- package/dist/orchestration/workflow-primitives.d.ts +1 -1
- package/dist/orchestration/workflow-primitives.js +1 -1
- package/dist/orchestration/workflow.d.ts +11 -0
- package/dist/orchestration/workflow.js +64 -39
- package/dist/prompts/supervisor.d.ts +1 -1
- package/dist/prompts/supervisor.js +3 -3
- package/dist/scenarios/scenario-registry.js +1 -1
- package/package.json +3 -1
- package/test/export-surface.snapshot.json +74 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 7.6.0 — 2026-09-07
|
|
4
|
+
|
|
5
|
+
**BREAKING.** design/390 S6 (three slices, merged): the tool gate's settlement/origin words become ONE `GateOutcome` record, `TaskResult` becomes ONE terminal record, MCP failures become ONE structural record with a delivery verdict, and the durable off switch becomes a word. Every consumer that read the retired keys must migrate (server 7.64.0, cli/client-core, web-admin, desktop — the criteria post lists the frames old→new).
|
|
6
|
+
|
|
7
|
+
### BREAKING — exports removed (10)
|
|
8
|
+
- `APPROVAL_SETTLED_BY_VALUES`, `ASK_DENY_RESOLUTION_VALUES`, `isApprovalSettledBy`, `isAskDenyResolution`, `type ApprovalSettledBy`, `type AskDenyResolution`, `type PermissionDeniedSource` (S6-A — replaced by `GateOutcome` / `Settlement` / `DeniedBy`).
|
|
9
|
+
- `MCP_FAILURE_CODES`, `mcpFailureCodeOf`, `type McpFailureCode` (S6-B — replaced by `McpFailure` / `MCP_FAILURE_KINDS` / `classifyMcpFailure`).
|
|
10
|
+
|
|
11
|
+
### BREAKING — same-name shape changes
|
|
12
|
+
- `TaskResult`: the eight plane fields `status` / `errorCode` / `errorMessage` / `blockedReason` / `checkpointToken` / `checkpointId` / `checkpointGate` / `workspaceRestoreMode` are deleted; the run's end is ONE required `terminal: TerminalCause` (`completed` | `failed{code?, message?, nestedPause?}` | `blocked{reason}` | `paused{gate, token, checkpointId?, restoreMode?}`). `terminalProjection(terminal)` is the explicit projection for a face that keeps the old shape. The `done` frame, the HTTP task body and SSE `done.result` are the result itself, so they lose the eight keys and carry `terminal`; a nested boundary's pause is `failed` + `nestedPause` (its token no longer rides `checkpointToken`).
|
|
13
|
+
- `TaskSpec.checkpointStore`: the per-run durable off switch is the word `"disabled"`; the retired `null` is refused at the first prepare with `config.invalid_checkpoint_store` (also through a worktree baseline overlay). `engine_notice` cause `task_store_null` → `task_store_disabled`.
|
|
14
|
+
- `Checkpoint` is a type (`CheckpointRow & CheckpointPause`) whose gate × pendingAction pairing is fixed by `PAUSE_REGISTRY`; hand-built rows go through `checkpointFrom` / `pauseOf`. A dry-run `needs_review` row carries its own `pendingAction.kind: "review"`.
|
|
15
|
+
- `ResumeOutcome.policy_ask.hostDecision` is required: a host resolving a park supplies decision FACTS (`{decision, decidedBy: "person" | "sla_timeout", …}`) and core mints every settlement word — a host never spells a kind.
|
|
16
|
+
- `RealApprovalGateBit.origin` is the full `AskOrigin` set (was a five-word subset) and gains the org FACT member `org?: "rule" | "unavailable"`; read governance through `realApprovalOrgFact(bit)`, never through the routing word. `AskOrigin` gains `safety_tighten` and `shell_gate_tighten`.
|
|
17
|
+
- `TeacherRunResult` and `VerificationResult` (they extend `TaskResult`) lose the same eight plane keys; `ResumeOutcome` loses `settledBy` / `approver` (the host supplies `hostDecision` facts instead).
|
|
18
|
+
- `ResolvedAsk` loses its four settlement keys; `RepairResult.terminal` → `repairTerminal`; `McpErrorMarks.errorKind` is replaced by `McpFailure{kind, delivered, httpStatus?}`; `SubagentErrorKind` drops `overloaded` and gains `unknown`.
|
|
19
|
+
|
|
20
|
+
### BREAKING — wire frames
|
|
21
|
+
- `tool_end`: `settledBy` / `resolution` / `autoDenied` / `approver` deleted → `gate?: GateOutcome` (`disposition: {kind:"allowed"} | {kind:"denied", deniedBy}`, `settlement?: Settlement` (12 kinds, `who` fixed by `kind`), `origin?: AskOrigin`); `errorCode` speaks `McpFailureKind` (`connection_failed` / `connection_closed` / `timeout` / `protocol` / `http_status` / …; `network` and `http_<n>` retired) or a result code (`mcp.task_required`, `mcp.tool_error`, `mcp.server_revoked`); new `delivered?: "yes" | "no" | "unknown"`.
|
|
22
|
+
- `permissionDenied` observer payload: `source` / `resolution` / `autoDenied` deleted → `gate: GateOutcome` (frozen). `DeniedBy` = policy / hook / org / classifier / plan_mode / compliance / write_protection / ask_resolution.
|
|
23
|
+
- `wiring_manifest.mcp[]`: `errorCode` in the new words, plus `delivered` and `httpStatus`.
|
|
24
|
+
- Checkpoint rows: `realApproval.origin` full set + `org`; resolved rows record `resolvedOutcome.gateOutcome`; a `review` pending kind exists.
|
|
25
|
+
- Agent card `error_kind`: `overloaded` → gone, `unknown` added (no structured code ⇒ `unknown`, not retryable).
|
|
26
|
+
|
|
27
|
+
### Changed (narrowings, named)
|
|
28
|
+
- An approval-factory approver's bare refusal on the parent thread halts the batch like a live approver's; a person's yes vetoed by a later layer is recorded as `human_allowed` beside the vetoing `deniedBy`; the post-CAS belt's refusal carries the veto record.
|
|
29
|
+
- The HTTP MCP transport no longer follows redirects (3xx ⇒ `http_status`, delivered `unknown`); a listing requiring task support is refused before any send (`mcp.task_required`, delivered `no`); a server's `isError:true` reply is `mcp.tool_error` with delivered `yes`; same-raw-name listings mount from one accepted view; a bare `TypeError` classifies as `unknown`, never `connection_failed`.
|
|
30
|
+
- A resume journal entry whose result carries no closed-set terminal cause (a journal written before `TaskResult.terminal`, or a malformed entry) refuses the resume with `WorkflowJournalIncompatibleError` (`workflow.journal_incompatible`) before any agent is dispatched — it no longer diverges into a live re-run of completed work. `TERMINAL_CAUSE_IS_REPLAYABLE` is the one table behind admission and replay.
|
|
31
|
+
- A background child's "durable pause without a token" arm is retired (unconstructible).
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- `GateOutcome` / `Settlement` / `DeniedBy` (+ `SETTLEMENT_KINDS`, `DENIED_BY_VALUES`, `SETTLEMENT_IS_REFUSAL`, `DENIED_BY_MAY_VETO`, `isSettlementKind`, `isDeniedBy`, `screenGateOutcome`), minted once at the gate exit (`mintGateOutcome`) and projected onto three faces; invariants I1–I4 screened at the wire entry; `ORIGIN_IMPLIES_REAL_APPROVAL`.
|
|
35
|
+
- `PAUSE_REGISTRY` (+ `GateKind`, `PendingKind`, `ResumeGate`, `isGateKind`, `resumeGateMatches`, `checkpointFrom`, `pauseOf`, `CheckpointFields`, `CheckpointPause`, `CheckpointRow`).
|
|
36
|
+
- `TerminalCause`, `PausedCause`, `terminalProjection`, `realApprovalOrgFact`, `resolveCheckpointStore`.
|
|
37
|
+
- `McpFailure`, `MCP_FAILURE_KINDS`, `MCP_DELIVERY_VERDICTS`, `McpDelivered`, `classifyMcpFailure` (ordered structural classifier, no text regex).
|
|
38
|
+
- `WorkflowJournalIncompatibleError`.
|
|
39
|
+
- Gates: `gate:closed-sets` (`docs/CLOSED-SETS.md` registry + `AssertAllKeysHandled` fences + switch exhaustiveness) and `gate:contract-sentences` (`@contract` ids, `docs/CONTRACT-SENTENCES.md`, duplicate-sentence baseline); invariant pins `test/gate-outcome-invariants.test.ts`; `test/design390-d8-terminal-only.test.ts`.
|
|
40
|
+
|
|
41
|
+
### Unchanged and pinned
|
|
42
|
+
- The suspendAsk 13-parameter `AskCarry`; the 23 gate stations (words, order); delegation lifecycle frames, `task.end` trace, agent cards, reports and workflow records keep their shape through the explicit projection; `engine_notice` codes other than the renamed cause; `wiring_manifest` keys other than `mcp[]`.
|
|
43
|
+
|
|
3
44
|
## 7.5.2 — 2026-09-06
|
|
4
45
|
|
|
5
46
|
Maintenance release: design/390 slices S3–S4 complete the `prepareTask` decomposition (4 756 → 1 666 driver lines, 34 phase modules), one settlement-path narrowing (#587), and the wire-manifest tooling that the 7.5.1 review asked for (#588 / #589). **No BREAKING change**: the export surface is byte-identical to 7.5.1; the only behaviour delta is that a reserved-tool-name collision now disposes an acquired protocol handle once instead of twice (below).
|
package/dist/agents/cascade.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Runner } from "../core/runner/runtask.js";
|
|
2
2
|
import type { RunInternals } from "../core/runner/prepare-task.js";
|
|
3
|
-
import type { ModelRef, TaskResult, TaskSpec } from "../core/types.js";
|
|
3
|
+
import type { ModelRef, TaskResult, TaskSpec, TaskStatus } from "../core/types.js";
|
|
4
4
|
/**
|
|
5
5
|
* Quality-gate cascade (design/27). Run the SAME task across a ladder of models (cheapest → strongest);
|
|
6
6
|
* after each rung a caller-supplied **decidable gate** judges "good enough" — pass = keep it, fail =
|
|
@@ -109,7 +109,7 @@ export interface CascadeAttempt {
|
|
|
109
109
|
* F4) — a fabricated 0 here both misreported the attempt and let escalation ride under a finite
|
|
110
110
|
* ceiling the engine could not actually enforce. */
|
|
111
111
|
costMicroUsd?: number;
|
|
112
|
-
status:
|
|
112
|
+
status: TaskStatus;
|
|
113
113
|
/** The rung's own failure code (e.g. "auth") if its `runTask` failed — distinct from "gate rejected it". */
|
|
114
114
|
errorCode?: string;
|
|
115
115
|
/** Set when the gate THREW (vs returned false) — surfaces a broken verifier-gate (expired key, etc.). */
|
package/dist/agents/cascade.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { terminalProjection } from "../core/runner/terminal-projection.js";
|
|
1
2
|
import { releaseSession } from "./session-util.js";
|
|
2
3
|
import { mapNestedSuspend, isDurablePause } from "./suspend-guard.js";
|
|
3
4
|
import { buildCumulativeStats } from "./cumulative-stats.js";
|
|
@@ -10,9 +11,13 @@ function cascadeConfigError(message) {
|
|
|
10
11
|
e.code = CASCADE_CONFIG_ERROR_CODE;
|
|
11
12
|
return e;
|
|
12
13
|
}
|
|
14
|
+
function attemptTerminal(result) {
|
|
15
|
+
const face = terminalProjection(result.terminal);
|
|
16
|
+
return { status: face.status, errorCode: face.errorCode };
|
|
17
|
+
}
|
|
13
18
|
function createDefaultGate(spec) {
|
|
14
19
|
const requiresStructured = spec.outputSchema != null;
|
|
15
|
-
return (result) => result.
|
|
20
|
+
return (result) => result.terminal.kind === "completed" && (!requiresStructured || result.structuredOutput !== undefined);
|
|
16
21
|
}
|
|
17
22
|
export async function runCascade(runner, spec, config, internals) {
|
|
18
23
|
const ladder = config.ladder;
|
|
@@ -126,9 +131,9 @@ export async function runCascade(runner, spec, config, internals) {
|
|
|
126
131
|
nestedTasks += s.nested.tasks;
|
|
127
132
|
nestedCostMicro += s.nested.costMicroUsd ?? 0;
|
|
128
133
|
}
|
|
129
|
-
if (isDurablePause(result.
|
|
134
|
+
if (isDurablePause(result.terminal)) {
|
|
130
135
|
const mapped = mapNestedSuspend(result);
|
|
131
|
-
attempts.push({ index: i, model: rung.model, passed: false, costMicroUsd: rungCost, status: result.status, errorCode: mapped.errorCode });
|
|
136
|
+
attempts.push({ index: i, model: rung.model, passed: false, costMicroUsd: rungCost, status: attemptTerminal(result).status, errorCode: attemptTerminal(mapped).errorCode });
|
|
132
137
|
return {
|
|
133
138
|
...mapped,
|
|
134
139
|
stats: cumulativeStats(result.stats),
|
|
@@ -145,8 +150,7 @@ export async function runCascade(runner, spec, config, internals) {
|
|
|
145
150
|
model: rung.model,
|
|
146
151
|
passed: false,
|
|
147
152
|
costMicroUsd: rungCost,
|
|
148
|
-
|
|
149
|
-
errorCode: result.errorCode,
|
|
153
|
+
...attemptTerminal(result),
|
|
150
154
|
...(deadlineFired ? { timedOut: true } : { cancelled: true }),
|
|
151
155
|
});
|
|
152
156
|
notifier.notify(() => config.onRung?.({ index: i, model: rung.model, passed: false, result }), CASCADE_ON_RUNG_SITE);
|
|
@@ -170,7 +174,7 @@ export async function runCascade(runner, spec, config, internals) {
|
|
|
170
174
|
passed = false;
|
|
171
175
|
gateError = e instanceof Error ? e.message : String(e);
|
|
172
176
|
}
|
|
173
|
-
const statusRejected = passed && config.acceptPartial !== true && result.
|
|
177
|
+
const statusRejected = passed && config.acceptPartial !== true && result.terminal.kind !== "completed";
|
|
174
178
|
if (statusRejected)
|
|
175
179
|
passed = false;
|
|
176
180
|
attempts.push({
|
|
@@ -178,8 +182,7 @@ export async function runCascade(runner, spec, config, internals) {
|
|
|
178
182
|
model: rung.model,
|
|
179
183
|
passed,
|
|
180
184
|
costMicroUsd: rungCost,
|
|
181
|
-
|
|
182
|
-
errorCode: result.errorCode,
|
|
185
|
+
...attemptTerminal(result),
|
|
183
186
|
gateError,
|
|
184
187
|
diagnostics,
|
|
185
188
|
...(statusRejected ? { statusRejected: true } : {}),
|
|
@@ -198,9 +201,8 @@ export async function runCascade(runner, spec, config, internals) {
|
|
|
198
201
|
return {
|
|
199
202
|
taskId: spec.taskId ?? "",
|
|
200
203
|
sessionId: "",
|
|
201
|
-
status: "failed",
|
|
202
204
|
result: `runCascade: the overall wall-clock budget (totalTimeoutMs ${config.totalTimeoutMs}ms) was already spent when the ladder was entered — no rung dispatched`,
|
|
203
|
-
|
|
205
|
+
terminal: { kind: "failed", code: CASCADE_NO_DISPATCH_ERROR_CODE },
|
|
204
206
|
stats: { tokens: 0, turns: 0, costMicroUsd: 0 },
|
|
205
207
|
cascadeOutcome: "exhausted",
|
|
206
208
|
escalated: false,
|
|
@@ -179,7 +179,7 @@ export interface RepairLoopConfig {
|
|
|
179
179
|
/** Per-attempt callback (observability). */
|
|
180
180
|
onAttempt?: (info: {
|
|
181
181
|
attempt: number;
|
|
182
|
-
|
|
182
|
+
repairTerminal?: RepairTerminal;
|
|
183
183
|
oracle: OracleResult;
|
|
184
184
|
}) => void;
|
|
185
185
|
/**
|
|
@@ -191,8 +191,10 @@ export interface RepairLoopConfig {
|
|
|
191
191
|
onWarn?: (warning: Error) => void;
|
|
192
192
|
}
|
|
193
193
|
export interface RepairResult extends VerificationResult {
|
|
194
|
-
/** The projected terminal (§2)
|
|
195
|
-
|
|
194
|
+
/** The projected REPAIR terminal (§2) — the loop's own word (fixed / candidate_only / gave_up / …), distinct
|
|
195
|
+
* from the inherited run terminal `terminal` (a {@link import("../core/types.js").TerminalCause}, WHY the
|
|
196
|
+
* worker's last leg ended). SAFE-tier never returns `fixed`. */
|
|
197
|
+
repairTerminal: RepairTerminal;
|
|
196
198
|
/** The final repair state (in-memory unless an orthogonal suspend serialized it — §4). */
|
|
197
199
|
bundle: RepairBundle;
|
|
198
200
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isDurablePause } from "./suspend-guard.js";
|
|
1
|
+
import { isDurablePause, pauseFamily } from "./suspend-guard.js";
|
|
2
2
|
import { delimitUntrusted, sanitizeUntrustedText } from "../core/untrusted-text.js";
|
|
3
3
|
import { assertOracleIsolation } from "../core/oracle-isolation.js";
|
|
4
4
|
import { buildCumulativeStats } from "./cumulative-stats.js";
|
|
@@ -48,12 +48,11 @@ export async function runRepairLoop(runner, implSpec, config) {
|
|
|
48
48
|
const oracle = { tier: "none", passed: false, flaky: false, retries: 0 };
|
|
49
49
|
return {
|
|
50
50
|
taskId: implSpec.taskId ?? "",
|
|
51
|
-
status: "failed",
|
|
52
51
|
result: `oracle isolation check failed: ${reason}`,
|
|
53
|
-
|
|
52
|
+
terminal: { kind: "failed", code: "oracle.unprotected", message: `oracle isolation check failed: ${reason}` },
|
|
54
53
|
sessionId: "",
|
|
55
54
|
stats: { tokens: 0, turns: 0, costMicroUsd: 0 },
|
|
56
|
-
|
|
55
|
+
repairTerminal: "oracle.unprotected",
|
|
57
56
|
...(isolationClass ? { isolationClass } : {}),
|
|
58
57
|
bundle: { ...freshBundle(), attemptCount: config.resumeBundle?.attemptCount ?? 0 },
|
|
59
58
|
oracleCostMicroUsd: 0,
|
|
@@ -157,12 +156,11 @@ export async function runRepairLoop(runner, implSpec, config) {
|
|
|
157
156
|
};
|
|
158
157
|
const exhaustedBeforeDispatch = (message, errorCode) => ({
|
|
159
158
|
taskId: implSpec.taskId ?? "",
|
|
160
|
-
status: "failed",
|
|
161
159
|
result: message ?? `repair loop: attempt budget already spent (attemptCount ${bundle.attemptCount} >= maxAttempts ${maxAttempts}) — no attempt dispatched`,
|
|
162
|
-
|
|
160
|
+
terminal: { kind: "failed", code: errorCode ?? "repair.attempts_exhausted", message: message ?? `repair loop: attempt budget already spent (attemptCount ${bundle.attemptCount} >= maxAttempts ${maxAttempts}) — no attempt dispatched` },
|
|
163
161
|
sessionId: implSpec.sessionId ?? "",
|
|
164
162
|
stats: { tokens: 0, turns: 0, costMicroUsd: 0 },
|
|
165
|
-
|
|
163
|
+
repairTerminal: "gave_up",
|
|
166
164
|
bundle,
|
|
167
165
|
...(isolationClass ? { isolationClass } : {}),
|
|
168
166
|
oracleCostMicroUsd,
|
|
@@ -208,22 +206,22 @@ export async function runRepairLoop(runner, implSpec, config) {
|
|
|
208
206
|
accumulate(result.stats);
|
|
209
207
|
lastResult = result;
|
|
210
208
|
bundle.attemptCount += 1;
|
|
211
|
-
if (isDurablePause(result.
|
|
209
|
+
if (isDurablePause(result.terminal)) {
|
|
212
210
|
return {
|
|
213
211
|
...result,
|
|
214
212
|
stats: cumulativeStats(result.stats),
|
|
215
|
-
|
|
213
|
+
repairTerminal: "gave_up",
|
|
216
214
|
bundle,
|
|
217
215
|
...(isolationClass ? { isolationClass } : {}),
|
|
218
216
|
oracleCostMicroUsd,
|
|
219
|
-
verification: { verdict: "unverified", unverifiedReason: result.
|
|
217
|
+
verification: { verdict: "unverified", unverifiedReason: pauseFamily(result.terminal), rounds: bundle.attemptCount, findings: [] },
|
|
220
218
|
};
|
|
221
219
|
}
|
|
222
|
-
if (result.
|
|
220
|
+
if (result.terminal.kind !== "completed") {
|
|
223
221
|
return {
|
|
224
222
|
...result,
|
|
225
223
|
stats: cumulativeStats(result.stats),
|
|
226
|
-
|
|
224
|
+
repairTerminal: "gave_up",
|
|
227
225
|
bundle,
|
|
228
226
|
...(isolationClass ? { isolationClass } : {}),
|
|
229
227
|
oracleCostMicroUsd,
|
|
@@ -237,12 +235,12 @@ export async function runRepairLoop(runner, implSpec, config) {
|
|
|
237
235
|
lastOracle = oracle;
|
|
238
236
|
bundle.oracleTier = oracle.tier;
|
|
239
237
|
const projected = terminalForTier(oracle);
|
|
240
|
-
config.onAttempt?.({ attempt: bundle.attemptCount,
|
|
238
|
+
config.onAttempt?.({ attempt: bundle.attemptCount, repairTerminal: projected, oracle });
|
|
241
239
|
if (projected !== undefined) {
|
|
242
240
|
return {
|
|
243
241
|
...result,
|
|
244
242
|
stats: cumulativeStats(result.stats),
|
|
245
|
-
|
|
243
|
+
repairTerminal: projected,
|
|
246
244
|
bundle,
|
|
247
245
|
...(isolationClass ? { isolationClass } : {}),
|
|
248
246
|
oracleCostMicroUsd,
|
|
@@ -266,7 +264,7 @@ export async function runRepairLoop(runner, implSpec, config) {
|
|
|
266
264
|
return {
|
|
267
265
|
...lastResult,
|
|
268
266
|
stats: cumulativeStats(lastResult.stats),
|
|
269
|
-
terminal,
|
|
267
|
+
repairTerminal: terminal,
|
|
270
268
|
bundle,
|
|
271
269
|
...(isolationClass ? { isolationClass } : {}),
|
|
272
270
|
oracleCostMicroUsd,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Runner } from "../core/runner/runtask.js";
|
|
2
|
-
import type { AgentDefinition, Model, ModelRef, TaskLimits, ToolSpec } from "../core/types.js";
|
|
2
|
+
import type { AgentDefinition, Model, ModelRef, TaskLimits, TerminalCause, ToolSpec } from "../core/types.js";
|
|
3
3
|
import { type ExecutionEnv } from "../internal/harness.js";
|
|
4
4
|
import type { RunInternals } from "../core/runner/prepare-task.js";
|
|
5
5
|
import type { TaskNotificationPayload } from "../core/task-notification.js";
|
|
@@ -215,45 +215,28 @@ export declare function createSubagentWorktreeHelper(baseEnv: ExecutionEnv, repo
|
|
|
215
215
|
/** Cap for the inline-defused worker-controlled report metadata lines (blocked_reason / error). Matches the
|
|
216
216
|
* ask-question.ts inline-value convention (300) — a one-line operator-facing reason, not a bulk payload. */
|
|
217
217
|
export declare const REPORT_FIELD_MAX = 300;
|
|
218
|
-
/** The machine-readable failure class stamped on a FAILED sub-agent report (sema form — see below). */
|
|
219
|
-
export type SubagentErrorKind = "rate_limit" | "overloaded" | "timeout" | "network" | "logic" | "governance";
|
|
220
218
|
/**
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
* that wants to re-auth and retry.
|
|
241
|
-
*
|
|
242
|
-
* Classification (unchanged) — a FAILED child run into a coarse `error_kind` +
|
|
243
|
-
* `retryable` pair so the PARENT model (and an orchestrating deployment) can react correctly without
|
|
244
|
-
* string-matching the report: a `rate_limit`/`overloaded`/`timeout`/`network` failure is transient
|
|
245
|
-
* (re-delegating the same subtask may succeed); a `logic` failure is not (auth/invalid_request/budget/
|
|
246
|
-
* output.* — re-delegating unchanged just burns tokens). Derived from the EXISTING taxonomy: the
|
|
247
|
-
* child's `TaskResult.errorCode` (assemble-result's priority chain — brain `[code]` prefixes lifted
|
|
248
|
-
* via `extractErrorCode`, `limits.max_walltime_exceeded`, `budget.*`, …) plus a message sniff for the two classes our
|
|
249
|
-
* BrainError codes fold together ("server" covers overloaded_error/529 AND plain 5xx; "network"
|
|
250
|
-
* covers both timeouts and resets). Returns undefined for a non-failed child (no error to classify).
|
|
219
|
+
* The machine-readable failure class stamped on a FAILED sub-agent report (the Agent card's `error_kind`
|
|
220
|
+
* beside `retryable`). A sema form, not a CC one: CC's kind lives on an error class and gates
|
|
221
|
+
* partial-output handback, not retry; sema's pair answers the parent's one question — re-delegate or not.
|
|
222
|
+
* · `rate_limit` / `network` / `timeout` — transient (re-delegating the same subtask may succeed);
|
|
223
|
+
* · `governance` — a registered policy-plane refusal; retryability is the
|
|
224
|
+
* governance table's transient/terminal split;
|
|
225
|
+
* · `logic` — a coded failure re-delegating unchanged cannot fix
|
|
226
|
+
* (auth / invalid_request / http / output.* / budget axes);
|
|
227
|
+
* · `unknown` — the child reported NO code: nothing structural to classify,
|
|
228
|
+
* and the class is not guessed from the message (not retried).
|
|
229
|
+
*/
|
|
230
|
+
export declare const SUBAGENT_ERROR_KINDS: readonly ["rate_limit", "timeout", "network", "logic", "governance", "unknown"];
|
|
231
|
+
export type SubagentErrorKind = (typeof SUBAGENT_ERROR_KINDS)[number];
|
|
232
|
+
/**
|
|
233
|
+
* Classify a FAILED child run into its `error_kind` + `retryable` pair from the child's STRUCTURED
|
|
234
|
+
* terminal code alone (the `TerminalCause.failed.code` taxonomy: brain codes, `limits.*`, `budget.*`,
|
|
235
|
+
* governance codes). The message is never read: a class read out of prose moved when the prose moved,
|
|
236
|
+
* and a remote's own error text could steer it. A child with no code is `unknown`. Returns undefined
|
|
237
|
+
* for a non-failed child (no error to classify).
|
|
251
238
|
*/
|
|
252
|
-
export declare function classifySubagentError(
|
|
253
|
-
status: string;
|
|
254
|
-
errorCode?: string;
|
|
255
|
-
errorMessage?: string;
|
|
256
|
-
}): {
|
|
239
|
+
export declare function classifySubagentError(terminal: TerminalCause): {
|
|
257
240
|
errorKind: SubagentErrorKind;
|
|
258
241
|
retryable: boolean;
|
|
259
242
|
} | undefined;
|
|
@@ -315,13 +298,12 @@ export declare function classifySubagentError(child: {
|
|
|
315
298
|
export declare function completedAgentCard(child: {
|
|
316
299
|
taskId: string;
|
|
317
300
|
sessionId: string;
|
|
318
|
-
status
|
|
301
|
+
/** The child's terminal cause. The card speaks its projection (`status` + the failure-attribution keys), never the
|
|
302
|
+
* cause's own members: a paused token, or the pause a nested boundary wrapped on `nestedPause`, is the resume CAPABILITY. */
|
|
303
|
+
terminal: TerminalCause;
|
|
319
304
|
model?: string;
|
|
320
305
|
result: string;
|
|
321
306
|
salvagedOutput?: string;
|
|
322
|
-
blockedReason?: string;
|
|
323
|
-
errorMessage?: string;
|
|
324
|
-
errorCode?: string;
|
|
325
307
|
/** The child run's provider-boundary fault assertion, verbatim from its `TaskResult.apiFailure`.
|
|
326
308
|
* PRESENCE is the claim ("this child's terminal failure came from the transport/provider, not from
|
|
327
309
|
* this deployment refusing to send, a limit, or unusable model output"); the members are whatever
|