@sema-agent/core 7.29.0 → 7.30.1
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 +393 -0
- package/dist/agents/child-model-seat.d.ts +59 -7
- package/dist/agents/child-model-seat.js +33 -7
- package/dist/agents/cross-session-judge.d.ts +27 -5
- package/dist/agents/cross-session-judge.js +23 -12
- package/dist/agents/list-agents-tool.d.ts +31 -6
- package/dist/agents/list-agents-tool.js +66 -14
- package/dist/agents/peer-admission.d.ts +20 -8
- package/dist/agents/peer-admission.js +21 -12
- package/dist/agents/peer-directory.d.ts +29 -0
- package/dist/agents/peer-directory.js +20 -0
- package/dist/agents/peer-held-queue.d.ts +31 -4
- package/dist/agents/peer-held-queue.js +32 -1
- package/dist/agents/peer-session-drain.d.ts +91 -13
- package/dist/agents/peer-session-drain.js +409 -102
- package/dist/agents/read-inbox-tool.d.ts +22 -0
- package/dist/agents/read-inbox-tool.js +39 -0
- package/dist/agents/roster-store.d.ts +2 -4
- package/dist/agents/roster-store.js +1 -1
- package/dist/agents/send-message-tool.d.ts +4 -4
- package/dist/agents/send-message-tool.js +22 -2
- package/dist/agents/subagent.js +62 -44
- package/dist/agents/team-role.d.ts +34 -0
- package/dist/agents/team-role.js +17 -0
- package/dist/agents/verify.js +2 -2
- package/dist/core/auto-compaction.d.ts +42 -0
- package/dist/core/auto-compaction.js +35 -2
- package/dist/core/child-clamp-seats.d.ts +11 -0
- package/dist/core/child-clamp-seats.js +3 -0
- package/dist/core/context-edit.d.ts +3 -2
- package/dist/core/context-edit.js +6 -5
- package/dist/core/context-guard.d.ts +2 -1
- package/dist/core/context-guard.js +3 -2
- package/dist/core/context-settings.d.ts +103 -0
- package/dist/core/context-settings.js +60 -0
- package/dist/core/engine-notice.d.ts +11 -1
- package/dist/core/frame-settlement.d.ts +97 -0
- package/dist/core/frame-settlement.js +36 -0
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +10 -10
- package/dist/core/mailbox-store.d.ts +41 -7
- package/dist/core/mailbox-store.js +9 -3
- package/dist/core/parent-spec-seat.d.ts +14 -1
- package/dist/core/parent-spec-seat.js +6 -0
- package/dist/core/permission-rule-model.js +1 -1
- package/dist/core/roles.d.ts +20 -0
- package/dist/core/roles.js +35 -16
- package/dist/core/runner/assemble-result.d.ts +2 -0
- package/dist/core/runner/assemble-result.js +1 -1
- package/dist/core/runner/compaction-call-options.d.ts +26 -2
- package/dist/core/runner/compaction-call-options.js +9 -0
- package/dist/core/runner/compaction-seams.d.ts +4 -3
- package/dist/core/runner/compaction-seams.js +13 -6
- package/dist/core/runner/contracts.d.ts +56 -7
- package/dist/core/runner/decide-continuation.d.ts +2 -1
- package/dist/core/runner/decide-continuation.js +11 -10
- package/dist/core/runner/initial-run-state.js +1 -1
- package/dist/core/runner/prepare-caps-and-workflow.js +9 -1
- package/dist/core/runner/prepare-config-doors.js +4 -1
- package/dist/core/runner/prepare-context-lane.d.ts +9 -2
- package/dist/core/runner/prepare-context-lane.js +15 -10
- package/dist/core/runner/prepare-delegation-surface.d.ts +3 -2
- package/dist/core/runner/prepare-delegation-surface.js +9 -3
- package/dist/core/runner/prepare-file-history.js +10 -8
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -0
- package/dist/core/runner/prepare-gate-stations.js +3 -1
- package/dist/core/runner/prepare-inherited-gate.js +1 -0
- package/dist/core/runner/prepare-prompt-inputs.d.ts +6 -0
- package/dist/core/runner/prepare-prompt-inputs.js +2 -1
- package/dist/core/runner/prepare-task.js +22 -9
- package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -1
- package/dist/core/runner/prepare-wiring-manifest.js +6 -1
- package/dist/core/runner/retired-runner-deps.d.ts +3 -1
- package/dist/core/runner/retired-runner-deps.js +1 -0
- package/dist/core/runner/run-compaction-machinery.d.ts +4 -2
- package/dist/core/runner/run-compaction-machinery.js +5 -3
- package/dist/core/runner/run-harness-handlers.js +1 -1
- package/dist/core/runner/run-identity-wiring.js +19 -1
- package/dist/core/runner/run-leg.js +1 -1
- package/dist/core/runner/run-notification-lane.js +8 -2
- package/dist/core/runner/run-recovery-lanes.js +9 -5
- package/dist/core/runner/run-settle-and-teardown.d.ts +4 -22
- package/dist/core/runner/run-settle-and-teardown.js +6 -10
- package/dist/core/runner/run-stop-and-final-verify.js +1 -0
- package/dist/core/runner/run-terminal-adoption.js +5 -5
- package/dist/core/runner/run-turn-boundary.js +32 -5
- package/dist/core/runner/runtask.d.ts +8 -1
- package/dist/core/runner/runtask.js +32 -1
- package/dist/core/runner-deps.d.ts +44 -13
- package/dist/core/secret-env.js +2 -1
- package/dist/core/swappable-deps.d.ts +20 -4
- package/dist/core/swappable-deps.js +6 -1
- package/dist/core/task-event.d.ts +5 -0
- package/dist/core/task-notification.d.ts +144 -2
- package/dist/core/task-notification.js +154 -5
- package/dist/core/task-result.d.ts +14 -0
- package/dist/core/task-spec.d.ts +7 -0
- package/dist/core/tool-catalog-entries.js +2 -1
- package/dist/core/tool-conformance.js +1 -0
- package/dist/core/tool-policy.d.ts +9 -4
- package/dist/core/tool-spec.d.ts +14 -0
- package/dist/core/wiring-manifest.d.ts +12 -0
- package/dist/core/wiring-manifest.js +5 -1
- package/dist/engine/harness/agent-harness.d.ts +14 -1
- package/dist/engine/harness/agent-harness.js +28 -3
- package/dist/engine/harness/types.d.ts +3 -1
- package/dist/engine/llm/types.d.ts +8 -7
- package/dist/engine/llm/types.js +1 -1
- package/dist/engine/lsp/node-lsp-manager.d.ts +3 -0
- package/dist/engine/lsp/node-lsp-manager.js +5 -3
- package/dist/engine/session/import-validate.js +4 -0
- package/dist/index.d.ts +10 -7
- package/dist/index.js +7 -5
- package/dist/orchestration/run-workflow-tool.d.ts +4 -4
- package/dist/orchestration/workflow.d.ts +1 -1
- package/dist/orchestration/workflow.js +8 -5
- package/dist/shell/lex.d.ts +38 -54
- package/dist/shell/lex.js +239 -286
- package/dist/stores/cc/mailbox-store.js +3 -2
- package/dist/stores/file/corrupt-read-sink.d.ts +28 -2
- package/dist/stores/file/file-history-store.d.ts +2 -4
- package/dist/stores/file/file-history-store.js +1 -1
- package/dist/stores/file/fs-atomic.d.ts +16 -11
- package/dist/stores/file/fs-atomic.js +17 -6
- package/dist/stores/file/index.d.ts +5 -6
- package/dist/stores/file/index.js +1 -1
- package/dist/stores/file/mailbox-store.d.ts +4 -9
- package/dist/stores/file/mailbox-store.js +29 -30
- package/dist/stores/file/session-policy-store.d.ts +2 -0
- package/dist/stores/file/session-policy-store.js +1 -1
- package/dist/stores/file/session-store.d.ts +11 -7
- package/dist/stores/file/session-store.js +23 -16
- package/dist/stores/file/shared-ledger.js +3 -14
- package/dist/stores/file/tool-result-store.d.ts +2 -0
- package/dist/stores/file/tool-result-store.js +5 -2
- package/dist/stores/file/workflow-journal-store.js +14 -9
- package/dist/tools/fs/bash-program-position.d.ts +15 -24
- package/dist/tools/fs/bash-program-position.js +11 -29
- package/dist/tools/fs/bash-readonly-classifier.d.ts +131 -117
- package/dist/tools/fs/bash-readonly-classifier.js +404 -272
- package/dist/tools/fs/shell-read-check.js +3 -3
- package/dist/tools/fs/shell-read-establish.d.ts +1 -1
- package/dist/tools/fs/shell-read-establish.js +5 -33
- package/dist/tools/fs/shell-read-identity.d.ts +13 -0
- package/dist/tools/fs/shell-read-identity.js +39 -0
- package/dist/tools/fs/shell-read-judge.d.ts +8 -0
- package/dist/tools/fs/shell-read-judge.js +7 -0
- package/dist/tools/fs/shell-read-plan.d.ts +15 -6
- package/dist/tools/fs/shell-read-plan.js +171 -195
- package/dist/tools/fs/shell-read-word.d.ts +64 -0
- package/dist/tools/fs/shell-read-word.js +94 -0
- package/dist/tools/fs/shell-reentry-text.d.ts +10 -0
- package/dist/tools/fs/shell-reentry-text.js +73 -0
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +58 -8
- package/wire-changes/core@7.30.0.json +1821 -0
- package/wire-changes/core@7.30.1.json +154 -0
|
@@ -44,6 +44,10 @@ export interface MailboxPeerMeta {
|
|
|
44
44
|
* — a delivery receipt's state (`kind: "delivery_notice"`) or an idle notice's kind
|
|
45
45
|
* (`kind: "idle_notice"`). The record's `content` is a human-readable mirror; THIS is the authority. */
|
|
46
46
|
notice?: MailboxPeerNoticeMeta;
|
|
47
|
+
/** `peer_message` only — the SENDER marked it urgent. The recipient's drain presents an urgent record
|
|
48
|
+
* ahead of the non-urgent ones of the same pass and counts it on the inbox notice; it never changes
|
|
49
|
+
* WHEN the recipient reads (the recipient's setting decides that, never the sender). */
|
|
50
|
+
urgent?: boolean;
|
|
47
51
|
}
|
|
48
52
|
/** design/385 — the typed body of a notice-kind record. `state` is drawn from the receipt states on a
|
|
49
53
|
* `delivery_notice` (`held|denied|expired|delivered|refused|dropped`) and from the idle kinds on an
|
|
@@ -67,10 +71,23 @@ export interface MailboxPeerNoticeMeta {
|
|
|
67
71
|
}
|
|
68
72
|
export declare const MAILBOX_PEER_FROM_MODES: readonly ["bypass", "prompting"];
|
|
69
73
|
export type MailboxPeerFromMode = (typeof MAILBOX_PEER_FROM_MODES)[number];
|
|
70
|
-
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
|
|
74
|
+
/**
|
|
75
|
+
* design/385: `peer_message` runs the parity judgment; `idle_subscription` registers the sender as an
|
|
76
|
+
* idle subscriber of the box owner (§5.2, the store form of CC's `notify_when_idle` frame);
|
|
77
|
+
* `idle_notice` / `delivery_notice` land on the notice face (rendered, never enveloped as a peer's words).
|
|
78
|
+
*
|
|
79
|
+
* @contract mailbox.engine_frame_is_not_a_peers_words — an `engine_frame` record is the ENGINE's own
|
|
80
|
+
* task-notification frame parked durably (a child's terminal, a monitor batch, a workflow settle),
|
|
81
|
+
* written by the park seat of the session that owns the box and only over a deployment that vouches
|
|
82
|
+
* every drainer of the box reads the codec (`RunnerDeps.sessionBoxEngineFrames`). Its `content` is the
|
|
83
|
+
* versioned codec text (`encodeEngineFrame`), never a message: the drain decodes it and re-injects the
|
|
84
|
+
* frame through the engine's own notification lane — no parity judgment, no admission gate, no peer
|
|
85
|
+
* envelope — and a codec version this engine does not read STOPS the drain at that record (the box
|
|
86
|
+
* waits for an engine that reads it) rather than rendering engine speech as a peer's words. Only the
|
|
87
|
+
* engine's own lanes (`background_agent` / `monitor` / `workflow`) may be parked this way; an
|
|
88
|
+
* `external` event never is.
|
|
89
|
+
*/
|
|
90
|
+
export declare const MAILBOX_PEER_RECORD_KINDS: readonly ["peer_message", "idle_notice", "delivery_notice", "idle_subscription", "engine_frame"];
|
|
74
91
|
export type MailboxPeerRecordKind = (typeof MAILBOX_PEER_RECORD_KINDS)[number];
|
|
75
92
|
/** The `notice.state` vocabulary the validator admits (the union of both notice families; the drain
|
|
76
93
|
* checks the kind↔state pairing). Spelled here, beside the record kinds, so the store contract is
|
|
@@ -183,7 +200,7 @@ export interface MailboxAppendMessage {
|
|
|
183
200
|
* persists it and hands it back on `claimLease` byte-for-byte (a detached copy), absent stays absent,
|
|
184
201
|
* and a malformed value is REFUSED with `"mailbox.invalid_peer_meta"` before any side effect
|
|
185
202
|
* (`readMailboxPeerMeta` is the one validator; bundled backends call it first). T1 cases in
|
|
186
|
-
* `mailboxStoreContract` cover the
|
|
203
|
+
* `mailboxStoreContract` cover the pass trip, the refusal and the aliasing.
|
|
187
204
|
* - CROSS-PROCESS SAFETY (design/385, optional capability declared on the store): the session-box
|
|
188
205
|
* drain shares ONE box between several OS processes. A backend that is correct under that sharing —
|
|
189
206
|
* seq minted once across processes, lease/ack never crossing, one process's housekeeping never
|
|
@@ -192,6 +209,12 @@ export interface MailboxAppendMessage {
|
|
|
192
209
|
* that does not declare it is refused by the lane at mount time with a named reason
|
|
193
210
|
* ({@link mailboxCrossProcessMountVerdict}) — never silently mounted on luck.
|
|
194
211
|
*/
|
|
212
|
+
/** #1036 — what {@link MailboxStore.ack} answers: did this call actually consume the prefix?
|
|
213
|
+
* `false` = the lease fence refused it (this caller does not hold the box), so nothing was deleted
|
|
214
|
+
* and the records are still parked for whoever does. */
|
|
215
|
+
export interface MailboxAckResult {
|
|
216
|
+
readonly acked: boolean;
|
|
217
|
+
}
|
|
195
218
|
export interface MailboxStore {
|
|
196
219
|
/** design/385 — cross-process safety declaration (see the interface notes). `true` = this backend
|
|
197
220
|
* passed `mailboxCrossProcessContract` over real OS processes; `false` = deliberately process-local
|
|
@@ -202,7 +225,18 @@ export interface MailboxStore {
|
|
|
202
225
|
* that its recipient is in the deployment's pre-delete state (see the interface notes above). */
|
|
203
226
|
append(scope: string, handle: string, msg: MailboxAppendMessage): Promise<number>;
|
|
204
227
|
claimLease(scope: string, handle: string, owner: string, ttlMs: number, now?: number): Promise<MailboxLease | null>;
|
|
205
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Consume the leased prefix up to `upToSeq` (the records are DELETED). Fenced by the current lease:
|
|
230
|
+
* a caller that does not hold it consumes nothing.
|
|
231
|
+
*
|
|
232
|
+
* #1036 — the fence's verdict is REPORTED (`{acked:false}`), not silent. The fence itself is
|
|
233
|
+
* older (MB1): it exists so a stale owner whose lease a live rival already took over cannot delete
|
|
234
|
+
* the rival's messages. What was missing is that a no-op and a success were the same `void` to the
|
|
235
|
+
* caller, so a drain that had lost its lease would clear its own watermark as if the store had
|
|
236
|
+
* obeyed it — the one shape where "the records stay parked" turns into "the records are forgotten".
|
|
237
|
+
* Implementations report `{acked:true}` only when they actually consumed the prefix.
|
|
238
|
+
*/
|
|
239
|
+
ack(scope: string, handle: string, owner: string, upToSeq: number): Promise<MailboxAckResult>;
|
|
206
240
|
releaseLease(scope: string, handle: string, owner: string): Promise<void>;
|
|
207
241
|
/** Observation face (the "N pending" receipt figure) — count of currently-visible messages. */
|
|
208
242
|
peekCount(scope: string, handle: string): Promise<number>;
|
|
@@ -253,7 +287,7 @@ export declare class InMemoryMailboxStore implements MailboxStore {
|
|
|
253
287
|
private box;
|
|
254
288
|
append(scope: string, handle: string, msg: MailboxAppendMessage): Promise<number>;
|
|
255
289
|
claimLease(scope: string, handle: string, owner: string, ttlMs: number, now?: number): Promise<MailboxLease | null>;
|
|
256
|
-
ack(scope: string, handle: string, owner: string, upToSeq: number): Promise<
|
|
290
|
+
ack(scope: string, handle: string, owner: string, upToSeq: number): Promise<MailboxAckResult>;
|
|
257
291
|
releaseLease(scope: string, handle: string, owner: string): Promise<void>;
|
|
258
292
|
peekCount(scope: string, handle: string): Promise<number>;
|
|
259
293
|
drop(scope: string, handle: string): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { assertRetentionPolicy } from "./retention-policy.js";
|
|
2
2
|
export const MAILBOX_PEER_FROM_MODES = ["bypass", "prompting"];
|
|
3
|
-
export const MAILBOX_PEER_RECORD_KINDS = ["peer_message", "idle_notice", "delivery_notice", "idle_subscription"];
|
|
3
|
+
export const MAILBOX_PEER_RECORD_KINDS = ["peer_message", "idle_notice", "delivery_notice", "idle_subscription", "engine_frame"];
|
|
4
4
|
export const MAILBOX_PEER_NOTICE_STATES = ["held", "denied", "expired", "delivered", "refused", "dropped", "idle", "exited", "unavailable"];
|
|
5
5
|
export const MAILBOX_INVALID_PEER_META_CODE = "mailbox.invalid_peer_meta";
|
|
6
6
|
export const MAILBOX_CROSS_PROCESS_UNSAFE_CODE = "mailbox.cross_process_unsafe";
|
|
@@ -42,6 +42,11 @@ export function readMailboxPeerMeta(raw) {
|
|
|
42
42
|
else if (k === "notice") {
|
|
43
43
|
out.notice = readMailboxPeerNoticeMeta(v, refuse);
|
|
44
44
|
}
|
|
45
|
+
else if (k === "urgent") {
|
|
46
|
+
if (typeof v !== "boolean")
|
|
47
|
+
return refuse("urgent must be a boolean");
|
|
48
|
+
out.urgent = v;
|
|
49
|
+
}
|
|
45
50
|
else {
|
|
46
51
|
return refuse(`carries an unknown key ${JSON.stringify(k)}`);
|
|
47
52
|
}
|
|
@@ -171,12 +176,13 @@ export class InMemoryMailboxStore {
|
|
|
171
176
|
async ack(scope, handle, owner, upToSeq) {
|
|
172
177
|
const b = this.boxes.get(this.key(scope, handle));
|
|
173
178
|
if (!b)
|
|
174
|
-
return;
|
|
179
|
+
return { acked: false };
|
|
175
180
|
if (b.lease === undefined || b.lease.owner !== owner)
|
|
176
|
-
return;
|
|
181
|
+
return { acked: false };
|
|
177
182
|
b.messages = b.messages.filter((m) => m.seq > upToSeq);
|
|
178
183
|
if (b.lease.maxSeq <= upToSeq)
|
|
179
184
|
b.lease = undefined;
|
|
185
|
+
return { acked: true };
|
|
180
186
|
}
|
|
181
187
|
async releaseLease(scope, handle, owner) {
|
|
182
188
|
const b = this.boxes.get(this.key(scope, handle));
|
|
@@ -13,7 +13,7 @@ import type { Hooks } from "./hooks.js";
|
|
|
13
13
|
import type { ToolExecuteContext } from "./tool-spec.js";
|
|
14
14
|
import type { TaskSpec } from "./types.js";
|
|
15
15
|
/** The fields of a spec the seat carries — one `Pick`, shared by the mint's input and the apply's target. */
|
|
16
|
-
export type ParentSpecSeatFields = Pick<TaskSpec, "principal" | "oneShot" | "clientContext" | "onQuestion" | "hooks" | "additionalDirectories" | "additionalReadDirectories" | "envFacts" | "memoryPersistenceCapable" | "memory">;
|
|
16
|
+
export type ParentSpecSeatFields = Pick<TaskSpec, "principal" | "oneShot" | "clientContext" | "onQuestion" | "hooks" | "additionalDirectories" | "additionalReadDirectories" | "envFacts" | "memoryPersistenceCapable" | "memory" | "compaction" | "skillListingBudgetFraction" | "skillListingMaxDescChars">;
|
|
17
17
|
/**
|
|
18
18
|
* The seat a run hands its children. Every member is the parent's own value, frozen at mint (arrays copied and
|
|
19
19
|
* frozen; the facts object copied). Members present iff the parent carries them — an absent member is "nothing to
|
|
@@ -33,6 +33,16 @@ export type ParentSpecSeatFields = Pick<TaskSpec, "principal" | "oneShot" | "cli
|
|
|
33
33
|
* `true` a default a child's own declaration may narrow.
|
|
34
34
|
* · `memoryOff` — the request-level "memory is off" FACT (`spec.memory.enabled === false`): a REMOVAL
|
|
35
35
|
* (floor) that REWRITES the child's own memory declaration instead of travelling as a value.
|
|
36
|
+
* · `compaction` — the request's CONTEXT-MANAGEMENT settings (enabled / withinTask / reserve / keepRecent /
|
|
37
|
+
* instructions / attachWorkingFiles / staleToolResultOffload / clampTolerance). One set of settings for the
|
|
38
|
+
* whole delegation tree, measured per leg against the leg's OWN window: the numbers are repaired against the
|
|
39
|
+
* child's model by the same sanitizer every leg runs (`sanitizeCompactionSettings`), so a parent's 128k-tuned
|
|
40
|
+
* reserve does not have to be re-tuned to be legal on a 6k child. `enabled: false` is NOT a removal — the
|
|
41
|
+
* reference implementation shares one settings object down the tree rather than flooring children, and a
|
|
42
|
+
* child that authors its own settings wins the whole object (an ORDINARY seat member).
|
|
43
|
+
* · `skillListingBudgetFraction` / `skillListingMaxDescChars` — the listing-budget knobs, the same shape for the
|
|
44
|
+
* same reason: a fraction the parent tuned is a fraction OF EACH LEG'S OWN window, so it travels as a number
|
|
45
|
+
* and every leg multiplies it by its own.
|
|
36
46
|
*/
|
|
37
47
|
export interface ParentSpecSeat {
|
|
38
48
|
readonly principal?: string;
|
|
@@ -45,6 +55,9 @@ export interface ParentSpecSeat {
|
|
|
45
55
|
readonly envFacts?: TaskSpec["envFacts"];
|
|
46
56
|
readonly memoryPersistenceCapable?: boolean;
|
|
47
57
|
readonly memoryOff?: true;
|
|
58
|
+
readonly compaction?: TaskSpec["compaction"];
|
|
59
|
+
readonly skillListingBudgetFraction?: number;
|
|
60
|
+
readonly skillListingMaxDescChars?: number;
|
|
48
61
|
}
|
|
49
62
|
/** Mint the seat off the parent's REBOUND spec and its frozen question face (spec over deps — the caller resolves it once,
|
|
50
63
|
* the same value the parent's own question routing reads). Absent fields stay absent; `oneShot` only when `true`. */
|
|
@@ -9,6 +9,9 @@ export function parentSpecSeatOf(spec, frozenOnQuestion) {
|
|
|
9
9
|
...(spec.additionalReadDirectories !== undefined ? { additionalReadDirectories: Object.freeze([...spec.additionalReadDirectories]) } : {}),
|
|
10
10
|
...(spec.envFacts !== undefined ? { envFacts: Object.freeze({ ...spec.envFacts }) } : {}),
|
|
11
11
|
...(spec.memoryPersistenceCapable !== undefined ? { memoryPersistenceCapable: spec.memoryPersistenceCapable } : {}),
|
|
12
|
+
...(spec.compaction !== undefined ? { compaction: Object.freeze({ ...spec.compaction }) } : {}),
|
|
13
|
+
...(spec.skillListingBudgetFraction !== undefined ? { skillListingBudgetFraction: spec.skillListingBudgetFraction } : {}),
|
|
14
|
+
...(spec.skillListingMaxDescChars !== undefined ? { skillListingMaxDescChars: spec.skillListingMaxDescChars } : {}),
|
|
12
15
|
...(spec.memory?.enabled === false ? { memoryOff: true } : {}),
|
|
13
16
|
});
|
|
14
17
|
}
|
|
@@ -25,6 +28,9 @@ export function applyParentSpecSeat(child, seat) {
|
|
|
25
28
|
...fill("additionalDirectories", (seat.additionalDirectories !== undefined ? [...seat.additionalDirectories] : undefined)),
|
|
26
29
|
...fill("additionalReadDirectories", (seat.additionalReadDirectories !== undefined ? [...seat.additionalReadDirectories] : undefined)),
|
|
27
30
|
...fill("envFacts", (seat.envFacts !== undefined ? { ...seat.envFacts } : undefined)),
|
|
31
|
+
...fill("compaction", (seat.compaction !== undefined ? { ...seat.compaction } : undefined)),
|
|
32
|
+
...fill("skillListingBudgetFraction", seat.skillListingBudgetFraction),
|
|
33
|
+
...fill("skillListingMaxDescChars", seat.skillListingMaxDescChars),
|
|
28
34
|
...(seat.oneShot === true ? { oneShot: true } : {}),
|
|
29
35
|
...(seat.memoryPersistenceCapable === false ? { memoryPersistenceCapable: false } : fill("memoryPersistenceCapable", seat.memoryPersistenceCapable)),
|
|
30
36
|
...(seat.memoryOff === true ? { memory: memoryTurnedOff(child.memory) } : {}),
|
|
@@ -263,7 +263,7 @@ export function parseRuleText(text, behavior) {
|
|
|
263
263
|
}
|
|
264
264
|
const shape = ruleLaneShapeOf(body, MATCH_READING);
|
|
265
265
|
if ("reject" in shape) {
|
|
266
|
-
if (body.trim() === "")
|
|
266
|
+
if (body.trim() === "" || shape.reject === "empty command")
|
|
267
267
|
return reject("invalid.empty_command", `rule "${text}" names no command`);
|
|
268
268
|
if (foldSpacing(body) === undefined)
|
|
269
269
|
return reject("invalid.unbalanced_quotes", `rule "${text}" has unbalanced quoting, so the command it names is not determinable`);
|
package/dist/core/roles.d.ts
CHANGED
|
@@ -37,6 +37,13 @@ export declare function resolveModelDisplayLabel(ref: string): string;
|
|
|
37
37
|
* `resolveModel("best")` refuses like any unknown ref.
|
|
38
38
|
*/
|
|
39
39
|
export declare function expandTiers(models: Record<string, Model> | undefined, tiers: Record<string, ModelRef> | undefined): Record<string, Model> | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* The words a catalog word stands in for under the tier layer, nearest first — what {@link expandTiers}
|
|
42
|
+
* recorded for a key IT wrote: the tier words its resolution passed through and the binding's own catalog
|
|
43
|
+
* word, each naming the model the key resolves to. A deployment's own key (a shadowing one included), and any
|
|
44
|
+
* catalog that was not tier-expanded, stands in for nothing.
|
|
45
|
+
*/
|
|
46
|
+
export declare function tierAliasVia(word: string, models: Record<string, Model> | undefined): readonly string[];
|
|
40
47
|
export interface ModelMention {
|
|
41
48
|
/** The matched model name — always one of `allowedNames` — or undefined if none was found. */
|
|
42
49
|
model?: string;
|
|
@@ -98,6 +105,19 @@ export declare const ROLE_TIER_DEFAULTS: Readonly<Partial<Record<ModelRole, stri
|
|
|
98
105
|
export declare function roleSpecNamesModel(spec: RoleSpec | undefined): boolean;
|
|
99
106
|
export interface ResolvedRole {
|
|
100
107
|
model: Model;
|
|
108
|
+
/**
|
|
109
|
+
* WHICH REF CHOSE {@link model} — the word, when a word chose it (the explicit `spec.model` string, the
|
|
110
|
+
* role's own `model` ref, or the role→tier default's catalog key), else the `Model` object itself (an
|
|
111
|
+
* explicit object, or one a `select` criteria picked: neither has a catalog word).
|
|
112
|
+
*
|
|
113
|
+
* The distinction is load-bearing wherever a LATER tick must ask the catalog the same question again: a
|
|
114
|
+
* word re-resolves against the catalog generation in force at that tick (a hot swap redirects it, a
|
|
115
|
+
* retirement refuses it loudly), while an object is pinned and never re-resolved. The engine-spawned
|
|
116
|
+
* child that inherits its parent's model inherits THIS, not the resolved object, so it lands on the
|
|
117
|
+
* generation its own prepare sees rather than on the one its parent started under; the same word keys
|
|
118
|
+
* the deployment's per-model context-window overlay.
|
|
119
|
+
*/
|
|
120
|
+
modelRef: ModelRef;
|
|
101
121
|
/** The effective thinking level: explicit `spec.thinking` wins, else the role's default. */
|
|
102
122
|
thinking?: ThinkingLevel;
|
|
103
123
|
/** The requested role's preset system prompt, if it set one (independent of model fallback). */
|
package/dist/core/roles.js
CHANGED
|
@@ -22,59 +22,75 @@ export function resolveModelDisplayLabel(ref) {
|
|
|
22
22
|
return Object.hasOwn(CC_MODEL_TIER_ALIASES, ref) ? CC_MODEL_TIER_ALIASES[ref] : ref;
|
|
23
23
|
}
|
|
24
24
|
const TIERS_ACTIVE = Symbol.for("sema.tiersActive");
|
|
25
|
+
const TIER_ALIAS_VIA = Symbol.for("sema.tierAliasVia");
|
|
25
26
|
export function expandTiers(models, tiers) {
|
|
26
27
|
if (!tiers || Object.keys(tiers).length === 0)
|
|
27
28
|
return models;
|
|
28
29
|
const out = { ...models };
|
|
29
30
|
out[TIERS_ACTIVE] = true;
|
|
31
|
+
const aliasVia = new Map();
|
|
32
|
+
out[TIER_ALIAS_VIA] = aliasVia;
|
|
30
33
|
const bound = (name) => {
|
|
31
34
|
const b = Object.hasOwn(tiers, name) ? tiers[name] : undefined;
|
|
32
35
|
return b === undefined ? undefined : resolveModel(b, models);
|
|
33
36
|
};
|
|
34
|
-
const
|
|
35
|
-
|
|
37
|
+
const ownKey = (k) => models !== undefined && Object.hasOwn(models, k) && Boolean(models[k]);
|
|
38
|
+
const landing = (t, self) => {
|
|
39
|
+
const m = bound(t);
|
|
40
|
+
if (!m)
|
|
41
|
+
return undefined;
|
|
42
|
+
const b = Object.hasOwn(tiers, t) ? tiers[t] : undefined;
|
|
43
|
+
return { model: m, via: [...(t !== self && !ownKey(t) ? [t] : []), ...(typeof b === "string" ? [b] : [])] };
|
|
44
|
+
};
|
|
45
|
+
const resolveTier = (name, self = name) => {
|
|
46
|
+
const direct = landing(name, self);
|
|
36
47
|
if (direct)
|
|
37
48
|
return direct;
|
|
38
49
|
const at = DEFAULT_TIER_ORDER.indexOf(name);
|
|
39
50
|
if (at === -1)
|
|
40
51
|
return undefined;
|
|
41
52
|
for (let i = at + 1; i < DEFAULT_TIER_ORDER.length; i++) {
|
|
42
|
-
const next =
|
|
53
|
+
const next = landing(DEFAULT_TIER_ORDER[i], self);
|
|
43
54
|
if (next)
|
|
44
|
-
return next;
|
|
55
|
+
return { model: next.model, via: [...(name !== self && !ownKey(name) ? [name] : []), ...next.via] };
|
|
45
56
|
}
|
|
46
57
|
return undefined;
|
|
47
58
|
};
|
|
48
59
|
const shadowed = (key) => Object.hasOwn(out, key) && Boolean(out[key]);
|
|
49
|
-
const put = (key, m) => {
|
|
60
|
+
const put = (key, m, via) => {
|
|
50
61
|
Object.defineProperty(out, key, { value: m, writable: true, enumerable: true, configurable: true });
|
|
62
|
+
aliasVia.set(key, via);
|
|
51
63
|
};
|
|
52
64
|
const tierNames = new Set([...DEFAULT_TIER_ORDER, ...Object.keys(tiers)]);
|
|
53
65
|
for (const name of tierNames) {
|
|
54
66
|
if (shadowed(name))
|
|
55
67
|
continue;
|
|
56
|
-
const
|
|
57
|
-
if (
|
|
58
|
-
put(name,
|
|
68
|
+
const r = resolveTier(name);
|
|
69
|
+
if (r)
|
|
70
|
+
put(name, r.model, r.via);
|
|
59
71
|
}
|
|
60
72
|
for (const [alias, tier] of Object.entries(CC_MODEL_TIER_ALIASES)) {
|
|
61
73
|
if (shadowed(alias))
|
|
62
74
|
continue;
|
|
63
|
-
const
|
|
64
|
-
if (
|
|
65
|
-
put(alias,
|
|
75
|
+
const r = resolveTier(tier, alias);
|
|
76
|
+
if (r)
|
|
77
|
+
put(alias, r.model, r.via);
|
|
66
78
|
}
|
|
67
79
|
if (!shadowed("best")) {
|
|
68
80
|
for (const name of DEFAULT_TIER_ORDER) {
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
71
|
-
put("best",
|
|
81
|
+
const r = landing(name, "best");
|
|
82
|
+
if (r) {
|
|
83
|
+
put("best", r.model, r.via);
|
|
72
84
|
break;
|
|
73
85
|
}
|
|
74
86
|
}
|
|
75
87
|
}
|
|
76
88
|
return out;
|
|
77
89
|
}
|
|
90
|
+
export function tierAliasVia(word, models) {
|
|
91
|
+
const via = models?.[TIER_ALIAS_VIA];
|
|
92
|
+
return via?.get(word) ?? [];
|
|
93
|
+
}
|
|
78
94
|
export function parseModelMention(text, allowedNames) {
|
|
79
95
|
const allowed = new Map();
|
|
80
96
|
for (const n of allowedNames)
|
|
@@ -181,6 +197,7 @@ export function resolveTaskModel(spec, deps) {
|
|
|
181
197
|
const startParts = specParts(mergeRoles(deps.roles, spec.roles)[start]);
|
|
182
198
|
return {
|
|
183
199
|
model: resolveModel(spec.model, deps.models),
|
|
200
|
+
modelRef: spec.model,
|
|
184
201
|
thinking: spec.thinking ?? startParts.thinking,
|
|
185
202
|
systemPrompt: startParts.systemPrompt,
|
|
186
203
|
};
|
|
@@ -190,9 +207,11 @@ export function resolveTaskModel(spec, deps) {
|
|
|
190
207
|
const startSystemPrompt = specParts(merged[start]).systemPrompt;
|
|
191
208
|
for (const role of [start, ...FALLBACK[start]]) {
|
|
192
209
|
const parts = specParts(merged[role]);
|
|
193
|
-
const
|
|
210
|
+
const fromParts = partsModel(parts, deps.models);
|
|
211
|
+
const model = fromParts ?? roleTierModel(role, deps.models);
|
|
194
212
|
if (model) {
|
|
195
|
-
|
|
213
|
+
const modelRef = fromParts !== undefined ? (parts.model ?? model) : (ROLE_TIER_DEFAULTS[role] ?? model);
|
|
214
|
+
return { model, modelRef, thinking: spec.thinking ?? parts.thinking, systemPrompt: startSystemPrompt };
|
|
196
215
|
}
|
|
197
216
|
}
|
|
198
217
|
throw new Error(`No model for role "${start}": set TaskSpec.model, or configure RunnerDeps.roles / TaskSpec.roles["${start}"] (or a "default" role). A "select" RoleSpec also fails here if no catalog model matches.`);
|
|
@@ -165,6 +165,8 @@ export interface ResultFlags {
|
|
|
165
165
|
* `reasoning.resolved` trace frame carried (runtask resolves once per leg — two faces, one mint);
|
|
166
166
|
* absent when thinking was off/unset for the leg, so the key is omitted. */
|
|
167
167
|
effectiveReasoning?: TaskResult["effectiveReasoning"];
|
|
168
|
+
/** The run's compaction record (see `TaskResult.compaction`); assembly omits the key when absent. */
|
|
169
|
+
compaction?: TaskResult["compaction"];
|
|
168
170
|
/** ruled 2026-08-04 — the usage-governance wait hint carried by the platform terminal the run adopted
|
|
169
171
|
* (`undefined` for every other cause: an expiring environment has no return time to give, and a store
|
|
170
172
|
* failure is not a window). Passed as data rather than read back off `threw` so the seat has a typed
|
|
@@ -178,5 +178,5 @@ export function assembleResult(spec, sessionId, final, stats, flags) {
|
|
|
178
178
|
if (flags.unpricedSpend)
|
|
179
179
|
delete publicStats.costMicroUsd;
|
|
180
180
|
const stampHaltedByUser = haltConsumed(flags.haltConsumption);
|
|
181
|
-
return { taskId, ...(flags.runId !== undefined ? { runId: flags.runId } : {}), sessionId, terminal, ...(flags.model !== undefined ? { model: flags.model } : {}), ...(responseModel !== undefined ? { responseModel } : {}), result: result.trim(), salvagedOutput, ...(apiFailure !== undefined ? { apiFailure } : {}), ...(retryAfterMs !== undefined ? { retryAfterMs } : {}), ...(flags.rewindNotes !== undefined && flags.rewindNotes.length > 0 ? { rewindNotes: flags.rewindNotes } : {}), ...(flags.editedFiles !== undefined && flags.editedFiles.length > 0 ? { editedFiles: flags.editedFiles } : {}), ...(flags.haltedOnUserRejection === true ? { haltedOnUserRejection: true } : {}), ...(stampHaltedByUser ? { haltedByUser: true } : {}), ...(flags.remoteEnvFailures !== undefined && flags.remoteEnvFailures.length > 0 ? { remoteEnvFailures: [...flags.remoteEnvFailures] } : {}), ...(flags.strandedHumanAnswers !== undefined && flags.strandedHumanAnswers.length > 0 ? { strandedHumanAnswers: flags.strandedHumanAnswers } : {}), ...(flags.effectiveReadFace !== undefined ? { effectiveReadFace: flags.effectiveReadFace } : {}), ...(flags.effectiveWriteFace !== undefined ? { effectiveWriteFace: flags.effectiveWriteFace } : {}), ...(flags.effectiveReadDenyPatterns !== undefined && flags.effectiveReadDenyPatterns.length > 0 ? { effectiveReadDenyPatterns: flags.effectiveReadDenyPatterns } : {}), ...(flags.effectiveMemoryScopes !== undefined ? { effectiveMemoryScopes: flags.effectiveMemoryScopes } : {}), ...(flags.effectiveReasoning !== undefined ? { effectiveReasoning: flags.effectiveReasoning } : {}), stats: publicStats };
|
|
181
|
+
return { taskId, ...(flags.runId !== undefined ? { runId: flags.runId } : {}), sessionId, terminal, ...(flags.model !== undefined ? { model: flags.model } : {}), ...(responseModel !== undefined ? { responseModel } : {}), result: result.trim(), salvagedOutput, ...(apiFailure !== undefined ? { apiFailure } : {}), ...(retryAfterMs !== undefined ? { retryAfterMs } : {}), ...(flags.rewindNotes !== undefined && flags.rewindNotes.length > 0 ? { rewindNotes: flags.rewindNotes } : {}), ...(flags.editedFiles !== undefined && flags.editedFiles.length > 0 ? { editedFiles: flags.editedFiles } : {}), ...(flags.haltedOnUserRejection === true ? { haltedOnUserRejection: true } : {}), ...(stampHaltedByUser ? { haltedByUser: true } : {}), ...(flags.remoteEnvFailures !== undefined && flags.remoteEnvFailures.length > 0 ? { remoteEnvFailures: [...flags.remoteEnvFailures] } : {}), ...(flags.strandedHumanAnswers !== undefined && flags.strandedHumanAnswers.length > 0 ? { strandedHumanAnswers: flags.strandedHumanAnswers } : {}), ...(flags.effectiveReadFace !== undefined ? { effectiveReadFace: flags.effectiveReadFace } : {}), ...(flags.effectiveWriteFace !== undefined ? { effectiveWriteFace: flags.effectiveWriteFace } : {}), ...(flags.effectiveReadDenyPatterns !== undefined && flags.effectiveReadDenyPatterns.length > 0 ? { effectiveReadDenyPatterns: flags.effectiveReadDenyPatterns } : {}), ...(flags.effectiveMemoryScopes !== undefined ? { effectiveMemoryScopes: flags.effectiveMemoryScopes } : {}), ...(flags.effectiveReasoning !== undefined ? { effectiveReasoning: flags.effectiveReasoning } : {}), ...(flags.compaction !== undefined ? { compaction: flags.compaction } : {}), stats: publicStats };
|
|
182
182
|
}
|
|
@@ -3,7 +3,9 @@ import type { MaybeCompactOptions } from "../auto-compaction.js";
|
|
|
3
3
|
import type { StaleToolResultOffloadOptions, TaskSpec } from "../types.js";
|
|
4
4
|
import type { Context } from "../../internal/llm.js";
|
|
5
5
|
import { type ToolResultStore } from "../tool-result-store.js";
|
|
6
|
-
import type { Prepared } from "./contracts.js";
|
|
6
|
+
import type { Prepared, RunnerDepsSeat } from "./contracts.js";
|
|
7
|
+
import { type ContextWindowOverlay } from "../context-settings.js";
|
|
8
|
+
import { type CompactionSettings } from "../../internal/harness.js";
|
|
7
9
|
/**
|
|
8
10
|
* The maybeCompact call arguments that MUST be assembled identically on all three
|
|
9
11
|
* of runtask's compaction lanes (turn boundary / prompt-too-long recovery / end-of-task).
|
|
@@ -17,7 +19,8 @@ import type { Prepared } from "./contracts.js";
|
|
|
17
19
|
*
|
|
18
20
|
* Every export is a free function: the turn-boundary lane assembles its call inside `createTurnBoundary`
|
|
19
21
|
* (a module-level function with no `this`), so a method would not be reachable from all three sites.
|
|
20
|
-
* Nothing here
|
|
22
|
+
* Nothing here WRITES runner state; one export ({@link legContextOverlayOption}) READS the live deps seat,
|
|
23
|
+
* because reading it at the moment of the pass — not at prepare — is the whole of what it states.
|
|
21
24
|
*/
|
|
22
25
|
/**
|
|
23
26
|
* Opt-in working-file attachments (LONGRUN-2 / CC 198 post-compact restore parity).
|
|
@@ -142,3 +145,24 @@ writtenRefs: Set<string>): Promise<Context>;
|
|
|
142
145
|
* scope inside `finish()`.
|
|
143
146
|
*/
|
|
144
147
|
export declare function emitInputTruncated(tracer: TracerHook | undefined, taskId: string): NonNullable<MaybeCompactOptions["onInputTruncated"]>;
|
|
148
|
+
/**
|
|
149
|
+
* The deployment's per-model window overlay in force for THIS pass — the one option of the three lanes that
|
|
150
|
+
* is deliberately a LIVE read rather than a prepared value.
|
|
151
|
+
*
|
|
152
|
+
* Two reads, both at the moment of the pass: the leg's own catalog word (the harness's current ref, so a
|
|
153
|
+
* mid-task degrade moves the key along with the model) and the Runner's current deps seat (so a `swapDeps`
|
|
154
|
+
* reaches a leg already running). An object-pinned leg has no word and therefore no overlay — the key is
|
|
155
|
+
* simply absent, which `maybeCompact` reads as "the model card's own declarations", the pre-seat behavior.
|
|
156
|
+
*/
|
|
157
|
+
export declare function legContextOverlayOption(prepared: Prepared, runner: RunnerDepsSeat): Pick<MaybeCompactOptions, "contextOverlay">;
|
|
158
|
+
/**
|
|
159
|
+
* The compaction SETTINGS a pass runs under — the assembly all three lanes share.
|
|
160
|
+
*
|
|
161
|
+
* `{ ...DEFAULT_COMPACTION_SETTINGS, ...spec.compaction }` was hand-copied at each lane, and it is where the
|
|
162
|
+
* deployment's live `enabled` declaration belongs: `maybeCompact` has exactly one enablement gate (it reads
|
|
163
|
+
* `settings.enabled`), so folding the overlay in HERE makes the deployment's switch reach the boundary pass,
|
|
164
|
+
* the recovery pass and the end-of-task summary by one edit instead of three, and keeps "who decides whether
|
|
165
|
+
* compaction runs" a single expression ({@link compactionEnabled}: the request authored it > the deployment
|
|
166
|
+
* declared it > on).
|
|
167
|
+
*/
|
|
168
|
+
export declare function legCompactionSettings(spec: TaskSpec, overlay: ContextWindowOverlay | undefined): CompactionSettings;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { emitTrace } from "../trace.js";
|
|
2
2
|
import { buildToolResultRef, OFFLOAD_TOOL_NAME, PERSISTED_OUTPUT_PREFIX, toolResultContentSegment, toolResultProvenanceOf, } from "../tool-result-store.js";
|
|
3
|
+
import { compactionEnabled, contextOverlayFor } from "../context-settings.js";
|
|
4
|
+
import { DEFAULT_COMPACTION_SETTINGS } from "../../internal/harness.js";
|
|
3
5
|
export function buildWorkingFileAttachments(spec, prepared) {
|
|
4
6
|
if (spec.compaction?.attachWorkingFiles === false || !prepared.readTaskFile)
|
|
5
7
|
return undefined;
|
|
@@ -115,3 +117,10 @@ export function emitInputTruncated(tracer, taskId) {
|
|
|
115
117
|
ts: Date.now(),
|
|
116
118
|
}));
|
|
117
119
|
}
|
|
120
|
+
export function legContextOverlayOption(prepared, runner) {
|
|
121
|
+
const overlay = contextOverlayFor(runner.deps.contextSettings, prepared.harness.getModelRef(), runner.deps);
|
|
122
|
+
return overlay !== undefined ? { contextOverlay: overlay } : {};
|
|
123
|
+
}
|
|
124
|
+
export function legCompactionSettings(spec, overlay) {
|
|
125
|
+
return { ...DEFAULT_COMPACTION_SETTINGS, ...spec.compaction, enabled: compactionEnabled(spec.compaction?.enabled, overlay) };
|
|
126
|
+
}
|
|
@@ -8,10 +8,11 @@ import type { Prepared, RunnerDepsSeat } from "./contracts.js";
|
|
|
8
8
|
* Runner OWNS the consecutive-reuse counter (`prepared.compactionReuseRef`) so the
|
|
9
9
|
* `maxConsecutiveProviderReuse` drift guard spans the whole task across both sites: it FEEDS the current
|
|
10
10
|
* count in as `consecutiveProviderReuse`, and {@link recordCompactionReuse} updates it from the result.
|
|
11
|
-
*
|
|
12
|
-
* the
|
|
11
|
+
* The provider half is absent when no provider is wired (byte-identical to the prior behavior at every
|
|
12
|
+
* call site); the #1036 `onCommitted` effect sink rides unconditionally, which is why the
|
|
13
|
+
* function itself always returns an object.
|
|
13
14
|
*/
|
|
14
|
-
export declare function seamCCompactionOptions(runner: RunnerDepsSeat, prepared: Prepared): Pick<MaybeCompactOptions, "summaryProvider" | "onCompaction" | "maxConsecutiveProviderReuse" | "consecutiveProviderReuse"
|
|
15
|
+
export declare function seamCCompactionOptions(runner: RunnerDepsSeat, prepared: Prepared): Pick<MaybeCompactOptions, "summaryProvider" | "onCompaction" | "maxConsecutiveProviderReuse" | "consecutiveProviderReuse" | "onCommitted">;
|
|
15
16
|
/** Resolve the pre/postCompact lifecycle callbacks (whole-slot `spec.hooks ??
|
|
16
17
|
* deps.hooks`, same resolution as the stop hook) and wrap each in a SWALLOW+TRACE shell before
|
|
17
18
|
* threading them into maybeCompact. The wrapper owns the observability half of the R3 MED contract
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { hookSeatExpiredError, resolveHookTimeoutMs, runHookSeat } from "../hooks.js";
|
|
2
2
|
import { asThrownError } from "../thrown-value.js";
|
|
3
3
|
export function seamCCompactionOptions(runner, prepared) {
|
|
4
|
-
if (!runner.deps.summaryProvider)
|
|
5
|
-
return undefined;
|
|
6
4
|
return {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
...(runner.deps.summaryProvider
|
|
6
|
+
? {
|
|
7
|
+
summaryProvider: runner.deps.summaryProvider,
|
|
8
|
+
onCompaction: runner.deps.onCompaction,
|
|
9
|
+
maxConsecutiveProviderReuse: runner.deps.maxConsecutiveProviderReuse,
|
|
10
|
+
consecutiveProviderReuse: prepared.compactionReuseRef.consecutive,
|
|
11
|
+
}
|
|
12
|
+
: {}),
|
|
13
|
+
onCommitted: (effect) => {
|
|
14
|
+
if (prepared.frameSettlement.wantsEffects?.() !== true)
|
|
15
|
+
return;
|
|
16
|
+
prepared.frameSettlement.compactions.push(effect);
|
|
17
|
+
},
|
|
11
18
|
};
|
|
12
19
|
}
|
|
13
20
|
export function compactionHookOptions(runner, spec, sessionId, trigger, identity, seatBound) {
|
|
@@ -47,7 +47,7 @@ import type { SystemInjectionPriority, TaskNotificationPayload } from "../task-n
|
|
|
47
47
|
import type { OnAsk, PermissionResult, ResolvedAsk, ToolCallRequest, ToolPolicy } from "../tool-policy.js";
|
|
48
48
|
import type { RemoteExecutionEnv, SnapshotId, WorkspaceHandle } from "../remote-env.js";
|
|
49
49
|
import type { ToolDisclosureManifest } from "../trace.js";
|
|
50
|
-
import type { AgentDefinition, ApproverPosture, Brain, CompactOutcome, ModelRoles, NestedUsageAccum, RunnerDeps, ShellGateDoctrine, TaskEvent, TaskEventIdentity, TaskResult, TaskSpec, TaskStream, ToolActivity, ToolEffect } from "../types.js";
|
|
50
|
+
import type { AgentDefinition, ApproverPosture, Brain, CompactOutcome, ModelRef, ModelRoles, NestedUsageAccum, RunnerDeps, ShellGateDoctrine, TaskEvent, TaskEventIdentity, TaskResult, TaskSpec, TaskStream, ToolActivity, ToolEffect } from "../types.js";
|
|
51
51
|
import type { WiringManifest } from "../wiring-manifest.js";
|
|
52
52
|
import type { ActiveSkillFrame } from "./active-skill-scope.js";
|
|
53
53
|
import type { BudgetAxis } from "./assemble-result.js";
|
|
@@ -248,6 +248,11 @@ export interface Prepared {
|
|
|
248
248
|
* prepare emits run-scoped disclosures of its own and each must have a terminal that names it.
|
|
249
249
|
*/
|
|
250
250
|
runId: string;
|
|
251
|
+
/** The (owner, scope) key this run's registry-facing tools register rows under — (host task id, mount domain), minted once at prepare; the teardown sweeps read it and never re-derive it. */
|
|
252
|
+
registryAccess: {
|
|
253
|
+
readonly owner: string;
|
|
254
|
+
readonly scope: string;
|
|
255
|
+
};
|
|
251
256
|
/** The session's reminder provenance mark this run mints under (adopted
|
|
252
257
|
* through the prepare adoption ladder: checkpoint seed → trusted fork channel → session entry →
|
|
253
258
|
* fresh mint). Every engine-authored `<system-reminder>` open tag in the run carries it, and the
|
|
@@ -257,6 +262,8 @@ export interface Prepared {
|
|
|
257
262
|
* disclosure outlets at tool-execute time; read once at result assembly into
|
|
258
263
|
* `stats.mechanisms.reminderDisclosures` when any key is non-zero). Always present. */
|
|
259
264
|
reminderDisclosureCounts: import("../reminder-disclosure.js").ReminderDisclosureCounts;
|
|
265
|
+
/** Whether the full shell is on this leg's roster (the inherited-gate phase's bit, asserted against the mount). */
|
|
266
|
+
fullShellReachable: boolean;
|
|
260
267
|
/** The run's RESOLVED approval-posture facts — the auto-mode intent and the declared approver posture,
|
|
261
268
|
* folded once by the chain assembly. The first user turn renders them into the engine's own marked
|
|
262
269
|
* reminder; nothing else reads them, and no gate decision keys on either. */
|
|
@@ -471,6 +478,28 @@ export interface Prepared {
|
|
|
471
478
|
* drains — one mount judgment, the drain and the park read it alike. Absent ⇒ in-process parking.
|
|
472
479
|
*/
|
|
473
480
|
sessionBox?: import("../task-notification.js").SessionBoxBinding;
|
|
481
|
+
/**
|
|
482
|
+
* #1036 — the leg's TWO SETTLEMENT LEDGERS, one cell shared by the three beats that fill and
|
|
483
|
+
* read them: the harness's transcript-append sink writes receipts, the compaction commit beat
|
|
484
|
+
* writes effects, and the session-box drain's settlement half-pass reads both and clears what it
|
|
485
|
+
* consumed. Always present (the cell is minted with the leg); empty on a run with no session box,
|
|
486
|
+
* because nothing registers an interest and the receipt sink only records awaited keys.
|
|
487
|
+
*/
|
|
488
|
+
frameSettlement: import("../frame-settlement.js").FrameSettlement;
|
|
489
|
+
/**
|
|
490
|
+
* #1036 — the session-box drain's BOUNDARY PASS, called by the turn-boundary lane as its tail
|
|
491
|
+
* (in a `finally`, so every early exit of the boundary still settles). Present iff this leg bound
|
|
492
|
+
* the drain. `continues` = this leg will issue another request after this boundary, which is what
|
|
493
|
+
* decides whether the pass's NEW-delivery half runs; the settlement half runs either way.
|
|
494
|
+
*
|
|
495
|
+
* It is a tail call and not a `turn_boundary` hook of the drain's own because the ORDER matters and
|
|
496
|
+
* a hook's position is registration-order luck: settlement must run AFTER this boundary's
|
|
497
|
+
* compaction, or a record whose frame the compaction just summarized away is already acked (deleted
|
|
498
|
+
* from the box) by the time anyone could notice.
|
|
499
|
+
*/
|
|
500
|
+
peerBoundaryRound?: (o: {
|
|
501
|
+
continues: boolean;
|
|
502
|
+
}) => Promise<void>;
|
|
474
503
|
/**
|
|
475
504
|
* The per-invocation TIME BOUND every hook seat of this leg runs under (`Hooks.timeoutMs`, already
|
|
476
505
|
* validated — a garbage value was refused to the default and disclosed ONCE, here, rather than on
|
|
@@ -1699,6 +1728,19 @@ export interface RunInternals {
|
|
|
1699
1728
|
* TRUSTED run-scoped channel (NOT a {@link TaskSpec} field), mirroring `insideFork`.
|
|
1700
1729
|
*/
|
|
1701
1730
|
defaultSystemPrompt?: string;
|
|
1731
|
+
/**
|
|
1732
|
+
* The catalog WORD that chose the model this engine-spawned child was handed on its spec.
|
|
1733
|
+
*
|
|
1734
|
+
* The two halves of one fact travel on two channels on purpose: the spec carries the RESOLVED `Model`
|
|
1735
|
+
* object, so nothing re-resolves between the spawn's judgement and this child's prepare (the model the
|
|
1736
|
+
* spawn frames name is the model that runs); this carries the word that object came from, so the child
|
|
1737
|
+
* is not PINNED by having been handed an object — its own children inherit the word in turn, and the
|
|
1738
|
+
* deployment's per-model window overlay (keyed by word) still reaches it. Absent ⇒ no word exists for
|
|
1739
|
+
* this child's model (a caller-pinned object, a `select` criteria), and such a leg is deliberately never
|
|
1740
|
+
* re-resolved and never overlaid. Trusted channel, never a `TaskSpec` field: it is the engine's own
|
|
1741
|
+
* statement about a model the engine itself resolved, and a caller cannot author it.
|
|
1742
|
+
*/
|
|
1743
|
+
inheritedModelRef?: ModelRef;
|
|
1702
1744
|
/**
|
|
1703
1745
|
* GOAL MODE flag, a TRUSTED internal channel set ONLY by `runGoal` (a core caller),
|
|
1704
1746
|
* NEVER a {@link TaskSpec} field. It drives `featureFlags.goalEnabled` → injects `GOAL_COMPLETION_GUIDANCE`.
|
|
@@ -2105,7 +2147,7 @@ export interface RunInternals {
|
|
|
2105
2147
|
* `leg` is the LEG IDENTITY, and the engine mints NONE of it. It is present only where a
|
|
2106
2148
|
* composition labelled the leg it dispatched: the verify entries hand each leg a per-dispatch
|
|
2107
2149
|
* copy of this object whose sink closes over that leg's identity, so a consumer can tell the
|
|
2108
|
-
* implementation leg from
|
|
2150
|
+
* implementation leg from pass 2's verifier without inferring it from arrival order (the
|
|
2109
2151
|
* ordering is all the sibling sinks have — see the attribution paragraph on `verifyCompleted`).
|
|
2110
2152
|
* ABSENT therefore means "nobody labelled this leg", never "implementation": a plain `runTask`,
|
|
2111
2153
|
* a workflow agent call and a cascade rung all reach this sink with no identity, and reading one
|
|
@@ -2113,13 +2155,13 @@ export interface RunInternals {
|
|
|
2113
2155
|
* OWN `leg` field ({@link WiringManifest.leg}, `root` / `child` / `resume`), which is a fact about
|
|
2114
2156
|
* how the ENGINE reached this run; this one is a fact about the composition that dispatched it, and
|
|
2115
2157
|
* a resumed fix leg carries both at once — `manifest.leg.kind === "resume"` and `leg.kind === "fix"`
|
|
2116
|
-
* are both true of it. `
|
|
2158
|
+
* are both true of it. `pass` is 1-based over the gate's verification rounds: a `verifier` leg
|
|
2117
2159
|
* carries the one it verifies, a `fix` leg the one whose findings it answers, and the entry
|
|
2118
2160
|
* implementation leg carries 0 — before the first. The axis is relative to the gate INVOCATION,
|
|
2119
2161
|
* not to the session's history: a resume entry's work leg is THAT invocation's implementation leg
|
|
2120
|
-
* (`impl`,
|
|
2121
|
-
* fix
|
|
2122
|
-
* it — one axis for both fields, rather than a leg that reads "fix
|
|
2162
|
+
* (`impl`, pass 0) even when the checkpoint it resumes was minted inside a previous invocation's
|
|
2163
|
+
* fix pass, because the invocation's own pass counter (`VerificationResult.rounds`) restarts with
|
|
2164
|
+
* it — one axis for both fields, rather than a leg that reads "fix pass 1" inside a result whose
|
|
2123
2165
|
* rounds begin at 1 again.
|
|
2124
2166
|
*
|
|
2125
2167
|
* Observe-only and failure-isolated through the SAME per-run notifier as {@link onActivity} (one
|
|
@@ -2357,6 +2399,9 @@ export interface RunState {
|
|
|
2357
2399
|
/** B15 三期终件补遗:压缩地板/背压 latch — rs.counters.compactionFloor 跨 drainManualCompact(写)/R9(读写)/收尾(读)三方共享,rs.counters.trimForceBackoff 为 R9 跨调用 latch(同款只改绑定不改时机)。 */
|
|
2358
2400
|
compactionFloor: number;
|
|
2359
2401
|
trimForceBackoff: boolean;
|
|
2402
|
+
/** Landed compactions (boundary + prompt-too-long lanes) and the last one's kind — the `TaskResult.compaction` source (the breaker state is read off the breaker itself). */
|
|
2403
|
+
compactionPasses: number;
|
|
2404
|
+
compactionKind?: import("../task-notification.js").CompactionKind;
|
|
2360
2405
|
repetitionCuts: number;
|
|
2361
2406
|
repetitionSpared: number;
|
|
2362
2407
|
repetitionEvents: Array<{
|
|
@@ -2544,7 +2589,7 @@ export interface TurnBoundaryDeps {
|
|
|
2544
2589
|
}, ctx?: import("../hooks.js").PostToolBatchContext) => PostToolBatchResult | undefined | Promise<PostToolBatchResult | undefined>) | undefined;
|
|
2545
2590
|
batchArgs: Map<string, unknown> | undefined;
|
|
2546
2591
|
compactionBrain: Brain;
|
|
2547
|
-
withinTaskCompaction: boolean;
|
|
2592
|
+
withinTaskCompaction: () => boolean;
|
|
2548
2593
|
compactionBreaker: {
|
|
2549
2594
|
failures: number;
|
|
2550
2595
|
};
|
|
@@ -2658,6 +2703,10 @@ export interface RunnerSelfSeat {
|
|
|
2658
2703
|
models?: Record<string, Model>;
|
|
2659
2704
|
roles?: ModelRoles;
|
|
2660
2705
|
};
|
|
2706
|
+
/** The context-window overlay a leg on `ref` reads RIGHT NOW (`RunnerDeps.contextSettings`, tier aliases followed
|
|
2707
|
+
* against the catalog in force): prepare hands its leg a call-time reader over it, because this is the one seat a
|
|
2708
|
+
* running leg re-reads (geometry, not route — see `context-settings.ts`). */
|
|
2709
|
+
contextOverlayOf?(ref: import("../model-seat.js").ModelRef | undefined): import("../context-settings.js").ContextWindowOverlay | undefined;
|
|
2661
2710
|
/** The deployment-level gating baseline (deps toolPolicy / hooks) as delegate wrappers — for assemblers that compose with it. */
|
|
2662
2711
|
readonly gateBaseline: {
|
|
2663
2712
|
toolPolicy?: RunnerDeps["toolPolicy"];
|
|
@@ -92,5 +92,6 @@ export declare function assertOutcomeText(value: string | undefined, field: "edi
|
|
|
92
92
|
* `prompt(text)` (it always appends a user message — there is no "continue from tool results" entry), so
|
|
93
93
|
* resume re-enters via a `<system-reminder>`-wrapped user message that tells the model the gated decision
|
|
94
94
|
* was applied. The "user message wart" is accepted (API-valid, and clearer than a silent continuation).
|
|
95
|
+
* `fullShellReachable` is the resumed leg's own roster fact, read by {@link reorientClause}.
|
|
95
96
|
*/
|
|
96
|
-
export declare function resumeContinuation(resume: ResumeRun, mark: string | undefined): string;
|
|
97
|
+
export declare function resumeContinuation(resume: ResumeRun, mark: string | undefined, fullShellReachable: boolean): string;
|