@sema-agent/core 5.56.0 → 5.58.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 +122 -0
- package/dist/agents/cascade.d.ts +1 -1
- package/dist/agents/cumulative-stats.d.ts +1 -1
- package/dist/agents/observer.d.ts +2 -2
- package/dist/agents/peer-admission.d.ts +1 -1
- package/dist/agents/retain-ledger.d.ts +2 -2
- package/dist/agents/roster-store.d.ts +8 -8
- package/dist/agents/send-message-tool.d.ts +13 -2
- package/dist/agents/send-message-tool.js +34 -12
- package/dist/agents/subagent-steps.d.ts +1 -1
- package/dist/agents/subagent.d.ts +13 -13
- package/dist/agents/team.d.ts +15 -6
- package/dist/agents/team.js +1 -0
- package/dist/agents/tool-filter.d.ts +2 -2
- package/dist/agents/verify.d.ts +1 -1
- package/dist/bench/metrics.d.ts +35 -35
- package/dist/brain/anthropic.js +15 -5
- package/dist/brain/circuit-breaker.js +2 -1
- package/dist/brain/degrading.d.ts +1 -1
- package/dist/brain/degrading.js +4 -1
- package/dist/brain/errors.d.ts +3 -3
- package/dist/brain/failover.js +16 -1
- package/dist/brain/open-responses.js +15 -5
- package/dist/brain/openai.js +16 -5
- package/dist/brain/reasoning.d.ts +2 -2
- package/dist/brain/repetition.d.ts +1 -1
- package/dist/brain/request-params.d.ts +30 -27
- package/dist/brain/request-params.js +1 -7
- package/dist/brain/route-adjudicator.d.ts +190 -0
- package/dist/brain/route-adjudicator.js +189 -0
- package/dist/brain/route-conformance.d.ts +55 -0
- package/dist/brain/route-conformance.js +136 -0
- package/dist/brain/routing.js +8 -3
- package/dist/brain/status-sink.d.ts +2 -2
- package/dist/brain/stream-shared.d.ts +1 -1
- package/dist/config/catalog.d.ts +5 -5
- package/dist/core/arg-summary.d.ts +4 -4
- package/dist/core/ask-class.d.ts +2 -2
- package/dist/core/ask-question.d.ts +1 -1
- package/dist/core/auto-compaction.d.ts +15 -15
- package/dist/core/auto-mode.d.ts +5 -5
- package/dist/core/background-agent-store.d.ts +20 -20
- package/dist/core/background-shell.d.ts +4 -4
- package/dist/core/checkpoint-store.d.ts +35 -27
- package/dist/core/context-edit.d.ts +1 -1
- package/dist/core/context-guard.d.ts +1 -1
- package/dist/core/exec-output-tail.d.ts +6 -6
- package/dist/core/file-snapshot-store.d.ts +8 -8
- package/dist/core/git-worktree-env.d.ts +3 -3
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +73 -33
- package/dist/core/hooks.js +87 -25
- package/dist/core/image-downsample.d.ts +1 -1
- package/dist/core/locked-config.d.ts +1 -1
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/mailbox-store.d.ts +1 -1
- package/dist/core/mcp.d.ts +3 -3
- package/dist/core/mcp.js +4 -4
- package/dist/core/memory-engine/consolidation-driver.d.ts +207 -0
- package/dist/core/memory-engine/consolidation-driver.js +378 -0
- package/dist/core/memory-engine/consolidation.d.ts +46 -2
- package/dist/core/memory-engine/consolidation.js +1 -0
- package/dist/core/memory-engine/data-plane.d.ts +1 -1
- package/dist/core/memory-engine/distiller.d.ts +550 -0
- package/dist/core/memory-engine/distiller.js +598 -0
- package/dist/core/memory-engine/dual-root.d.ts +1 -1
- package/dist/core/memory-engine/engine.d.ts +62 -8
- package/dist/core/memory-engine/engine.js +40 -4
- package/dist/core/memory-engine/file-backend.d.ts +1 -1
- package/dist/core/memory-engine/index.d.ts +4 -2
- package/dist/core/memory-engine/index.js +4 -2
- package/dist/core/memory-engine/origin-clearance.d.ts +1 -1
- package/dist/core/memory-engine/scope-contract.d.ts +4 -4
- package/dist/core/memory-engine/sync-client.d.ts +16 -16
- package/dist/core/memory-engine/sync.d.ts +4 -4
- package/dist/core/memory-recall.d.ts +1 -1
- package/dist/core/memory.d.ts +2 -2
- package/dist/core/permission-rule-consent.d.ts +230 -36
- package/dist/core/permission-rule-consent.js +258 -54
- package/dist/core/permission-rule-model.d.ts +295 -97
- package/dist/core/permission-rule-model.js +132 -41
- package/dist/core/permission-rules.d.ts +9 -9
- package/dist/core/remote-env.d.ts +8 -8
- package/dist/core/roles.d.ts +3 -3
- package/dist/core/roles.js +1 -0
- package/dist/core/runner/assemble-result.d.ts +2 -2
- package/dist/core/runner/compaction-call-options.d.ts +3 -3
- package/dist/core/runner/memory-consolidation-driver.d.ts +49 -0
- package/dist/core/runner/memory-consolidation-driver.js +60 -0
- package/dist/core/runner/memory-consolidation.d.ts +1 -1
- package/dist/core/runner/prepare-config-doors.d.ts +3 -3
- package/dist/core/runner/prepare-task.d.ts +21 -21
- package/dist/core/runner/prepare-task.js +54 -18
- package/dist/core/runner/prepare-workspace-restore.d.ts +2 -2
- package/dist/core/runner/runtask.d.ts +15 -12
- package/dist/core/runner/runtask.js +48 -0
- package/dist/core/runner/session-rule-policy.d.ts +1 -1
- package/dist/core/runner/teardown-bounded.d.ts +1 -1
- package/dist/core/runner/tool-disclosure.d.ts +2 -2
- package/dist/core/runner/turn-attachments.d.ts +11 -11
- package/dist/core/scheduler.d.ts +10 -5
- package/dist/core/secret-env.d.ts +1 -1
- package/dist/core/sensitive-path-policy.d.ts +1 -1
- package/dist/core/session-policy-store.d.ts +2 -2
- package/dist/core/session-reconcile.d.ts +2 -2
- package/dist/core/session-store.d.ts +3 -3
- package/dist/core/session.d.ts +1 -1
- package/dist/core/shutdown-debug.d.ts +2 -2
- package/dist/core/side-query.d.ts +14 -7
- package/dist/core/spec-contract.d.ts +1 -1
- package/dist/core/store-contracts/contract-harness.d.ts +2 -2
- package/dist/core/store-contracts/contract-kit-version.d.ts +2 -2
- package/dist/core/store-contracts/mailbox-store-contract.d.ts +1 -1
- package/dist/core/store-contracts/mailbox-store-contract.js +1 -1
- package/dist/core/task-notification.d.ts +5 -5
- package/dist/core/task-registry-agent.d.ts +12 -12
- package/dist/core/task-registry-monitor.d.ts +1 -1
- package/dist/core/task-registry-shared.d.ts +41 -41
- package/dist/core/task-registry.d.ts +12 -12
- package/dist/core/tool-detach.d.ts +2 -2
- package/dist/core/tool-errors.d.ts +3 -3
- package/dist/core/tool-policy.d.ts +55 -28
- package/dist/core/tool-result-budget.d.ts +1 -1
- package/dist/core/tool-result-store.d.ts +2 -2
- package/dist/core/tools.d.ts +1 -1
- package/dist/core/trace.d.ts +26 -23
- package/dist/core/types.d.ts +155 -70
- package/dist/core/untrusted-egress.d.ts +1 -1
- package/dist/core/untrusted-text.d.ts +7 -7
- package/dist/core/wiring-manifest.d.ts +5 -5
- package/dist/core/workflow-journal-store.d.ts +14 -14
- package/dist/core/workflow-run-store-contract.d.ts +1 -1
- package/dist/core/workflow-run-store-contract.js +1 -1
- package/dist/core/workflow-run-store.d.ts +4 -4
- package/dist/engine/compaction/compaction.d.ts +3 -3
- package/dist/engine/compaction/utils.d.ts +2 -2
- package/dist/engine/execution-env/kill-tree.d.ts +1 -1
- package/dist/engine/execution-env/node-execution-env.d.ts +8 -8
- package/dist/engine/harness/agent-harness.d.ts +6 -6
- package/dist/engine/harness/agent-harness.js +26 -1
- package/dist/engine/harness/messages.d.ts +1 -1
- package/dist/engine/harness/types.d.ts +15 -11
- package/dist/engine/llm/types.d.ts +79 -14
- package/dist/engine/loop/agent-loop.d.ts +3 -3
- package/dist/engine/loop/types.d.ts +4 -4
- package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
- package/dist/engine/session/import-validate.d.ts +1 -1
- package/dist/engine/session/log-digest.d.ts +1 -1
- package/dist/engine/session/memory-repo.d.ts +2 -2
- package/dist/engine/session/session.d.ts +4 -4
- package/dist/fixtures/index.d.ts +4 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +5 -2
- package/dist/internal/llm.d.ts +1 -1
- package/dist/orchestration/goal.d.ts +1 -1
- package/dist/orchestration/run-spec.d.ts +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +12 -12
- package/dist/orchestration/workflow-governance.d.ts +4 -4
- package/dist/orchestration/workflow-observe.d.ts +1 -1
- package/dist/orchestration/workflow-script-runner.d.ts +1 -1
- package/dist/orchestration/workflow-script-store.d.ts +9 -9
- package/dist/orchestration/workflow-size-guideline.d.ts +1 -1
- package/dist/orchestration/workflow-types.d.ts +5 -5
- package/dist/orchestration/workflow.d.ts +10 -10
- package/dist/prompt-assembly/artifact-store.d.ts +1 -1
- package/dist/prompt-assembly/artifact.d.ts +1 -1
- package/dist/prompt-assembly/assemble.d.ts +1 -1
- package/dist/prompt-assembly/composer.d.ts +2 -2
- package/dist/prompt-assembly/epoch.d.ts +2 -2
- package/dist/prompt-assembly/event-registry.d.ts +1 -1
- package/dist/prompt-assembly/explain.d.ts +3 -3
- package/dist/prompt-assembly/tool-catalog.d.ts +1 -1
- package/dist/prompt-assembly/turn-snapshot.d.ts +4 -4
- package/dist/prompt-assembly/types.d.ts +12 -12
- package/dist/prompts/coordinator.d.ts +1 -1
- package/dist/prompts/default.d.ts +10 -10
- package/dist/prompts/default.js +2 -0
- package/dist/prompts/simple-sections.d.ts +3 -3
- package/dist/prompts/supervisor.d.ts +2 -2
- package/dist/scenarios/full-body.d.ts +3 -3
- package/dist/scenarios/scenario-registry.d.ts +6 -2
- package/dist/scenarios/scenario-registry.js +4 -2
- package/dist/stores/cc/sidecar-transcript.d.ts +3 -3
- package/dist/stores/file/fs-atomic.d.ts +2 -2
- package/dist/stores/file/index.d.ts +1 -1
- package/dist/stores/file/session-store.d.ts +2 -2
- package/dist/stores/file/workflow-journal-store.d.ts +4 -4
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
- package/dist/tools/fs/encoding.d.ts +4 -4
- package/dist/tools/fs/fs-bash.d.ts +3 -3
- package/dist/tools/fs/fs-pdf.d.ts +1 -1
- package/dist/tools/fs/fs-shared.d.ts +6 -6
- package/dist/tools/fs/index.d.ts +2 -2
- package/dist/tools/fs/index.js +8 -1
- package/dist/tools/fs/notebook.d.ts +1 -1
- package/dist/tools/fs/pdf.d.ts +1 -1
- package/dist/tools/fs/read-deny.d.ts +1 -1
- package/dist/tools/fs/safety.d.ts +9 -9
- package/dist/tools/fs/search.d.ts +2 -2
- package/dist/tools/monitor.d.ts +3 -3
- package/dist/tools/scheduler-tools.js +28 -6
- package/dist/tools/task-list.d.ts +2 -2
- package/dist/tools/web.d.ts +19 -4
- package/dist/tools/web.js +8 -2
- package/dist/tools/worktree.d.ts +5 -5
- package/dist/tools/worktree.js +2 -2
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +74 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,127 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.58.0 — 2026-08-24
|
|
4
|
+
|
|
5
|
+
### BREAKING (design/375 case A — per-segment batch consent; ships as one window, no compatibility arms)
|
|
6
|
+
- **`AskRequest.ruleSuggestions` → `ruleOffers`**: a closed discriminated union
|
|
7
|
+
(`single{rule,match,command}` | `batch{rules(1..5), uncoveredSegments}`); at most 2 offers, the
|
|
8
|
+
whole-string exact single always at index 0, the batch always last; choosing a batch is ONE yes to
|
|
9
|
+
all its members. `PendingAction.tool_approval` carries the same seat. An unknown offer kind
|
|
10
|
+
degrades to a single opaque row preserving the original wire index (fail toward asking).
|
|
11
|
+
- **`RuleApprovalRecord` schema:2**: `schema`+`offers` required; `selectedCandidate` → `selectedOffer`.
|
|
12
|
+
Pre-v2 rows refuse loudly (`record_schema_stale`, envelope read, ownership concealment keeps
|
|
13
|
+
precedence) — pending approvals from before the upgrade are re-asked, never migrated. Supplying the
|
|
14
|
+
retired `selectedCandidate` key (or `selectedOffer: null`) refuses `config.invalid_argument`.
|
|
15
|
+
- **`redeemRuleBatch`** returns a per-member discriminated table `{members, rev}` keyed by
|
|
16
|
+
`candidateIndex` (success rows carry `alreadyRedeemed`+`dot`, refused rows carry `reason`;
|
|
17
|
+
exactly one row per selected-offer member, projection map fixed); the three-array `ImportResult`
|
|
18
|
+
shape is deleted. `RuleApprovalRecordStore.get` may return `StaleRuleApprovalRecord` (envelope).
|
|
19
|
+
- **Engine conjunction arm** (§5.1): a compound command whose EVERY segment is admitted by some
|
|
20
|
+
eligible persisted rule is allowed — the segment deny/ask fence stays strictly ahead, whole-string
|
|
21
|
+
exact and the compound-prefix form keep their precedence, and a single-command prefix still never
|
|
22
|
+
admits a compound. `PersistedRuleHit` becomes `{ rules }` (covering set; evidence dots = union).
|
|
23
|
+
Eligibility is two-layered and single-sourced (`eligiblePersisted`/`eligibleContext`;
|
|
24
|
+
tombstoned/foreign-scope rules can never join a conjunction).
|
|
25
|
+
- The suggester mints offers (`suggestRulesForCommand` returns `RuleOffer[]`; only uncovered
|
|
26
|
+
segments enter a batch; the compound-prefix candidate is no longer offered — existing
|
|
27
|
+
compound-prefix rules keep matching forever); the card-edit face accepts one edited rule judged by
|
|
28
|
+
the single-rule coverage predicate.
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **LLM-driven memory consolidation, slices 1+2 (design/376; default OFF, additive)**: the fold-plan
|
|
32
|
+
distiller becomes a product module (frozen prompt contract byte-equal to the benchmark's, canonical
|
|
33
|
+
hash pinned; structural repairs counted, repair-budget abort); `runMemoryConsolidationDriver` host
|
|
34
|
+
verb with a first-class run row (claim/attempt single-writer, stale-rev replay guard, write-failure
|
|
35
|
+
groups end the run `driver_failed`, `memory.consolidation_incomplete` notice, FORCED announcement
|
|
36
|
+
once per run); `consolidate` model role resolving consolidate → summarize → loud refusal (never the
|
|
37
|
+
default model). The bench rig now consumes the product module (scripted-arm projection digest
|
|
38
|
+
unchanged across the port). Auto-trigger wiring is a later slice; nothing runs without an explicit
|
|
39
|
+
driver seat.
|
|
40
|
+
- **Dependency-direction gate**: the engine's bottom-of-graph position is frozen mechanically (no
|
|
41
|
+
sibling `@sema-agent/*` in manifest or src imports).
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
- **Internal-wording sweep over the shipped surface** (S10 class): board-coordinate and campaign-name
|
|
45
|
+
vocabulary cleared to zero across shipped `.d.ts` JSDoc and runtime strings (744 comment lines
|
|
46
|
+
rewritten 1:1, two runtime string leaks fixed); the wording gate's lexicon now also catches
|
|
47
|
+
3-digit coordinate forms.
|
|
48
|
+
- Bench provenance axis (P1) landed with two harness fixes (seed origin carriage, read/write
|
|
49
|
+
provenance mode mismatch) — measurement only, no engine behavior change.
|
|
50
|
+
|
|
51
|
+
## 5.57.0 — 2026-08-23
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
- **key×URL pairing adjudicator** (#309 cross-repo case, [5060]-[5063] consensus): `adjudicateModelRoute`
|
|
55
|
+
is the single source of the credential-pairing law. Per-model credential = paired by construction;
|
|
56
|
+
the deployment-config credential passes only on the deployment's own declared root; absent credential
|
|
57
|
+
is legal keyless except for an entry declaring its own off-root URL. Codes `route.credential_mismatch`
|
|
58
|
+
/ `route.credential_missing` (refusal detail carries entry id + both URL halves + a one-line fixHint,
|
|
59
|
+
fail-closed by ruling). The three first-party brains gate inside buildRequest (refusal terminates
|
|
60
|
+
before any fetch) and expose `Brain.adjudicateRoute`; routing/failover/degrading/circuit-breaker
|
|
61
|
+
re-judge per leg (failover serves from the paired leg; a broken degrading hop is skipped). Two-leg
|
|
62
|
+
disposition: a NAMED model surfaces the refusal; a DERIVED model (compaction summarize, auto-mode
|
|
63
|
+
classifier, suggestions) pre-flights and falls back to the primary with a `route.fallback_to_primary`
|
|
64
|
+
notice; `route.base_url_changed_key_unchanged` mints at swapModels. `ROUTE_ADJUDICATION_CONFORMANCE_CORPUS`
|
|
65
|
+
(16 vectors) exported as the cross-codebase anchor. **Narrowings (each with a fixHint)**: declared-root
|
|
66
|
+
deployments' off-root entries now refuse instead of silently borrowing the gateway credential; an
|
|
67
|
+
entry-declared auth header now wins over the deployment key. Preserved byte-identical: unpinned
|
|
68
|
+
quick-start, keyless single-gateway, header-only boot token, gateway dual-auth.
|
|
69
|
+
- **Per-model auth seats for WebFetch summarizer and team surfaces** (#417): `getApiKeyAndHeaders`
|
|
70
|
+
on `WebFetchSummarizerOptions` / `TeamDiscussionOptions` / `runScenario` (absent seat = byte-identical).
|
|
71
|
+
- **Compound-prefix permission rules** (#364 case B, ruled; registered divergence): `Bash(cd /tmp && adb pull:*)`
|
|
72
|
+
— leading segments byte-exact, only the final segment takes arguments. The validator accepts the
|
|
73
|
+
chain form (a `*` in any other position still refuses); the matcher admits on segment-count equality
|
|
74
|
+
+ byte-prefix at a word boundary (a single-command prefix still never admits a compound; the segment
|
|
75
|
+
deny/ask fence stays strictly ahead of the allow lane); the suggester mints the compound-prefix
|
|
76
|
+
sibling at index 1 when the final segment fits the same grammar as the simple seat; the card-edit
|
|
77
|
+
face accepts the respelling; org tighten gains the same grammar (a compound-prefix deny is enforceable
|
|
78
|
+
instead of bricking its snapshot). **Widenings**: validator accepts the new form; eligible compounds
|
|
79
|
+
offer 2 seats; card edit + import accept it; org snapshots carrying it are enforceable. **Mixed-fleet
|
|
80
|
+
note**: older engines quarantine compound-prefix rows (bytes preserved, disclosed) — do not publish
|
|
81
|
+
compound-prefix org rules before the fleet is level.
|
|
82
|
+
- **Generic prefix grammar for rule suggestions** (#364 R1, CC 2.1.223 iNo corpus): the prefix arm
|
|
83
|
+
uses the corpus rule `^[a-z][a-z0-9]*(-[a-z0-9]+)*$` with the interpreter/wrapper blacklist; the
|
|
84
|
+
125-line lexicon demotes to a bonus for multi-word deepening; ASCII-closed head-name screen.
|
|
85
|
+
- **`precheckEditedRuleText(text, command)`** (#428, server pickup): the card-edit face's three text
|
|
86
|
+
gates (spelling normalization → grammar → coverage bound) extracted to one shared body and exported
|
|
87
|
+
(`EditedRuleTextPrecheck`). `ok` means SUBMITTABLE (record-level gates stay with `confirmRuleApproval`);
|
|
88
|
+
`canonicalRule` may differ from the submitted bytes; refusal words match `edit_rejected.detail`
|
|
89
|
+
verbatim (`code` rides validator refusals only). The entry screens unrenderable command bytes loudly
|
|
90
|
+
(`config.invalid_argument`).
|
|
91
|
+
- **ScheduleWakeup honesty family** (#424 A-1/A-4): the wakeup intent carries `lifetime:"session"`
|
|
92
|
+
where the backend vouched for the reap contract; an undeclared backend keeps the historic durable
|
|
93
|
+
intent with receipt + description disclosure; `reason` rides `details.reason`. An incomplete
|
|
94
|
+
replace (stale wakeup possibly still armed) is disclosed on the receipt.
|
|
95
|
+
- **SendMessage completion promises follow mount truth** (#424 A-6): `notificationWired?` / `oneShot?`
|
|
96
|
+
seats (defaults preserve wired behavior byte-identical); the unwired arm teaches retrieval, the
|
|
97
|
+
one-shot arm instructs blocking retrieval now; ten sites across two wordings guarded.
|
|
98
|
+
|
|
99
|
+
### Fixed
|
|
100
|
+
- **Derived-route pre-flight can never sink the main task** (pre-ship rescan P1): the judge call and
|
|
101
|
+
the whole seat (including URL normalization of garbage catalog values) now abstain on throw instead
|
|
102
|
+
of failing task preparation and leaking the acquired session view; both derived seats share the
|
|
103
|
+
guarded helper.
|
|
104
|
+
- **Route URL comparison is wire-equivalent** (rescan): scheme/host case-fold + default-port elision
|
|
105
|
+
(path half stays byte-ordered; parse failure falls back to raw) — case-only respellings of the same
|
|
106
|
+
endpoint no longer refuse as `credential_mismatch`.
|
|
107
|
+
- **MCP revocation copy tells the standing truth at all four outlets** (rescan; #424 A-5 completed):
|
|
108
|
+
the ListMcpResources arm joins the other three ("stays on this run's roster; every call refused
|
|
109
|
+
the same way"), with an extinction tripwire for the old sentence.
|
|
110
|
+
- **AgentHarness auth carriers refuse loudly at the two host seats** (rescan hardening): a
|
|
111
|
+
deployment-wide auth header in `streamOptions.headers` is refused with a migration hint instead of
|
|
112
|
+
silently riding beside per-model credentials; `stripAuthHeaders` retired (zero callers).
|
|
113
|
+
- **ExitWorktree parameter texts describe this tool** (#424 A-8): detached worktrees have no branch;
|
|
114
|
+
a changed tree is KEPT (not refused) — CC originals and reasoning recorded at the schema.
|
|
115
|
+
- **Read-only memory notice restores CC's recall-framing paragraph** (#424 A-9, byte-compared).
|
|
116
|
+
- **MCP/scheduler small truths** (rescan): the wakeup mount note is led by the `supportsSessionWakeup:false`
|
|
117
|
+
arm; an explicitly-declared `supportsSessionLifetime:false` backend behaves like an undeclared one
|
|
118
|
+
(seam defines the two spellings as one state — the refusal arm from an unshipped interim build rolled back).
|
|
119
|
+
|
|
120
|
+
### Bench (not part of the package surface)
|
|
121
|
+
- LLM distillation arm for the memory benchmark (three-clause instruction arc: retained 20.8%→100%,
|
|
122
|
+
convergence restored; distillation quality flat with the hand-authored ceiling on this corpus's
|
|
123
|
+
measurable axes); live provider key no longer travels to the loopback observation plane.
|
|
124
|
+
|
|
3
125
|
## 5.56.0 — 2026-08-23
|
|
4
126
|
|
|
5
127
|
### Fixed
|
package/dist/agents/cascade.d.ts
CHANGED
|
@@ -105,7 +105,7 @@ export interface CascadeAttempt {
|
|
|
105
105
|
index: number;
|
|
106
106
|
model: ModelRef;
|
|
107
107
|
passed: boolean;
|
|
108
|
-
/** This rung's OWN+nested spend. ABSENT when the rung ran unpriced (RB-368 knownness
|
|
108
|
+
/** This rung's OWN+nested spend. ABSENT when the rung ran unpriced (RB-368 knownness batch-4
|
|
109
109
|
* F4) — a fabricated 0 here both misreported the attempt and let escalation ride under a finite
|
|
110
110
|
* ceiling the engine could not actually enforce. */
|
|
111
111
|
costMicroUsd?: number;
|
|
@@ -58,7 +58,7 @@ export interface CumulativeStatsAccumulator {
|
|
|
58
58
|
/**
|
|
59
59
|
* TRUE when ANY contributing leg published no `costMicroUsd`, i.e. it ran on a model with neither a
|
|
60
60
|
* `RunnerDeps.pricing` entry nor a `Model.cost` declaration (`stats.costMicroUsd` is contractually
|
|
61
|
-
* ABSENT there — types.ts / RB-368
|
|
61
|
+
* ABSENT there — types.ts / RB-368).
|
|
62
62
|
*
|
|
63
63
|
* Accumulating such a leg as `?? 0` publishes a total that is not one: the operation's real cost is
|
|
64
64
|
* unknown, and reporting the priced legs' partial sum makes "no price table" indistinguishable from
|
|
@@ -257,12 +257,12 @@ export declare class ObserverPairing {
|
|
|
257
257
|
retire(state: Exclude<ObserverPairingState, "armed">): void;
|
|
258
258
|
}
|
|
259
259
|
export declare function markObserverTaskId(taskId: string): void;
|
|
260
|
-
/**
|
|
260
|
+
/** lifecycle revocation: the wiring unmarks at observed-run settle (after the final
|
|
261
261
|
* drain + session release), so the set tracks LIVE observers only instead of growing per delegation
|
|
262
262
|
* forever (and a long-dead observer id no longer trips the SendMessage target refusal). */
|
|
263
263
|
export declare function unmarkObserverTaskId(taskId: string): void;
|
|
264
264
|
export declare function isObserverTaskId(taskId: string): boolean;
|
|
265
|
-
/** Diagnostic face
|
|
265
|
+
/** Diagnostic face: how many observer identities are currently LIVE — a test's
|
|
266
266
|
* lifecycle assertion ("armed here, revoked after settle") without exposing the ids themselves. */
|
|
267
267
|
export declare function observerTaskIdCount(): number;
|
|
268
268
|
/** CC @18371202 — SendMessage refusal when the SENDER is an observer run. */
|
|
@@ -127,7 +127,7 @@ export interface PeerAdmissionOptions {
|
|
|
127
127
|
export declare function createPeerAdmission(options?: PeerAdmissionOptions): PeerAdmission;
|
|
128
128
|
export declare function peerAdmissionFor(scope: string | undefined, recipientKey: string, config: PeerAdmissionConfig, options?: PeerAdmissionOptions): PeerAdmission;
|
|
129
129
|
/**
|
|
130
|
-
* The delivery legs' ONE admission entry
|
|
130
|
+
* The delivery legs' ONE admission entry: registry seat-commit follows the SAME
|
|
131
131
|
* refusal-is-side-effect-free rule as the sender table inside `admit` — the instance is looked up
|
|
132
132
|
* WITHOUT an LRU touch (a detached fresh one serves a first-contact recipient), judged, and only an
|
|
133
133
|
* ADMITTED message commits the seat (insert + touch + bounded eviction). A refusal to a
|
|
@@ -96,7 +96,7 @@ export interface RetainLedgerHooks {
|
|
|
96
96
|
* `prepareTask` when the spec opts in, threaded to delegation tools as the TRUSTED `ctx.subagentRetain`,
|
|
97
97
|
* and disposed by the Runner in the task's terminal `finally` (D4: abort in-flight resumes + unpin +
|
|
98
98
|
* release every retained session — retain is NOT durable; resume is reachable only while the parent run
|
|
99
|
-
* lives
|
|
99
|
+
* lives). Leaks are double-bounded by `max` + `ttlMs`.
|
|
100
100
|
*/
|
|
101
101
|
export declare class SubagentRetainLedger {
|
|
102
102
|
readonly ttlMs: number;
|
|
@@ -159,7 +159,7 @@ export declare class SubagentRetainLedger {
|
|
|
159
159
|
get size(): number;
|
|
160
160
|
get(parentToolCallId: string): SubagentRetainEntry | undefined;
|
|
161
161
|
wasEvicted(parentToolCallId: string): boolean;
|
|
162
|
-
/**
|
|
162
|
+
/** LAZY TTL sweep: evict every settled idle entry whose retain TTL
|
|
163
163
|
* elapsed (unpin + release + tombstone), so an expired session is freed at the NEXT ledger touch
|
|
164
164
|
* (every spawn-registration and resume entry call this) rather than only when its own resume is tried.
|
|
165
165
|
* fidelity R4-1: no longer the only reaper — `markSettled` also arms a per-entry ACTIVE timer, so
|
|
@@ -8,7 +8,7 @@ export interface RosterEntry {
|
|
|
8
8
|
sessionId?: string;
|
|
9
9
|
/** The spawn's parent tool-call id (retain-ledger key), when known. */
|
|
10
10
|
toolUseId?: string;
|
|
11
|
-
/**
|
|
11
|
+
/** the ROOT host session of the delegation tree at spawn (recovery-face grouping
|
|
12
12
|
* key; equals the spawner's session at depth 1). Stored verbatim; no predicate arm consumes it
|
|
13
13
|
* yet (enumeration/recovery is the reader). */
|
|
14
14
|
rootSessionId?: string;
|
|
@@ -19,11 +19,11 @@ export interface RosterEntry {
|
|
|
19
19
|
* inherited default. Closed set, single member today; absent = bound normally (or no word). */
|
|
20
20
|
modelFallback?: "inherit_no_tier_binding";
|
|
21
21
|
/** Spawn owner (task/session id) — consumers re-apply access checks against these two axes.
|
|
22
|
-
*
|
|
22
|
+
* A-2: REQUIRED (default-deny predicate; an axis-less row would be unreachable). */
|
|
23
23
|
owner: string;
|
|
24
|
-
/** Spawn principal scope.
|
|
24
|
+
/** Spawn principal scope. A-2: REQUIRED (`"default"` is the single-tenant spelling). */
|
|
25
25
|
scope: string;
|
|
26
|
-
/**
|
|
26
|
+
/** mirrors the live registry's explicit session-scoping flag: session-ID owner matching
|
|
27
27
|
* is permitted ONLY when the spawn was session-scoped (TaskRegistry.canAccess parity — without
|
|
28
28
|
* the flag, a task-scoped agent that fell out of the live registry would become visible through
|
|
29
29
|
* the durable fallback to same-session callers the registry itself rejects). */
|
|
@@ -33,7 +33,7 @@ export interface RosterEntry {
|
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* The caller's access axes for a roster read — the SAME predicate the live task registry applies
|
|
36
|
-
* (`canAccess`): scope mismatch = invisible; then owner match, or session match.
|
|
36
|
+
* (`canAccess`): scope mismatch = invisible; then owner match, or session match. (S1
|
|
37
37
|
* review): resolution MUST filter the candidate pool by access BEFORE the latest-wins reduce —
|
|
38
38
|
* reduce-then-check lets one tenant's newer same-name entry shadow (and thereby suppress) another
|
|
39
39
|
* tenant's older authorized binding. Implementations (incl. pg/tidb) apply this in the query.
|
|
@@ -43,7 +43,7 @@ export interface RosterAccess {
|
|
|
43
43
|
scope?: string;
|
|
44
44
|
sessionId?: string;
|
|
45
45
|
}
|
|
46
|
-
/**
|
|
46
|
+
/** Ruled 2026-07-22: DEFAULT-DENY both axes (TaskRegistry.canAccess byte-parity —
|
|
47
47
|
* the polarity split was the defect). Entries are written with both axes (spawn chain guarantees
|
|
48
48
|
* it; {@link RosterEntry} requires them), so a missing axis is a broken row, answered with a miss. */
|
|
49
49
|
export declare function entryAccessible(e: RosterEntry, access: RosterAccess): boolean;
|
|
@@ -77,7 +77,7 @@ export interface RosterStore {
|
|
|
77
77
|
/** Record (or supersede — latest-wins per normalized name is applied at READ time) a binding. */
|
|
78
78
|
record(entry: RosterEntry): void | Promise<void>;
|
|
79
79
|
/** Resolve a name for a CALLER: filter by {@link RosterAccess} FIRST, then latest `createdAt`
|
|
80
|
-
* wins within the authorized pool (
|
|
80
|
+
* wins within the authorized pool (filter-before-reduce). Undefined = miss. */
|
|
81
81
|
resolve(name: string, access: RosterAccess): RosterEntry | undefined | Promise<RosterEntry | undefined>;
|
|
82
82
|
/** All live entries (diagnostics / deployment listing; order unspecified). */
|
|
83
83
|
list(): RosterEntry[] | Promise<RosterEntry[]>;
|
|
@@ -148,7 +148,7 @@ export declare class FileRosterStore implements RosterStore {
|
|
|
148
148
|
* miss on resolve/list — advisory layer), but it is no longer SILENT: an IO failure or corrupt
|
|
149
149
|
* document was indistinguishable from an honestly empty roster. Never fires on plain ENOENT. */
|
|
150
150
|
private discloseCorrupt;
|
|
151
|
-
/**
|
|
151
|
+
/** two read grades: MISSING file (ENOENT) is an honest empty roster, but a corrupt or
|
|
152
152
|
* transiently unreadable file must THROW on the mutation path — treating it as empty would let
|
|
153
153
|
* the next `record` atomically REPLACE the existing file with just one row (silent data loss).
|
|
154
154
|
* Read paths (resolve/list) degrade the throw to a miss via `lenient`. */
|
|
@@ -33,6 +33,17 @@ export interface SendMessageToolOptions {
|
|
|
33
33
|
notify?: (n: TaskNotificationPayload, opts?: {
|
|
34
34
|
priority?: "now" | "next" | "later";
|
|
35
35
|
}) => void;
|
|
36
|
+
/** Whether a completion notification really reaches the sender — drives every "you will be notified"
|
|
37
|
+
* sentence on this face (description + four receipts), mirroring TaskOutput's `notificationWired`.
|
|
38
|
+
* Default = `notify !== undefined`, which is the truth on both the first-party mount and a direct
|
|
39
|
+
* mount that wires its own sink here. Pass `true` only when the deployment announces a finished
|
|
40
|
+
* agent through a channel of its own (this tool then keeps the wired wording); `false` states the
|
|
41
|
+
* degraded truth explicitly. */
|
|
42
|
+
notificationWired?: boolean;
|
|
43
|
+
/** RB-220 mirror of {@link import("../core/types.js").TaskSpec.oneShot} (the Runner mount fills it):
|
|
44
|
+
* this run's process exits when the turn ends, so no completion notification can ever land — checked
|
|
45
|
+
* AHEAD of {@link notificationWired}, since no amount of wiring makes a later turn exist. */
|
|
46
|
+
oneShot?: boolean;
|
|
36
47
|
/** Steer-handle sink: the revived run re-emits a FRESH handle (design/122 risk-table contract). */
|
|
37
48
|
sink?: (handle: SubagentSteerHandle) => void;
|
|
38
49
|
/**
|
|
@@ -48,7 +59,7 @@ export interface SendMessageToolOptions {
|
|
|
48
59
|
senderName?: string;
|
|
49
60
|
/** design/147 S1c — the deployment's durable roster, consulted after the live registry misses. */
|
|
50
61
|
roster?: import("./roster-store.js").RosterStore;
|
|
51
|
-
/** design/147 S3a
|
|
62
|
+
/** design/147 S3a — the PARENT run's retain ledger (RunInternals.parentRetainLedger):
|
|
52
63
|
* the sibling leg's retain entries live there. Consulted AFTER the own-run and session ledgers. */
|
|
53
64
|
siblingRetain?: SubagentRetainLedger;
|
|
54
65
|
/** RB-390 — the SPAWNING run's taskId when THIS run is a delegated child (RunInternals.parentTaskId,
|
|
@@ -67,7 +78,7 @@ export interface SendMessageToolOptions {
|
|
|
67
78
|
* session-scoped sibling registers with owner = the parent's sessionId, which the parent's
|
|
68
79
|
* taskId alone cannot satisfy when the two differ (same rationale as ToolExecuteContext.parentSessionId). */
|
|
69
80
|
parentSessionId?: string;
|
|
70
|
-
/**
|
|
81
|
+
/** the process-level background-child observer (RunnerDeps.onBackgroundChildEvent) — the
|
|
71
82
|
* mount fills this so a SendMessage resume re-emits the spawn→tick→terminal family (fleet row
|
|
72
83
|
* revival). Rides the OPTS closure like notify; RB-409's {@link enrichCtx} feeds the ctx twin. */
|
|
73
84
|
onBackgroundChildEvent?: (event: import("../core/types.js").BackgroundChildEvent) => void;
|
|
@@ -46,6 +46,21 @@ function targetLaneKey(scope, targetId) {
|
|
|
46
46
|
const OPERATOR_CONTINUATION_CTX = Symbol("sema.operator_continuation");
|
|
47
47
|
export function createSendMessageTool(opts) {
|
|
48
48
|
const tier3Capable = opts.agentStore !== undefined && opts.mailbox !== undefined && opts.reviveSpawn !== undefined;
|
|
49
|
+
const completionMode = opts.oneShot === true ? "one_shot" : (opts.notificationWired ?? opts.notify !== undefined) ? "notified" : "silent";
|
|
50
|
+
const notifyWired = completionMode === "notified";
|
|
51
|
+
const NO_COMPLETION_NOTICE = completionMode === "one_shot"
|
|
52
|
+
? "this is a ONE-SHOT submission — there is no later turn for a completion notification to land in, so retrieve its result NOW with TaskOutput(task_id, block: true) rather than ending your turn"
|
|
53
|
+
: "its completion is NOT announced on this mount — retrieve its status and result with TaskOutput(task_id) where mounted";
|
|
54
|
+
const AWAIT_COMPLETION = notifyWired
|
|
55
|
+
? "Wait for its completion notification"
|
|
56
|
+
: completionMode === "one_shot"
|
|
57
|
+
? "Wait for it NOW with TaskOutput(task_id, block: true) — this one-shot submission ends with this turn"
|
|
58
|
+
: "Check for its completion with TaskOutput(task_id) where mounted";
|
|
59
|
+
const awaitCompletion = notifyWired
|
|
60
|
+
? "wait for its completion notification"
|
|
61
|
+
: completionMode === "one_shot"
|
|
62
|
+
? "wait for it NOW with TaskOutput(task_id, block: true) — this one-shot submission ends with this turn"
|
|
63
|
+
: "check for its completion with TaskOutput(task_id) where mounted";
|
|
49
64
|
const sendMessagePins = new Map();
|
|
50
65
|
const pinGuard = (targetId, targetName, rung, to) => {
|
|
51
66
|
if (rung === "other")
|
|
@@ -86,8 +101,11 @@ export function createSendMessageTool(opts) {
|
|
|
86
101
|
`background run with its full prior conversation preserved, so don't re-explain what it already knows. Names ` +
|
|
87
102
|
`keep working after an agent completes; but if a name you already messaged is later taken by a NEWER agent, the ` +
|
|
88
103
|
`send is refused rather than silently redirected — re-send with the task_id of whichever agent you meant. ` +
|
|
89
|
-
|
|
90
|
-
|
|
104
|
+
(notifyWired
|
|
105
|
+
? `You will be notified automatically when it completes — prefer ending your turn; do not poll. `
|
|
106
|
+
: completionMode === "one_shot"
|
|
107
|
+
? `This is a ONE-SHOT submission: there is no later turn for a completion notification to land in, so do NOT end your turn expecting one — wait actively with TaskOutput(task_id, block: true) when you need a continued agent's result. `
|
|
108
|
+
: `A finished agent is NOT announced on this mount — check on it with TaskOutput(task_id) where mounted rather than ending your turn to wait for a notification that never comes. `) +
|
|
91
109
|
(tier3Capable
|
|
92
110
|
? `Continuing a finished agent works for agents with a durable record — by name or task_id, even across restarts — and for runs that retain sub-agent sessions; when neither covers it you get an honest error and should launch a new agent with the needed context instead.`
|
|
93
111
|
: `Continuing a finished agent requires the run to retain sub-agent sessions; when the session was not ` +
|
|
@@ -255,7 +273,7 @@ export function createSendMessageTool(opts) {
|
|
|
255
273
|
if (row.status === "running") {
|
|
256
274
|
if (row.writerId === opts.registry.writerId) {
|
|
257
275
|
return {
|
|
258
|
-
content: `Message not sent: ${whoT3} is currently running in this process but its mid-run delivery channel is not reachable from here.
|
|
276
|
+
content: `Message not sent: ${whoT3} is currently running in this process but its mid-run delivery channel is not reachable from here. ${AWAIT_COMPLETION}, then send again to continue it.`,
|
|
259
277
|
details: { error: "still_running", to },
|
|
260
278
|
isError: true,
|
|
261
279
|
};
|
|
@@ -268,7 +286,7 @@ export function createSendMessageTool(opts) {
|
|
|
268
286
|
};
|
|
269
287
|
}
|
|
270
288
|
return {
|
|
271
|
-
content: `Message not sent: ${whoT3} is running on another host — this process has no delivery channel to it.
|
|
289
|
+
content: `Message not sent: ${whoT3} is running on another host — this process has no delivery channel to it. ${AWAIT_COMPLETION}, then send again to continue it.`,
|
|
272
290
|
details: { error: "running_elsewhere", to },
|
|
273
291
|
isError: true,
|
|
274
292
|
};
|
|
@@ -501,7 +519,9 @@ export function createSendMessageTool(opts) {
|
|
|
501
519
|
const priorCount = lease.messages.length - 1;
|
|
502
520
|
return {
|
|
503
521
|
content: `Message sent — ${whoT3} was revived in the background with its prior context intact${priorCount > 0 ? ` (${priorCount} earlier pending message(s) delivered with it)` : ""}. ` +
|
|
504
|
-
|
|
522
|
+
(notifyWired
|
|
523
|
+
? `You will be notified automatically when it completes. Continue with other work — do not poll.`
|
|
524
|
+
: `${NO_COMPLETION_NOTICE.charAt(0).toUpperCase()}${NO_COMPLETION_NOTICE.slice(1)}.`),
|
|
505
525
|
details: { type: "send-message", status: "revived", to, task_id: handle, seq: nextSeq, ...(priorCount > 0 ? { priorMessages: priorCount } : {}) },
|
|
506
526
|
};
|
|
507
527
|
}
|
|
@@ -628,10 +648,10 @@ export function createSendMessageTool(opts) {
|
|
|
628
648
|
}, { priority: "next" });
|
|
629
649
|
if (delivered.ok) {
|
|
630
650
|
const receiptText = delivered.disposition === "parked"
|
|
631
|
-
? `Message parked for ${who}: the agent finished before reading it — it will be delivered when the agent is next continued. You will be notified of its completion; continue with other work.`
|
|
651
|
+
? `Message parked for ${who}: the agent finished before reading it — it will be delivered when the agent is next continued. ${notifyWired ? "You will be notified of its completion; continue with other work." : `Note: ${NO_COMPLETION_NOTICE}.`}`
|
|
632
652
|
: delivered.disposition === "pending"
|
|
633
|
-
? `Message accepted for ${who} but delivery is UNCONFIRMED (its channel did not confirm within the wait window) — it stays queued and will deliver if the channel binds. You will be notified of the agent's completion either way; resend then if it went unanswered. ${DEDUP_RETRY_NOTE}`
|
|
634
|
-
: `Message queued for delivery to ${who} at its next turn. If it finishes before reading it, the message may not survive — you will be notified of its completion either way; resend then if it went unanswered. Continue with other work; do not poll. ${DEDUP_RETRY_NOTE}`;
|
|
653
|
+
? `Message accepted for ${who} but delivery is UNCONFIRMED (its channel did not confirm within the wait window) — it stays queued and will deliver if the channel binds. ${notifyWired ? "You will be notified of the agent's completion either way" : `Note: ${NO_COMPLETION_NOTICE}`}; resend then if it went unanswered. ${DEDUP_RETRY_NOTE}`
|
|
654
|
+
: `Message queued for delivery to ${who} at its next turn. If it finishes before reading it, the message may not survive — ${notifyWired ? "you will be notified of its completion either way" : NO_COMPLETION_NOTICE}; resend then if it went unanswered. ${notifyWired ? "Continue with other work; do not poll. " : ""}${DEDUP_RETRY_NOTE}`;
|
|
635
655
|
return {
|
|
636
656
|
content: receiptText,
|
|
637
657
|
details: { type: "send-message", status: "delivered_running", disposition: delivered.disposition, to, task_id: targetId, summary },
|
|
@@ -639,7 +659,7 @@ export function createSendMessageTool(opts) {
|
|
|
639
659
|
}
|
|
640
660
|
if (delivered.reason === "no_channel") {
|
|
641
661
|
return {
|
|
642
|
-
content: `Message not sent: ${who} is still running and this deployment has no mid-run delivery channel for it.
|
|
662
|
+
content: `Message not sent: ${who} is still running and this deployment has no mid-run delivery channel for it. ${AWAIT_COMPLETION}, then SendMessage to continue it. ${DEDUP_RETRY_NOTE}`,
|
|
643
663
|
details: { error: "still_running", to },
|
|
644
664
|
isError: true,
|
|
645
665
|
};
|
|
@@ -705,7 +725,7 @@ export function createSendMessageTool(opts) {
|
|
|
705
725
|
}
|
|
706
726
|
if (ledger.get(resumeToolUseId)?.running === true) {
|
|
707
727
|
return {
|
|
708
|
-
content: `Message not sent: ${who} (or a prior follow-up to it) is still running —
|
|
728
|
+
content: `Message not sent: ${who} (or a prior follow-up to it) is still running — ${awaitCompletion}.`,
|
|
709
729
|
details: { error: "steering.still_running", to },
|
|
710
730
|
isError: true,
|
|
711
731
|
};
|
|
@@ -761,7 +781,9 @@ export function createSendMessageTool(opts) {
|
|
|
761
781
|
const marker = await resume(`${fromPrefix}[${safeSummary}] ${safeMessage}`);
|
|
762
782
|
return {
|
|
763
783
|
content: `Message sent — ${who} resumed in the background with its prior context intact (correlation marker [${marker}]).\n` +
|
|
764
|
-
|
|
784
|
+
(notifyWired
|
|
785
|
+
? `You will be notified automatically when it completes; its reply will carry [${marker}]. Continue with other work — do not poll.`
|
|
786
|
+
: `Its reply will carry [${marker}], but ${NO_COMPLETION_NOTICE}.`),
|
|
765
787
|
details: { type: "send-message", status: "resumed", to, task_id: targetId, marker, summary },
|
|
766
788
|
};
|
|
767
789
|
}
|
|
@@ -778,7 +800,7 @@ export function createSendMessageTool(opts) {
|
|
|
778
800
|
? `${who} reached its resume cap (${SUBAGENT_RESUME_CAP} follow-ups per agent) — relaunch a new agent instead.`
|
|
779
801
|
: code === "steering.still_running"
|
|
780
802
|
?
|
|
781
|
-
`${who} (or a prior follow-up to it) is still running —
|
|
803
|
+
`${who} (or a prior follow-up to it) is still running — ${awaitCompletion}. ${DEDUP_RETRY_NOTE}`
|
|
782
804
|
: code === "resume.row_recycling"
|
|
783
805
|
?
|
|
784
806
|
`${who}'s registry row is being adjudicated right now (a revival claim or a reap sweep holds it) — send again in a moment. ${DEDUP_RETRY_NOTE}`
|
|
@@ -84,7 +84,7 @@ export declare class SubagentStepRecorder {
|
|
|
84
84
|
editedFiles(): SubagentEditedFile[] | undefined;
|
|
85
85
|
/** The child's most recent tool intent as one human line ("Bash npm test", "Edit src/x.ts"); undefined if none. */
|
|
86
86
|
currentAction(): string | undefined;
|
|
87
|
-
/**
|
|
87
|
+
/** {@link currentAction} pre-formatted into a fleet-view Progress-section
|
|
88
88
|
* shape — the SAME `{tool, target}` pair `currentAction` already concatenates into one line, exposed
|
|
89
89
|
* separately so a consumer can look the tool up in its own registry instead of parsing prose.
|
|
90
90
|
* Undefined if none observed (mirrors {@link currentAction}'s own undefined case exactly). */
|
|
@@ -335,8 +335,8 @@ export interface SubagentSteerHandle {
|
|
|
335
335
|
/**
|
|
336
336
|
* design/122 D1 — the retained child session id; present ONLY when the parent run enabled
|
|
337
337
|
* {@link import("../core/types.js").TaskSpec.retainSubagentSessions} AND this child was actually
|
|
338
|
-
* retained. ⚠️ Control-plane only
|
|
339
|
-
* clients; target children by the opaque `parentToolCallId` instead
|
|
338
|
+
* retained. ⚠️ Control-plane only: this is a continuation CAPABILITY — never expose it to
|
|
339
|
+
* clients; target children by the opaque `parentToolCallId` instead.
|
|
340
340
|
*/
|
|
341
341
|
childSessionId?: string;
|
|
342
342
|
/**
|
|
@@ -385,7 +385,7 @@ export declare function createSubagentResume(deps: {
|
|
|
385
385
|
* apply to EVERY stop cycle, spawn and resume alike). Absent ⇒ honest ungated degradation (no
|
|
386
386
|
* registry to count against — the pre-C1 immediate send). */
|
|
387
387
|
registry?: import("../core/task-registry.js").TaskRegistry;
|
|
388
|
-
/** design/147 S1a
|
|
388
|
+
/** design/147 S1a — the RESUMING caller's live injection entry: overrides the retained
|
|
389
389
|
* snapshot's spawn-turn `parentNotify` (that lane is torn down with its turn — uplinks through it
|
|
390
390
|
* would PARK instead of reaching the currently active parent turn, behind a success receipt). */
|
|
391
391
|
currentParentNotify?: (n: TaskNotificationPayload, opts?: {
|
|
@@ -442,7 +442,7 @@ export declare function createSubagentResume(deps: {
|
|
|
442
442
|
taskId?: string;
|
|
443
443
|
/** S2b RB-27② — the resuming caller's resolved registry access (pairs with taskId). */
|
|
444
444
|
taskAccess?: import("../core/task-registry.js").TaskAccess;
|
|
445
|
-
/**
|
|
445
|
+
/** the process-level background-child observer (ctx.onBackgroundChildEvent, Runner-filled).
|
|
446
446
|
* When present TOGETHER with a revived registry row (taskId + successful revive), the resume cycle
|
|
447
447
|
* re-emits the SAME spawn→tick→terminal event family as a first spawn — a fleet view's row revives
|
|
448
448
|
* on the spawn frame (server treats spawn-after-tombstone as row revival). The spawn frame is
|
|
@@ -450,11 +450,11 @@ export declare function createSubagentResume(deps: {
|
|
|
450
450
|
* tick — the observer's tombstone-period tick rejection depends on that order). No revived row ⇒
|
|
451
451
|
* no frames (the steer-handle resume path has no a*-domain row to project). */
|
|
452
452
|
bgSink?: (event: import("../core/types.js").BackgroundChildEvent) => void;
|
|
453
|
-
/**
|
|
453
|
+
/** row lifetime class echoed onto the revive frames (mirrors the registry row). */
|
|
454
454
|
sessionScoped?: boolean;
|
|
455
|
-
/**
|
|
455
|
+
/** the row's display description, echoed onto the revive spawn frame (resume-marked). */
|
|
456
456
|
rowDescription?: string;
|
|
457
|
-
/**
|
|
457
|
+
/** the row's original observer metadata, reproduced on the revive frames so
|
|
458
458
|
* a consumer rebuilding a tombstoned row gets its TYPE/name/ancestry back (never a blank row). */
|
|
459
459
|
rowName?: string;
|
|
460
460
|
rowAgentType?: string;
|
|
@@ -516,10 +516,10 @@ export interface SubagentToolOptions {
|
|
|
516
516
|
*/
|
|
517
517
|
background?: {
|
|
518
518
|
registry: import("../core/task-registry.js").TaskRegistry;
|
|
519
|
-
/**
|
|
519
|
+
/** A-2 (BREAKING 1.365.0): REQUIRED — the registry is default-deny on both axes, so a
|
|
520
520
|
* background registration without a declared owner would be unreachable by every caller. */
|
|
521
521
|
owner: string;
|
|
522
|
-
/**
|
|
522
|
+
/** A-2 (BREAKING 1.365.0): REQUIRED — `"default"` is the single-tenant spelling (explicit,
|
|
523
523
|
* matching the engine chain's `principal ?? "default"`), never implied by omission. */
|
|
524
524
|
scope: string;
|
|
525
525
|
/**
|
|
@@ -559,7 +559,7 @@ export interface SubagentToolOptions {
|
|
|
559
559
|
* vetoes the park: the child settles failed exactly as pre-153, and the already-minted
|
|
560
560
|
* checkpoint is expired (no orphans). Never called for sync children or non-suspending runs.
|
|
561
561
|
*
|
|
562
|
-
* ⚠️ Implementation obligation (
|
|
562
|
+
* ⚠️ Implementation obligation (field-proven): "migrates it here"
|
|
563
563
|
* means ACTIVELY PROMOTE — a check-only implementation that merely LOOKS UP the host durable
|
|
564
564
|
* store rejects every child whose session lives in a split/transient tier (a subRunner's
|
|
565
565
|
* private TTL store), and the veto fires on EVERY park: the checkpoint expires within
|
|
@@ -658,7 +658,7 @@ export interface SubagentToolOptions {
|
|
|
658
658
|
* agent is selected) govern them verbatim: an explicit allowlist must NAME an injected tool for the
|
|
659
659
|
* child to see it; `"*"`/absent allowlist = all. Nested delegation threads the SAME factory down
|
|
660
660
|
* (`createSubagentToolNode(opts, depth+1)` carries it), so a grandchild spawn re-evaluates it — per-spawn,
|
|
661
|
-
* at every level; each child gets its own instances bound to its own spawn moment (
|
|
661
|
+
* at every level; each child gets its own instances bound to its own spawn moment (the
|
|
662
662
|
* server-side factory is execute-time late-bound, so per-spawn evaluation is the confirmed shape).
|
|
663
663
|
* A THROWING/rejecting factory degrades THAT spawn to zero injected tools (the child still runs)
|
|
664
664
|
* with a FIXED generic `note:` disclosure on the report/async card (same lane as the model-override
|
|
@@ -793,7 +793,7 @@ export declare function asyncLaunchedReceipt(p: {
|
|
|
793
793
|
taskId: string;
|
|
794
794
|
/** The lane's own "what is running" opener — the Agent lane and the fork lane say different things. */
|
|
795
795
|
workingLine: string;
|
|
796
|
-
/** Whether a real notification sink is wired (
|
|
796
|
+
/** Whether a real notification sink is wired (the receipt speaks the RUNTIME sink truth). */
|
|
797
797
|
notify: boolean;
|
|
798
798
|
/**
|
|
799
799
|
* RB-220 — mirrors {@link import("../core/types.js").ToolExecuteContext.oneShot}: this run has no
|
|
@@ -821,7 +821,7 @@ export declare function createSubagentTool(opts: SubagentToolOptions): ToolSpec;
|
|
|
821
821
|
* "All tools except …"; neither ⇒ "All tools". sema delta: `allowTools: ["*"]` is the documented
|
|
822
822
|
* allow-everything sentinel (AgentDefinition.allowTools) — treated as NO allowlist, not a literal list.
|
|
823
823
|
*
|
|
824
|
-
*
|
|
824
|
+
* deliberate: this renders the AUTHORED list raw — upstream's listing does too (gHm reads the
|
|
825
825
|
* definition; the unknown-item split happens later, at spawn, in its resolveAgentTools). It is the
|
|
826
826
|
* DECLARED boundary, NOT the effective child roster: an unknown entry may appear here while the
|
|
827
827
|
* spawn-time filter (resolveToolSubset — the authority) drops it, and an alias-form divergence can
|
package/dist/agents/team.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Runner } from "../core/runner/runtask.js";
|
|
2
|
-
import type { McpServerSpec, ModelRef, ModelRole, TaskResult, ToolSpec } from "../core/types.js";
|
|
2
|
+
import type { McpServerSpec, ModelRef, ModelRole, TaskResult, TaskSpec, ToolSpec } from "../core/types.js";
|
|
3
3
|
export interface TeamMember {
|
|
4
4
|
/** The member's role / specialty, e.g. "安全评审" or "performance". */
|
|
5
5
|
role: string;
|
|
@@ -45,7 +45,7 @@ export type TeamEvent = {
|
|
|
45
45
|
role: string;
|
|
46
46
|
text: string;
|
|
47
47
|
}
|
|
48
|
-
/**
|
|
48
|
+
/** budget axes: the cumulative team budget was exhausted after this member's turn settled —
|
|
49
49
|
* remaining rounds/members are skipped and the discussion goes straight to synthesis. */
|
|
50
50
|
| {
|
|
51
51
|
type: "budget_stop";
|
|
@@ -99,12 +99,21 @@ export interface TeamDiscussionOptions {
|
|
|
99
99
|
denyTools?: string[];
|
|
100
100
|
mcp?: McpServerSpec[];
|
|
101
101
|
};
|
|
102
|
+
/**
|
|
103
|
+
* Per-model auth — MIRRORS {@link TaskSpec.getApiKeyAndHeaders} (forwarded into every member /
|
|
104
|
+
* summary / synthesizer run, which resolve it against their own resolved models). Without this
|
|
105
|
+
* seat a team whose member/synthesizer models live on per-model-credential routes had NO way to
|
|
106
|
+
* carry the resolver: every nested run fell to the brain's construction-time credential, which the
|
|
107
|
+
* key↔URL pairing gate refuses off the deployment root — the teacher/verify delegation family
|
|
108
|
+
* carries the same seat for the same reason.
|
|
109
|
+
*/
|
|
110
|
+
getApiKeyAndHeaders?: TaskSpec["getApiKeyAndHeaders"];
|
|
102
111
|
/** Progress callback. */
|
|
103
112
|
onEvent?: (e: TeamEvent) => void;
|
|
104
113
|
/**
|
|
105
114
|
* `maxWalltimeMs`/`maxTurns` are PER-RUN caps forwarded to every member/summary/synthesizer run.
|
|
106
115
|
*
|
|
107
|
-
* `maxTokens`/`maxCostUsd` (
|
|
116
|
+
* `maxTokens`/`maxCostUsd` (CollabTemplate.budget mid-flight enforcement) are CUMULATIVE
|
|
108
117
|
* team budgets over member + summary + synthesizer spend (nested/delegated spend included, same
|
|
109
118
|
* coordinate as the `stats` totals). Enforcement is checked after each member turn settles and is
|
|
110
119
|
* booked — the crossing member is never killed in flight — and once a budget is exhausted
|
|
@@ -167,7 +176,7 @@ export interface TeamResult {
|
|
|
167
176
|
* conclusion — so callers can tell a junk conclusion from a legitimate one. */
|
|
168
177
|
conclusionValid: boolean;
|
|
169
178
|
transcript: TeamTurn[];
|
|
170
|
-
/** `costMicroUsd
|
|
179
|
+
/** `costMicroUsd`: cumulative team LLM spend in integer micro-USD (member + summary +
|
|
171
180
|
* synthesizer, nested included) — the same engine coordinate as `TaskResult.stats.costMicroUsd`.
|
|
172
181
|
* Always set (0 when no run reported cost); optional only for type-level back-compat. */
|
|
173
182
|
stats: {
|
|
@@ -176,7 +185,7 @@ export interface TeamResult {
|
|
|
176
185
|
costMicroUsd?: number;
|
|
177
186
|
};
|
|
178
187
|
/**
|
|
179
|
-
*
|
|
188
|
+
* budget-stop attribution: set when a cumulative budget axis was exhausted and the
|
|
180
189
|
* discussion stopped dispatching further members/rounds early. `round`/`role`/`memberIndex`
|
|
181
190
|
* identify the LAST member turn that ran (the one whose settled totals crossed the budget);
|
|
182
191
|
* everything scheduled after it was skipped and the transcript went straight to synthesis.
|
|
@@ -193,7 +202,7 @@ export interface TeamResult {
|
|
|
193
202
|
failures: number;
|
|
194
203
|
/** How many times the shared transcript was summarized to stay under maxTranscriptTokens. */
|
|
195
204
|
transcriptCompactions: number;
|
|
196
|
-
/** design/80 D-B
|
|
205
|
+
/** design/80 D-B: set when a member durably PAUSED (suspended/needs_review) on a HITL gate —
|
|
197
206
|
* the discussion STOPS (no synthesis on a half-done team) and surfaces the resume capability so the caller
|
|
198
207
|
* can resume the paused member via the token, then re-run. `conclusionValid` is false in this case. */
|
|
199
208
|
durablePause?: boolean;
|
package/dist/agents/team.js
CHANGED
|
@@ -117,6 +117,7 @@ export async function runTeamDiscussion(opts) {
|
|
|
117
117
|
limits: memberLimits,
|
|
118
118
|
signal: opts.signal,
|
|
119
119
|
...(opts.principal !== undefined ? { principal: opts.principal } : {}),
|
|
120
|
+
...(opts.getApiKeyAndHeaders !== undefined ? { getApiKeyAndHeaders: opts.getApiKeyAndHeaders } : {}),
|
|
120
121
|
}, { isDelegatedChild: true });
|
|
121
122
|
tokens += res.stats.tokens + (res.stats.nested?.tokens ?? 0);
|
|
122
123
|
turns += res.stats.turns + (res.stats.nested?.turns ?? 0);
|
|
@@ -13,10 +13,10 @@ import type { ToolSpec } from "../core/types.js";
|
|
|
13
13
|
* newly-added sensitive tool to every agent. Names not present in the pool are ignored (no error) — an
|
|
14
14
|
* allow/deny list is a filter over what's available, not an assertion that those tools exist.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
16
|
+
* anchor ruling (dual-leg verified, adversarially reviewed): this spawn-time item-level filter IS
|
|
17
17
|
* the upstream shape for allow entries — CC's resolveAgentTools partitions unknown names into an
|
|
18
18
|
* `invalidTools` bucket nobody consumes at runtime (88 readable source), and a live 2.1.207 probe shows
|
|
19
|
-
* the agent stays listed/delegable with the unknown item silently dropped, zero warnings. The
|
|
19
|
+
* the agent stays listed/delegable with the unknown item silently dropped, zero warnings. The
|
|
20
20
|
* "rejected at startup" posture this replaced had no verbatim anchor and did not survive verification.
|
|
21
21
|
* The asymmetric prepare-time fail-loud for `TaskSpec.agents` DENY entries is a deliberate sema
|
|
22
22
|
* extension (no upstream deny-list exists): an allow-typo silently narrows (safe direction), a
|
package/dist/agents/verify.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ import type { ModelRef, TaskResult, TaskSpec, ToolSpec } from "../core/types.js"
|
|
|
25
25
|
* orthogonal to and composable with the Stop hook (wire the verdict into a stop() hook to make it a
|
|
26
26
|
* hard completion gate).
|
|
27
27
|
*
|
|
28
|
-
* DEPLOYMENT POSTURE (
|
|
28
|
+
* DEPLOYMENT POSTURE (ruled 2026-07-14): opt-in library primitive ONLY — never a scenario default,
|
|
29
29
|
* never deployed implicitly. It is a **thin composition** over existing core seams — a verifier subtask
|
|
30
30
|
* (own model role), a read-only tool set (via tool `effect`), {@link TaskSpec.outputSchema} for the
|
|
31
31
|
* verdict, and the teacher-style fix loop — so it adds no Runner-core surface. Off by default; opt in
|