@sema-agent/core 5.61.0 → 5.63.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 +107 -0
- package/dist/agents/subagent.d.ts +12 -2
- package/dist/agents/subagent.js +3 -2
- package/dist/brain/open-responses.js +8 -3
- package/dist/brain/openai.js +4 -4
- package/dist/brain/stream-engine.d.ts +13 -2
- package/dist/brain/stream-engine.js +3 -3
- package/dist/core/auto-compaction.d.ts +6 -4
- package/dist/core/auto-compaction.js +3 -0
- package/dist/core/auto-mode-prompt-assets.js +1 -1
- package/dist/core/checkpoint-store.d.ts +36 -4
- package/dist/core/checkpoint-store.js +1 -0
- package/dist/core/context-edit.d.ts +36 -29
- package/dist/core/context-edit.js +3 -3
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +86 -4
- package/dist/core/hooks.js +3 -3
- package/dist/core/memory-engine/engine.d.ts +11 -0
- package/dist/core/memory-engine/engine.js +29 -3
- package/dist/core/memory-engine/index.d.ts +1 -1
- package/dist/core/memory-engine/origin-clearance.d.ts +28 -0
- package/dist/core/park-selfcheck.js +2 -0
- package/dist/core/pricing.d.ts +24 -0
- package/dist/core/pricing.js +18 -0
- package/dist/core/runner/prepare-config-doors.d.ts +36 -2
- package/dist/core/runner/prepare-config-doors.js +66 -8
- package/dist/core/runner/prepare-task.d.ts +113 -12
- package/dist/core/runner/prepare-task.js +239 -131
- package/dist/core/runner/runtask.d.ts +7 -0
- package/dist/core/runner/runtask.js +325 -95
- package/dist/core/runner/turn-attachments.d.ts +137 -5
- package/dist/core/runner/turn-attachments.js +25 -2
- package/dist/core/store-contracts/checkpoint-store-contract.js +19 -0
- package/dist/core/tool-errors.d.ts +2 -1
- package/dist/core/tool-policy.d.ts +27 -0
- package/dist/core/trace.d.ts +5 -4
- package/dist/core/types.d.ts +163 -29
- package/dist/core/untrusted-text.d.ts +5 -4
- package/dist/core/untrusted-text.js +8 -0
- package/dist/core/usage-window-store.d.ts +109 -8
- package/dist/core/usage-window-store.js +79 -12
- package/dist/engine/harness/agent-harness.js +20 -5
- package/dist/engine/harness/types.d.ts +38 -0
- package/dist/engine/loop/agent-loop.js +20 -1
- package/dist/engine/loop/types.d.ts +41 -1
- package/dist/index.d.ts +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +2 -2
- package/dist/orchestration/workflow-types.d.ts +48 -1
- package/dist/orchestration/workflow-types.js +12 -4
- package/dist/orchestration/workflow.d.ts +14 -3
- package/dist/orchestration/workflow.js +44 -19
- package/dist/prompt-assembly/event-registry.js +2 -0
- package/dist/prompts/default.js +1 -1
- package/dist/server/http.d.ts +1 -1
- package/dist/stores/file/usage-window-store.d.ts +1 -1
- package/dist/stores/file/usage-window-store.js +27 -6
- package/dist/tools/loop-tick.js +1 -1
- package/dist/tools/scheduler-tools.js +9 -1
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +3 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { McpDroppedTool } from "../mcp.js";
|
|
2
|
+
import type { TaskSpec } from "../types.js";
|
|
2
3
|
import { type SkillListingEntry } from "./synthetic-tools.js";
|
|
3
4
|
/**
|
|
4
5
|
* design/133 §R3 — turn-boundary attachment seam: the PURE producer layer (CC `getContextAttachments`
|
|
@@ -28,6 +29,44 @@ export declare const TOOL_SEARCH_REMINDER_CONFIG: {
|
|
|
28
29
|
readonly EVERY_N_TURNS: 15;
|
|
29
30
|
readonly MAX_NAMES: 10;
|
|
30
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* RB-318 — the `total_tokens_reminder` mode set, CC 2.1.245-VERBATIM and in CC's declaration order
|
|
34
|
+
* (bundle `R9o`; the settings schema declares the same five for its `totalTokensReminder` key).
|
|
35
|
+
* Each arm names what the rendered number IS, per CC's own schema prose:
|
|
36
|
+
* - `off` — the lane is silent. Kept as a member rather than folded into the opt-in flag because it
|
|
37
|
+
* is the DEPLOYMENT-RESOLVED kill switch (CC resolves the mode from env
|
|
38
|
+
* `CLAUDE_CODE_TOTAL_TOKENS_REMINDER` → settings → gate; sema keeps env resolution at the shell and
|
|
39
|
+
* carries only the resolved mode — the {@link AttachmentInputs.config.todoReminderMode} contract
|
|
40
|
+
* verbatim, where "wired on" and "silenced by policy" are also two independent bits).
|
|
41
|
+
* - `infinite` — the literal text `Infinite`.
|
|
42
|
+
* - `fixed` — the constant {@link TOTAL_TOKENS_FIXED_ARM_VALUE}. Together with `infinite` these are
|
|
43
|
+
* CC's two CONSTANT arms: they consume no measurement at all, which is exactly why they exist
|
|
44
|
+
* (they are the controls the countdown arms are measured against).
|
|
45
|
+
* - `countdown` — the live remaining budget, raw.
|
|
46
|
+
* - `padded-countdown` — the same, smoothed by a monotone floor so the number never jumps back.
|
|
47
|
+
*/
|
|
48
|
+
export declare const TOTAL_TOKENS_REMINDER_MODES: readonly ["off", "infinite", "fixed", "countdown", "padded-countdown"];
|
|
49
|
+
/**
|
|
50
|
+
* RB-318 rider — the closed set is spelled TWICE (the public `TaskSpec.attachments.
|
|
51
|
+
* totalTokensReminderMode` literal union and this array), and only the TaskSpec→array direction had
|
|
52
|
+
* a compile chain (runtask's AttachmentInputs assignment). The config door widens this array to
|
|
53
|
+
* `readonly string[]` before `includes`, so a member added HERE and never to the public union used
|
|
54
|
+
* to compile clean, pass the door, and render — while the public type declared it illegal. Both
|
|
55
|
+
* directions now refuse at compile time (the governance-codes `satisfies` lockstep form):
|
|
56
|
+
* - array ⊆ TaskSpec — the `satisfies` on the declaration above;
|
|
57
|
+
* - TaskSpec ⊆ array — the conditional below collapses the exported type to `never` (the default-
|
|
58
|
+
* mode constant two lines down errors immediately) when the public union grows an unlisted member.
|
|
59
|
+
*/
|
|
60
|
+
type TaskSpecTotalTokensReminderMode = NonNullable<NonNullable<TaskSpec["attachments"]>["totalTokensReminderMode"]>;
|
|
61
|
+
export type TotalTokensReminderMode = [TaskSpecTotalTokensReminderMode] extends [(typeof TOTAL_TOKENS_REMINDER_MODES)[number]] ? (typeof TOTAL_TOKENS_REMINDER_MODES)[number] : never;
|
|
62
|
+
/** RB-318 — CC 2.1.245's own default ("Defaults to padded-countdown"). The 2026-07-30 registration of
|
|
63
|
+
* this lane rested on the 2.1.220 premise "OFF by default even in 220"; 245 flipped it, which is the
|
|
64
|
+
* fact that reopened the ruling. Applies only ONCE the deployment has opted the lane in. */
|
|
65
|
+
export declare const TOTAL_TOKENS_REMINDER_DEFAULT_MODE: TotalTokensReminderMode;
|
|
66
|
+
/** RB-318 — CC's `fixed` arm constant (bundle `A9o`). A fixed anchor is the POINT of that arm (the
|
|
67
|
+
* number is meant not to move), so it is copied as the constant it is rather than re-pointed at a
|
|
68
|
+
* declared ceiling — a deployment that wants its own number picks a countdown arm instead. */
|
|
69
|
+
export declare const TOTAL_TOKENS_FIXED_ARM_VALUE = 5000000;
|
|
31
70
|
/** F5: per-boundary stat scan upper bound — at most this many most-recently-read files are stat'ed. */
|
|
32
71
|
export declare const CHANGED_FILES_MAX = 20;
|
|
33
72
|
/**
|
|
@@ -39,7 +78,7 @@ export declare const CHANGED_FILES_MAX = 20;
|
|
|
39
78
|
export declare const CHANGED_FILES_MTIME_EPS_MS = 2000;
|
|
40
79
|
/** Per-boundary payload byte cap over the whole bundle (weak-model context economics). */
|
|
41
80
|
export declare const ATTACHMENT_BYTE_CAP: number;
|
|
42
|
-
export type AttachmentSource = "todo_reminder" | "task_reminder" | "tool_search_usage_reminder" | "changed_files" | "plan_mode" | "date_change" | "instructions_change" | "workflow_size_guideline_change" | "budget_usd" | "background_tasks" | "tools_delta" | "agent_listing" | "skills_listing" | "mcp_instructions" | "mcp_dropped_tools";
|
|
81
|
+
export type AttachmentSource = "todo_reminder" | "task_reminder" | "tool_search_usage_reminder" | "changed_files" | "plan_mode" | "date_change" | "instructions_change" | "workflow_size_guideline_change" | "budget_usd" | "total_tokens_reminder" | "background_tasks" | "tools_delta" | "agent_listing" | "skills_listing" | "mcp_instructions" | "mcp_dropped_tools";
|
|
43
82
|
/** G1 续批 — one agent type on the delegation tool's roster (ToolSpec.agentListing, filled by
|
|
44
83
|
* createSubagentTool: defined agents + the built-in fork when offered). */
|
|
45
84
|
export interface AgentListingEntry {
|
|
@@ -164,6 +203,33 @@ export interface AttachmentState {
|
|
|
164
203
|
* agent frame permanently starving the skills frame (each frame individually fits the cap by
|
|
165
204
|
* construction — agent roster ≤ cap by deployment size, skills block ≤ SKILLS_BLOCK_MAX_BYTES). */
|
|
166
205
|
skillsListingStarved?: boolean;
|
|
206
|
+
/**
|
|
207
|
+
* RB-318 — the `padded-countdown` arm's SMOOTHING FLOOR: the highest usage figure this run has
|
|
208
|
+
* already published against. CC's `cumulativeUsed` (bundle: `Math.max(storedFloor, rolledOver +
|
|
209
|
+
* used − anchor)`, stored back) exists so the countdown never RUNS BACKWARDS when the live usage
|
|
210
|
+
* coordinate drops under it — a model that watched its budget shrink and then saw it grow again
|
|
211
|
+
* learns the number is noise.
|
|
212
|
+
*
|
|
213
|
+
* Two of CC's three maps are structurally degenerate here and that is a mapping, not a loss:
|
|
214
|
+
* - the per-agent KEY — CC's tracker is session-scoped and keyed by `agentId ?? "main"` because one
|
|
215
|
+
* CC session hosts the main agent and its subagents; a sema {@link AttachmentState} is already
|
|
216
|
+
* per-RUN, and a delegated child is its own run with its own state, so this scalar IS that slot.
|
|
217
|
+
* - the ANCHOR (`reanchorTaskBudget`, re-armed on every regular user prompt so a new user task
|
|
218
|
+
* counts down from the full budget again) — a sema LEG is one task epoch, so the anchor is fixed
|
|
219
|
+
* at 0 for the leg's whole life and the epoch reset is the next `runTask` invocation — a
|
|
220
|
+
* durable-resume leg INCLUDED (it re-enters through `runTask`, rebuilds this state, re-derives
|
|
221
|
+
* its slice window and restarts the spend coordinate, so its countdown re-anchors to the new
|
|
222
|
+
* leg's real remaining — the CC re-anchor arm, not a floor violation; the floor deliberately
|
|
223
|
+
* does NOT ride the checkpoint, since a carried floor against a fresh slice window would freeze
|
|
224
|
+
* the readout at "0 tokens left" over an allowance the run genuinely holds). Same lifecycle
|
|
225
|
+
* reasoning as the plan_mode lane's `countPlanModeAttachmentsSinceLastExit` note.
|
|
226
|
+
* - the ROLLOVER (`rollOverContext`, which adds each compacted-away context back so the count keeps
|
|
227
|
+
* advancing) is likewise not owed: sema feeds a CUMULATIVE spend coordinate (`stats.tokens`),
|
|
228
|
+
* which a compaction never rewinds, where CC feeds the live context size.
|
|
229
|
+
* `undefined` = the padded arm has not rendered yet (an OFF lane, or a raw-countdown one, never
|
|
230
|
+
* allocates it).
|
|
231
|
+
*/
|
|
232
|
+
totalTokensFloor?: number;
|
|
167
233
|
}
|
|
168
234
|
/**
|
|
169
235
|
* A1-R — the date_change lane's OWN state, deliberately NOT an
|
|
@@ -314,6 +380,25 @@ export interface AttachmentInputs {
|
|
|
314
380
|
used: number;
|
|
315
381
|
total: number;
|
|
316
382
|
};
|
|
383
|
+
/** RB-318 total_tokens_reminder lane (裁 B, 2026-08-26) — the TOKEN twin of {@link budgetUsd}, fed
|
|
384
|
+
* from the same place for the same reason: `used` is the run's cumulative token spend
|
|
385
|
+
* (`stats.tokens`) and `total` is the ceiling the budget gate enforces against it
|
|
386
|
+
* (`rs.budget.maxTokensWindow` = min(`limits.maxTokens`, the cross-slice allocation's remainder)),
|
|
387
|
+
* so a model-visible countdown can never disagree with an eventual `limits.max_tokens_exceeded`.
|
|
388
|
+
* Core neither estimates nor discovers this pair: no ceiling declared ⇒ absent ⇒ the countdown arms
|
|
389
|
+
* are silent (CC's own `maxBudgetUsd === void 0 → []` posture on the sibling lane).
|
|
390
|
+
*
|
|
391
|
+
* COORDINATE NOTE (candidate divergence registration): CC's two countdown arms read two DIFFERENT
|
|
392
|
+
* sources — `countdown` the live remaining context window, `padded-countdown` a synthetic task
|
|
393
|
+
* budget (its default 15_000_000 is far larger than any real window). sema carries ONE pair, the
|
|
394
|
+
* enforced spend coordinate, and lets the mode pick the arithmetic over it: publishing a context
|
|
395
|
+
* window would mean publishing a figure core cannot make true (BYOM — the window, the tokenizer and
|
|
396
|
+
* the accounting belong to the deployment's model), while the enforced ceiling is the one token
|
|
397
|
+
* number core owns end to end. */
|
|
398
|
+
totalTokens?: {
|
|
399
|
+
used: number;
|
|
400
|
+
total: number;
|
|
401
|
+
};
|
|
317
402
|
config: {
|
|
318
403
|
todoReminder: boolean;
|
|
319
404
|
/** 口径③ — CC `r2o()` kill-switch parity (pretty.js:479167-479171; consumed by both producers at
|
|
@@ -349,6 +434,36 @@ export interface AttachmentInputs {
|
|
|
349
434
|
* through a workflow governance baseline (`WorkflowGovernanceBaseline.base`, which explicitly
|
|
350
435
|
* snapshots `maxCostUsd` and every other governance field) reaches the lane. */
|
|
351
436
|
budgetUsd?: boolean;
|
|
437
|
+
/**
|
|
438
|
+
* RB-318 (裁 B, 2026-08-26) — `total_tokens_reminder` (CC 2.1.245 producer `MPs`, renderer `Oje`,
|
|
439
|
+
* registered in the SHARED producer group beside `budget_usd`, so a subagent carrying its own
|
|
440
|
+
* ceiling sees it too — the RB-311 attribution verbatim). Opt-in, default OFF like every other 133
|
|
441
|
+
* member: an un-opted deployment renders no reminder frame — the ATTACHMENT lane itself is
|
|
442
|
+
* byte-identical to the pre-lane engine. (Scoped deliberately to this lane: registering
|
|
443
|
+
* `<total_tokens>` in ENGINE_ENVELOPES changed the SANITIZE/DISCLOSURE faces for every
|
|
444
|
+
* deployment, opted or not — untrusted text carrying that spelling is now defused on the fenced
|
|
445
|
+
* lanes and envelope-shaped external data trips the design/319 disclosure tail. That is the
|
|
446
|
+
* defensive direction and unconditional by design: the envelope family must be un-forgeable
|
|
447
|
+
* whether or not anyone renders the real frame.)
|
|
448
|
+
*
|
|
449
|
+
* WHY IT EXISTS NOW. The 2026-07-30 registration refused it as a product-face question and rested
|
|
450
|
+
* on "OFF by default even in 220". 245 flips exactly that premise — its settings schema reads
|
|
451
|
+
* "Defaults to padded-countdown", i.e. upstream now publishes a token countdown to the model by
|
|
452
|
+
* default. The BYOM honesty objection is answered by SHAPE rather than by dropping it: core
|
|
453
|
+
* estimates nothing. The numbers are the ones the engine already enforces against
|
|
454
|
+
* ({@link AttachmentInputs.totalTokens}), the ceiling is the deployment's own declared
|
|
455
|
+
* `limits.maxTokens`, and with no ceiling declared the countdown arms simply never fire.
|
|
456
|
+
*
|
|
457
|
+
* The arm is chosen by {@link totalTokensReminderMode} (default {@link
|
|
458
|
+
* TOTAL_TOKENS_REMINDER_DEFAULT_MODE}); `off` there silences the lane without un-wiring it.
|
|
459
|
+
*/
|
|
460
|
+
totalTokensReminder?: boolean;
|
|
461
|
+
/** RB-318 — the RESOLVED mode (see {@link TOTAL_TOKENS_REMINDER_MODES}). CC resolves it from env /
|
|
462
|
+
* settings / a server gate; sema keeps env resolution at the deployment shell and carries only the
|
|
463
|
+
* resolved value, exactly like {@link todoReminderMode}. Absent ⇒ {@link
|
|
464
|
+
* TOTAL_TOKENS_REMINDER_DEFAULT_MODE}. A value outside the closed set is refused at the config
|
|
465
|
+
* door (`config.attachment_invalid`), never folded to the default. */
|
|
466
|
+
totalTokensReminderMode?: TotalTokensReminderMode;
|
|
352
467
|
/** G1: post-compact background-task announce (opt-in, default OFF like the 133 members). */
|
|
353
468
|
backgroundTasks?: boolean;
|
|
354
469
|
/** G1: deferred-tool materialization announce (design/36 setTools delta → boundary notice). */
|
|
@@ -441,10 +556,11 @@ export interface AttachmentInputs {
|
|
|
441
556
|
* done HERE because the caller only invokes this once per boundary after its injection gate passed —
|
|
442
557
|
* splitting "decide" from "mark sent" would just invite a drift between the two.
|
|
443
558
|
*
|
|
444
|
-
* Returns attachments in EVIDENCE-STRENGTH order (todo/task →
|
|
445
|
-
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
559
|
+
* Returns attachments in EVIDENCE-STRENGTH order (todo/task → tool_search_usage_reminder →
|
|
560
|
+
* plan_mode → budget_usd → total_tokens_reminder → background_tasks → tools_delta → agent_listing →
|
|
561
|
+
* skills_listing → mcp_instructions → mcp_dropped_tools → changed_files), which is also the §R3
|
|
562
|
+
* MED-6 truncation order read backwards: under the 8KB cap changed_files is sacrificed first, the
|
|
563
|
+
* todo/task list last. The G1/续批 members are registry/engine ground truth (strong), but the
|
|
448
564
|
* todo/plan lane keeps priority: it carries the run's own work-tracking state, which the model can
|
|
449
565
|
* least afford to lose.
|
|
450
566
|
*/
|
|
@@ -528,6 +644,21 @@ export declare function commitInstructionsChange(state: InstructionsChangeState,
|
|
|
528
644
|
contentHash: string | null;
|
|
529
645
|
}>): void;
|
|
530
646
|
export declare function renderBudgetUsd(used: number, total: number): string;
|
|
647
|
+
/**
|
|
648
|
+
* RB-318 — CC 2.1.245 `Oje` VERBATIM: the whole body is the one-line envelope
|
|
649
|
+
* `<total_tokens>N tokens left</total_tokens>`, where N is the arm's own substitution — the literal
|
|
650
|
+
* `Infinite`, the {@link TOTAL_TOKENS_FIXED_ARM_VALUE} constant, or the remaining count clamped at
|
|
651
|
+
* zero (CC's `Math.max(0, …)`: an over-spent run reads `0 tokens left`, never a negative number).
|
|
652
|
+
*
|
|
653
|
+
* `remaining` is ignored by the two constant arms — the caller passes whatever it has (the producer
|
|
654
|
+
* passes 0), matching CC, whose own producer computes `0` for them.
|
|
655
|
+
*
|
|
656
|
+
* The `<total_tokens>` tag is an ENGINE-MINTED authority envelope: it is registered in the
|
|
657
|
+
* `ENGINE_ENVELOPES` census (untrusted-text.ts) and is in the fenced family, so the same spelling
|
|
658
|
+
* arriving inside untrusted content is defused rather than read as this readout. Its own body needs no
|
|
659
|
+
* escaping in return — every byte here is engine copy or a finite number.
|
|
660
|
+
*/
|
|
661
|
+
export declare function renderTotalTokensReminder(mode: TotalTokensReminderMode, remaining: number): string;
|
|
531
662
|
/**
|
|
532
663
|
* SR-7 — CC 2.1.198 VERBATIM inner text (bundle pretty.js:698391-698398, `F6c`): the aggregated
|
|
533
664
|
* orphaned-background-task notice a restarted/resumed leg injects ONCE (CC's own `<system-reminder>`
|
|
@@ -829,3 +960,4 @@ export declare function selectMcpDroppedBatch<T extends McpDroppedTool>(entries:
|
|
|
829
960
|
* is unchanged: this is a pure function of (string, number).
|
|
830
961
|
*/
|
|
831
962
|
export declare function clipToBytes(s: string, maxBytes: number): string;
|
|
963
|
+
export {};
|
|
@@ -15,15 +15,21 @@ export const TOOL_SEARCH_REMINDER_CONFIG = {
|
|
|
15
15
|
EVERY_N_TURNS: 15,
|
|
16
16
|
MAX_NAMES: 10,
|
|
17
17
|
};
|
|
18
|
+
export const TOTAL_TOKENS_REMINDER_MODES = ["off", "infinite", "fixed", "countdown", "padded-countdown"];
|
|
19
|
+
export const TOTAL_TOKENS_REMINDER_DEFAULT_MODE = "padded-countdown";
|
|
20
|
+
export const TOTAL_TOKENS_FIXED_ARM_VALUE = 5_000_000;
|
|
18
21
|
export const CHANGED_FILES_MAX = 20;
|
|
19
22
|
export const CHANGED_FILES_MTIME_EPS_MS = 2000;
|
|
20
23
|
export const ATTACHMENT_BYTE_CAP = 8 * 1024;
|
|
21
24
|
const PROJECTION_ITEMS_MAX = 50;
|
|
22
25
|
const PROJECTION_CONTENT_MAX = 80;
|
|
23
26
|
const ATTACHMENT_TAGS_DEFAULT = [...SHELLED_BODY_ENVELOPE_TAGS];
|
|
24
|
-
const
|
|
27
|
+
const ATTACHMENT_TAGS_OWNED = {
|
|
28
|
+
skills_listing: SHELLED_BODY_ENVELOPE_TAGS.filter((t) => t !== "skills"),
|
|
29
|
+
total_tokens_reminder: SHELLED_BODY_ENVELOPE_TAGS.filter((t) => t !== "total_tokens"),
|
|
30
|
+
};
|
|
25
31
|
export function attachmentEnvelopeTags(source) {
|
|
26
|
-
return source
|
|
32
|
+
return ATTACHMENT_TAGS_OWNED[source] ?? ATTACHMENT_TAGS_DEFAULT;
|
|
27
33
|
}
|
|
28
34
|
export const INSTRUCTIONS_CHANGE_BYTE_CAP = 512;
|
|
29
35
|
export function createAttachmentState() {
|
|
@@ -166,6 +172,19 @@ export function collectDueAttachments(state, inp) {
|
|
|
166
172
|
if (inp.config.budgetUsd && inp.budgetUsd !== undefined) {
|
|
167
173
|
(out ??= []).push({ source: "budget_usd", body: renderBudgetUsd(inp.budgetUsd.used, inp.budgetUsd.total) });
|
|
168
174
|
}
|
|
175
|
+
if (inp.config.totalTokensReminder === true) {
|
|
176
|
+
const mode = inp.config.totalTokensReminderMode ?? TOTAL_TOKENS_REMINDER_DEFAULT_MODE;
|
|
177
|
+
if (mode === "infinite" || mode === "fixed") {
|
|
178
|
+
(out ??= []).push({ source: "total_tokens_reminder", body: renderTotalTokensReminder(mode, 0) });
|
|
179
|
+
}
|
|
180
|
+
else if ((mode === "countdown" || mode === "padded-countdown") && inp.totalTokens !== undefined) {
|
|
181
|
+
const { used, total } = inp.totalTokens;
|
|
182
|
+
if (Number.isFinite(used) && Number.isFinite(total) && used >= 0 && total >= 0) {
|
|
183
|
+
const effectiveUsed = mode === "padded-countdown" ? (state.totalTokensFloor = Math.max(state.totalTokensFloor ?? 0, used)) : used;
|
|
184
|
+
(out ??= []).push({ source: "total_tokens_reminder", body: renderTotalTokensReminder(mode, total - effectiveUsed) });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
169
188
|
if (inp.config.backgroundTasks && state.postCompactPending) {
|
|
170
189
|
state.postCompactPending = false;
|
|
171
190
|
if (inp.backgroundTasks !== undefined && inp.backgroundTasks.length > 0) {
|
|
@@ -362,6 +381,10 @@ export function commitInstructionsChange(state, announced) {
|
|
|
362
381
|
export function renderBudgetUsd(used, total) {
|
|
363
382
|
return `USD budget: $${used}/$${total}; $${total - used} remaining`;
|
|
364
383
|
}
|
|
384
|
+
export function renderTotalTokensReminder(mode, remaining) {
|
|
385
|
+
const shown = mode === "infinite" ? "Infinite" : mode === "fixed" ? TOTAL_TOKENS_FIXED_ARM_VALUE : Math.max(0, remaining);
|
|
386
|
+
return `<total_tokens>${shown} tokens left</total_tokens>`;
|
|
387
|
+
}
|
|
365
388
|
export function renderOrphanedBackgroundTasks(tasks) {
|
|
366
389
|
const safe = (t) => sanitizeUntrustedText(t, SHELLED_BODY_ENVELOPE_TAGS);
|
|
367
390
|
return (`The container was restarted. The following background tasks were running and are now stopped:\n` +
|
|
@@ -212,6 +212,25 @@ export async function checkpointStoreContract(make, runAssertion) {
|
|
|
212
212
|
const stored = (await store.get(bitless.token)).pendingAction;
|
|
213
213
|
assert.equal("hasBidiControls" in stored, false, "projection backfill must not write back to the row");
|
|
214
214
|
});
|
|
215
|
+
run("#457 previewWithheld three-form matrix: a row's spelling survives + projects; absent stays absent; an out-of-contract spelling reads as absent", async () => {
|
|
216
|
+
const store = make();
|
|
217
|
+
const oversize = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "pw-oversize" });
|
|
218
|
+
oversize.pendingAction.previewWithheld = "oversize";
|
|
219
|
+
const unavailable = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "pw-unavailable" });
|
|
220
|
+
unavailable.pendingAction.previewWithheld = "unavailable";
|
|
221
|
+
const absent = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "pw-absent" });
|
|
222
|
+
const bogus = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "pw-bogus" });
|
|
223
|
+
bogus.pendingAction.previewWithheld = "shrugged";
|
|
224
|
+
for (const cp of [oversize, unavailable, absent, bogus])
|
|
225
|
+
await store.put(cp.token, cp);
|
|
226
|
+
const back = (await store.get(oversize.token)).pendingAction;
|
|
227
|
+
assert.equal(back.previewWithheld, "oversize", "the row's previewWithheld must survive the round-trip verbatim");
|
|
228
|
+
const byId = new Map((await store.listByScope("tenant-a")).map((s) => [s.sessionId, s]));
|
|
229
|
+
assert.equal(byId.get("pw-oversize")?.previewWithheld, "oversize");
|
|
230
|
+
assert.equal(byId.get("pw-unavailable")?.previewWithheld, "unavailable");
|
|
231
|
+
assert.equal("previewWithheld" in byId.get("pw-absent"), false, "absent must project the key OMITTED, not null/empty");
|
|
232
|
+
assert.equal("previewWithheld" in byId.get("pw-bogus"), false, "an out-of-contract spelling must read as absent, never project verbatim");
|
|
233
|
+
});
|
|
215
234
|
await settle();
|
|
216
235
|
}
|
|
217
236
|
const sortByToken = (a, b) => a.token.localeCompare(b.token);
|
|
@@ -118,7 +118,8 @@ export type WorkerErrorClass = "budget" | "limit" | "output" | "suspend" | "revi
|
|
|
118
118
|
* The `limits.` namespace splits into the `budget` and `limit` classes by exact code — see
|
|
119
119
|
* {@link EXACT_CODE_CLASS}. Operation-level dotted codes that are surfaced to a *caller* and never become a
|
|
120
120
|
* task outcome are deliberately OUT of scope: `steering.*` (`steering.not_running`/`steering.invalid_content`/
|
|
121
|
-
* `steering.duplicate_input_id`, rejected to the `steer()` caller
|
|
121
|
+
* `steering.duplicate_input_id`/`steering.blocked_by_hook`, rejected to the `steer()` caller — the fourth also
|
|
122
|
+
* rides the resume face as a `CheckpointError` code) and `mcp.*` (`mcp.server_unavailable`, an `onWarn` warning code) — neither
|
|
122
123
|
* reaches `TaskResult.errorCode`, so a caller will never pass them here. A genuinely unmapped code → `"unknown"` (which therefore means
|
|
123
124
|
* "known-but-foreign or no code", e.g. a leaked fs/Node code, NOT "an OUR terminal class we forgot to add").
|
|
124
125
|
*/
|
|
@@ -853,6 +853,33 @@ export interface AskRequest {
|
|
|
853
853
|
* with contextual escaping and show {@link args} alongside — the preview can misrepresent the
|
|
854
854
|
* executable action and never replaces args. Never adjudication input. */
|
|
855
855
|
readonly preview?: unknown;
|
|
856
|
+
/**
|
|
857
|
+
* #457 ② — PRESENT ⇔ this tool DECLARES an approval preview and the gate could not present a usable
|
|
858
|
+
* one, naming which way it failed: `"oversize"` (produced, but past the 16KiB display bound — the
|
|
859
|
+
* truncation stub still rides {@link preview}) or `"unavailable"` (the projection threw, or its value
|
|
860
|
+
* has no JSON serialization, so nothing was produced at all).
|
|
861
|
+
*
|
|
862
|
+
* ABSENT is the ordinary world and covers three cases that are NOT withholdings: the tool declares no
|
|
863
|
+
* preview, the projection declined to speak for these args, and the projection succeeded. A surface
|
|
864
|
+
* must therefore read presence, never absence: absence is not a claim that the preview is faithful.
|
|
865
|
+
*
|
|
866
|
+
* A DISCLOSURE, not a verdict and not a transform — the same posture as {@link hasBidiControls}. Core
|
|
867
|
+
* refuses nothing and narrows nothing on account of it: {@link args} and {@link boundInputHash} are
|
|
868
|
+
* always carried, so unlike a surface whose only content IS the projection, a core approval card can
|
|
869
|
+
* still show the person exactly what will run. What the bit buys is the honest sentence a card owes
|
|
870
|
+
* when it is rendering less than the tool meant it to — and the ground for a surface that chooses to
|
|
871
|
+
* withhold its own PERSISTENT "allow and stop asking me this" affordance while the action cannot be
|
|
872
|
+
* reviewed as intended (upstream's form: a withheld preview vetoes the standing row, leaving one-time
|
|
873
|
+
* approval only). Core deliberately does NOT apply that veto to {@link ruleOffers} itself — core's
|
|
874
|
+
* offers speak for shell COMMAND text, which rides `args` and is shown whatever the preview did.
|
|
875
|
+
*
|
|
876
|
+
* Filled at the ask MINT sites that resolve a preview (the synchronous gate leg), not at `resolveAsk`
|
|
877
|
+
* — the chokepoint receives an already-built request and has no tool table to project from. The
|
|
878
|
+
* durable park leg's twin is `PendingAction.tool_approval.previewWithheld` on the row, judged over
|
|
879
|
+
* that row's own fidelity-projected args snapshot; the two faces can honestly differ exactly as the
|
|
880
|
+
* bidi bit's two faces can.
|
|
881
|
+
*/
|
|
882
|
+
readonly previewWithheld?: "oversize" | "unavailable";
|
|
856
883
|
/** Canonical digest of {@link args} as presented in THIS ask, computed by the engine's one
|
|
857
884
|
* `boundInputHashOf` — the same digest a durable park binds its checkpoint to, so an aggregating
|
|
858
885
|
* approver can reconcile a synchronous ask row against a parked checkpoint row for the same call
|
package/dist/core/trace.d.ts
CHANGED
|
@@ -734,10 +734,11 @@ export type TraceEvent = {
|
|
|
734
734
|
* occurrences were replaced with markers in one pass. `trigger` names the arm: `"frontier"`
|
|
735
735
|
* = the proactive request-build pass (anchored estimate crossed the edit budget),
|
|
736
736
|
* `"refusal"` = the MC-R rejection-recovery arm (provider said input-too-long), `"blocking"`
|
|
737
|
-
* = the slice-3
|
|
738
|
-
*
|
|
739
|
-
* `microCompact.machine: "cc"
|
|
740
|
-
* the
|
|
737
|
+
* = the slice-3 guard-chain arm A (the machine's one pre-guard shot when the frontier pass
|
|
738
|
+
* is off, `microCompact.machine: "off"`). SCOPE (X1): emitted only by the cc machine — the
|
|
739
|
+
* `"frontier"` arm requires `microCompact.machine: "cc"` (the default since the slice-3
|
|
740
|
+
* flip), the `"refusal"` arm requires `microCompact.clearOnRejection` (also default-on);
|
|
741
|
+
* the legacy OPT-OUT machine clears silently exactly as pre-374 (its clears are ledger-less
|
|
741
742
|
* and re-fire per request, so a frame there would re-count the same occurrences and break
|
|
742
743
|
* this frame's cardinality clause). Cardinality: exactly ONE frame per firing pass — a retry
|
|
743
744
|
* chain re-sending an already-cleared view emits none. A `"refusal"` frame also marks one
|