@sema-agent/core 7.5.0 → 7.5.2
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 +44 -0
- package/dist/core/auto-mode.d.ts +9 -0
- package/dist/core/auto-mode.js +11 -0
- package/dist/core/checkpoint-store.js +5 -1
- package/dist/core/protocol-table.d.ts +5 -0
- package/dist/core/protocol-table.js +1 -0
- package/dist/core/runner/abort-race.d.ts +41 -0
- package/dist/core/runner/abort-race.js +38 -0
- package/dist/core/runner/checkpoint-scope.d.ts +44 -0
- package/dist/core/runner/checkpoint-scope.js +7 -0
- package/dist/core/runner/compaction-call-options.d.ts +1 -1
- package/dist/core/runner/content-ask-bindings.d.ts +27 -0
- package/dist/core/runner/content-ask-bindings.js +1 -0
- package/dist/core/runner/contracts.d.ts +1990 -0
- package/dist/core/runner/contracts.js +1 -0
- package/dist/core/runner/denial-limit-arms.d.ts +24 -1
- package/dist/core/runner/denial-limit-arms.js +21 -0
- package/dist/core/runner/derived-route-fallback.d.ts +34 -0
- package/dist/core/runner/derived-route-fallback.js +16 -0
- package/dist/core/runner/inherited-ask-grants.d.ts +46 -0
- package/dist/core/runner/inherited-ask-grants.js +29 -0
- package/dist/core/runner/park-commit.d.ts +108 -0
- package/dist/core/runner/park-commit.js +32 -0
- package/dist/core/runner/{prepare-permission-rules.d.ts → permission-rule-lanes.d.ts} +109 -3
- package/dist/core/runner/{prepare-permission-rules.js → permission-rule-lanes.js} +47 -1
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +1 -1
- package/dist/core/runner/prepare-ask-lane.d.ts +110 -0
- package/dist/core/runner/prepare-ask-lane.js +133 -0
- package/dist/core/runner/prepare-boundary-parks.d.ts +105 -0
- package/dist/core/runner/prepare-boundary-parks.js +169 -0
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +170 -0
- package/dist/core/runner/prepare-caps-and-workflow.js +255 -0
- package/dist/core/runner/prepare-config-doors.d.ts +2 -10
- package/dist/core/runner/prepare-context-lane.d.ts +119 -0
- package/dist/core/runner/prepare-context-lane.js +230 -0
- package/dist/core/runner/prepare-defer-classify.d.ts +86 -0
- package/dist/core/runner/prepare-defer-classify.js +107 -0
- package/dist/core/runner/prepare-delegation-surface.d.ts +104 -0
- package/dist/core/runner/prepare-delegation-surface.js +144 -0
- package/dist/core/runner/prepare-execution-env.d.ts +54 -0
- package/dist/core/runner/prepare-execution-env.js +86 -0
- package/dist/core/runner/prepare-file-history.d.ts +95 -0
- package/dist/core/runner/prepare-file-history.js +383 -0
- package/dist/core/runner/prepare-gate-stations.d.ts +177 -0
- package/dist/core/runner/prepare-gate-stations.js +290 -0
- package/dist/core/runner/prepare-hands-readface.d.ts +9 -11
- package/dist/core/runner/prepare-hands-readface.js +1 -1
- package/dist/core/runner/prepare-inherited-gate.d.ts +268 -0
- package/dist/core/runner/prepare-inherited-gate.js +266 -0
- package/dist/core/runner/prepare-listings.d.ts +77 -0
- package/dist/core/runner/prepare-listings.js +76 -0
- package/dist/core/runner/prepare-lsp.d.ts +55 -0
- package/dist/core/runner/prepare-lsp.js +27 -0
- package/dist/core/runner/prepare-memory-engine-session.d.ts +84 -0
- package/dist/core/runner/prepare-memory-engine-session.js +233 -0
- package/dist/core/runner/prepare-memory.d.ts +1 -1
- package/dist/core/runner/prepare-offload-wrappers.d.ts +62 -0
- package/dist/core/runner/prepare-offload-wrappers.js +45 -0
- package/dist/core/runner/prepare-park-ask.d.ts +164 -0
- package/dist/core/runner/prepare-park-ask.js +377 -0
- package/dist/core/runner/prepare-policy-chain.d.ts +208 -0
- package/dist/core/runner/prepare-policy-chain.js +584 -0
- package/dist/core/runner/prepare-project-context.d.ts +119 -0
- package/dist/core/runner/prepare-project-context.js +148 -0
- package/dist/core/runner/prepare-prompt-assembly.d.ts +95 -0
- package/dist/core/runner/prepare-prompt-assembly.js +162 -0
- package/dist/core/runner/prepare-prompt-inputs.d.ts +119 -0
- package/dist/core/runner/prepare-prompt-inputs.js +141 -0
- package/dist/core/runner/prepare-protocol-tools.d.ts +91 -0
- package/dist/core/runner/prepare-protocol-tools.js +179 -0
- package/dist/core/runner/prepare-question-face.d.ts +101 -0
- package/dist/core/runner/prepare-question-face.js +84 -0
- package/dist/core/runner/prepare-run-refs.d.ts +89 -0
- package/dist/core/runner/prepare-run-refs.js +39 -0
- package/dist/core/runner/prepare-safety-scan.d.ts +3 -7
- package/dist/core/runner/prepare-safety-scan.js +1 -2
- package/dist/core/runner/prepare-suspend-saga.d.ts +170 -0
- package/dist/core/runner/prepare-suspend-saga.js +308 -0
- package/dist/core/runner/prepare-task.d.ts +14 -1976
- package/dist/core/runner/prepare-task.js +182 -5162
- package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +111 -0
- package/dist/core/runner/prepare-tool-disclosure-mount.js +219 -0
- package/dist/core/runner/prepare-turn-wiring.d.ts +154 -0
- package/dist/core/runner/prepare-turn-wiring.js +201 -0
- package/dist/core/runner/prepare-wiring-manifest.d.ts +192 -0
- package/dist/core/runner/prepare-wiring-manifest.js +247 -0
- package/dist/core/runner/prepare-workspace-restore.d.ts +3 -56
- package/dist/core/runner/prepare-workspace-restore.js +4 -38
- package/dist/core/runner/prompt-hash-salt.d.ts +1 -0
- package/dist/core/runner/prompt-hash-salt.js +2 -0
- package/dist/core/runner/remote-env-retry.d.ts +29 -0
- package/dist/core/runner/remote-env-retry.js +16 -0
- package/dist/core/runner/rollback-stack.d.ts +32 -0
- package/dist/core/runner/rollback-stack.js +30 -0
- package/dist/core/runner/runtask.js +1 -1
- package/dist/core/runner/workspace-path.d.ts +33 -0
- package/dist/core/runner/workspace-path.js +22 -0
- package/dist/core/session.d.ts +12 -0
- package/dist/core/session.js +3 -0
- package/dist/core/tool-policy.d.ts +16 -0
- package/dist/core/tool-policy.js +3 -0
- package/dist/core/types.d.ts +2 -2
- package/dist/core/write-protect.js +3 -2
- package/package.json +6 -2
- /package/dist/core/runner/{prepare-announce-once.d.ts → announce-once-ledger.d.ts} +0 -0
- /package/dist/core/runner/{prepare-announce-once.js → announce-once-ledger.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 7.5.2 — 2026-09-06
|
|
4
|
+
|
|
5
|
+
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).
|
|
6
|
+
|
|
7
|
+
### Changed — design/390 S3–S4: the rest of `prepareTask` becomes phases
|
|
8
|
+
- Extracted verbatim, each with one Input (every seat classified) and one Result: memory-engine session, prompt assembly (two live accessor cells `systemPromptSeat` / `centerAdoptionRef`), policy chain (1 351 lines; the ask-origin mint sites move, the words and the closed set do not), context lane, turn wiring, the park lane as four phases (`prepare-ask-lane` / `prepare-suspend-saga` / `prepare-boundary-parks` / `prepare-park-ask`), and the two tool-gate stations (`prepare-gate-stations`). The driver holds five direct phase calls where it held nested closures and an `if` block; the block-activation predicate is minted once (`gateMachineryActive`).
|
|
9
|
+
- Layer 1 machinery (reached down for by phases, never a phase): `permission-rule-lanes.ts` (formerly `prepare-permission-rules.ts`), `inherited-ask-grants.ts`, `prompt-hash-salt.ts`, `abort-race.ts`, `remote-env-retry.ts`, `park-commit.ts`, `content-ask-bindings.ts`, `announce-once-ledger.ts` (formerly `prepare-announce-once.ts`), `compaction-call-options.ts`; `docs/LAYERING.json` `uncovered` list is empty.
|
|
10
|
+
- Contract seats: `AskLane` / `SuspendSaga` / `ParkAsk` are one fact each (a lane exists or it does not) rather than several independently-optional closures; `PromptFeatureFlags` / `SuspendSagaOutcome` and the park-lane seat types live in `contracts.ts`.
|
|
11
|
+
- Unchanged and pinned: the suspendAsk 13-parameter `AskCarry`, `ASK_ORIGINS` and its fence, the 23 gate stations (words, order, deny sources), the durable park row, `tool_end` settlement words, the tool roster order (owner table on `Prepared.tools`).
|
|
12
|
+
|
|
13
|
+
### Changed (narrowing, named) — #587 one releaser on the reserved-name path
|
|
14
|
+
- A caller tool whose name collides with a protocol tool's reserved name still makes prepare throw `config.reserved_tool_name`; the acquired MCP / A2A handle is now released exactly once by the RollbackStack unwind (A2A before MCP). 7.5.1 disposed it inline and again on unwind. Pinned as "exactly once" at the transcript and unit level.
|
|
15
|
+
|
|
16
|
+
### Gates / tooling
|
|
17
|
+
- `test/runner-layer-order.test.ts`: the five-layer order (vocabulary < machinery < phases < orchestrator < runner) is asserted over the REAL import graph of `src/core/runner/*.ts`; the three upward exemptions are enumerated and the table cannot grow silently.
|
|
18
|
+
- `test/prepare-prompt-assembly-zero-write-window.test.ts` (design/238 T16): prompt assembly performs no session write between its start and the prompt-epoch pin; unknown storage methods count as writes (fail-closed).
|
|
19
|
+
- `scripts/wire-changes.mjs`: `declarationMoves[]` (#589) lists every module-exported name whose declaring file changed while the name stayed exported (`onSurface` marks barrel names) — informational, never counted as breaking; the CLI says on stderr when `to` resolves to HEAD (#588: amending that commit orphans the manifest; the release order is tag first, then generate against the tag). `wire-changes/core@7.5.1.json` was regenerated against its tag with 16 informational move rows.
|
|
20
|
+
- `scripts/ship-post-lint.mjs`: a checksum label followed by one markdown backtick still labels the digest (the 7.5.1 post had hand-segmented its shasum to get past this leg).
|
|
21
|
+
- G5 phase-contract floor `KNOWN_INPUT_FIELDS` 371 → 667; unannotated-Input exceptions 4 → 1; receiving-side pins added for the context lane's `charsPerToken` wiring.
|
|
22
|
+
|
|
23
|
+
## 7.5.1 — 2026-09-06
|
|
24
|
+
|
|
25
|
+
Maintenance release: the design/390 runner decomposition (slices S0–S2), the post-7.5.0 gate repairs, and one summary hardening (#566). **No BREAKING change**: the export surface is byte-identical to 7.5.0 (export snapshot unchanged); the only observable delta is the label text of a wedged dispose on the prepare-throw path (below).
|
|
26
|
+
|
|
27
|
+
### Changed — design/390 S0–S2: `prepareTask` decomposed into phase modules (14 229 → 7 723 lines), one contract each
|
|
28
|
+
- 24 phase modules under `src/core/runner/prepare-*.ts`, each `prepareX(input: Input): Result` with every Input seat classified (owned / borrowed-readonly / borrowed-mutable + writer table / ownership-ref) and the driver reduced to one destructuring call per phase. Extracted verbatim: offload wrappers, execution-env (`OwnedEnvSeat`), file-history, run-refs, protocol-tools (MCP/A2A), question-face, LSP, project-context, prompt-inputs, defer-classify, listings, inherited-gate, caps-and-workflow, delegation-surface, tool-disclosure-mount, wiring-manifest; helpers `contracts.ts`, `workspace-path.ts`, `derived-route-fallback.ts`, `checkpoint-scope.ts`, `denial-limit-arms.ts`.
|
|
29
|
+
- **RollbackStack** (`rollback-stack.ts`): every resource acquired during prepare registers its disposer the moment it is acquired (env, MCP clients, A2A peers); a prepare throw unwinds them in reverse order, each bounded and reported, replacing the driver's explicit `if (handle) dispose` catch legs. The A2A registration keys on the acquisition decision read ONCE (a caller replacing `spec.a2a` during materialization can no longer unregister an acquired handle).
|
|
30
|
+
- **Disclosed delta**: a dispose that hangs past its budget on the prepare-throw path now reports leg `"<disposer> (rollback leg N of M, prepare-throw)"` (e.g. `mcpDispose (rollback leg 2 of 3, prepare-throw)`) instead of `"mcp.dispose (prepare-throw leg)"` / `"a2a.dispose (prepare-throw leg)"` / `"ownedEnv.destroy (prepare-throw leg)"`. Error class and budget unchanged; no test or consumer referenced the old text.
|
|
31
|
+
- Contract sentence `@contract prepare.deps-read-stable`: the host keeps `deps` / `internals` / `executionEnv` read-stable for the duration of `prepareTask`; an async phase returning a microtask later than the inlined code is within contract.
|
|
32
|
+
- Roster mutation owner table: which phase pushes/splices which tool under which condition is written once on `Prepared.tools` (contracts.ts), not scattered in prose.
|
|
33
|
+
- `isLiveApproverSeat` consumers (3) now read the one predicate in `tool-policy.ts`.
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
- #566 `CheckpointSummary.denialLimitFallback` is produced by `readDenialLimitFallback` (the same reader the park row and `AskRequest` use): exactly the four typed members when the row's value is well-formed, no key otherwise — a hand-edited or partial value is dropped, never echoed.
|
|
37
|
+
- Wire-change generator: inherited keys are keys the type HAS — `readTreeModel` folds an interface's `extends` / intersection bases, so moving members onto a base interface no longer reports a false "lost keys" BREAKING item (the two false items in `wire-changes/core@7.5.0.json` are left as published and noted there).
|
|
38
|
+
- `gate:message-branching` (the mcp.ts `transport.kind` fold's five sites are the ONE reader, exemption count corrected) and `gate:domain-lexicon` (UNC anchor test written with `isUncPath`) — two CI-only gates that had been red since the A-089 merge without the local chain running them.
|
|
39
|
+
- Two load-sensitive pins (#583) measure by best-of-three / a generous spawn timeout instead of a single wall-clock reading.
|
|
40
|
+
|
|
41
|
+
### Tooling / gates
|
|
42
|
+
- `node scripts/gate-all.mjs [--with-dist] [--rc]` runs the whole `gate:*` roster in one command; a `gate:*` script without a roster seat fails `test/gate-all-roster.test.ts` (the release chain's L3 line now points here).
|
|
43
|
+
- New gates: **G1** module line-count ratchet (`test/module-size-ratchet.test.ts`, banked per extraction), **G2** dependency-direction gate (`scripts/verify-layering.mjs` + `docs/LAYERING.json`, four layers: contracts ← prepare-path machinery ← phases ← orchestrator ← runtask; exemptions 13 → 3), **G5** phase-contract gate (`scripts/verify-phase-api.mjs`: every `prepare-*.ts` exports one Input/Result pair, every Input field classified; `KNOWN_INPUT_FIELDS` anti-blindness floor 371), `gate:agent-returns` (every archived car receipt's unresolved line carries a ticket / DEBTS id / DV / slice home).
|
|
44
|
+
- Release criteria: `retiredIn` annotation lets a historic criteria file name a face that a later version removed without rewriting history (`criteria-lint` accepts an absent face carrying the annotation).
|
|
45
|
+
- 16 runtime exports added in 7.5.0 registered in the consumer smoke probe; `test/prepare-lsp-ignore-filter.test.ts` pins the LSP tool's git-ignore wiring (a receiving-side mutation had left every LSP test green).
|
|
46
|
+
|
|
3
47
|
## 7.5.0 — 2026-09-05
|
|
4
48
|
|
|
5
49
|
**BREAKING release** (the 7.4.1 bug batch merged into it — one publish, one pickup). 13 exports removed, 5 public types lose keys, one store contract replaced whole; every item is named below with its replacement. Nothing here is a wire FRAME change: `TaskEvent`, `PendingAction`, `CheckpointSummary`, `WiringManifest` only GAIN keys.
|
package/dist/core/auto-mode.d.ts
CHANGED
|
@@ -169,6 +169,15 @@ export interface DenialLimitFallback extends DenialLimitCounts {
|
|
|
169
169
|
* which is a break with nothing behind it (the routing invariant constrains where a window is WRITTEN,
|
|
170
170
|
* never who may read one). */
|
|
171
171
|
export type DenialLimitFallbackFace = UnarmedDenialLimitFallback | DenialLimitFallback;
|
|
172
|
+
/**
|
|
173
|
+
* A stored or foreign value read back AS a fallback member, or `undefined` when it is not one: exactly
|
|
174
|
+
* the four members, each of the right kind (finite non-negative counts, the closed `limit` word, a
|
|
175
|
+
* finite non-negative window), nothing else carried. A deployment-written row (a checkpoint store is a
|
|
176
|
+
* host's) can hold any shape; the faces that echo it (the inbox summary) read through here, so a bad
|
|
177
|
+
* shape reads as ABSENT rather than reaching a consumer as a malformed card. Not a parser of intent —
|
|
178
|
+
* `"3"` is not 3.
|
|
179
|
+
*/
|
|
180
|
+
export declare function readDenialLimitFallback(v: unknown): DenialLimitFallback | undefined;
|
|
172
181
|
/** The window-less route's member, spelled in ONE place: every station that hands a fallback somewhere
|
|
173
182
|
* nothing can count down (a durable park row, a headless deny, a string `onAsk` seat, a member this
|
|
174
183
|
* run's tracker did not mint) passes through here rather than writing a `0` of its own. */
|
package/dist/core/auto-mode.js
CHANGED
|
@@ -99,6 +99,17 @@ class AutoModeTimeout extends Error {
|
|
|
99
99
|
super("auto-mode classify timeout");
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
|
+
export function readDenialLimitFallback(v) {
|
|
103
|
+
if (typeof v !== "object" || v === null)
|
|
104
|
+
return undefined;
|
|
105
|
+
const o = v;
|
|
106
|
+
const count = (x) => typeof x === "number" && Number.isFinite(x) && x >= 0;
|
|
107
|
+
if (!count(o["consecutive"]) || !count(o["total"]) || !count(o["autoDenyAfterMs"]))
|
|
108
|
+
return undefined;
|
|
109
|
+
if (o["limit"] !== "consecutive" && o["limit"] !== "total")
|
|
110
|
+
return undefined;
|
|
111
|
+
return { consecutive: o["consecutive"], total: o["total"], limit: o["limit"], autoDenyAfterMs: o["autoDenyAfterMs"] };
|
|
112
|
+
}
|
|
102
113
|
export function unarmedWindow(fallback) {
|
|
103
114
|
return { ...countsOf(fallback), autoDenyAfterMs: 0 };
|
|
104
115
|
}
|
|
@@ -2,6 +2,7 @@ import { randomBytes, randomUUID } from "node:crypto";
|
|
|
2
2
|
import { uuidv7 } from "../internal/harness.js";
|
|
3
3
|
import { PROBE_CAUSE_PATH_MAX, inlineUntrusted, sanitizeUntrustedText } from "./untrusted-text.js";
|
|
4
4
|
import { carriesBidiControls } from "./tool-policy.js";
|
|
5
|
+
import { readDenialLimitFallback } from "./auto-mode.js";
|
|
5
6
|
import { isAskOrigin } from "./ask-origin.js";
|
|
6
7
|
import { renderUntrustedCommandText, stripFormatCharacters } from "./permission-rule-model.js";
|
|
7
8
|
import { redactSecrets } from "./untrusted-egress.js";
|
|
@@ -264,7 +265,10 @@ export function summarizeCheckpoint(cp) {
|
|
|
264
265
|
...(tool?.preview !== undefined ? { preview: tool.preview } : {}),
|
|
265
266
|
...(tool?.previewWithheld === "oversize" || tool?.previewWithheld === "unavailable" ? { previewWithheld: tool.previewWithheld } : {}),
|
|
266
267
|
...(tool?.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
267
|
-
...(
|
|
268
|
+
...(() => {
|
|
269
|
+
const fb = readDenialLimitFallback(tool?.denialLimitFallback);
|
|
270
|
+
return fb !== undefined ? { denialLimitFallback: fb } : {};
|
|
271
|
+
})(),
|
|
268
272
|
...(tool !== undefined && isAskOrigin(tool.origin) ? { origin: tool.origin } : {}),
|
|
269
273
|
...(hasBidi ? { hasBidiControls: true } : {}),
|
|
270
274
|
};
|
|
@@ -75,6 +75,11 @@ export declare const A2A_NAMESPACE: ProtocolNamespace<typeof A2A_PREFIX_NAME>;
|
|
|
75
75
|
/** Every protocol namespace the engine knows. APPEND-ONLY: adding a protocol must not change how any
|
|
76
76
|
* existing name resolves — prefixes must stay pairwise non-overlapping (pinned in the table test). */
|
|
77
77
|
export declare const PROTOCOL_TABLE: readonly ProtocolNamespace[];
|
|
78
|
+
/** The namespaced-name shapes the protocol table currently owns, rendered for the two messages that have
|
|
79
|
+
* to name them (the caller-name reservation and the policy audit's unprefixed-name arm). Read from the
|
|
80
|
+
* table rather than written out: a message that hard-codes ONE protocol becomes wrong — while staying
|
|
81
|
+
* green — the moment a second one is appended, and both messages tell a deployment what to write. */
|
|
82
|
+
export declare const NAMESPACED_NAME_SHAPES: string;
|
|
78
83
|
/** The namespace owning `name`, or `undefined` for a caller/first-party tool. */
|
|
79
84
|
export declare function protocolOf(name: string): ProtocolNamespace | undefined;
|
|
80
85
|
export {};
|
|
@@ -37,6 +37,7 @@ const A2A_PREFIX_NAME = `a2a${NAME_SEP}`;
|
|
|
37
37
|
export const MCP_NAMESPACE = makeProtocolNamespace("mcp", MCP_PREFIX_NAME);
|
|
38
38
|
export const A2A_NAMESPACE = makeProtocolNamespace("a2a", A2A_PREFIX_NAME);
|
|
39
39
|
export const PROTOCOL_TABLE = [MCP_NAMESPACE, A2A_NAMESPACE];
|
|
40
|
+
export const NAMESPACED_NAME_SHAPES = PROTOCOL_TABLE.map((ns) => `${ns.prefix}<peer>__<tool>`).join(", ");
|
|
40
41
|
export function protocolOf(name) {
|
|
41
42
|
return PROTOCOL_TABLE.find((ns) => name.startsWith(ns.prefix));
|
|
42
43
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The abort-signal RACING vocabulary the park lane's synchronous-wait seats stand on — the per-call signal
|
|
3
|
+
* composition, the value-mapping race and the tagged three-state race — moved whole out of the orchestrator so
|
|
4
|
+
* the ask-lane phase (adjudicate / resolveAsk), the suspend-saga phase (the paused-VM compensation) and the
|
|
5
|
+
* park-ask phase (the content-ask delivery race, the projection re-adjudication, the fence) reach DOWN for the
|
|
6
|
+
* same three helpers instead of each carrying a copy. Pure: no engine state, no clock.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* design/384 slice 1 — the per-call signal composition all three synchronous-wait seats share
|
|
10
|
+
* (adjudicate / resolveAsk / resolveContentAsk): `AbortSignal.any([run, call])` when the gate
|
|
11
|
+
* threaded a per-call signal, the bare run signal otherwise (host-driven gates and unthreaded emits
|
|
12
|
+
* keep the historical binding byte for byte). The run signal is ALSO composed into the loop's turn
|
|
13
|
+
* controller, so the double source is a belt, not a dependency — this layer must not assume the
|
|
14
|
+
* loop's internal wiring. The composed product lives exactly as long as the one wait it bounds
|
|
15
|
+
* (both sources outlive it), so nothing here retains across calls.
|
|
16
|
+
*/
|
|
17
|
+
export declare function composeCallSignal(runSignal: AbortSignal, callSignal: AbortSignal | undefined): AbortSignal;
|
|
18
|
+
/** design/384 slice 2 — how a raced await ended. The generalized sibling of the ask-side
|
|
19
|
+
* `raceAskWaitAgainstSignal` (tool-policy.ts): same three-state form over any value domain.
|
|
20
|
+
* `aborted` means the SIGNAL settled the race — the promise may still be pending and stays the
|
|
21
|
+
* caller's to detach. `threw` reports the rejection AS a rejection, never folded into the abort
|
|
22
|
+
* arm: the value-mapping `raceAbort` below resolves `onAbort()` for a rejection too, which at a
|
|
23
|
+
* DECISION seat would disguise a real failure as a concession (and feed the concession value into
|
|
24
|
+
* whatever door consumes the raced result) — a decision seat must race with THIS form. */
|
|
25
|
+
export type RacedSettlement<T> = {
|
|
26
|
+
tag: "value";
|
|
27
|
+
value: T;
|
|
28
|
+
} | {
|
|
29
|
+
tag: "threw";
|
|
30
|
+
error: unknown;
|
|
31
|
+
} | {
|
|
32
|
+
tag: "aborted";
|
|
33
|
+
};
|
|
34
|
+
/** design/384 slice 2 — settle a raced await the moment `signal` aborts, WITHOUT waiting for the
|
|
35
|
+
* promise to notice. Pre-aborted entry answers at once; the listener is removed on settle
|
|
36
|
+
* whichever side wins (the `raceAbort` hygiene: `{once}` alone leaks a closure on the signal when
|
|
37
|
+
* the promise settles first). The mapped promise attaches BOTH handlers up front, so an abort-arm
|
|
38
|
+
* return never leaves an unhandled rejection behind. */
|
|
39
|
+
export declare function raceSettlementAgainstSignal<T>(p: Promise<T>, signal: AbortSignal): Promise<RacedSettlement<T>>;
|
|
40
|
+
/** Race a promise against an abort signal; on abort, resolve with `onAbort()`. Cleans up its listener. */
|
|
41
|
+
export declare function raceAbort<T>(p: Promise<T>, signal: AbortSignal, onAbort: () => T): Promise<T>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export function composeCallSignal(runSignal, callSignal) {
|
|
2
|
+
return callSignal !== undefined ? AbortSignal.any([runSignal, callSignal]) : runSignal;
|
|
3
|
+
}
|
|
4
|
+
export function raceSettlementAgainstSignal(p, signal) {
|
|
5
|
+
const settled = p.then((value) => ({ tag: "value", value }), (error) => ({ tag: "threw", error }));
|
|
6
|
+
if (signal.aborted)
|
|
7
|
+
return Promise.resolve({ tag: "aborted" });
|
|
8
|
+
return new Promise((resolve) => {
|
|
9
|
+
let done = false;
|
|
10
|
+
const finish = (r) => {
|
|
11
|
+
if (done)
|
|
12
|
+
return;
|
|
13
|
+
done = true;
|
|
14
|
+
signal.removeEventListener("abort", onAbortEvent);
|
|
15
|
+
resolve(r);
|
|
16
|
+
};
|
|
17
|
+
const onAbortEvent = () => finish({ tag: "aborted" });
|
|
18
|
+
signal.addEventListener("abort", onAbortEvent, { once: true });
|
|
19
|
+
void settled.then(finish);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function raceAbort(p, signal, onAbort) {
|
|
23
|
+
if (signal.aborted)
|
|
24
|
+
return Promise.resolve(onAbort());
|
|
25
|
+
return new Promise((resolve) => {
|
|
26
|
+
let settled = false;
|
|
27
|
+
const finish = (v) => {
|
|
28
|
+
if (settled)
|
|
29
|
+
return;
|
|
30
|
+
settled = true;
|
|
31
|
+
signal.removeEventListener("abort", onAbortEvent);
|
|
32
|
+
resolve(v);
|
|
33
|
+
};
|
|
34
|
+
const onAbortEvent = () => finish(onAbort());
|
|
35
|
+
signal.addEventListener("abort", onAbortEvent, { once: true });
|
|
36
|
+
p.then(finish, () => finish(onAbort()));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The durable-suspend checkpoint ROW-IDENTITY vocabulary — the default isolation scope, the ONE derivation of a row's
|
|
3
|
+
* scope, and the ONE reading of the placement fields' empty string — moved whole out of the orchestrator so the
|
|
4
|
+
* wiring-manifest phase (the synthesized durableApproval), the park-lane phases (the mint sites and the suspend stamp),
|
|
5
|
+
* the driver (the restore fold) and runtask (the resume rung) reach DOWN for the same names. Pure: a constant and two
|
|
6
|
+
* string functions.
|
|
7
|
+
*/
|
|
8
|
+
/** design/77 §4.4: the multi-tenant scope used when a durable suspend fires for an IRREVERSIBLE tool in an
|
|
9
|
+
* unattended deployment that did NOT opt into `durableApproval` (so there is no caller-supplied scope). The
|
|
10
|
+
* checkpoint carries this scope; resume reads it back from the checkpoint (`cp.scope`), so it is
|
|
11
|
+
* self-consistent without needing the original `TaskSpec`. Kept distinct from any tenant key to make an
|
|
12
|
+
* unattended irreversible suspend auditable as such. */
|
|
13
|
+
export declare const DEFAULT_IRREVERSIBLE_SCOPE = "irreversible";
|
|
14
|
+
/**
|
|
15
|
+
* design/153 §7.1 — the SINGLE derivation of a durable-suspend checkpoint's scope (both gate mint
|
|
16
|
+
* sites + the bg-watcher park lane's expire compensation/arbitration consume THIS; a re-derived copy
|
|
17
|
+
* that drifted was the exact bug the park tests caught — expire against the wrong scope silently
|
|
18
|
+
* no-ops). `|| DEFAULT` (not `??`): an EMPTY-string principal must not become a shared scope bucket.
|
|
19
|
+
*
|
|
20
|
+
* RB-75 (2026-07-25, red probe): that rule is stated twice in this file and was enforced on ONE of the two
|
|
21
|
+
* inputs — the principal half used `||`, the `durableApproval.scope` half used `??`, so an empty string
|
|
22
|
+
* arriving through the scope field (a config-centre / env lookup that came back blank is the realistic
|
|
23
|
+
* source) sailed through as the literal scope `""`. Two different tenants both landed in that one bucket,
|
|
24
|
+
* where `listByScope("")` reads BOTH their pending approvals — including each summary's `toolInput`
|
|
25
|
+
* preview of the raw arguments — and `reap("")` / `resolve(token, "")` act across both. `durableApproval.
|
|
26
|
+
* scope` is documented as "Multi-tenant isolation key … Required"; a blank string is the absence of an
|
|
27
|
+
* isolation key wearing its clothes, so both halves now fall through to the default isolation scope.
|
|
28
|
+
*/
|
|
29
|
+
export declare function checkpointScopeOf(spec: {
|
|
30
|
+
durableApproval?: {
|
|
31
|
+
scope?: string;
|
|
32
|
+
};
|
|
33
|
+
principal?: string;
|
|
34
|
+
}): string;
|
|
35
|
+
/**
|
|
36
|
+
* rescan C5 — the ONE spelling of the placement fields' empty-string discipline: `""` is absence
|
|
37
|
+
* wearing clothes (the resume entry's principal-rung posture), and every placement read that must
|
|
38
|
+
* treat it so — the resume rung's two sides (runtask), the restore fold's seed and the suspend
|
|
39
|
+
* stamp — goes through THIS helper, so three sites cannot drift into three readings. Deliberately
|
|
40
|
+
* NOT applied to the live `internals.placementRoot`/`rootSessionId` reads of the RESOLUTION fold:
|
|
41
|
+
* an empty supplied claim there is an assembly error the execution-env phase's `mintPlacementRootSessionId` refuses
|
|
42
|
+
* loudly on the factory path, and normalizing it away would silently repair what should be loud.
|
|
43
|
+
*/
|
|
44
|
+
export declare function placementValueOrAbsent(value: string | undefined): string | undefined;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const DEFAULT_IRREVERSIBLE_SCOPE = "irreversible";
|
|
2
|
+
export function checkpointScopeOf(spec) {
|
|
3
|
+
return spec.durableApproval?.scope || spec.principal || DEFAULT_IRREVERSIBLE_SCOPE;
|
|
4
|
+
}
|
|
5
|
+
export function placementValueOrAbsent(value) {
|
|
6
|
+
return value || undefined;
|
|
7
|
+
}
|
|
@@ -3,7 +3,7 @@ import type { MaybeCompactOptions } from "../auto-compaction.js";
|
|
|
3
3
|
import type { StaleToolResultOffloadOptions, TaskSpec } from "../types.js";
|
|
4
4
|
import type { Context } from "../../internal/llm.js";
|
|
5
5
|
import { type ToolResultStore } from "../tool-result-store.js";
|
|
6
|
-
import type { Prepared } from "./
|
|
6
|
+
import type { Prepared } from "./contracts.js";
|
|
7
7
|
/**
|
|
8
8
|
* REF-A2 (car R11) — the maybeCompact call arguments that MUST be assembled identically on all three
|
|
9
9
|
* of runtask's compaction lanes (turn boundary / prompt-too-long recovery / end-of-task).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The content-ask BINDING vocabulary: the leak bound the routing lane checks against and the one entry shape the
|
|
3
|
+
* binding table holds. It lived in the question-face phase (which mints the table) while the routing lane was still
|
|
4
|
+
* orchestrator code; the lane is a phase now, and a phase reaching SIDEWAYS into a sibling for a constant and a type
|
|
5
|
+
* is the wrong reading — both phases reach DOWN for them here.
|
|
6
|
+
*/
|
|
7
|
+
import type { QuestionAnswer } from "../ask-question.js";
|
|
8
|
+
export declare const CONTENT_ASK_BINDING_CAP = 32;
|
|
9
|
+
/** One gate-routed content-ask outcome, keyed by the call id it was produced for (see the table's own note). */
|
|
10
|
+
export type ContentAskBinding = ({
|
|
11
|
+
kind: "answered";
|
|
12
|
+
answer: QuestionAnswer;
|
|
13
|
+
} | {
|
|
14
|
+
kind: "failed";
|
|
15
|
+
error: unknown;
|
|
16
|
+
}) & {
|
|
17
|
+
/** Digest of the exact question batch this outcome belongs to. The call id alone is not enough
|
|
18
|
+
* to redeem a binding: it comes from the model/provider and can repeat, so an entry that
|
|
19
|
+
* outlived its call (its call was allowed but never executed) could otherwise be handed to a
|
|
20
|
+
* LATER call that happens to reuse the id. Matching on the batch as well means an outcome can
|
|
21
|
+
* only ever be delivered for the question it was produced for. */
|
|
22
|
+
questionsHash: string;
|
|
23
|
+
/** The engine-minted per-delivery identity (see AskQuestionRequest.deliveryId) — carried so a
|
|
24
|
+
* stranded-answer disclosure names DELIVERIES, not call ids: call ids can repeat, and a
|
|
25
|
+
* disclosure keyed on them would collapse two lost answers into one. */
|
|
26
|
+
deliveryId: string;
|
|
27
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const CONTENT_ASK_BINDING_CAP = 32;
|