@sema-agent/core 5.13.0 → 5.15.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 +418 -0
- package/dist/agents/send-message-tool.js +1 -0
- package/dist/agents/subagent.d.ts +4 -0
- package/dist/agents/subagent.js +133 -41
- package/dist/brain/anthropic.js +33 -10
- package/dist/brain/context-overflow.d.ts +20 -0
- package/dist/brain/context-overflow.js +58 -0
- package/dist/brain/errors.js +21 -1
- package/dist/brain/open-responses.js +24 -10
- package/dist/brain/openai.js +29 -11
- package/dist/brain/request-params.d.ts +2 -0
- package/dist/brain/request-params.js +16 -0
- package/dist/brain/retry.d.ts +5 -0
- package/dist/brain/retry.js +16 -4
- package/dist/brain/stream-engine.d.ts +9 -1
- package/dist/brain/stream-engine.js +261 -28
- package/dist/brain/timeout.d.ts +1 -0
- package/dist/brain/timeout.js +1 -0
- package/dist/core/a2a.d.ts +2 -2
- package/dist/core/a2a.js +3 -3
- package/dist/core/ask-question.d.ts +47 -2
- package/dist/core/ask-question.js +209 -28
- package/dist/core/background-agent-store.d.ts +2 -0
- package/dist/core/checkpoint-store.d.ts +41 -17
- package/dist/core/checkpoint-store.js +137 -6
- package/dist/core/hooks.d.ts +24 -2
- package/dist/core/hooks.js +97 -10
- package/dist/core/human-input-projection.d.ts +12 -0
- package/dist/core/human-input-projection.js +27 -0
- package/dist/core/mcp.d.ts +7 -2
- package/dist/core/mcp.js +7 -7
- package/dist/core/memory-admission.d.ts +4 -0
- package/dist/core/memory-admission.js +3 -0
- package/dist/core/memory-engine/engine.d.ts +3 -1
- package/dist/core/memory-engine/engine.js +4 -3
- package/dist/core/memory-recall.d.ts +1 -1
- package/dist/core/memory-recall.js +3 -2
- package/dist/core/runner/assemble-result.d.ts +1 -0
- package/dist/core/runner/assemble-result.js +1 -1
- package/dist/core/runner/prepare-memory.d.ts +1 -0
- package/dist/core/runner/prepare-memory.js +3 -3
- package/dist/core/runner/prepare-task.d.ts +19 -6
- package/dist/core/runner/prepare-task.js +343 -35
- package/dist/core/runner/runtask.d.ts +3 -6
- package/dist/core/runner/runtask.js +290 -64
- package/dist/core/runner/tool-disclosure.d.ts +5 -0
- package/dist/core/runner/tool-disclosure.js +65 -16
- package/dist/core/runner/tool-output-projection.js +1 -0
- package/dist/core/runner/turn-attachments.d.ts +4 -0
- package/dist/core/runner/turn-attachments.js +15 -2
- package/dist/core/session-store.d.ts +3 -0
- package/dist/core/session-store.js +4 -0
- package/dist/core/session.d.ts +1 -0
- package/dist/core/store-contracts/background-agent-store-contract.js +19 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +62 -3
- package/dist/core/task-notification.d.ts +2 -0
- package/dist/core/task-notification.js +5 -3
- package/dist/core/task-registry-agent.d.ts +1 -0
- package/dist/core/task-registry-agent.js +6 -0
- package/dist/core/task-registry.d.ts +1 -0
- package/dist/core/task-registry.js +4 -1
- package/dist/core/task-tool-shape.js +4 -3
- package/dist/core/tool-policy.d.ts +5 -0
- package/dist/core/tool-policy.js +2 -1
- package/dist/core/trace.d.ts +6 -0
- package/dist/core/types.d.ts +32 -1
- package/dist/core/wiring-manifest.d.ts +97 -0
- package/dist/core/wiring-manifest.js +186 -0
- package/dist/engine/compaction/compaction.js +2 -2
- package/dist/engine/harness/agent-harness.d.ts +2 -1
- package/dist/engine/harness/agent-harness.js +8 -1
- package/dist/engine/harness/types.d.ts +3 -1
- package/dist/engine/llm/types.d.ts +7 -0
- package/dist/engine/llm/types.js +8 -1
- package/dist/engine/session/import-validate.d.ts +6 -1
- package/dist/engine/session/import-validate.js +29 -6
- package/dist/engine/session/memory-repo.d.ts +3 -1
- package/dist/engine/session/memory-repo.js +2 -2
- package/dist/index.d.ts +10 -7
- package/dist/index.js +8 -5
- package/dist/internal/harness-types.d.ts +1 -1
- package/dist/internal/llm.d.ts +2 -2
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +4 -0
- package/dist/orchestration/run-workflow-tool.js +3 -0
- package/dist/orchestration/workflow-types.d.ts +8 -0
- package/dist/orchestration/workflow-types.js +14 -0
- package/dist/orchestration/workflow.d.ts +4 -0
- package/dist/orchestration/workflow.js +134 -5
- package/dist/prompts/default.js +1 -1
- package/dist/prompts/supervisor.d.ts +2 -2
- package/dist/prompts/supervisor.js +5 -4
- package/dist/stores/file/checkpoint-store.d.ts +3 -5
- package/dist/stores/file/checkpoint-store.js +31 -2
- package/dist/stores/file/index.js +1 -1
- package/dist/stores/file/session-store.d.ts +3 -1
- package/dist/stores/file/session-store.js +2 -2
- package/dist/stores/file/shared-ledger.js +8 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -0
- package/dist/tools/fs/bash-readonly-classifier.js +94 -0
- package/dist/tools/fs/fs-bash.d.ts +1 -0
- package/dist/tools/fs/fs-bash.js +32 -13
- package/dist/tools/fs/gh-rate-limit.d.ts +1 -1
- package/dist/tools/fs/gh-rate-limit.js +4 -3
- package/dist/tools/fs/index.d.ts +1 -0
- package/dist/tools/fs/index.js +1 -0
- package/dist/tools/fs/safety.js +34 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,423 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.15.0 — 2026-08-06
|
|
4
|
+
|
|
5
|
+
### BREAKING
|
|
6
|
+
|
|
7
|
+
- **`TaskSpec.toolMaterializeStrategy` defaults to `"swap"` again** (it defaulted to `"static"` for one
|
|
8
|
+
release window). Under `"static"` a deferred tool's placeholder never swaps: the tools block keeps
|
|
9
|
+
advertising `{"type":"object","properties":{}}` and the real schema reaches the model only as text in
|
|
10
|
+
the `ToolSearch` result. That is fine for a model whose tool arguments are free-form JSON, and
|
|
11
|
+
structurally unusable for one served with **constrained decoding**, where the advertised wire schema is
|
|
12
|
+
enforced at the sampler. On the mainstream implementations — grammar compiled from the declared
|
|
13
|
+
`properties` — `{}` becomes the only argument object the model can emit, so the engine's corrective
|
|
14
|
+
invalid-arguments rejection cannot be acted on and the run burns turns without converging. (A strictly
|
|
15
|
+
draft-faithful decoder would read the absent `additionalProperties` as permissive; the model still has
|
|
16
|
+
no schema to form other keys from, so that path degrades to guessing rather than converging.)
|
|
17
|
+
The condition for `"static"` is also a property of the WHOLE serving route rather than of one model —
|
|
18
|
+
the degrading brain can fall back across providers mid-run and `limits.degrade` can hand the run to a
|
|
19
|
+
different model outright, and neither rebuilds the disclosure strategy — so it is now a strict explicit
|
|
20
|
+
opt-in: set it only if every model the run can reach, fallback targets included, has been verified to
|
|
21
|
+
read schemas from result text. **Who is affected:** a deployment that relied on the default to keep its
|
|
22
|
+
provider prompt cache intact across activations now sees the pre-`"static"` behavior (activation calls
|
|
23
|
+
`setTools`, invalidating the cache suffix) unless it sets `toolMaterializeStrategy: "static"` itself.
|
|
24
|
+
**Pinned faces that move with the default:** the `tools_delta` attachment says "now available … Their
|
|
25
|
+
full schemas are loaded" (not "now active"), the `ToolSearch` description says activation "loads its
|
|
26
|
+
full parameter schema" (not "returns … in the result"), the `ToolSearch` result no longer inlines
|
|
27
|
+
`parameters:` per matched tool, and the post-activation tools block carries the real schema again — a
|
|
28
|
+
consumer pinning any of these under the default must re-pin. `SEMA_TOOL_MATERIALIZE_STRATEGY` still
|
|
29
|
+
fills an absent spec value, and an env-sourced `"static"` on a `deferSelfResolve: false` task still
|
|
30
|
+
degrades to `"swap"` (the explicit spec pairing stays refused with `config.tool_materialize_unreachable`).
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- **`prompt.assembled` reports the resolved deferred-tool disclosure strategy** —
|
|
35
|
+
`toolDisclosure: {deferredTools, strategy, source}` (new exported type `ToolDisclosureManifest`;
|
|
36
|
+
absent when the leg deferred nothing). `strategy` is the EFFECTIVE value after the direct-call-lane
|
|
37
|
+
interlock, and `source` names the seat that chose it: `"spec"` / `"env"` / `"default"` /
|
|
38
|
+
`"degraded_no_direct_lane"` (the interlock narrowed a `"static"` request to `"swap"`; that value
|
|
39
|
+
implies an env-sourced request, since the spec pairing is refused at prepare and the default is not
|
|
40
|
+
`"static"`). "Which strategy did this leg run under, and who chose it" was previously answerable only
|
|
41
|
+
by re-deriving spec > env > release default by hand.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- **Model-visible text stops teaching retired tool names** (#181 census F batch). Three faces taught
|
|
46
|
+
names a model cannot call (RB-476-A retired alias resolution — a retired name is a loud roster
|
|
47
|
+
miss): the selective-recall manifest affordance said "call Recall" (a name core registers as
|
|
48
|
+
removed; the affordance's tool name is now caller-supplied via `composeSelectiveBody`'s new
|
|
49
|
+
optional `recallToolName` parameter, name-free when omitted); both `ORCHESTRATION_GUIDANCE`
|
|
50
|
+
blocks said `run_workflow` — on the deferred short form a complete dead link, since `ToolSearch`'s
|
|
51
|
+
`select:` arm matches exact wire names — and now interpolate `RUN_WORKFLOW_TOOL_NAME`
|
|
52
|
+
(`"Workflow"`); TaskOutput's lanes description and `task_id` parameter said `RunWorkflow` and now
|
|
53
|
+
say `Workflow`. A consumer pinning any of these strings must re-pin. A new gate
|
|
54
|
+
(`test/tool-name-literal-gate.test.ts`) scans every src string literal against the whole
|
|
55
|
+
`RETIRED_TOOL_NAMES` table with a frozen per-bucket ratchet, so this class cannot regrow silently.
|
|
56
|
+
- **The `# Memory` write instruction requires the Write tool on the roster** (behavior face). The
|
|
57
|
+
memory engine's injection gated the CC-verbatim write instruction on a writable scope alone;
|
|
58
|
+
a `handsReadOnly` (or hands-less) run with a memory `writeScope` was instructed to write with a
|
|
59
|
+
tool its roster does not carry. `MemoryEngine.inject` takes an optional `writeToolMounted`
|
|
60
|
+
(omitted ⇒ historic behavior for engine-direct hosts; the Runner passes the real hands-write-half
|
|
61
|
+
predicate), and the RB-276 index seed follows the same gate. **Who is affected:** a deployment
|
|
62
|
+
running memory-enabled tasks with `handsReadOnly: true` (or no execution env) no longer receives
|
|
63
|
+
the `# Memory` instruction or the index read-seed on those runs — the fenced index still injects.
|
|
64
|
+
- **The gh rate-limit hint's Monitor clause follows the real Monitor mount.** The SR-2 reminder
|
|
65
|
+
unconditionally closed with "use the Monitor tool"; Monitor mounts only when background task tools
|
|
66
|
+
do. `ghRateLimitHint` (and `HandsToolkitOptions`/`createBashTool` `monitorToolActive`) drop exactly
|
|
67
|
+
that clause when the caller declares Monitor unmounted; omitted keeps the byte-identical historic
|
|
68
|
+
wording.
|
|
69
|
+
- **`ToolSearch` no longer activates a name the roster has withdrawn.** The deferred registry is frozen
|
|
70
|
+
at prepare; the roster is not — an MCP refresh can take a deferred name off the mount. An exact
|
|
71
|
+
`select:` still resolved through the stale registry, added the name to the active set, "succeeded" at
|
|
72
|
+
a rematerialize that mounted nothing, and announced a tool that could not be called. Withdrawn names
|
|
73
|
+
are now reported as `No longer available: <names> — withdrawn by its provider and cannot be activated
|
|
74
|
+
or called`, ride the result's `details.missing`, and never enter the active set.
|
|
75
|
+
- **The deferred placeholder's corrective round is now bounded.** A shape-invalid direct call is answered
|
|
76
|
+
with the real declared schema so the corrected call is one turn away — which assumes the caller can act
|
|
77
|
+
on a schema once it has one. A caller whose arguments are constrained to the ADVERTISED schema cannot,
|
|
78
|
+
and re-sent the identical rejected arguments for as many turns as the budget allowed. After
|
|
79
|
+
`DEFERRED_NO_PROGRESS_LIMIT` (3) consecutive rejections of the IDENTICAL failure shape on one
|
|
80
|
+
placeholder, the lane stops re-teaching: it returns a terminal rejection that names the condition with
|
|
81
|
+
the stable token `tool.deferred_schema_incompatible` (in the model-facing text and on the tool result's
|
|
82
|
+
`details.noProgress`) and votes the tool batch terminated. Any other outcome — a different validation
|
|
83
|
+
error, or a successful call — resets the count, so the bound tracks being STUCK, not being wrong.
|
|
84
|
+
`TaskResult.errorCode` is unchanged: this terminal is reported on the tool result, not as a task
|
|
85
|
+
failure code.
|
|
86
|
+
- **The invalid-arguments rejection no longer overstates where its schema lives.** It used to say "use it
|
|
87
|
+
for this and later calls" under both strategies; under `"static"` the schema is carried by that one
|
|
88
|
+
result and is gone with the next compaction. The text now says either "the next request's tools list
|
|
89
|
+
will advertise it too" (swap) or "carried by THIS result only" plus the `ToolSearch` re-select spelling
|
|
90
|
+
(static). A declaration too large to inline is called an "ABRIDGED copy" instead of "full" — past the
|
|
91
|
+
model-facing bound the serialization comes back with its middle spliced out and is not valid JSON.
|
|
92
|
+
- **A declaration the static face cannot carry in text is exempted from the static face per tool.** Under
|
|
93
|
+
`"static"` the only in-context schema carrier is result text; a declaration that does not serialize, or
|
|
94
|
+
that the model-facing bound truncates, has no carrier there, and the tool was announced as activated
|
|
95
|
+
with a schema the model never received in usable form. Such a tool now materializes into the tools block
|
|
96
|
+
on activation (the rest of the run stays static), the `ToolSearch` line says where its declaration is,
|
|
97
|
+
and the result head stops promising schemas it did not print. The `tools_delta` boundary frame carries
|
|
98
|
+
the same exception (one `Exception: <names> — too large to inline…` line) instead of asserting compact
|
|
99
|
+
placeholders for a name whose full schema is visibly on the wire; with no exemptions in play the frame
|
|
100
|
+
is byte-identical to before. The exemption is read from the LIVE roster on every call, so an MCP
|
|
101
|
+
refresh that changes a declaration's size cannot leave the lane describing the old carrier — and the
|
|
102
|
+
exemption is MONOTONE within a leg: a declaration that shrinks back under the bound does not put the
|
|
103
|
+
compact placeholder back on a tool whose schema was only ever delivered through the tools block.
|
|
104
|
+
|
|
105
|
+
### Fixed (receive-time additions)
|
|
106
|
+
|
|
107
|
+
- Ruled at receive: the deferred no-progress terminal stays a TOOL-RESULT face (`tool.deferred_schema_incompatible`
|
|
108
|
+
marker + `details.noProgress`) and does NOT mint a `TaskResult.errorCode` — the run can continue on other
|
|
109
|
+
tools, so a run-level code would misclassify a per-tool condition.
|
|
110
|
+
- Ruled at receive: a malformed `SEMA_TOOL_MATERIALIZE_STRATEGY` still refuses the task loudly even when a
|
|
111
|
+
valid spec value is present — a deployment running with a broken env var must hear about it before the
|
|
112
|
+
first task that omits the spec value inherits the typo.
|
|
113
|
+
|
|
114
|
+
## 5.14.0 — 2026-08-06
|
|
115
|
+
|
|
116
|
+
> **Post-release addendum (2026-08-06, disclosure gap reported by a consumer):** the fail-open survey
|
|
117
|
+
> (shipped in 5.13.0's window, but its consequence surfaced against 5.14.0 pickups) hardened
|
|
118
|
+
> `canonicalizeTarget`'s existence probe — an ERRORED `exists` no longer reads as "does not exist yet"
|
|
119
|
+
> and instead reports `{ok:false, unresolvedSymlink:true}`. Combined with `createSensitivePathPolicy`'s
|
|
120
|
+
> deny on `unresolvedSymlink`, an execution env whose `exists` always throws (a stub/lexical env with
|
|
121
|
+
> no real filesystem) now sees every write target denied — the gate degrades from "guarded" to
|
|
122
|
+
> "closed". That is the intended fail-closed direction for a PROBE FAILURE, but such an env should
|
|
123
|
+
> answer honestly instead of throwing: return `ok(false)` ("this env cannot see a filesystem") and the
|
|
124
|
+
> gate resolves normally. Also: `DelegationTaskType` was named in the ship note but missed the package
|
|
125
|
+
> root; the export lands in the next release — type the `taskType` key as an open `string` until then.
|
|
126
|
+
|
|
127
|
+
### BREAKING
|
|
128
|
+
|
|
129
|
+
- **`CheckpointStore.setPendingSteer` APPENDS to a bounded ordered queue instead of overwriting a single seat**
|
|
130
|
+
(design/171 §5.3/§6.1/§6.3). Two people steering one durably-suspended run used to mean the second steer
|
|
131
|
+
silently destroyed the first — an undelivered operator instruction, gone with no record that anything was
|
|
132
|
+
lost. `CheckpointState` gains `pendingSteerQueue: PendingSteerEntry[]`
|
|
133
|
+
(`{text, trusted, actor?, seq, inputId, priority?}`); resume drains the WHOLE queue in `seq` order, each
|
|
134
|
+
entry framed under its own trust semantics. New exports: `readPendingSteerQueue` (the single read point —
|
|
135
|
+
it folds a pre-queue row's legacy `pendingSteer` seat in as member 0, so old checkpoints deliver unchanged
|
|
136
|
+
with no migration step), `appendPendingSteer` (the shared append every backend must build its next queue
|
|
137
|
+
with: bounds + `seq` mint live there, not once per store), `PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES` (48,000 —
|
|
138
|
+
under a MySQL `TEXT` column with UTF-8 headroom), `MAX_PENDING_STEER_ENTRIES` (derived from it and
|
|
139
|
+
`MAX_PENDING_STEER_CHARS`), `PENDING_STEER_FROZEN_FIELDS` / `ACTOR_ASSERTION_FROZEN_FIELDS`, and the
|
|
140
|
+
`ActorAssertion` type (`{id (namespaced), hostAsserted, issuer?}` — attribution ONLY, never authority;
|
|
141
|
+
`hostAsserted` must be derived by the host from ingress credentials and never taken from a request body).
|
|
142
|
+
Bounds are fail-loud: crossing either throws the **new error code `steering.queue_full`** rather than
|
|
143
|
+
evicting an accepted instruction. `validatePendingSteer` now REFUSES an unknown field
|
|
144
|
+
(`steering.invalid_content`) instead of dropping it, so a producer one release ahead learns its field would
|
|
145
|
+
not survive the parked leg. Idempotency moved from last-writer-wins to the `inputId` key: re-appending the
|
|
146
|
+
same `inputId` with an IDENTICAL payload is a no-op returning `true`, while the same `inputId` carrying
|
|
147
|
+
DIFFERENT content is refused with the **new error code `steering.duplicate_input_id`** (swallowing it would
|
|
148
|
+
reintroduce exactly the silent instruction loss the queue replaces); an absent `inputId` is minted (uuidv7),
|
|
149
|
+
and the synthetic id a pre-queue seat reads back as is reserved against caller supply. The file backend's
|
|
150
|
+
ledger replay also gained a fail-loud arm: an event kind the reader does not recognise now refuses the whole
|
|
151
|
+
replay (`checkpoint.unsupported_version`) instead of folding in as a silent no-op — **note that a binary
|
|
152
|
+
released BEFORE this one still ignores unknown kinds, so rolling back across the queue event loses steers
|
|
153
|
+
parked in the un-compacted ledger tail.**
|
|
154
|
+
**Consumer flips**: ① any code reading `state.pendingSteer` directly sees `undefined` for every new write —
|
|
155
|
+
read through `readPendingSteerQueue`; ② probes pinning "a second setPendingSteer overwrites the first" red;
|
|
156
|
+
③ a custom `CheckpointStore` must round-trip BOTH state fields and build its next queue with
|
|
157
|
+
`appendPendingSteer` (the cross-backend contract kit gained the queue arms and will fail it otherwise);
|
|
158
|
+
④ `steering.queue_full` and `steering.duplicate_input_id` are new members of the `CheckpointError` code
|
|
159
|
+
union — exhaustive consumers add both arms.
|
|
160
|
+
|
|
161
|
+
### Added
|
|
162
|
+
|
|
163
|
+
- **Shared-session attribution (design/171, core half).** Four pieces, one contract: ① `UserMessage.actor`
|
|
164
|
+
carries an `ActorAssertion` (attribution ONLY, never authority; snapshot-minted at the API boundary, wire
|
|
165
|
+
metadata stripped). ② ONE projection point (`human-input-projection.ts`, exported `projectHumanInput` /
|
|
166
|
+
`buildHumanInputEvent`) renders the speaker envelope for every human-input carrier — objective, live steer,
|
|
167
|
+
nextTurn, parked-steer resume frames, wake — as `[from "<id>"]` (+ ` (unverified)` when the host did not
|
|
168
|
+
derive the identity from ingress credentials), through the same neutralizers as the external-notification
|
|
169
|
+
header, always INSIDE the trust frame it attributes. No actor, or `source:"system"` ⇒ byte-identical
|
|
170
|
+
passthrough, so every pre-171 caller and single-user host is pinned unchanged. ③ **New TaskEvent arm
|
|
171
|
+
`human_input`** — the lifecycle ledger of who fed the run what: `{inputId, sessionSeq (leg-scoped),
|
|
172
|
+
carrier, source, delivery, issuer?, actor?, principal?, entryId?}`; live emissions precede the commit and
|
|
173
|
+
omit `entryId` (join via `message_committed` + stream order). Exhaustive TaskEvent switches need an arm.
|
|
174
|
+
④ The compaction attribution invariant: speaker labels survive summarization across all three summary-path
|
|
175
|
+
variants (the summarizer is instructed to preserve `[from …]` attributions).
|
|
176
|
+
|
|
177
|
+
- **Assembly self-evidence (design/173, all eight items).** The engine can now PROVE what it wired instead of
|
|
178
|
+
the operator inferring it from behavior:
|
|
179
|
+
- `describeStaticWiring(spec, deps)` (package-root export) — the pure static half of the wiring manifest;
|
|
180
|
+
per-leg EFFECTIVE manifests are built at prepare and emitted as the **new TaskEvent arm `wiring_manifest`**
|
|
181
|
+
(root/child/resume legs each emit their own). Together with `human_input` above this release takes
|
|
182
|
+
`TaskEvent` **16→18** — an exhaustive switch adds TWO arms, not one. A child leg's manifest rides the
|
|
183
|
+
CHILD's own stream and is deliberately not in the parent-forwarding whitelist: "every leg self-evidences"
|
|
184
|
+
means on its own stream; a host that wants a delegated child's manifest subscribes to the child. The manifest covers ask (form/provenance/effective),
|
|
185
|
+
question (three-valued channel state incl. the engine-stripped bg lane, plus the composition-lie flag
|
|
186
|
+
`interactiveToolsWithoutDeliveryFace`), elicit, the park lane (capability vs effective policy, reason
|
|
187
|
+
codes, checkpoint durability), session-store durability, fleet seats, and a governance presence section
|
|
188
|
+
stamped `audience:"operator"` — **a serving layer forwarding this event to a multi-tenant stream MUST
|
|
189
|
+
project the governance section for operators only; no projection ⇒ do not disclose**. `configFingerprint`
|
|
190
|
+
(sha256 prefix over the manifest's own resolved facts) correlates legs that ran under the same assembly.
|
|
191
|
+
- **Store durability declarations**: `SessionStore`/`CheckpointStore` gain `readonly durability?`
|
|
192
|
+
("durable" | "process-local"); absent reads fail-closed as process-local, unparseable is refused loud
|
|
193
|
+
(`config.store_durability_invalid`). Built-ins declare themselves; an armed park lane over a
|
|
194
|
+
process-local store is now a REPORTABLE degrade shape instead of a silent one.
|
|
195
|
+
- **`TaskSpec.interactionPosture` / `RunnerDeps.interactionPosture`** ("interactive" | "headless") with a
|
|
196
|
+
fail-loud prepare door: posture `"interactive"` refuses a leg whose resolved wiring cannot reach a human
|
|
197
|
+
(`config.interaction_posture` / `config.interaction_wiring`) instead of silently auto-answering. Child
|
|
198
|
+
legs resolve `spec ?? parent posture (trusted internals) ?? deps`. A deployment that declares interactive
|
|
199
|
+
at deps level must supply a persistent question face for session-scoped bg legs — the door refusing that
|
|
200
|
+
leg is the honest reading of an unfulfillable declaration.
|
|
201
|
+
- **AskUserQuestion's three exits mint an in-band card** (`details.type: "ask-question"`, a new
|
|
202
|
+
`CC_DETAIL_TYPES` member): `continuationSource: "human_response" | "synthetic_self_answer_instruction"`
|
|
203
|
+
plus reason codes (a THREE-member closed set: `seam_absent` / `callback_failed` /
|
|
204
|
+
`declined_unavailable`), so a consumer can tell a human answer from the engine's self-answer fallback
|
|
205
|
+
without prose-matching. The card is a two-arm union — the coded-failure arm (`question.human_channel_failed` /
|
|
206
|
+
`question.human_unavailable`) carries neither `continuationSource` nor `runContinues`, so consumers
|
|
207
|
+
must branch on `code` FIRST and only then read `continuationSource`. Under posture `"interactive"`, the callback-failed
|
|
208
|
+
arm becomes a coded failure (`question.human_channel_failed`) unless the explicit
|
|
209
|
+
`interactiveQuestionFallback` knob opts back into degrade; the degrade path emits onError
|
|
210
|
+
(phase `"degraded"`, classification `"no-human-autoanswered"`).
|
|
211
|
+
- **The four question-face strip sites pair-produce a disclosure flag** through one helper: when the engine
|
|
212
|
+
deliberately strips a spawn turn's per-request question face from a bg/fork child, the manifest reports
|
|
213
|
+
the channel as `"stripped_bg_lane"` (flag minted only when a face was actually stripped).
|
|
214
|
+
- **`effectiveShellGate === "off"` with a real writable shell now leaves a per-prepare forensic note**
|
|
215
|
+
(onError phase `"config"`, classification `"shell-gate-off"`) — the assembly state that previously had
|
|
216
|
+
zero observable trace. onError `classification` is filled on the config phase for the first time.
|
|
217
|
+
- `isDelegatedAgentTerminal` is re-exported at the package root so a serving layer's escalation code shares
|
|
218
|
+
core's own terminal classification.
|
|
219
|
+
|
|
220
|
+
- **The brain honors a provider's explicit retry verdict, and recovers from the context-overflow 400.**
|
|
221
|
+
① The `x-should-retry` response header is now read double-sided: `true` retries a normally-terminal status,
|
|
222
|
+
`false` stops retrying a normally-retryable one; header absent ⇒ prior behavior byte-identical.
|
|
223
|
+
② The `input length and max_tokens exceed context limit` 400 (previously terminal `invalid_request`) now
|
|
224
|
+
adaptively lowers `max_tokens` and retries, with two loud guards: a floor (3000 output tokens — at the
|
|
225
|
+
floor and still overflowing ⇒ give up) and a no-progress check (same error after a cut ⇒ give up); every
|
|
226
|
+
cut is disclosed as a status frame. The narrow error-shape parser refuses anything it does not recognize
|
|
227
|
+
(prior terminal behavior preserved).
|
|
228
|
+
|
|
229
|
+
- **Question sync-first (design/174).** With a live question face, an adjudicated `AskUserQuestion` is
|
|
230
|
+
answered in-stream — same turn, no checkpoint; the durable park is what happens when nobody is there
|
|
231
|
+
(no live face / the face affirms nobody is reachable / `forceDurableGate` — and the third park-lane arming,
|
|
232
|
+
the safety vocabulary, behaves the same: **any park-lane arming keeps the park**, sync-first only applies
|
|
233
|
+
to the durable-approval posture with a live face). Assemblies without a live face are pinned byte-identical
|
|
234
|
+
to the previous release. `OnQuestion` may now return `{kind: "unavailable"}` — implementers additive,
|
|
235
|
+
**callers BREAKING** (`.answers` direct access goes red; `isQuestionUnavailable` is exported for relaying
|
|
236
|
+
wrappers). `AskQuestionRequest` gains `boundInputHash` and an engine-minted per-delivery `deliveryId`
|
|
237
|
+
(the identity; `(taskId, toolCallId, boundInputHash)` repeats for two identical sequential questions and is
|
|
238
|
+
reconciliation data only). The question tool executes in its own batch (`executionMode: "sequential"`).
|
|
239
|
+
New closed-set members: `SyntheticContinuationReason` += `declined_unavailable`; card `code` +=
|
|
240
|
+
`question.human_unavailable`; onError classification += `"unconsumed-human-answer"` and
|
|
241
|
+
`"interaction-posture-refused"`.
|
|
242
|
+
|
|
243
|
+
- **Pre-release verification hardening (test AI's A/B groups + the convergence review).**
|
|
244
|
+
- A question outcome claiming NEITHER arm (no `unavailable` discriminant, no `answers` array — a failed
|
|
245
|
+
decode) is now refused as a delivery failure instead of being read as "the user selected nothing";
|
|
246
|
+
the explicit `{answers: []}` stays a real answer. The resume lane applies the same rule pre-CAS and
|
|
247
|
+
captures the redeemed answer ONCE (`structuredClone`) — the persisted outcome and the delivered answer
|
|
248
|
+
are the same snapshot, so a stateful getter can no longer make audit and delivery diverge.
|
|
249
|
+
- **`TaskResult.strandedHumanAnswers`** (new field): `{deliveryId, toolCallId}` records of questions a
|
|
250
|
+
person answered that no call executed to collect — keyed by the engine-minted delivery identity, since
|
|
251
|
+
call ids can repeat (two lost answers on one call id are two records). This is the MANDATORY disclosure
|
|
252
|
+
face; the `onError` (classification `"unconsumed-human-answer"`) alert remains as an additional lane.
|
|
253
|
+
An answer arriving after the result is already terminal can only reach `onError` — the structural limit
|
|
254
|
+
of a result face; a value that does not READ as an answer is never recorded as one.
|
|
255
|
+
- **`AskRequest.riskAxes`** (additive): `{irreversible?, egress?}`, filled by the gate from the SAME
|
|
256
|
+
resolved axes the safety tightens read (declared tiers + `toolAxes` folds + shellGate marks; `"maybe"`
|
|
257
|
+
counts as irreversible). Either axis ABSENT = the engine did not judge it — consumers must render
|
|
258
|
+
"unjudged", never fold absence to `false`. An EXPLICIT caller negative (`egress:false` /
|
|
259
|
+
`irreversibility:"never"` via MCP/A2A `toolAxes`) now survives the override algebra and reports as a
|
|
260
|
+
judged `false` — enforcement stays tighten-only and ignores negatives.
|
|
261
|
+
- **`WiringManifest.interaction.posture`** (new section): the posture declaration ("interactive" /
|
|
262
|
+
"headless" / "absent") joins the manifest — previously the one interactive-face declaration it did not
|
|
263
|
+
report. A posture refusal now also emits an onError frame (phase `"config"`,
|
|
264
|
+
classification `"interaction-posture-refused"`): the coded `TaskResult.errorCode` remains the primary
|
|
265
|
+
carrier (neither entry point throws), the frame serves hosts wired only to `onError`.
|
|
266
|
+
- **`configFingerprint` now hashes the ASSEMBLY, excluding leg identity AND seat provenance** (the
|
|
267
|
+
delegation lane re-homes a parent's deps face onto the child's spec seat — same callback, different
|
|
268
|
+
seat) — root/child/resume legs of one assembly really do share a fingerprint (its advertised use).
|
|
269
|
+
Fingerprint VALUES change with this release; pin the equality relation, not literals.
|
|
270
|
+
Presence condition for the resume leg: a resume's assembly comes from the `ResumeTaskConfig` you
|
|
271
|
+
pass, not from the root's spec — omit a seam face there (e.g. `onQuestion`) and the resume leg
|
|
272
|
+
HONESTLY reports a different assembly (and a different fingerprint), because that leg really has no
|
|
273
|
+
in-stream answerer. Re-supply the same faces on resume to keep the fingerprint equal.
|
|
274
|
+
- The synthetic-continuation disclosure dedup is **per ask-call** (key = tool-call id; one call may carry
|
|
275
|
+
1–4 questions and discloses once) and scoped to ONE leg — a continuation leg re-discloses, and a host
|
|
276
|
+
aggregating across legs dedups on `(sessionId, toolCallId)` itself.
|
|
277
|
+
|
|
278
|
+
- **Capture-domain narrowing (design/174 convergence review, rounds 9–14).** Deployment-supplied resume
|
|
279
|
+
values are read ONCE and captured as canonical plain data; the canonicalizer refuses what the JSON
|
|
280
|
+
checkpoint store cannot faithfully round-trip. Concretely:
|
|
281
|
+
- resume `updatedInput` and a content-ask `answer` now REFUSE (pre-CAS, `checkpoint.invalid_outcome`,
|
|
282
|
+
checkpoint stays pending) values carrying Map/Set/Date/buffers/class instances, shared references or
|
|
283
|
+
cycles, sparse or expando arrays, non-finite numbers, bigint/symbol/function anywhere in the tree;
|
|
284
|
+
object keys with `undefined` values drop and `-0` normalizes to `0` (JSON semantics, applied at capture
|
|
285
|
+
so audit, replay comparison and execution all read the same value);
|
|
286
|
+
- `decision` is domain-checked at capture: anything other than `"allow"`/`"deny"` refuses pre-CAS
|
|
287
|
+
(previously an unknown word could fall past the deny check into the execute arm);
|
|
288
|
+
- `updatedInput: null` flows into the tool's own validation and fails THERE, instead of silently
|
|
289
|
+
executing the ORIGINAL arguments while the record said the input was rewritten;
|
|
290
|
+
- the gate discriminant and every `policy_ask` field are read once into a plain twin consumed by all
|
|
291
|
+
guards, the env-failed replay equality, persistence and the answer face; array equality visits every
|
|
292
|
+
index and compares named non-index keys;
|
|
293
|
+
- upgrade note: a winner persisted RAW by an older release still replays (equality compares canonical
|
|
294
|
+
forms — no checkpoint migration), but an OLD row whose winner is outside the new domain fails closed
|
|
295
|
+
on replay; the row stays recoverable by re-deciding.
|
|
296
|
+
- The direct tool lane applies the same one reader: an answer payload with a throwing accessor refuses
|
|
297
|
+
the WHOLE outcome (no partial salvage of well-formed siblings), and `{}` is a failed decode, not
|
|
298
|
+
"selected nothing" — `{answers: []}` remains the legitimate empty selection.
|
|
299
|
+
|
|
300
|
+
- **`AskRequest.boundInputHash`** (additive): the canonical digest of the presented args, minted once at
|
|
301
|
+
the `resolveAsk` chokepoint over the retained snapshot — the SAME `boundInputHashOf` digest a durable
|
|
302
|
+
park binds its checkpoint to, so an aggregating approver can reconcile a synchronous ask row against a
|
|
303
|
+
parked checkpoint row for the same call on `(toolCallId, hash)` equality. Reconciliation metadata only
|
|
304
|
+
(repeats for identical args; re-minted per `updatedInput` edit round); a caller-supplied value is not
|
|
305
|
+
trusted over the chokepoint's own.
|
|
306
|
+
|
|
307
|
+
- **Cross-process revival inherits the row's org-admission verdict (issue #22, tier-3 half).**
|
|
308
|
+
`BackgroundAgentRecord` gains `admittedOrgScopes?: string[]` and `admittedOrgWriteScope?: string | null`
|
|
309
|
+
(both additive): each leg writes its own adjudicated org verdict at the injector-ready barrier, and a
|
|
310
|
+
tier-3 claim seeds the revived child's admission fold from the row (seed ∩ live — narrow-only, the same
|
|
311
|
+
fold the in-process half uses). A row with the fields ABSENT reads as ZERO admission (`{scopes: [],
|
|
312
|
+
writeScope: null}`) — "no record" and "adjudicated to nothing" deliberately converge fail-closed.
|
|
313
|
+
Store contract additions (the cross-backend kit enforces both): the two fields round-trip verbatim
|
|
314
|
+
(`null` write-scope stays `null`), and ABSENT must read back absent, never materialize as `[]`.
|
|
315
|
+
Behavioral note: a revival leg that carries a seeded verdict now counts as governed, so an `org:`-shaped
|
|
316
|
+
scope in a non-v2 spelling is refused on that leg even with no resolver configured. Fork rows are not
|
|
317
|
+
written (they refuse tier-3 claims).
|
|
318
|
+
|
|
319
|
+
- **`task_progress` gains `taskType`** (additive; new exported type `DelegationTaskType` =
|
|
320
|
+
`"background_agent" | "workflow"`): the discriminator a consumer needs to route a progress frame
|
|
321
|
+
without inferring the task's kind from its id shape. Stamped at both mint sites for background/fork
|
|
322
|
+
legs and both workflow spawn legs (retained-resume included); absent on a synchronous child's frames —
|
|
323
|
+
absence means "no fleet row", tolerate it.
|
|
324
|
+
|
|
325
|
+
- **The scratchpad prompt section states volatility**: one added sentence ("Treat it as ephemeral — it may
|
|
326
|
+
not survive a long suspension or a resume on a different worker; keep durable outputs in the working
|
|
327
|
+
directory"); the CC-verbatim remainder is byte-unchanged. sema runs under durable suspend / multi-replica
|
|
328
|
+
serving where the scratchpad is a local-disk copy; without the sentence a model parks critical
|
|
329
|
+
intermediates in a directory that can vanish mid-task.
|
|
330
|
+
|
|
331
|
+
- **`shellGate:"classify"` now auto-allows a bounded read-only polling loop** (`classifyBoundedReadonlyPollLoop`,
|
|
332
|
+
consulted by `bashReversibilityProbe` only after the plain compound face rejects). A monitoring consumer's
|
|
333
|
+
core idiom is `for i in $(seq 1 8); do tail -n 5 x.log; sleep 2; done`; the compound classifier rejects any
|
|
334
|
+
control structure (`for` is not an allowlisted name), so `classify` behaved like `always` for the Monitor
|
|
335
|
+
tool — an approval prompt on every poll. The new arm accepts EXACTLY that grammar and nothing else: a loop
|
|
336
|
+
head with a LITERAL finite bound (`$(seq <int> <int>)`, ascending `{<int>..<int>}`, or a literal word list,
|
|
337
|
+
capped at 120 iterations), a body of `;`-separated allowlisted readers plus a literal `sleep` (≤600s), the
|
|
338
|
+
SAME read-boundary scan the plain face runs (RB-412/413, unchanged; an unexpanded glob rejects — stricter
|
|
339
|
+
than the plain face), and everything else banned wholesale (redirection, pipes, backgrounding, substitution
|
|
340
|
+
other than the one `$(seq)` exemption, subshells, braces, escapes, nested control structures, and any
|
|
341
|
+
non-ASCII/control whitespace). The loop variable must be a single lowercase letter, so it cannot shadow
|
|
342
|
+
`PATH`/`IFS`/`LD_PRELOAD` and alter how the body's commands resolve. Additive and fail-closed: it only ever
|
|
343
|
+
converts a rejection into an allow for this exact shape, never the reverse, and any unparseable input falls
|
|
344
|
+
through to a rejection — so a deployment on `off`/`always`, or one not polling, is byte-identical. New
|
|
345
|
+
exports from the fs tools barrel: `classifyBoundedReadonlyPollLoop`, `POLL_LOOP_MAX_BEATS` (120),
|
|
346
|
+
`POLL_LOOP_MAX_SLEEP_SECONDS` (600).
|
|
347
|
+
|
|
348
|
+
- **`HookToolContext.env`** (additive): a read-only path-resolution capability face over the env the task's
|
|
349
|
+
hands run against, on the PreToolUse / PostToolUse / PostToolUseFailure contexts alike. A hook that judges
|
|
350
|
+
paths (containment, symlink destinations) must resolve them in the filesystem the tools actually write to —
|
|
351
|
+
for a sandboxed or remote deployment that env is minted by `executionEnvFactory` DURING prepare, after the
|
|
352
|
+
caller built its hooks, so a hook closed over a spec-time env answers about the wrong machine; reading it
|
|
353
|
+
off the CALL context removes the ordering problem and picks up a resumed leg's rebuilt env with no
|
|
354
|
+
re-instantiation protocol. The face (new exported type `HookEnvCapabilities`, builder
|
|
355
|
+
`createHookEnvCapabilities` — public because `runToolGate` is) carries FOUR wrapped read primitives under
|
|
356
|
+
the env's own names: `canonicalPath`, `exists`, `readLink`, `cwd()` (the seam sketch's `canonicalize`/`root`
|
|
357
|
+
— `ExecutionEnv` declares no "root", so the honest anchor is the env's own working directory, read live).
|
|
358
|
+
**`cwd()` is the ENVIRONMENT's directory, not the task's tracked cwd** — the engine tracks a separate
|
|
359
|
+
per-task cwd (starting at the resolved task root, moving with `cd`/worktree entry) that the TOOLS' relative
|
|
360
|
+
paths resolve against and the env is never told about, so a hook judging a RELATIVE target must judge
|
|
361
|
+
absolute paths or get the tracked cwd through the deployment's own channel.
|
|
362
|
+
Deliberately capabilities and not the env object: no back-reference, null prototype, frozen, each primitive
|
|
363
|
+
captured once at build time. **Every member is optional and ABSENCE is the capability signal** — a member is
|
|
364
|
+
present iff the env exposes that primitive, never a stub that throws or an emulation that guesses, so a hook
|
|
365
|
+
branches on the shape; `ctx.env` itself is absent when the deployment wired no execution env at all
|
|
366
|
+
(`null` included). Existing hooks are unaffected.
|
|
367
|
+
|
|
368
|
+
### Fixed
|
|
369
|
+
|
|
370
|
+
- **The auto-mode handback review now runs on EVERY sub-agent completion path, not only the synchronous
|
|
371
|
+
spawn.** A child finishing on the sync-fork path, on either background resolve leg (plain and fork),
|
|
372
|
+
through the parked-resume drive, or on a woken retained-resume cycle handed its output to the parent
|
|
373
|
+
without the completed-work review the sync path has performed since it landed — so exactly the
|
|
374
|
+
delegation shapes that outlive the spawning call were the ones that skipped it. The review, its
|
|
375
|
+
evidence set (the child's final text, the step recorder's observed tool activity, and — on the one path
|
|
376
|
+
that delivers it — the streamed partial-findings tail of a child that stopped without completing), its
|
|
377
|
+
framing and its fail-open posture are now one shared mint point that every call site uses. Carriers per path: the
|
|
378
|
+
fork report card leads with the warning line exactly as the sync card does; a background or resumed
|
|
379
|
+
child's warning is prefixed to the one value the durable row and the completion notification BOTH
|
|
380
|
+
derive from, so those two faces can never disagree about whether a child was flagged. Two deliberate
|
|
381
|
+
skips: a lane whose abort already fired (a stopped child settles on its stop story instead of waiting
|
|
382
|
+
on a classifier — the residual is stated at `reviewHandback`), and a durably-paused child (it has
|
|
383
|
+
handed nothing back yet — its resumed cycle gets the review). Deployments without auto-mode armed are
|
|
384
|
+
byte-identical on every path.
|
|
385
|
+
**Consumer notes**: ① the completed-agent structured card (`details`) gained an optional
|
|
386
|
+
**`handbackWarning`** key — the content face has always led with the warning line, but a host reading
|
|
387
|
+
`details` (afterToolCall hooks, persisted tool results) saw nothing; it rides as its own key because
|
|
388
|
+
`result` is contracted to be the child's text verbatim. Present only when a child was flagged, so
|
|
389
|
+
presence must not be read as a signal of anything else. ② the classifier sees one new `toolName` value,
|
|
390
|
+
`Agent(fork handback)`, beside the existing `Agent(handback)`. ③ `createSubagentResume` gained a
|
|
391
|
+
`currentAutoModeReview` seat in the same `current*` family as `currentOnQuestion`/`currentClamps` (the
|
|
392
|
+
waking run's decider, not the frozen spawn snapshot's); a host wiring SendMessage itself supplies it
|
|
393
|
+
from its own tool ctx, and absent it a woken cycle carries through unreviewed.
|
|
394
|
+
|
|
395
|
+
- **A retained background child's revival leg now inherits the session's own org-admission verdict.** The
|
|
396
|
+
in-process resume leg (a settled retained child woken onto its existing session) is a same-session
|
|
397
|
+
continuation that never goes through a checkpoint, so it re-adjudicated org memory admission from scratch
|
|
398
|
+
with no session freeze: a resolver whose answer WIDENED between the two legs remounted a tenant layer the
|
|
399
|
+
session had already lost, and a read-only first leg could gain an org WRITE grant on the revival — the
|
|
400
|
+
exact "a continuation can never widen" invariant the checkpoint plane enforces with seed ∩ live. The
|
|
401
|
+
verdict now rides `RunInternals.ownOrgAdmissionRef` (trusted internal, one ref per spawned child, threaded
|
|
402
|
+
through the frozen internals snapshot the revival replays); prepare INTERSECTS it with any checkpoint seed
|
|
403
|
+
rather than picking one, so the fold narrows along both the scope and the write axis. Deployments with no
|
|
404
|
+
governance surface are byte-identical (the ref is never read or written). The CROSS-PROCESS (tier-3) revival
|
|
405
|
+
half stays open and is now recorded in `memory-admission.ts`'s header instead of the old blanket residual
|
|
406
|
+
note: that leg rebuilds the spec from the reviving caller's mount, and the durable agent row records lookup
|
|
407
|
+
keys only, so it has no carrier for the original verdict.
|
|
408
|
+
|
|
409
|
+
- **A background delegation no longer needs a NAME to park at an approval gate.** The §7.3 park predicate
|
|
410
|
+
carried an `agentName !== undefined` term, so an ANONYMOUS background child that hit an approval gate was
|
|
411
|
+
sentenced to `no_park_lane`: the row settled `failed`, and the approval never surfaced anywhere an operator
|
|
412
|
+
could decide it (the checkpoint stayed committed but undiscoverable through the agent faces). A name was
|
|
413
|
+
never a structural precondition — the park is keyed on the taskId (`parkBackgroundAgent(taskId, …)`), the
|
|
414
|
+
claim/resume chain addresses the row by handle, and every revival face already treats `row.name` as optional.
|
|
415
|
+
The term is dropped from BOTH sites of the family in one commit: the settle-time park predicate and the
|
|
416
|
+
`durableApproval` forwarding predicate (a divergence would auto-deny an anonymous child's plain ask while its
|
|
417
|
+
safety-tier ask parks). The fork lane is unaffected (r4 F-07 — it has no park block at all), and genuinely
|
|
418
|
+
un-wired deployments still take `no_park_lane`, with the reason text no longer naming the retired
|
|
419
|
+
precondition. Consumer note: probes pinning "an anonymous background child never parks" red.
|
|
420
|
+
|
|
3
421
|
## 5.13.0 — 2026-08-05
|
|
4
422
|
|
|
5
423
|
### BREAKING
|
|
@@ -534,6 +534,7 @@ export function createSendMessageTool(opts) {
|
|
|
534
534
|
...(ctx.interactiveTools === false ? { interactiveTools: false } : {}),
|
|
535
535
|
...(ctx.oneShot === true ? { oneShot: true } : {}),
|
|
536
536
|
},
|
|
537
|
+
...(ctx.autoModeReview !== undefined ? { currentAutoModeReview: ctx.autoModeReview } : {}),
|
|
537
538
|
});
|
|
538
539
|
const fromPrefix = senderIsChild ? `(message from teammate "${senderLabel}")\n` : "";
|
|
539
540
|
try {
|
|
@@ -66,6 +66,7 @@ export declare function completedAgentCard(child: {
|
|
|
66
66
|
worktreePath?: string;
|
|
67
67
|
toolStats?: SubagentToolStats;
|
|
68
68
|
modelFallback?: "inherit_no_tier_binding";
|
|
69
|
+
handbackWarning?: string;
|
|
69
70
|
}): Record<string, unknown>;
|
|
70
71
|
export declare const SUBAGENT_SUSPENDED_AWAITING_APPROVAL = "suspended.awaiting_approval";
|
|
71
72
|
export declare const SUBAGENT_SUSPENDED_NEEDS_REVIEW = "suspended.needs_review";
|
|
@@ -96,6 +97,9 @@ export declare function createSubagentResume(deps: {
|
|
|
96
97
|
interactiveTools?: false;
|
|
97
98
|
oneShot?: true;
|
|
98
99
|
};
|
|
100
|
+
currentAutoModeReview?: {
|
|
101
|
+
decider: import("../core/auto-mode.js").AutoModeDecider;
|
|
102
|
+
};
|
|
99
103
|
taskId?: string;
|
|
100
104
|
taskAccess?: import("../core/task-registry.js").TaskAccess;
|
|
101
105
|
bgSink?: (event: import("../core/types.js").BackgroundChildEvent) => void;
|