@sema-agent/core 5.44.0 → 5.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/dist/agents/subagent.d.ts +3 -1
- package/dist/brain/reasoning.d.ts +50 -4
- package/dist/brain/reasoning.js +28 -7
- package/dist/brain/request-params.d.ts +0 -12
- package/dist/brain/request-params.js +1 -1
- package/dist/core/governance-codes.js +1 -0
- package/dist/core/memory-engine/content-origin.d.ts +6 -3
- package/dist/core/memory-engine/delegation-provenance.d.ts +12 -7
- package/dist/core/runner/assemble-result.d.ts +5 -0
- package/dist/core/runner/assemble-result.js +1 -1
- package/dist/core/runner/prepare-config-doors.d.ts +6 -0
- package/dist/core/runner/prepare-config-doors.js +17 -0
- package/dist/core/runner/prepare-task.d.ts +3 -1
- package/dist/core/runner/prepare-task.js +25 -3
- package/dist/core/runner/runtask.js +20 -17
- package/dist/core/trace.d.ts +17 -2
- package/dist/core/types.d.ts +72 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.45.0 — 2026-08-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `RunnerDeps.memoryDelegationEvidence?: "static-face" | "attested-only"` (design/324, ruling-1
|
|
7
|
+
stopgap): the deployment's evidence standard for delegation-driven memory pollution.
|
|
8
|
+
`"attested-only"` retires ONLY the static capability-face mark (the "a child COULD reach
|
|
9
|
+
external content" over-approximation); the attestation-observed mark (`att === "external"`),
|
|
10
|
+
the chain's `incomplete` honesty, `recordExternal`, non-delegation classification and the
|
|
11
|
+
pre-call direct-class mark all stay. Key absent ≡ `"static-face"` ≡ byte-identical behavior.
|
|
12
|
+
A malformed value is refused loudly (`config.memory_delegation_evidence`, exact-spelling gate).
|
|
13
|
+
ACCEPTED COST (the deployment's to own): with `"attested-only"`, a BACKGROUND child's real
|
|
14
|
+
external contact does not mark this session — its content re-enters via TaskOutput /
|
|
15
|
+
task-notification / AgentTranscript, none of which carries an attestation.
|
|
16
|
+
- `memory.delegation_static_mark_waived` EngineNotice — mandatory companion: minted at most once
|
|
17
|
+
per prepared leg when the knob actually waives a static-face mark on a pollution-armed chain
|
|
18
|
+
(`detail: {subagentType?, sessionId?}`; reason carries the waived mark's own sentence, bounded).
|
|
19
|
+
- `TaskResult.effectiveReasoning?: ResolvedReasoning` (#327b): the leg's effective reasoning
|
|
20
|
+
resolution echoed on the result — same object the `reasoning.resolved` trace event carries
|
|
21
|
+
(two faces, one mint); rides the backstop/`resume.tool_unavailable` carrier like its
|
|
22
|
+
precedents. `ReasoningFormat` gains `"responses"` (dispatched by api family, single-source
|
|
23
|
+
`RESPONSES_APIS`).
|
|
24
|
+
- Cross-session recall pins (#260 verdict: engine clean): the consumer contract is pinned —
|
|
25
|
+
the model's final answer text exists BEFORE the terminal harvest commits, `TaskStream.result()`
|
|
26
|
+
is the commit boundary, and a consumer that prints the answer and kills the worker without
|
|
27
|
+
awaiting `result()` strands the entry id-less on disk (the incident's exact evidence shape).
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- The reasoning resolver mirrors `thinkingLevelMap`'s null arm (5.45 rescan): a clamped tier the
|
|
31
|
+
model maps to `null` is reported tier-not-honored (`graded:false`, intent echo) — matching what
|
|
32
|
+
the wire appliers actually send (nothing) instead of claiming "honored exactly"; the r3/r4
|
|
33
|
+
mirror comment now names all three arms. `resolveEffort` reads a malformed non-array
|
|
34
|
+
`reasoningEffortLevels` as undeclared (member-level filtering: garbage/sparse/"off" entries can
|
|
35
|
+
no longer become clamp targets) — a catalog typo no longer fails the whole thinking-on leg with
|
|
36
|
+
a raw TypeError (5.44.0 regression window closed before release).
|
|
37
|
+
- The #260 pins tell the bounded-teardown truth: `result()` settles after the harvest LEG settled
|
|
38
|
+
(committed, or its 15s timeout REPORTED — never silent), the discriminative arm polls 50 ticks
|
|
39
|
+
(the abandon arm sat inside the old 1-tick slack), and the incident-scale argument is stated.
|
|
40
|
+
- `reasoning.resolved` now fires a LOUD DROP frame (`dropped: true`, `effective: "off"`) on
|
|
41
|
+
models whose `Model.reasoning` is falsy — a user-requested effort tier no longer evaporates
|
|
42
|
+
silently (#325). The public `resolveReasoning` reports the drop arm for such models; the
|
|
43
|
+
capable arm is byte-identical. The capability predicate is truthiness (matching every adapter),
|
|
44
|
+
and `supportsReasoningEffort === false` mirrors the ungraded intent-only arm.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
- The two 5.44.0 pollution notices are DISPOSITIONED in the governance registry and the
|
|
48
|
+
error-surface cap vocabulary gained `inlineUntrusted`/`pollutionSentence` (both bounded by
|
|
49
|
+
contract) — landed as gate-family debts caught by the full-suite leg.
|
|
50
|
+
|
|
51
|
+
### Notes
|
|
52
|
+
- Commit `2f78edb7` (the delegation-evidence knob) carries the `TaskResult.effectiveReasoning`
|
|
53
|
+
declaration hunk of the parallel effort car (shared-checkout staging race; HEAD is consistent).
|
|
54
|
+
Do not cherry-pick that commit alone.
|
|
55
|
+
|
|
3
56
|
## 5.44.0 — 2026-08-19
|
|
4
57
|
|
|
5
58
|
### Added
|
|
@@ -297,7 +297,9 @@ export declare function completedAgentCard(child: {
|
|
|
297
297
|
* recorder aggregate at delivery. Present only when the parent chain armed the recorder; the
|
|
298
298
|
* parent-side judgment (the content-origin wrap) reads it off this card — `clean` retires the
|
|
299
299
|
* static face verdict for this call, `external` marks with the observed-event reason, `unknown`
|
|
300
|
-
* (or absence) keeps the static floor
|
|
300
|
+
* (or absence) keeps the static floor, whose mark action follows the parent run's deployment
|
|
301
|
+
* evidence standard (design/324, `RunnerDeps.memoryDelegationEvidence`). Deliberate whitelist
|
|
302
|
+
* admission (see the boundary note). */
|
|
301
303
|
attestation?: import("../core/memory-engine/delegation-provenance.js").DelegationAttestation;
|
|
302
304
|
}): Record<string, unknown>;
|
|
303
305
|
/**
|
|
@@ -34,7 +34,20 @@ export type ReasoningFormat = "openai" | "openrouter" | "deepseek" | "together"
|
|
|
34
34
|
/** Anthropic `output_config.effort` (CC 2.1.198 / Fable-5 class, design/119): the tier is a named
|
|
35
35
|
* effort string, clamped to `compat.effortLevels` — the anthropic-side twin of the OpenAI
|
|
36
36
|
* `reasoning_effort` path (thinking FORM is `thinkingMode`; effort carries the intensity). */
|
|
37
|
-
| "effort"
|
|
37
|
+
| "effort"
|
|
38
|
+
/** OpenAI Responses API (`openai-responses` / `azure-openai-responses`, design/163): the tier rides
|
|
39
|
+
* the NESTED `reasoning: { effort }` request field (open-responses.ts `resolveWireEffort`), clamped
|
|
40
|
+
* by the same {@link resolveEffort} against `compat.reasoningEffortLevels` — NOT the completions
|
|
41
|
+
* top-level `reasoning_effort` the `"openai"` tag names. #325 review r3: before this member the
|
|
42
|
+
* resolver fell through to the completions default and labeled Responses resolutions `"openai"`. */
|
|
43
|
+
| "responses";
|
|
44
|
+
/**
|
|
45
|
+
* The Open Responses API family — every `Api` value `createOpenResponsesBrain` serves (design/163).
|
|
46
|
+
* The SINGLE family discriminant: request-params.ts (reserved-key set selection) and
|
|
47
|
+
* {@link resolveReasoning} (format dispatch, #325 review r4) both key off THIS set, so a new
|
|
48
|
+
* Responses api value added here reaches every family-scoped behavior instead of one of two twins.
|
|
49
|
+
*/
|
|
50
|
+
export declare const RESPONSES_APIS: ReadonlySet<string>;
|
|
38
51
|
/** How a requested intensity resolved against one endpoint's real capability. */
|
|
39
52
|
export interface ReasoningResolution {
|
|
40
53
|
/** The level the caller asked for. */
|
|
@@ -43,9 +56,10 @@ export interface ReasoningResolution {
|
|
|
43
56
|
effective: ThinkingLevel;
|
|
44
57
|
/**
|
|
45
58
|
* True when the endpoint varies behavior by intensity (effort tiers / token budget). False = binary
|
|
46
|
-
* enable-only (qwen / zai / qwen-chat-template,
|
|
47
|
-
* `supportsReasoningEffort:false
|
|
48
|
-
*
|
|
59
|
+
* enable-only (qwen / zai / qwen-chat-template, an effort endpoint that declares
|
|
60
|
+
* `supportsReasoningEffort:false`, or a tier `Model.thinkingLevelMap` maps to `null` — the wire then
|
|
61
|
+
* carries NO effort value for it): thinking is on or off and the tier is NOT honored — read this
|
|
62
|
+
* alongside {@link effective}, which then echoes the request as intent only.
|
|
49
63
|
*/
|
|
50
64
|
graded: boolean;
|
|
51
65
|
/** True when {@link effective} differs from {@link requested} (the request couldn't be honored exactly). */
|
|
@@ -62,6 +76,23 @@ export interface ResolvedReasoning extends ReasoningResolution {
|
|
|
62
76
|
format: ReasoningFormat;
|
|
63
77
|
/** A coarse endpoint label for the trace (`model.api` — e.g. `openai-completions`, `anthropic-messages`). */
|
|
64
78
|
endpoint: string;
|
|
79
|
+
/**
|
|
80
|
+
* Present (true) only when the model declares NO reasoning capability (`Model.reasoning` falsy): every
|
|
81
|
+
* brain early-returns on that flag (openai.ts applyThinking / anthropic.ts / open-responses.ts
|
|
82
|
+
* resolveWireEffort), so NO thinking
|
|
83
|
+
* parameter reaches the wire at all — the requested tier is DROPPED entirely, not clamped or
|
|
84
|
+
* downgraded-to-binary. `effective:"off"` here states the ENGINE side of that fact (nothing was
|
|
85
|
+
* requested), NOT a measured gateway state: on the binary enable-only formats (qwen / zai /
|
|
86
|
+
* qwen-chat-template) parameter ABSENCE is provider-default, and a default-on gateway may still
|
|
87
|
+
* reason at its own tier — the brains deliberately send no disable key for a model declared
|
|
88
|
+
* non-reasoning, so the engine cannot claim a measured off there; `format` tells a consumer which
|
|
89
|
+
* family applies (on every other format, absence is the closest the wire has to off — see
|
|
90
|
+
* applyThinking's own contract). `format`/`endpoint` report the family that WOULD have carried the
|
|
91
|
+
* tier (the why-shape a consumer diagnoses with, not a claim about the request). Absent on every
|
|
92
|
+
* reasoning-capable resolution, so existing consumers see byte-identical objects. Loud-bad-values
|
|
93
|
+
* rule: the one arm where the request evaporates must not be the one arm with no report.
|
|
94
|
+
*/
|
|
95
|
+
dropped?: true;
|
|
65
96
|
}
|
|
66
97
|
/**
|
|
67
98
|
* Resolve a requested intensity against a model END-TO-END, dispatching on its wire format the SAME way the
|
|
@@ -74,6 +105,17 @@ export interface ResolvedReasoning extends ReasoningResolution {
|
|
|
74
105
|
* - Binary enable-only formats (qwen / zai / qwen-chat-template) → `graded:false` (tier not honored).
|
|
75
106
|
* - An effort endpoint with `supportsReasoningEffort:false` → `graded:false` (enable key only, no effort tier).
|
|
76
107
|
* - Otherwise effort-based → clamp DOWN to the endpoint's `reasoningEffortLevels` (default minimal|low|medium|high).
|
|
108
|
+
* - A CLAMPED tier that `model.thinkingLevelMap` maps to `null` (declared unsupported on this model) →
|
|
109
|
+
* `graded:false`: both effort-wire appliers key the map by the post-clamp tier and then carry NO effort
|
|
110
|
+
* value (thinking still enables via the format's own enable key where one exists), so the tier is not
|
|
111
|
+
* honored. Previously this resolver never read the map and reported such a request as exactly honored
|
|
112
|
+
* (`graded:true`, `clamped:false`) while the wire dropped the value — trace/result-face drift.
|
|
113
|
+
*
|
|
114
|
+
* - A model whose `reasoning` capability flag is FALSY drops the request ENTIRELY (neither brain emits any
|
|
115
|
+
* thinking parameter, whatever the format) → `effective:"off"`, `graded:false`, `clamped:true`,
|
|
116
|
+
* `dropped:true` — the loud-drop arm. Previously this resolver described the capability dispatch for such
|
|
117
|
+
* a model (a resolution the request never carried), and the runner's trace guard skipped the frame — the
|
|
118
|
+
* one arm where the request evaporates was the one arm with no disclosure.
|
|
77
119
|
*
|
|
78
120
|
* `off`/falsy never enables thinking, so it resolves trivially (no clamp, graded:true) — the caller decides
|
|
79
121
|
* whether to emit at all.
|
|
@@ -82,12 +124,16 @@ export declare function resolveReasoning(requested: ThinkingLevel, model: {
|
|
|
82
124
|
api?: string;
|
|
83
125
|
reasoning?: boolean;
|
|
84
126
|
compat?: unknown;
|
|
127
|
+
thinkingLevelMap?: Readonly<Partial<Record<ThinkingLevel, string | null>>>;
|
|
85
128
|
}): ResolvedReasoning;
|
|
86
129
|
/**
|
|
87
130
|
* Resolve a requested intensity for an effort-based endpoint (`reasoning_effort` / `reasoning.effort`). Picks
|
|
88
131
|
* the requested tier when supported; otherwise the highest supported tier ≤ requested (clamp DOWN, never
|
|
89
132
|
* silently up); if none is ≤ requested (the endpoint's set is entirely higher — unusual), the lowest supported
|
|
90
133
|
* tier. Never returns a value outside `allowed`, so the brain can't emit a tier the endpoint would 422.
|
|
134
|
+
* A malformed `allowed` reads as UNDECLARED → the conservative default set (non-array, empty, or no
|
|
135
|
+
* valid member); individually invalid MEMBERS (garbage strings, sparse holes, `"off"` — not a legal
|
|
136
|
+
* member of the 6-tier compat effort sets) are dropped, so they can never become a clamp target.
|
|
91
137
|
*/
|
|
92
138
|
export declare function resolveEffort(requested: ThinkingLevel, allowed?: readonly ThinkingLevel[]): ReasoningResolution;
|
|
93
139
|
/**
|
package/dist/brain/reasoning.js
CHANGED
|
@@ -15,7 +15,18 @@ export function rankOf(level) {
|
|
|
15
15
|
}
|
|
16
16
|
export const DEFAULT_EFFORT_LEVELS = ["minimal", "low", "medium", "high"];
|
|
17
17
|
const BINARY_FORMATS = new Set(["qwen", "zai", "qwen-chat-template"]);
|
|
18
|
+
export const RESPONSES_APIS = new Set(["openai-responses", "azure-openai-responses", "openai-chatgpt-responses"]);
|
|
18
19
|
export function resolveReasoning(requested, model) {
|
|
20
|
+
const resolved = dispatchReasoning(requested, model);
|
|
21
|
+
if (requested !== "off" && !model.reasoning) {
|
|
22
|
+
return { requested, effective: "off", graded: false, clamped: true, format: resolved.format, endpoint: resolved.endpoint, dropped: true };
|
|
23
|
+
}
|
|
24
|
+
return resolved;
|
|
25
|
+
}
|
|
26
|
+
function effortTierUnmapped(requested, effective, model) {
|
|
27
|
+
return requested !== "off" && model.thinkingLevelMap?.[effective] === null;
|
|
28
|
+
}
|
|
29
|
+
function dispatchReasoning(requested, model) {
|
|
19
30
|
const endpoint = model.api ?? "unknown";
|
|
20
31
|
const compat = (model.compat ?? {});
|
|
21
32
|
if (model.api === "anthropic-messages") {
|
|
@@ -24,6 +35,16 @@ export function resolveReasoning(requested, model) {
|
|
|
24
35
|
}
|
|
25
36
|
return { requested, effective: requested, graded: true, clamped: false, format: "budget", endpoint };
|
|
26
37
|
}
|
|
38
|
+
if (model.api !== undefined && RESPONSES_APIS.has(model.api)) {
|
|
39
|
+
if (compat.supportsReasoningEffort === false) {
|
|
40
|
+
return { requested, effective: requested, graded: false, clamped: false, format: "responses", endpoint };
|
|
41
|
+
}
|
|
42
|
+
const responsesResolved = resolveEffort(requested, compat.reasoningEffortLevels ?? DEFAULT_EFFORT_LEVELS);
|
|
43
|
+
if (effortTierUnmapped(requested, responsesResolved.effective, model)) {
|
|
44
|
+
return { requested, effective: requested, graded: false, clamped: false, format: "responses", endpoint };
|
|
45
|
+
}
|
|
46
|
+
return { ...responsesResolved, format: "responses", endpoint };
|
|
47
|
+
}
|
|
27
48
|
const format = compat.thinkingFormat ?? "openai";
|
|
28
49
|
if (BINARY_FORMATS.has(format)) {
|
|
29
50
|
return { ...resolveBinary(requested), format, endpoint };
|
|
@@ -32,15 +53,15 @@ export function resolveReasoning(requested, model) {
|
|
|
32
53
|
if (!supportsEffort && format !== "openrouter") {
|
|
33
54
|
return { requested, effective: requested, graded: false, clamped: false, format, endpoint };
|
|
34
55
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
format,
|
|
38
|
-
|
|
39
|
-
};
|
|
56
|
+
const resolved = resolveEffort(requested, compat.reasoningEffortLevels ?? DEFAULT_EFFORT_LEVELS);
|
|
57
|
+
if (effortTierUnmapped(requested, resolved.effective, model)) {
|
|
58
|
+
return { requested, effective: requested, graded: false, clamped: false, format, endpoint };
|
|
59
|
+
}
|
|
60
|
+
return { ...resolved, format, endpoint };
|
|
40
61
|
}
|
|
41
62
|
export function resolveEffort(requested, allowed = DEFAULT_EFFORT_LEVELS) {
|
|
42
|
-
|
|
43
|
-
|
|
63
|
+
const declared = Array.isArray(allowed) ? allowed.filter((lvl) => isThinkingLevel(lvl) && lvl !== "off") : [];
|
|
64
|
+
allowed = declared.length > 0 ? declared : DEFAULT_EFFORT_LEVELS;
|
|
44
65
|
if (requested === "off" || allowed.includes(requested)) {
|
|
45
66
|
return { requested, effective: requested, graded: true, clamped: false };
|
|
46
67
|
}
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Request-parameter passthrough (design/40). A deployment can set official provider params it wants but
|
|
3
|
-
* core doesn't model as first-class fields (OpenAI `frequency_penalty`/`presence_penalty`/`top_p`/`seed`/
|
|
4
|
-
* `logit_bias`; Anthropic `top_k`/`top_p`/`stop_sequences`; …) via `Model.extraBody`, and core merges them
|
|
5
|
-
* into the brain's request body. Anchored at the **Model** level (not per-turn) so the serialized body
|
|
6
|
-
* stays byte-stable across turns → the prefix cache holds (design/9/31).
|
|
7
|
-
*
|
|
8
|
-
* Symmetric: each brain owns its structural + tuning keys (`reserved`) and ALWAYS wins — `extraBody` can
|
|
9
|
-
* only supply the long tail, never clobber `messages`/`tools`/`temperature`/etc. Stripping is the safety
|
|
10
|
-
* enforcement (the brains are standalone-usable); `prepareTask` separately warns on a collision (it has
|
|
11
|
-
* `onError`, the brain doesn't — council design/40).
|
|
12
|
-
*/
|
|
13
1
|
/** OpenAI request-body keys core owns; `extraBody` cannot override these. */
|
|
14
2
|
export declare const OPENAI_RESERVED: ReadonlySet<string>;
|
|
15
3
|
/** Anthropic request-body keys core owns; `extraBody` cannot override these. (Note the asymmetry vs
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RESPONSES_APIS } from "./reasoning.js";
|
|
1
2
|
export const OPENAI_RESERVED = new Set([
|
|
2
3
|
"model",
|
|
3
4
|
"messages",
|
|
@@ -38,7 +39,6 @@ export const RESPONSES_RESERVED = new Set([
|
|
|
38
39
|
"previous_response_id",
|
|
39
40
|
"conversation",
|
|
40
41
|
]);
|
|
41
|
-
const RESPONSES_APIS = new Set(["openai-responses", "azure-openai-responses", "openai-chatgpt-responses"]);
|
|
42
42
|
export function reservedFor(api) {
|
|
43
43
|
if (RESPONSES_APIS.has(api))
|
|
44
44
|
return RESPONSES_RESERVED;
|
|
@@ -16,6 +16,7 @@ export const NON_GOVERNANCE_MEMORY_CODES = new Set([
|
|
|
16
16
|
"memory.pollution_mark_failed",
|
|
17
17
|
"memory.session_polluted",
|
|
18
18
|
"memory.harvest_quarantined",
|
|
19
|
+
"memory.delegation_static_mark_waived",
|
|
19
20
|
"memory.challenge_sweep_failed",
|
|
20
21
|
"memory.lineage_settle_failed",
|
|
21
22
|
"memory.challenge_ledger_corrupt",
|
|
@@ -66,9 +66,12 @@ export interface AgentPoolTool {
|
|
|
66
66
|
* A child that can reach a network or protocol tool returns content from outside the trust boundary
|
|
67
67
|
* just as surely as calling that tool in this session would, and the parent's transcript is where it
|
|
68
68
|
* lands. The judgment is STATIC — the child's face is known from its definition before the call — so
|
|
69
|
-
* nothing here tracks what the child actually did (runtime provenance is
|
|
70
|
-
* it conservative in the safe direction: a child that COULD reach external content counts as
|
|
71
|
-
* done so.
|
|
69
|
+
* nothing here tracks what the child actually did (runtime provenance is design/180 half A). That
|
|
70
|
+
* makes it conservative in the safe direction: a child that COULD reach external content counts as
|
|
71
|
+
* having done so. Whether this verdict MARKS the judging session's memory when no attestation
|
|
72
|
+
* arrives is the deployment's evidence standard (design/324,
|
|
73
|
+
* `RunnerDeps.memoryDelegationEvidence`) — the classification itself is value-independent, and the
|
|
74
|
+
* wrap computes it on every standard (the waiver announcement keys on it).
|
|
72
75
|
*
|
|
73
76
|
* `pool` is the CHILD'S pool, not the parent's roster: a delegation tool carries its own tool set, and
|
|
74
77
|
* the two are explicitly allowed to differ — a parent mounting nothing but the delegation tool can
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* design/180 half A — delegation RUNTIME provenance: the three-value attestation and its monotonic
|
|
3
3
|
* aggregate. The static tool-face judgment ({@link import("./content-origin.js").delegationCallIsExternal})
|
|
4
|
-
* stays the
|
|
5
|
-
* clean proof is in hand; any evidence gap falls back to the floor. "We could not
|
|
6
|
-
* and "it is clean" are different answers — replacing the floor outright would fail
|
|
7
|
-
* evidence gap (old child vintages, crashes, un-armed sessions).
|
|
4
|
+
* stays the FLOOR of the attestation reduction: runtime evidence may only retire the static verdict
|
|
5
|
+
* when a COMPLETE clean proof is in hand; any evidence gap falls back to the floor. "We could not
|
|
6
|
+
* prove it clean" and "it is clean" are different answers — replacing the floor outright would fail
|
|
7
|
+
* OPEN on every evidence gap (old child vintages, crashes, un-armed sessions). Whether the floor's
|
|
8
|
+
* verdict MARKS the judging session's memory is a separate, deployment-governed question
|
|
9
|
+
* (design/324, `RunnerDeps.memoryDelegationEvidence`): the reduction semantics here never change
|
|
10
|
+
* with that key — only the mark action at the judging run's wrap does.
|
|
8
11
|
*
|
|
9
12
|
* The aggregate is two MONOTONIC bits plus versioning:
|
|
10
13
|
* - `sawExternal` — an actually-observed polluting-class invocation (own recorder, or a delivered
|
|
@@ -17,8 +20,9 @@
|
|
|
17
20
|
* "clean" unprovable; it can never make an observed event disappear).
|
|
18
21
|
*/
|
|
19
22
|
/** The three-value delegation attestation. Only `clean` changes behavior (the parent skips the
|
|
20
|
-
* static mark); `unknown` is byte-equivalent to absence (static floor governs
|
|
21
|
-
*
|
|
23
|
+
* static mark); `unknown` is byte-equivalent to absence (the static floor governs — its mark
|
|
24
|
+
* action subject to the judging run's deployment evidence standard, design/324); `external` marks
|
|
25
|
+
* unconditionally on every evidence standard, with the observed-event reason. */
|
|
22
26
|
export type DelegationAttestation = "clean" | "external" | "unknown";
|
|
23
27
|
/** The monotonic per-run provenance aggregate (in-process this slice; the durable-checkpoint
|
|
24
28
|
* persistence leg rides the background-face slice — absence after a resume reads `incomplete`,
|
|
@@ -58,5 +62,6 @@ export declare function reduceDelegationAttestation(agg: DelegationProvenanceAgg
|
|
|
58
62
|
completed: boolean;
|
|
59
63
|
}): DelegationAttestation;
|
|
60
64
|
/** Read a delivered card's attestation field (the explicit-whitelist handback seat). Anything but
|
|
61
|
-
* the three spellings — including absence — reads as undefined, i.e. the static floor governs
|
|
65
|
+
* the three spellings — including absence — reads as undefined, i.e. the static floor governs
|
|
66
|
+
* (whether that floor MARKS is the judging run's deployment evidence standard, design/324). */
|
|
62
67
|
export declare function readCardAttestation(details: unknown): DelegationAttestation | undefined;
|
|
@@ -133,6 +133,11 @@ export interface ResultFlags {
|
|
|
133
133
|
* read-posture seats above: present iff prepare completed (the memory-less states are their own
|
|
134
134
|
* values — absence means only "prepare never ran to completion"). */
|
|
135
135
|
effectiveMemoryScopes?: TaskResult["effectiveMemoryScopes"];
|
|
136
|
+
/** #327 — the leg's effective reasoning resolution, echoed on `TaskResult.effectiveReasoning`.
|
|
137
|
+
* Pure pass-through on every terminal (same law as the read-posture seats): the SAME object the
|
|
138
|
+
* `reasoning.resolved` trace frame carried (runtask resolves once per leg — two faces, one mint);
|
|
139
|
+
* absent when thinking was off/unset for the leg, so the key is omitted. */
|
|
140
|
+
effectiveReasoning?: TaskResult["effectiveReasoning"];
|
|
136
141
|
/** ruled 2026-08-04 — the usage-governance wait hint carried by the platform terminal the run adopted
|
|
137
142
|
* (`undefined` for every other cause: an expiring environment has no return time to give, and a store
|
|
138
143
|
* failure is not a window). Passed as data rather than read back off `threw` so the seat has a typed
|
|
@@ -165,5 +165,5 @@ export function assembleResult(spec, sessionId, final, stats, flags) {
|
|
|
165
165
|
void _internalCompaction;
|
|
166
166
|
if (flags.unpricedSpend)
|
|
167
167
|
delete publicStats.costMicroUsd;
|
|
168
|
-
return { taskId, sessionId, status, ...(flags.model !== undefined ? { model: flags.model } : {}), result: result.trim(), salvagedOutput, blockedReason, errorMessage, errorCode, ...(retryAfterMs !== undefined ? { retryAfterMs } : {}), checkpointToken, ...(checkpointId !== undefined ? { checkpointId } : {}), checkpointGate, ...(workspaceRestoreMode !== undefined ? { workspaceRestoreMode } : {}), ...(flags.rewindNotes !== undefined && flags.rewindNotes.length > 0 ? { rewindNotes: flags.rewindNotes } : {}), ...(flags.remoteEnvFailures !== undefined && flags.remoteEnvFailures.length > 0 ? { remoteEnvFailures: flags.remoteEnvFailures } : {}), ...(flags.strandedHumanAnswers !== undefined && flags.strandedHumanAnswers.length > 0 ? { strandedHumanAnswers: flags.strandedHumanAnswers } : {}), ...(flags.effectiveReadFace !== undefined ? { effectiveReadFace: flags.effectiveReadFace } : {}), ...(flags.effectiveReadDenyPatterns !== undefined && flags.effectiveReadDenyPatterns.length > 0 ? { effectiveReadDenyPatterns: flags.effectiveReadDenyPatterns } : {}), ...(flags.effectiveMemoryScopes !== undefined ? { effectiveMemoryScopes: flags.effectiveMemoryScopes } : {}), stats: publicStats };
|
|
168
|
+
return { taskId, sessionId, status, ...(flags.model !== undefined ? { model: flags.model } : {}), result: result.trim(), salvagedOutput, blockedReason, errorMessage, errorCode, ...(retryAfterMs !== undefined ? { retryAfterMs } : {}), checkpointToken, ...(checkpointId !== undefined ? { checkpointId } : {}), checkpointGate, ...(workspaceRestoreMode !== undefined ? { workspaceRestoreMode } : {}), ...(flags.rewindNotes !== undefined && flags.rewindNotes.length > 0 ? { rewindNotes: flags.rewindNotes } : {}), ...(flags.remoteEnvFailures !== undefined && flags.remoteEnvFailures.length > 0 ? { remoteEnvFailures: flags.remoteEnvFailures } : {}), ...(flags.strandedHumanAnswers !== undefined && flags.strandedHumanAnswers.length > 0 ? { strandedHumanAnswers: flags.strandedHumanAnswers } : {}), ...(flags.effectiveReadFace !== undefined ? { effectiveReadFace: flags.effectiveReadFace } : {}), ...(flags.effectiveReadDenyPatterns !== undefined && flags.effectiveReadDenyPatterns.length > 0 ? { effectiveReadDenyPatterns: flags.effectiveReadDenyPatterns } : {}), ...(flags.effectiveMemoryScopes !== undefined ? { effectiveMemoryScopes: flags.effectiveMemoryScopes } : {}), ...(flags.effectiveReasoning !== undefined ? { effectiveReasoning: flags.effectiveReasoning } : {}), stats: publicStats };
|
|
169
169
|
}
|
|
@@ -144,6 +144,12 @@ export interface PrepareConfigDoorsResult {
|
|
|
144
144
|
* material; the in-force arm never lands here — it throws at the door). */
|
|
145
145
|
discardedEnvRaw: string | undefined;
|
|
146
146
|
};
|
|
147
|
+
/** owned — the NORMALIZED per-leg delegation-evidence standard (design/324): the deps seat read
|
|
148
|
+
* ONCE, in this synchronous pre-await stretch, screened, and absent folded to the "static-face"
|
|
149
|
+
* default. The delegation wrap consumes THIS value, never the live deps object — a deps seat
|
|
150
|
+
* mutated (or getter-backed) after the door must not present an unscreened value to the mark
|
|
151
|
+
* branch (the #245 5.33 read-once posture). */
|
|
152
|
+
memoryDelegationEvidence: "static-face" | "attested-only";
|
|
147
153
|
/** owned — validated deployment governance windows (undefined = ungoverned). */
|
|
148
154
|
usageWindows: readonly UsageWindow[] | undefined;
|
|
149
155
|
/** owned, out-param cell — created EMPTY here; the brain-call wiring later installs into
|
|
@@ -132,6 +132,22 @@ export function prepareConfigDoors(input) {
|
|
|
132
132
|
}
|
|
133
133
|
assertReadFaceValue(spec.readFace, "TaskSpec.readFace");
|
|
134
134
|
assertReadFaceValue(deps.readFace, "readFace (deployment seat)");
|
|
135
|
+
const memoryDelegationEvidenceRaw = deps.memoryDelegationEvidence;
|
|
136
|
+
if (memoryDelegationEvidenceRaw !== undefined && memoryDelegationEvidenceRaw !== "static-face" && memoryDelegationEvidenceRaw !== "attested-only") {
|
|
137
|
+
const evidence = memoryDelegationEvidenceRaw;
|
|
138
|
+
const got = typeof evidence === "string"
|
|
139
|
+
? JSON.stringify(evidence.length > 64 ? `${evidence.slice(0, 64)}…` : evidence)
|
|
140
|
+
: evidence === null
|
|
141
|
+
? "null"
|
|
142
|
+
: Array.isArray(evidence)
|
|
143
|
+
? "an array"
|
|
144
|
+
: typeof evidence;
|
|
145
|
+
const e = new Error(`RunnerDeps.memoryDelegationEvidence must be "static-face" or "attested-only" when present (got ${got}) — ` +
|
|
146
|
+
`an unevaluable evidence standard is refused loudly, never folded to either standard.`);
|
|
147
|
+
e.code = "config.memory_delegation_evidence";
|
|
148
|
+
throw e;
|
|
149
|
+
}
|
|
150
|
+
const memoryDelegationEvidence = memoryDelegationEvidenceRaw === "attested-only" ? "attested-only" : "static-face";
|
|
135
151
|
if (spec.resumeAtMode !== undefined) {
|
|
136
152
|
if (spec.resumeAt === undefined) {
|
|
137
153
|
const e = new Error(`resumeAtMode "${spec.resumeAtMode}" requires resumeAt (there is no branch target to position against)`);
|
|
@@ -294,6 +310,7 @@ export function prepareConfigDoors(input) {
|
|
|
294
310
|
compModel,
|
|
295
311
|
fableMitigations,
|
|
296
312
|
modelGate,
|
|
313
|
+
memoryDelegationEvidence,
|
|
297
314
|
usageWindows,
|
|
298
315
|
brainCallGuardrailRef,
|
|
299
316
|
brainCallGuardrailMs,
|
|
@@ -1092,7 +1092,9 @@ export interface RunInternals {
|
|
|
1092
1092
|
* it); `contentSafety` is the chain's FROZEN classification snapshot — the child may narrow it
|
|
1093
1093
|
* with its own config, never widen (design/180 A-2). Trusted internals chain only, same posture as
|
|
1094
1094
|
* {@link inheritedGate}. Absent ⇒ the child records nothing (its deliveries then read `unknown`,
|
|
1095
|
-
* and every judgment falls back to the static floor — fail-closed by construction
|
|
1095
|
+
* and every judgment falls back to the static floor — fail-closed by construction; whether the
|
|
1096
|
+
* floor's verdict MARKS the judging session follows that run's deployment evidence standard,
|
|
1097
|
+
* {@link RunnerDeps.memoryDelegationEvidence}).
|
|
1096
1098
|
*/
|
|
1097
1099
|
delegationProvenance?: {
|
|
1098
1100
|
ref: {
|
|
@@ -333,7 +333,7 @@ function cwdConflictsRestoreError(requestedCwd) {
|
|
|
333
333
|
export async function prepareTask(spec, deps, sessions, resume, internals, runnerSelf) {
|
|
334
334
|
const doors = prepareConfigDoors({ spec, deps, sessions, resume, internals });
|
|
335
335
|
spec = doors.spec;
|
|
336
|
-
const { toolFaceSnapshot, promptProfile, lockedPreflight, resolvedInteractionPosture, resolvedRole, model, thinking, compModel, fableMitigations, usageWindows, brainCallGuardrailRef, brainCallGuardrailMs } = doors;
|
|
336
|
+
const { toolFaceSnapshot, promptProfile, lockedPreflight, resolvedInteractionPosture, resolvedRole, model, thinking, compModel, fableMitigations, memoryDelegationEvidence, usageWindows, brainCallGuardrailRef, brainCallGuardrailMs } = doors;
|
|
337
337
|
announceToolModelGate(deps.onNotice, model.id, doors.modelGate);
|
|
338
338
|
const { toolEffects, egressTools, irreversibleTools, irreversibilityTier, axisExplicitNegatives, reversibilityProbes, ownToolNames } = prepareSafetyScan({ spec, deps });
|
|
339
339
|
let shellGatedBash = false;
|
|
@@ -1855,6 +1855,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1855
1855
|
const delegationProvenanceChannel = internals?.delegationProvenance;
|
|
1856
1856
|
if (memoryEngineSession !== undefined || delegationProvenanceChannel !== undefined) {
|
|
1857
1857
|
const pollution = memoryEngineSession?.pollution;
|
|
1858
|
+
const delegationEvidenceAttestedOnly = memoryDelegationEvidence === "attested-only";
|
|
1859
|
+
let staticMarkWaiverAnnounced = false;
|
|
1858
1860
|
const effectiveSafety = narrowContentSafety(delegationProvenanceChannel?.contentSafety, memoryEngineSession?.contentSafety);
|
|
1859
1861
|
const trustedTools = effectiveSafety.trustedTools;
|
|
1860
1862
|
const execIsExternalContent = effectiveSafety.execIsExternalContent;
|
|
@@ -1934,8 +1936,28 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1934
1936
|
}
|
|
1935
1937
|
else if (att !== "clean") {
|
|
1936
1938
|
if (external) {
|
|
1937
|
-
|
|
1938
|
-
(typeof requested === "string" ? ` (subagent_type "${requested}")` : " (no subagent_type named — classified fail-closed)")
|
|
1939
|
+
const staticFaceReason = `tool "${t.name}" returned the output of a delegated agent whose tool face can reach external content` +
|
|
1940
|
+
(typeof requested === "string" ? ` (subagent_type "${requested}")` : " (no subagent_type named — classified fail-closed)");
|
|
1941
|
+
if (!delegationEvidenceAttestedOnly) {
|
|
1942
|
+
mark(staticFaceReason);
|
|
1943
|
+
}
|
|
1944
|
+
else if (pollution !== undefined && !staticMarkWaiverAnnounced) {
|
|
1945
|
+
staticMarkWaiverAnnounced = true;
|
|
1946
|
+
const waivedReason = inlineUntrusted(staticFaceReason, 200);
|
|
1947
|
+
deliverEngineNotice(deps.onNotice, {
|
|
1948
|
+
code: "memory.delegation_static_mark_waived",
|
|
1949
|
+
message: `Delegation static-face pollution mark waived: ${waivedReason}. The deployment configured ` +
|
|
1950
|
+
`memoryDelegationEvidence="attested-only", so a static tool-face verdict alone does not mark this ` +
|
|
1951
|
+
`session's memory polluted; a delivered "external" attestation and a direct polluting-class ` +
|
|
1952
|
+
`invocation still mark, and on a provenance-armed chain this delegation still records as ` +
|
|
1953
|
+
`incomplete. At most one notice per prepared task leg.`,
|
|
1954
|
+
detail: {
|
|
1955
|
+
reason: waivedReason,
|
|
1956
|
+
...(typeof requested === "string" ? { subagentType: inlineUntrusted(requested, 120) } : {}),
|
|
1957
|
+
sessionId,
|
|
1958
|
+
},
|
|
1959
|
+
});
|
|
1960
|
+
}
|
|
1939
1961
|
}
|
|
1940
1962
|
recordIncomplete();
|
|
1941
1963
|
}
|
|
@@ -1661,6 +1661,7 @@ export class Runner {
|
|
|
1661
1661
|
errorCode: code,
|
|
1662
1662
|
...(remoteEnvFailure !== undefined ? { remoteEnvFailures: remoteEnvFailure } : {}),
|
|
1663
1663
|
...(taskIdRef.effectiveMemoryScopes !== undefined ? { effectiveMemoryScopes: taskIdRef.effectiveMemoryScopes } : {}),
|
|
1664
|
+
...(taskIdRef.effectiveReasoning !== undefined ? { effectiveReasoning: taskIdRef.effectiveReasoning } : {}),
|
|
1664
1665
|
...(() => {
|
|
1665
1666
|
const hinted = err.retryAfterMs;
|
|
1666
1667
|
return code === "memory.admission_required" && typeof hinted === "number" && Number.isFinite(hinted) && hinted > 0
|
|
@@ -2468,23 +2469,24 @@ export class Runner {
|
|
|
2468
2469
|
ts: Date.now(),
|
|
2469
2470
|
}));
|
|
2470
2471
|
}
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
}
|
|
2487
|
-
|
|
2472
|
+
const reasoningResolution = prepared.thinking && prepared.thinking !== "off" ? resolveReasoning(prepared.thinking, prepared.model) : undefined;
|
|
2473
|
+
if (taskIdRef && reasoningResolution !== undefined)
|
|
2474
|
+
taskIdRef.effectiveReasoning = reasoningResolution;
|
|
2475
|
+
if (reasoningResolution !== undefined) {
|
|
2476
|
+
emitTrace(rs.telemetry.tracer, () => ({
|
|
2477
|
+
kind: "reasoning.resolved",
|
|
2478
|
+
version: 1,
|
|
2479
|
+
taskId: rs.telemetry.taskId,
|
|
2480
|
+
model: prepared.model.id,
|
|
2481
|
+
requested: reasoningResolution.requested,
|
|
2482
|
+
effective: reasoningResolution.effective,
|
|
2483
|
+
graded: reasoningResolution.graded,
|
|
2484
|
+
clamped: reasoningResolution.clamped,
|
|
2485
|
+
format: reasoningResolution.format,
|
|
2486
|
+
endpoint: reasoningResolution.endpoint,
|
|
2487
|
+
...(reasoningResolution.dropped === true ? { dropped: true } : {}),
|
|
2488
|
+
ts: Date.now(),
|
|
2489
|
+
}));
|
|
2488
2490
|
}
|
|
2489
2491
|
const effectiveTimeoutMs = spec.limits?.maxWalltimeMs;
|
|
2490
2492
|
const walltimeMonotonicDeadline = effectiveTimeoutMs !== undefined ? rs.telemetry.taskStartMonotonic + effectiveTimeoutMs : undefined;
|
|
@@ -3458,6 +3460,7 @@ export class Runner {
|
|
|
3458
3460
|
effectiveReadFace: prepared.effectiveReadFace,
|
|
3459
3461
|
effectiveReadDenyPatterns: prepared.effectiveReadDenyPatterns,
|
|
3460
3462
|
effectiveMemoryScopes: prepared.effectiveMemoryScopes,
|
|
3463
|
+
effectiveReasoning: reasoningResolution,
|
|
3461
3464
|
retryAfterMs: rs.limits.platformTerminal?.retryAfterMs,
|
|
3462
3465
|
abortedForTimeout: timeout.fired,
|
|
3463
3466
|
abortedForTurns: rs.limits.turnsExceeded,
|
package/dist/core/trace.d.ts
CHANGED
|
@@ -143,8 +143,13 @@ export type TraceEvent = {
|
|
|
143
143
|
/**
|
|
144
144
|
* How a task's requested reasoning intensity RESOLVED against the model's real capability (design/96 S6).
|
|
145
145
|
* Emitted once at task start when thinking is on, so a deployment can SEE — not silently swallow (§E
|
|
146
|
-
* honesty red-line) — that a binary provider ignored the tier (`graded:false`)
|
|
147
|
-
* clamped it down (`clamped:true`)
|
|
146
|
+
* honesty red-line) — that a binary provider ignored the tier (`graded:false`), that an effort endpoint
|
|
147
|
+
* clamped it down (`clamped:true`), or that a NON-reasoning model dropped the request entirely
|
|
148
|
+
* (`dropped:true` — the frame fires for that model too; it used to be the one arm with no report).
|
|
149
|
+
* Metadata-only (tiers + format + endpoint, never prompt content). The resolution is against the
|
|
150
|
+
* task's PRIMARY serving model at leg entry (same law as `TaskResult.model`): a mid-run
|
|
151
|
+
* degradation does not re-emit this frame — the switch is observed on its own seats
|
|
152
|
+
* (`TaskResult.degraded`).
|
|
148
153
|
*/
|
|
149
154
|
kind: "reasoning.resolved";
|
|
150
155
|
version: 1;
|
|
@@ -163,6 +168,16 @@ export type TraceEvent = {
|
|
|
163
168
|
format: string;
|
|
164
169
|
/** Coarse endpoint label (`model.api`, e.g. `openai-completions` / `anthropic-messages`). */
|
|
165
170
|
endpoint: string;
|
|
171
|
+
/**
|
|
172
|
+
* Present (true) only when the model declares NO reasoning capability (`Model.reasoning` falsy): the
|
|
173
|
+
* brains send no thinking parameter at all, so the requested tier was DROPPED — not clamped.
|
|
174
|
+
* `effective:"off"` states the ENGINE side (nothing was requested), not a measured gateway state:
|
|
175
|
+
* on the binary enable-only formats (qwen/zai/qwen-chat-template) parameter absence is
|
|
176
|
+
* provider-default and a default-on gateway may still reason at its own tier — read `format` to
|
|
177
|
+
* know which family applies. `format`/`endpoint` report the family that WOULD have carried the
|
|
178
|
+
* tier. Absent on every reasoning-capable resolution (old consumers see identical frames).
|
|
179
|
+
*/
|
|
180
|
+
dropped?: true;
|
|
166
181
|
/** design/148 S3 (additive, §10.2): the nine-element cache identity — digests only. */
|
|
167
182
|
snapshot?: {
|
|
168
183
|
cacheIdentity: string;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -846,7 +846,9 @@ export interface ToolExecuteContext {
|
|
|
846
846
|
* content-safety snapshot — the tool then mints the child's recorder ref and threads both into
|
|
847
847
|
* the child's trusted `RunInternals.delegationProvenance`. Undefined return / absent field ⇒ the
|
|
848
848
|
* child spawns without a recorder (its deliveries read `unknown` and every judgment stays on the
|
|
849
|
-
* static floor —
|
|
849
|
+
* static floor — whose MARK action follows the judging run's deployment evidence standard,
|
|
850
|
+
* {@link RunnerDeps.memoryDelegationEvidence}; under the `"static-face"` default this is v1
|
|
851
|
+
* behavior byte-identical). Same trust posture as
|
|
850
852
|
* {@link inheritedGateForChildren}: never a model/tool argument, never a TaskSpec field.
|
|
851
853
|
*/
|
|
852
854
|
delegationProvenanceForChildren?: () => import("./memory-engine/delegation-provenance.js").DelegationContentSafety | undefined;
|
|
@@ -2839,6 +2841,29 @@ export interface TaskResult {
|
|
|
2839
2841
|
* `TaskSpec.model` ref (which may be a role / name / `@mention`). Lets a UI echo "served by X" instead of the
|
|
2840
2842
|
* requested ref. A mid-run degradation is observed separately (see the degraded-model fields). */
|
|
2841
2843
|
model?: string;
|
|
2844
|
+
/**
|
|
2845
|
+
* #327 — the leg's effective REASONING resolution: the result-face twin of {@link model} for the thinking
|
|
2846
|
+
* knob. How the requested tier resolved against the serving model's real capability
|
|
2847
|
+
* (`requested`/`effective`/`graded`/`clamped`/`format`/`endpoint`, plus `dropped:true` when a
|
|
2848
|
+
* non-reasoning model dropped the request entirely — field semantics on
|
|
2849
|
+
* {@link import("../brain/reasoning.js").ResolvedReasoning}). It is the SAME resolver output the
|
|
2850
|
+
* `reasoning.resolved` trace frame carries, computed once per leg — the two faces cannot tell different
|
|
2851
|
+
* stories; this seat serves consumers without a tracer (the trace frame is the deployment-observability
|
|
2852
|
+
* face, this is the caller face).
|
|
2853
|
+
*
|
|
2854
|
+
* **In-presence condition** — mirrors the trace frame exactly: present on every terminal of a leg that ran
|
|
2855
|
+
* with a REQUESTED thinking tier other than off/unset (the `spec > role > model.defaultThinking` chain);
|
|
2856
|
+
* absent when thinking was off/unset for the leg, and on prepare failures (the resolution is minted after
|
|
2857
|
+
* prepare). On a resumed task each leg re-resolves against the leg's own serving model.
|
|
2858
|
+
*
|
|
2859
|
+
* **Degradation law** — same as {@link model}, whose resolution this is: the seat describes the leg's
|
|
2860
|
+
* PRIMARY serving model at leg entry. A mid-run degradation (reactive fallback / near-budget switch)
|
|
2861
|
+
* changes the serving model WITHOUT re-minting this seat or its trace twin — read {@link degraded} to see
|
|
2862
|
+
* the switch; the fallback's own reasoning capability is deliberately NOT re-reported here (re-resolving
|
|
2863
|
+
* one face would desync it from the task-start `reasoning.resolved` frame). A consumer needing the
|
|
2864
|
+
* fallback's reasoning posture resolves `degraded.to` itself (`resolveReasoning` is exported).
|
|
2865
|
+
*/
|
|
2866
|
+
effectiveReasoning?: import("../brain/reasoning.js").ResolvedReasoning;
|
|
2842
2867
|
/** Final assistant text. */
|
|
2843
2868
|
result: string;
|
|
2844
2869
|
/**
|
|
@@ -4710,6 +4735,22 @@ export interface EngineNotice {
|
|
|
4710
4735
|
* time — the withheld count stays true either way). Registered gap: the derived index (`MEMORY.md`) is
|
|
4711
4736
|
* contained on a path that mints no rejection row, so an index-ONLY containment produces no
|
|
4712
4737
|
* notice and is disclosed by the harvest report's warnings alone.
|
|
4738
|
+
* - `"memory.delegation_static_mark_waived"` (design/324, #324 ruling ①) — the deployment set
|
|
4739
|
+
* {@link RunnerDeps.memoryDelegationEvidence} to `"attested-only"` and a delegation call whose
|
|
4740
|
+
* STATIC tool-face verdict would have marked this session's memory polluted (attestation
|
|
4741
|
+
* missing/unknown + face can reach external content) was not marked: the waiver is announced —
|
|
4742
|
+
* the explicit dual of `"memory.session_polluted"` for this arm, so the arm has a voice where a
|
|
4743
|
+
* mark used to land. MINT-side guarantee only: delivery rides the shared guarded form
|
|
4744
|
+
* ({@link deliverEngineNotice} — a wired sink that throws owns that loss, exactly as at every
|
|
4745
|
+
* de-duplicating station), and the leg latch is consumed at mint. Minted only when a pollution
|
|
4746
|
+
* face is mounted (a
|
|
4747
|
+
* recorder-only child's mark is a no-op — nothing is waived there), at most ONCE PER PREPARED
|
|
4748
|
+
* TASK LEG (a resume leg may announce again — a new leg's audit stream is a new fact;
|
|
4749
|
+
* deliberately no durable once-per-session state), never on the `"static-face"` default, and
|
|
4750
|
+
* never for a delivered `"external"` attestation (that mark still lands);
|
|
4751
|
+
* `detail: { reason, subagentType?, sessionId? }` — `reason` is the same sentence the waived
|
|
4752
|
+
* mark would have carried, neutralized/length-bounded (tool and agent-type names are
|
|
4753
|
+
* host/model-controlled inputs).
|
|
4713
4754
|
*
|
|
4714
4755
|
* Deliberately NOT a notice family: brain retry/reconnect liveness (a rate limit, a 5xx, a
|
|
4715
4756
|
* transient network failure being retried). Those are per-attempt liveness frames with their own
|
|
@@ -4858,6 +4899,36 @@ export interface RunnerDeps {
|
|
|
4858
4899
|
* bypasses the gate as always — the human already adjudicated it).
|
|
4859
4900
|
*/
|
|
4860
4901
|
writeProtectedPaths?: readonly import("./write-protect.js").WriteProtectedEntry[];
|
|
4902
|
+
/**
|
|
4903
|
+
* design/324 (#324 ruling ① containment) — the EVIDENCE STANDARD the delegation arm of the
|
|
4904
|
+
* content-origin wrap applies when deciding whether a delegation call marks THIS session's memory
|
|
4905
|
+
* polluted (design/178 §3 / design/180 half A):
|
|
4906
|
+
* - `"static-face"` (absent ≡ this; the default) — today's behavior, byte-identical: a delegation
|
|
4907
|
+
* whose delivered attestation is missing/unknown and whose static tool face can reach external
|
|
4908
|
+
* content marks the session (the capability over-approximation: possibility counts as exposure).
|
|
4909
|
+
* - `"attested-only"` — exactly that ONE static-face mark is waived, and each prepared leg
|
|
4910
|
+
* announces the first waiver (`"memory.delegation_static_mark_waived"`). Everything else is
|
|
4911
|
+
* unchanged: a delivered `"external"` attestation still marks, the chain's `incomplete`
|
|
4912
|
+
* recording still happens, a non-delegation polluting-class tool still marks, and a delegation
|
|
4913
|
+
* tool that is ITSELF classified polluting still marks pre-call.
|
|
4914
|
+
* ACCEPTED COST (the deployment's to own, stated as mechanism, not as absence of risk): under
|
|
4915
|
+
* `"attested-only"` a BACKGROUND child's real external contact does not mark this session — its
|
|
4916
|
+
* content re-enters through the TaskOutput result, the task-notification injection, or the
|
|
4917
|
+
* AgentTranscript step summaries, none of which carries an attestation — and a foreground child
|
|
4918
|
+
* that ended abnormally (crash/salvage) is likewise not marked on its face alone (the chain still
|
|
4919
|
+
* records `incomplete`). Already-marked sessions are never retroactively cleaned; the key only
|
|
4920
|
+
* governs NEW marks.
|
|
4921
|
+
* DEPLOYMENT seat ONLY (same posture as {@link readDenyBuiltinTiers}): deliberately no TaskSpec
|
|
4922
|
+
* twin and not in the governed workflow whitelist — a task author or governed script gets no
|
|
4923
|
+
* channel to loosen the evidence standard below its deployment. Not frozen into checkpoints: a
|
|
4924
|
+
* resumed leg follows the CURRENT deployment configuration. Each run reads the deps of the Runner
|
|
4925
|
+
* that PREPARES it — a multi-runner assembly should configure every runner with the same value
|
|
4926
|
+
* (drift is the deployment's own configuration hazard; recorder/attestation semantics are
|
|
4927
|
+
* value-independent, so the chain's evidence quality never varies with this key). Any other value
|
|
4928
|
+
* refuses loudly at prepare (`config.memory_delegation_evidence`, #123 — exact spellings only,
|
|
4929
|
+
* never truthiness).
|
|
4930
|
+
*/
|
|
4931
|
+
memoryDelegationEvidence?: "static-face" | "attested-only";
|
|
4861
4932
|
/**
|
|
4862
4933
|
* design/199 件A — the DEPLOYMENT's read-face declaration
|
|
4863
4934
|
* ({@link import("../tools/fs/read-face.js").ReadFace}; see {@link TaskSpec.readFace} for the
|