@arnilo/prism 0.8.0 → 0.10.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 +62 -1
- package/README.md +13 -12
- package/dist/agent-approval.d.ts +17 -2
- package/dist/agent-approval.js +15 -6
- package/dist/agent-event-source.d.ts +9 -1
- package/dist/agent-event-source.js +10 -3
- package/dist/agent-loops.js +7 -4
- package/dist/agent-run-lifecycle.d.ts +15 -1
- package/dist/agent-run-lifecycle.js +82 -11
- package/dist/agent-run-state.d.ts +47 -6
- package/dist/agent-run-state.js +154 -6
- package/dist/agent-session/event-subscriber.d.ts +2 -0
- package/dist/agent-session/event-subscriber.js +3 -0
- package/dist/agent-session/helpers.js +14 -0
- package/dist/agent-session/session/assemble.js +281 -32
- package/dist/agent-session/session/persist.d.ts +11 -0
- package/dist/agent-session/session/persist.js +48 -16
- package/dist/agent-session/session/provider-round.d.ts +14 -4
- package/dist/agent-session/session/provider-round.js +226 -19
- package/dist/agent-session/session/tool-round.d.ts +2 -2
- package/dist/agent-session/session/tool-round.js +78 -6
- package/dist/agent-session/session/types.d.ts +44 -3
- package/dist/agent-session/session.d.ts +100 -5
- package/dist/agent-session/session.js +224 -13
- package/dist/attention-compiler.d.ts +51 -2
- package/dist/attention-compiler.js +282 -21
- package/dist/cache-helpers.d.ts +4 -2
- package/dist/cache-helpers.js +8 -6
- package/dist/checkpoint-restore.d.ts +45 -0
- package/dist/checkpoint-restore.js +54 -0
- package/dist/context-budget.d.ts +13 -1
- package/dist/context-budget.js +57 -4
- package/dist/contracts-core/agent.d.ts +52 -1
- package/dist/contracts-core/attention.d.ts +95 -0
- package/dist/contracts-core/content.d.ts +10 -0
- package/dist/contracts-core/extensions.d.ts +3 -0
- package/dist/contracts-core/guardrail-packs.d.ts +46 -0
- package/dist/contracts-core/guardrail-packs.js +2 -0
- package/dist/contracts-core/loop.d.ts +36 -0
- package/dist/contracts-core/provider.d.ts +30 -0
- package/dist/contracts-core/run-limits.d.ts +29 -1
- package/dist/contracts-core/session.d.ts +23 -5
- package/dist/contracts-core/session.js +21 -2
- package/dist/contracts-core/usage.d.ts +40 -0
- package/dist/contracts-core/usage.js +8 -0
- package/dist/contracts-core.d.ts +2 -0
- package/dist/contracts-core.js +2 -0
- package/dist/contracts-protocol.d.ts +81 -5
- package/dist/contracts-run-state.d.ts +91 -2
- package/dist/contributions.d.ts +2 -1
- package/dist/contributions.js +1 -0
- package/dist/extensions.d.ts +15 -1
- package/dist/extensions.js +68 -0
- package/dist/guardrail-packs/coding-standard.d.ts +3 -0
- package/dist/guardrail-packs/coding-standard.js +63 -0
- package/dist/guardrail-packs/destructive-commands.d.ts +3 -0
- package/dist/guardrail-packs/destructive-commands.js +46 -0
- package/dist/guardrail-packs/errors.d.ts +7 -0
- package/dist/guardrail-packs/errors.js +9 -0
- package/dist/guardrail-packs/index.d.ts +4 -0
- package/dist/guardrail-packs/index.js +15 -0
- package/dist/guardrail-packs/secrets-hygiene.d.ts +3 -0
- package/dist/guardrail-packs/secrets-hygiene.js +23 -0
- package/dist/guardrail-packs/types.d.ts +26 -0
- package/dist/guardrail-packs/types.js +2 -0
- package/dist/guardrail-packs/validation-respect.d.ts +3 -0
- package/dist/guardrail-packs/validation-respect.js +69 -0
- package/dist/guardrails.d.ts +61 -1
- package/dist/guardrails.js +377 -0
- package/dist/index.d.ts +16 -11
- package/dist/index.js +10 -7
- package/dist/input.d.ts +8 -1
- package/dist/input.js +68 -6
- package/dist/middleware.d.ts +37 -2
- package/dist/middleware.js +41 -0
- package/dist/node/session-store-jsonl.js +18 -3
- package/dist/observability.js +6 -0
- package/dist/provider-events.d.ts +8 -2
- package/dist/provider-events.js +60 -2
- package/dist/providers/openai-compatible.js +6 -3
- package/dist/run-bundle.d.ts +6 -1
- package/dist/run-bundle.js +5 -1
- package/dist/run-limits.d.ts +11 -1
- package/dist/run-limits.js +59 -0
- package/dist/session-stores.d.ts +12 -1
- package/dist/session-stores.js +21 -4
- package/dist/testing/agent-event-source-conformance.js +41 -2
- package/dist/testing/prefix-stability-conformance.d.ts +59 -0
- package/dist/testing/prefix-stability-conformance.js +172 -0
- package/dist/testing/session-store-conformance.d.ts +3 -2
- package/dist/testing/session-store-conformance.js +48 -0
- package/dist/tools.d.ts +5 -0
- package/dist/tools.js +21 -6
- package/dist/usage-estimation.d.ts +29 -0
- package/dist/usage-estimation.js +79 -0
- package/docs/agent-events.md +75 -4
- package/docs/agent-session-runtime.md +10 -6
- package/docs/attention-compiler.md +89 -8
- package/docs/caveman.md +1 -1
- package/docs/coding-agent-tools.md +1 -1
- package/docs/compaction-and-retry.md +1 -1
- package/docs/compaction-llm.md +2 -0
- package/docs/compaction-observational-memory.md +54 -7
- package/docs/durable-runs.md +46 -3
- package/docs/embeddings.md +9 -0
- package/docs/evaluations.md +5 -0
- package/docs/execution-timeline.md +79 -1
- package/docs/extensions.md +20 -3
- package/docs/guardrails.md +50 -4
- package/docs/hooks.md +282 -0
- package/docs/index.md +37 -15
- package/docs/input-and-prompt-assembly.md +4 -4
- package/docs/instruction-injection.md +1 -0
- package/docs/knowledge-sync.md +4 -0
- package/docs/live-testing.md +3 -1
- package/docs/memory-fabric.md +28 -0
- package/docs/middleware-hooks.md +90 -4
- package/docs/migrate-to-0.9.md +210 -0
- package/docs/migration.md +26 -0
- package/docs/multi-agent-patterns.md +25 -2
- package/docs/node-jsonl-session-store.md +7 -1
- package/docs/observability.md +7 -3
- package/docs/options-index.md +4 -1
- package/docs/policy-and-audit.md +26 -1
- package/docs/prefix-stability-conformance.md +143 -0
- package/docs/provider-caching.md +4 -4
- package/docs/provider-conformance.md +16 -0
- package/docs/provider-packages.md +20 -20
- package/docs/public-contracts.md +3 -2
- package/docs/rag.md +188 -3
- package/docs/release-and-install.md +45 -40
- package/docs/runs-and-usage.md +56 -10
- package/docs/scoped-agent-memory.md +270 -0
- package/docs/scoped-memory.md +138 -0
- package/docs/session-store-conformance.md +1 -2
- package/docs/session-stores.md +17 -17
- package/docs/supervisors.md +32 -12
- package/docs/tools.md +18 -1
- package/docs/wiki.md +4 -2
- package/docs/workflows.md +5 -0
- package/package.json +8 -2
package/dist/context-budget.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { capSkillCatalog, selectSkillsForPrompt, skillHasRenderableBody, skillPromptText, } from "./skill-disclosure.js";
|
|
2
|
+
import { estimateTextTokensForFamily, MODEL_FAMILY_TOKENS, resolveModelFamily } from "./usage-estimation.js";
|
|
2
3
|
export const CONTEXT_BUDGET_REPORT_METADATA_KEY = "contextBudgetReport";
|
|
3
4
|
export const HARD_MAX_CONTEXT_BUDGET_TOKENS = 2_000_000;
|
|
4
5
|
export const HARD_MAX_CONTEXT_BUDGET_BYTES = 32 * 1024 * 1024;
|
|
@@ -22,8 +23,29 @@ export function estimateTextTokens(text) {
|
|
|
22
23
|
export function estimateTextBytes(text) {
|
|
23
24
|
return Buffer.byteLength(text, "utf8");
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Single message → flattened text → estimator (budget accounting, never billing).
|
|
28
|
+
*
|
|
29
|
+
* Plan 091 Task 1 overload: a message array plus a model id, provider id, or
|
|
30
|
+
* family name returns a labeled {@link TokenEstimate}. It reuses this same
|
|
31
|
+
* per-message flattening and adds the family's per-message chat-template
|
|
32
|
+
* overhead; `unknown` families fall back to the conservative table with
|
|
33
|
+
* `lowConfidence: true`.
|
|
34
|
+
*/
|
|
35
|
+
export function estimateMessageTokens(input, estimatorOrFamily) {
|
|
36
|
+
if (isMessageArray(input)) {
|
|
37
|
+
const family = resolveModelFamily(estimatorOrFamily);
|
|
38
|
+
const table = MODEL_FAMILY_TOKENS[family];
|
|
39
|
+
let tokens = table.perMessageOverhead * input.length;
|
|
40
|
+
for (const message of input)
|
|
41
|
+
tokens += estimateTextTokensForFamily(messageText(message), family);
|
|
42
|
+
return { tokens, confidence: table.confidence, lowConfidence: table.confidence === "low" };
|
|
43
|
+
}
|
|
44
|
+
const estimateTokens = typeof estimatorOrFamily === "function" ? estimatorOrFamily : estimateTextTokens;
|
|
45
|
+
return estimateTokens(messageText(input));
|
|
46
|
+
}
|
|
47
|
+
function isMessageArray(value) {
|
|
48
|
+
return Array.isArray(value);
|
|
27
49
|
}
|
|
28
50
|
export function estimateMessageBytes(message) {
|
|
29
51
|
return estimateTextBytes(messageText(message));
|
|
@@ -224,7 +246,7 @@ function measureAll(groups, context, skills, tools, skillContext, demotedBodies,
|
|
|
224
246
|
for (const message of groups.toolResults)
|
|
225
247
|
addMessage(message);
|
|
226
248
|
for (const block of context) {
|
|
227
|
-
const text =
|
|
249
|
+
const text = contextBlockMeasureText(block);
|
|
228
250
|
tokens += estimateTokens(text);
|
|
229
251
|
bytes += estimateTextBytes(text);
|
|
230
252
|
}
|
|
@@ -234,12 +256,35 @@ function measureAll(groups, context, skills, tools, skillContext, demotedBodies,
|
|
|
234
256
|
bytes += estimateTextBytes(text);
|
|
235
257
|
}
|
|
236
258
|
if (tools?.length) {
|
|
237
|
-
const text =
|
|
259
|
+
const text = toolsMeasureText(tools);
|
|
238
260
|
tokens += estimateTokens(text);
|
|
239
261
|
bytes += estimateTextBytes(text);
|
|
240
262
|
}
|
|
241
263
|
return { tokens, bytes };
|
|
242
264
|
}
|
|
265
|
+
/** Plan 103 T6: the host's `contextBudget.tokenEstimator`, validated exactly like the budget pass
|
|
266
|
+
* validates it (a non-function, or a non-finite/negative count, fails closed with `TypeError`).
|
|
267
|
+
* `undefined` when no host estimator is configured, so callers can fall through to the built-in
|
|
268
|
+
* heuristic. Exported for the usage seam (`provider-round.ts`) — deliberately not re-exported by
|
|
269
|
+
* `src/index.ts`, so the public surface is unchanged. */
|
|
270
|
+
export function resolveHostTokenEstimator(budget) {
|
|
271
|
+
if (budget?.tokenEstimator === undefined)
|
|
272
|
+
return undefined;
|
|
273
|
+
return resolveTokenEstimator(budget);
|
|
274
|
+
}
|
|
275
|
+
/** Plan 103 T6: tool declarations and context blocks projected with the assembler's own
|
|
276
|
+
* `measureAll` text shapes, so the usage-fallback estimate and the budget pass cannot drift
|
|
277
|
+
* (never `JSON.stringify` of the raw schemas). Exported for the usage seam — deliberately not
|
|
278
|
+
* re-exported by `src/index.ts`. */
|
|
279
|
+
export function estimateRequestExtrasTokens(tools, context, estimateTokens) {
|
|
280
|
+
let tokens = 0;
|
|
281
|
+
if (context?.length)
|
|
282
|
+
for (const block of context)
|
|
283
|
+
tokens += estimateTokens(contextBlockMeasureText(block));
|
|
284
|
+
if (tools?.length)
|
|
285
|
+
tokens += estimateTokens(toolsMeasureText(tools));
|
|
286
|
+
return tokens;
|
|
287
|
+
}
|
|
243
288
|
function overBudget(cost, budget) {
|
|
244
289
|
if (budget.maxInputTokens !== undefined && cost.tokens > budget.maxInputTokens)
|
|
245
290
|
return true;
|
|
@@ -320,4 +365,12 @@ function contextBlockText(block) {
|
|
|
320
365
|
})
|
|
321
366
|
.join("\n");
|
|
322
367
|
}
|
|
368
|
+
/** The context block exactly as `measureAll` measures it (plan 103 T6 shares this shape with the usage seam). */
|
|
369
|
+
function contextBlockMeasureText(block) {
|
|
370
|
+
return `${block.title ? `${block.title}:\n` : "Context:\n"}${contextBlockText(block)}`;
|
|
371
|
+
}
|
|
372
|
+
/** The tool list exactly as `measureAll` measures it (plan 103 T6 shares this shape with the usage seam). */
|
|
373
|
+
function toolsMeasureText(tools) {
|
|
374
|
+
return `Available tools:\n${tools.map((tool) => `- ${tool.name}${tool.description ? `: ${tool.description}` : ""}`).join("\n")}`;
|
|
375
|
+
}
|
|
323
376
|
//# sourceMappingURL=context-budget.js.map
|
|
@@ -10,7 +10,8 @@ import type { ToolValidator } from "../tools.js";
|
|
|
10
10
|
import type { CompactionOptions, RetryOptions } from "./compaction.js";
|
|
11
11
|
import type { ContentBlock, ErrorInfo, JsonObject, Message, ModelConfig } from "./content.js";
|
|
12
12
|
import type { ProviderRequestPolicy, SystemPromptConfig } from "./extensions.js";
|
|
13
|
-
import type {
|
|
13
|
+
import type { GuardrailPackRef } from "./guardrail-packs.js";
|
|
14
|
+
import type { AgentLoopOptions, AgentLoopStrategy, StopHook } from "./loop.js";
|
|
14
15
|
import type { OwnershipScope } from "./persistence.js";
|
|
15
16
|
import type { AIProvider, ProviderRequestOptions, ProviderResolver } from "./provider.js";
|
|
16
17
|
import type { ResourceLoader } from "./resources.js";
|
|
@@ -47,6 +48,17 @@ export interface AgentDefinitionResolutionContext {
|
|
|
47
48
|
readonly activateAllCapabilities?: true;
|
|
48
49
|
readonly overrides?: Partial<AgentConfig>;
|
|
49
50
|
}
|
|
51
|
+
/** Per-turn tool menu. Called at `loopCtx.assemble` before each provider request. */
|
|
52
|
+
export interface ToolNarrowingContext {
|
|
53
|
+
/** 1-based provider turn this assemble precedes. */
|
|
54
|
+
readonly turn: number;
|
|
55
|
+
/** Text of the latest assistant message, when any. */
|
|
56
|
+
readonly lastAssistantText?: string;
|
|
57
|
+
/** Run-grant tool names (R11 snapshot, including generated `search_tools` when disclosure is search). */
|
|
58
|
+
readonly toolIds: readonly string[];
|
|
59
|
+
}
|
|
60
|
+
/** Host callback: return a subset of `toolIds`. Superset names are clamped; throw fails the turn. */
|
|
61
|
+
export type ToolNarrowing = (ctx: ToolNarrowingContext) => readonly string[] | Promise<readonly string[]>;
|
|
50
62
|
export interface AgentConfig {
|
|
51
63
|
readonly id?: string;
|
|
52
64
|
readonly name?: string;
|
|
@@ -64,11 +76,34 @@ export interface AgentConfig {
|
|
|
64
76
|
/** Tools disclosure: "all" (default) sends every active tool schema; "search" sends top-k + the generated `search_tools` tool. */
|
|
65
77
|
readonly toolsDisclosure?: import("../tool-search.js").ToolsDisclosure;
|
|
66
78
|
readonly toolsSearch?: import("../tool-search.js").ToolsSearchOptions;
|
|
79
|
+
/** Per-turn restrictive allow-list over the run grant. RunOptions override. */
|
|
80
|
+
readonly toolNarrowing?: ToolNarrowing;
|
|
81
|
+
/** Opt-in: tools hidden this turn stay callable by name (default off). */
|
|
82
|
+
readonly allowHiddenToolCalls?: true;
|
|
67
83
|
/** Opt-in projection-only fold for aged large tool results in provider view; store untouched. */
|
|
68
84
|
readonly toolResultFold?: import("../tool-result-fold.js").ToolResultFoldOptions;
|
|
69
85
|
/** Opt-in attention compiler (plan 074): `true` for defaults, an object to tune ratios/depth.
|
|
70
86
|
* Omitted keeps today's request bytes; per-run options may only relax this setting. */
|
|
71
87
|
readonly attentionCompiler?: import("./attention.js").AttentionCompilerSetting;
|
|
88
|
+
/**
|
|
89
|
+
* Missing-usage handling (plan 091 T2, plan 103 T5): `"fallback"` (default) records a labeled
|
|
90
|
+
* estimate when a provider turn reports no usage; `"off"` leaves usage absent — never zero;
|
|
91
|
+
* `"strict"` refuses a usage-less turn instead, failing the run with `code: "usage_missing"`
|
|
92
|
+
* (`name: "UsageMissingError"`) so a host whose cost gates cannot tolerate approximations never
|
|
93
|
+
* runs on an estimate. A refusal is a harness decision, not a provider failure, so it carries no
|
|
94
|
+
* `failureClass` and is never retried. Estimates are marked `Usage.estimated` and never priced.
|
|
95
|
+
*/
|
|
96
|
+
readonly usageEstimation?: "fallback" | "off" | "strict";
|
|
97
|
+
/**
|
|
98
|
+
* Session-turn context budget (plan 103 T6): forwarded to every `assembleProviderInput`
|
|
99
|
+
* call this agent's sessions make, so a session gets the same eviction, `tokenEstimator`,
|
|
100
|
+
* and `reportOmissions` semantics as a direct assembler caller. Mutually exclusive with
|
|
101
|
+
* `attentionCompiler` (rejected at assembly). With `usageEstimation: "fallback"`, the
|
|
102
|
+
* missing-usage estimate prefers this budget's own measurement: the request's
|
|
103
|
+
* `ContextBudgetReport.keptTokens` when `reportOmissions` is on, else the `tokenEstimator`
|
|
104
|
+
* projection — see [Runs and usage](../../docs/runs-and-usage.md).
|
|
105
|
+
*/
|
|
106
|
+
readonly contextBudget?: import("../context-budget.js").ContextBudget;
|
|
72
107
|
readonly inputBuilder?: InputBuilder;
|
|
73
108
|
readonly promptBuilder?: PromptBuilder;
|
|
74
109
|
readonly middleware?: MiddlewareRegistry;
|
|
@@ -102,6 +137,8 @@ export interface AgentConfig {
|
|
|
102
137
|
readonly inputLayout?: InputAssemblyLayout;
|
|
103
138
|
readonly loop?: AgentLoopStrategy | AgentLoopOptions;
|
|
104
139
|
readonly guardrails?: Guardrails;
|
|
140
|
+
/** Run-end stop hooks (plan 106 R1); `RunOptions.stopHooks` appends to this list. */
|
|
141
|
+
readonly stopHooks?: readonly StopHook[];
|
|
105
142
|
/** Opt-in durable interruption/checkpointing default for this agent. */
|
|
106
143
|
readonly runState?: AgentRunStateOptions;
|
|
107
144
|
/** Internal marker set by createSecureAgent(); makes security defaults immutable per run. */
|
|
@@ -134,6 +171,12 @@ export interface AgentSessionConfig {
|
|
|
134
171
|
readonly store?: SessionStore;
|
|
135
172
|
readonly leafId?: string;
|
|
136
173
|
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
174
|
+
/**
|
|
175
|
+
* Restrictive-only guardrail packs compiled once per session onto the existing tool interception
|
|
176
|
+
* seams (plan 092). Built-in ids are versioned; an input object with `rules` is an inline pack.
|
|
177
|
+
* Compiled rules can only deny or tripwire — they never grant permissions.
|
|
178
|
+
*/
|
|
179
|
+
readonly guardrailPacks?: readonly GuardrailPackRef[];
|
|
137
180
|
/**
|
|
138
181
|
* TTL of the in-memory `session.snapshot()` branch cache in milliseconds.
|
|
139
182
|
* Default `DEFAULT_SNAPSHOT_CACHE_TTL_MS`; `0` disables the cache (every snapshot read
|
|
@@ -155,6 +198,12 @@ export interface AgentSessionCloneOptions {
|
|
|
155
198
|
}
|
|
156
199
|
export type SubscriberOverflowPolicy = "close" | "drop_oldest" | "drop_newest";
|
|
157
200
|
export interface SubscribeOptions {
|
|
201
|
+
/**
|
|
202
|
+
* Plan 104 T5: `true` keeps this subscriber open across runs of the same session; it is then
|
|
203
|
+
* closed only by the host (`subscription.close()` / `session.closeSubscribers()`) or by an
|
|
204
|
+
* overflow under the default `close` policy. Default `false` (closed at run end).
|
|
205
|
+
*/
|
|
206
|
+
readonly acrossRuns?: boolean;
|
|
158
207
|
/** Maximum queued events for a subscriber that is not actively awaiting `next()`. Defaults to 1024. */
|
|
159
208
|
readonly maxQueuedEvents?: number;
|
|
160
209
|
/** What to do when `maxQueuedEvents` is reached. Defaults to `close`. */
|
|
@@ -277,6 +326,8 @@ export interface PromptBuildRequest {
|
|
|
277
326
|
readonly skills?: readonly Skill[];
|
|
278
327
|
readonly skillsDisclosure?: import("../skill-disclosure.js").SkillsDisclosure;
|
|
279
328
|
readonly loadedSkills?: import("../skill-disclosure.js").LoadedSkillSet;
|
|
329
|
+
/** Loaded skill bodies already appended to `messages` by the session tail allocator; render catalog entries only. */
|
|
330
|
+
readonly tailSkillBodies?: boolean;
|
|
280
331
|
/** Tools disclosure: "all" (default) sends every active tool schema; "search" sends top-k + the generated `search_tools` tool. */
|
|
281
332
|
readonly toolsDisclosure?: import("../tool-search.js").ToolsDisclosure;
|
|
282
333
|
readonly toolsSearch?: import("../tool-search.js").ToolsSearchOptions;
|
|
@@ -12,9 +12,75 @@ export interface AttentionInputCapOptions {
|
|
|
12
12
|
/** Output + next-turn headroom subtracted from the window (default 1024). */
|
|
13
13
|
readonly reserveTokens?: number;
|
|
14
14
|
}
|
|
15
|
+
/** Fold axes (plan 086 T2). `input_ratio` is the legacy `triggerRatio` axis; the rest are new. */
|
|
16
|
+
export type AttentionTriggerKind = "input_ratio" | "run_input_ratio" | "token_floor" | "predicate";
|
|
17
|
+
/** Per-turn inputs an axis reads. Frozen before a `predicate` sees it; estimates and ids only. */
|
|
18
|
+
export interface AttentionTriggerState {
|
|
19
|
+
/** Estimated tokens of the request this turn will send — what the ratio axes compare. */
|
|
20
|
+
readonly estimatedInputTokens: number;
|
|
21
|
+
/** Resolved per-request input cap (`resolveInputCap`). */
|
|
22
|
+
readonly inputCapTokens: number;
|
|
23
|
+
/** Cumulative run input budget when the run limits declare one; absent falls back to `inputCapTokens`. */
|
|
24
|
+
readonly runInputBudgetTokens?: number;
|
|
25
|
+
/** Run input tokens already charged by provider usage this run (0 when unknown). */
|
|
26
|
+
readonly runInputTokens: number;
|
|
27
|
+
/** 1-based provider turn index. */
|
|
28
|
+
readonly turn: number;
|
|
29
|
+
}
|
|
30
|
+
/** Host predicate axis. Runs host-supplied code under the same trust as `CompactionTrigger.custom`. */
|
|
31
|
+
export type AttentionTriggerFunction = (state: AttentionTriggerState) => boolean;
|
|
32
|
+
/** One fold gate. An array is any-of; the first axis that fires is the one attributed. */
|
|
33
|
+
export type AttentionTrigger =
|
|
34
|
+
/** Legacy axis: fires when the assembled request reaches `ratio` of the per-request input cap. */
|
|
35
|
+
{
|
|
36
|
+
readonly kind: "input_ratio";
|
|
37
|
+
readonly ratio: number;
|
|
38
|
+
}
|
|
39
|
+
/** Cumulative axis: fires when `runInputTokens + estimatedInputTokens` reaches `ratio` of the run
|
|
40
|
+
* input budget, so a run capped below the window folds before the cap kills it. Falls back to
|
|
41
|
+
* the `input_ratio` comparison when the run limits declare no input budget. */
|
|
42
|
+
| {
|
|
43
|
+
readonly kind: "run_input_ratio";
|
|
44
|
+
readonly ratio: number;
|
|
45
|
+
}
|
|
46
|
+
/** Absolute axis: fires when the assembled request reaches `tokens`, whatever the cap. */
|
|
47
|
+
| {
|
|
48
|
+
readonly kind: "token_floor";
|
|
49
|
+
readonly tokens: number;
|
|
50
|
+
}
|
|
51
|
+
/** Host axis: fires when `shouldFold` returns `true`. Called once per turn; must be synchronous. */
|
|
52
|
+
| {
|
|
53
|
+
readonly kind: "predicate";
|
|
54
|
+
readonly shouldFold: AttentionTriggerFunction;
|
|
55
|
+
};
|
|
56
|
+
/** Accepted `trigger` value: one axis, one predicate, or an any-of array of either. */
|
|
57
|
+
export type AttentionTriggerInput = AttentionTrigger | AttentionTriggerFunction | readonly (AttentionTrigger | AttentionTriggerFunction)[];
|
|
58
|
+
/** Result of evaluating the axes once against one turn's state. */
|
|
59
|
+
export interface AttentionTriggerDecision {
|
|
60
|
+
readonly shouldFold: boolean;
|
|
61
|
+
/** First axis that fired, in configured order (plan 087 attribution). */
|
|
62
|
+
readonly firedAxis?: AttentionTriggerKind;
|
|
63
|
+
/** Estimated-token target the sticky stages fold to; absent = fold every eligible row. */
|
|
64
|
+
readonly targetTokens?: number;
|
|
65
|
+
/** `true` when folding this request can settle the fired axis, so a still-firing axis after every
|
|
66
|
+
* eligible row throws `AttentionBudgetError`. Cumulative `run_input_ratio` axes are `false`: the
|
|
67
|
+
* spend is already booked, folding only slows the counter, and the run limit owns the cap. */
|
|
68
|
+
readonly failsClosed: boolean;
|
|
69
|
+
}
|
|
15
70
|
export interface AttentionCompilerOptions extends AttentionInputCapOptions {
|
|
16
71
|
/** Fraction of `inputCap` that triggers mutation; in `(0, 1)` (default 0.75). */
|
|
17
72
|
readonly triggerRatio?: number;
|
|
73
|
+
/**
|
|
74
|
+
* Fold axes (plan 086 T2). Omitted keeps the `triggerRatio` axis alone, so requests gate
|
|
75
|
+
* exactly as before. Given, it **replaces** the `triggerRatio` axis: the gate is the any-of of
|
|
76
|
+
* the listed axes, and `triggerRatio` stays the input-ratio reference for `compactRatio` and
|
|
77
|
+
* the report. A run overlay may not set it (the gate is agent-config only).
|
|
78
|
+
*
|
|
79
|
+
* Predicate axes execute host-supplied code, trusted exactly like `CompactionTrigger.custom`:
|
|
80
|
+
* the function runs once per turn with a frozen `AttentionTriggerState` and must return a
|
|
81
|
+
* boolean synchronously (a `Promise` return fails closed with a `TypeError`).
|
|
82
|
+
*/
|
|
83
|
+
readonly trigger?: AttentionTriggerInput;
|
|
18
84
|
/** Where compaction should fire relative to `triggerRatio`; must exceed it (default 0.9). */
|
|
19
85
|
readonly compactRatio?: number;
|
|
20
86
|
/** Newest thinking-bearing assistant turns kept intact (default 1). */
|
|
@@ -23,6 +89,17 @@ export interface AttentionCompilerOptions extends AttentionInputCapOptions {
|
|
|
23
89
|
readonly keepLast?: number;
|
|
24
90
|
/** Tool names whose results are never stubbed, whatever the ratio. */
|
|
25
91
|
readonly excludeTools?: readonly string[];
|
|
92
|
+
/**
|
|
93
|
+
* Durable folding (plan 086 T3): persist the fold ledger and its sticky frontier into the
|
|
94
|
+
* run's checkpoint at each fold, and restore them before the first turn after a resume.
|
|
95
|
+
* Requires a durable run (`runState` with a checkpoint store); independent of
|
|
96
|
+
* `persistSessionState`, which governs skill/tool session state instead.
|
|
97
|
+
*
|
|
98
|
+
* Off by default: durable folding costs one extra checkpoint write per fold (never per turn)
|
|
99
|
+
* and stores the folded bodies — already redacted, capped by `maxSummaryBytes` — so a resumed
|
|
100
|
+
* request carries the same folded rows a live run would. A run overlay may not set it.
|
|
101
|
+
*/
|
|
102
|
+
readonly durable?: boolean;
|
|
26
103
|
}
|
|
27
104
|
/** Where the compiler is switched on: `true` uses the defaults, an object tunes them, `false`
|
|
28
105
|
* (or omitted) leaves requests byte-for-byte as they are without the compiler. On
|
|
@@ -34,6 +111,10 @@ export interface AttentionCompilerContext {
|
|
|
34
111
|
readonly model?: Pick<ModelConfig, "limits">;
|
|
35
112
|
/** Validated at create so an unknown trigger type fails at config time, not on turn one. */
|
|
36
113
|
readonly compactionTrigger?: CompactionTrigger;
|
|
114
|
+
/** Cumulative run input budget the `run_input_ratio` axis folds against (the resolved
|
|
115
|
+
* `RunLimits.maxInputTokens`); `null`/omitted means no run budget, so that axis falls back to
|
|
116
|
+
* the per-request input cap. Distinct from `maxInputTokens`, which caps one request. */
|
|
117
|
+
readonly runInputBudget?: number | null;
|
|
37
118
|
}
|
|
38
119
|
/** Validated, frozen configuration returned by `createAttentionCompiler`. */
|
|
39
120
|
export interface AttentionCompiler {
|
|
@@ -44,6 +125,14 @@ export interface AttentionCompiler {
|
|
|
44
125
|
readonly thinkingKeepTurns: number;
|
|
45
126
|
readonly keepLast: number;
|
|
46
127
|
readonly excludeTools: readonly string[];
|
|
128
|
+
/** Normalized, frozen fold axes in evaluation order: the `input_ratio` default when no
|
|
129
|
+
* `trigger` was configured, otherwise exactly the configured axes. */
|
|
130
|
+
readonly trigger: readonly AttentionTrigger[];
|
|
131
|
+
/** Run input budget resolved at create; absent when the run limits declare none. */
|
|
132
|
+
readonly runInputBudget?: number;
|
|
133
|
+
/** Durable folding resolved at create (plan 086 T3); `true` opts the run's fold state into
|
|
134
|
+
* checkpoint persistence, so `assembleProviderInput` callers should pass the ledger. */
|
|
135
|
+
readonly durable: boolean;
|
|
47
136
|
}
|
|
48
137
|
/** One mutated turn. Under-ratio turns emit nothing and produce no report (C14). */
|
|
49
138
|
export interface AttentionReport {
|
|
@@ -53,12 +142,18 @@ export interface AttentionReport {
|
|
|
53
142
|
readonly usedAfter: number;
|
|
54
143
|
readonly inputCap: number;
|
|
55
144
|
readonly triggerRatio: number;
|
|
145
|
+
/** Axis that opened the gate on this turn, when one did (plan 087 attribution). */
|
|
146
|
+
readonly firedAxis?: AttentionTriggerKind;
|
|
56
147
|
/** Thinking turns absent from this request; rows re-applied from the sticky frontier count again. */
|
|
57
148
|
readonly droppedThinkingTurns: number;
|
|
58
149
|
/** Tool results stubbed in this request; rows re-applied from the sticky frontier count again. */
|
|
59
150
|
readonly stubbedToolResults: number;
|
|
60
151
|
/** Payload bytes the stubs took out of this request (never the stub text itself). */
|
|
61
152
|
readonly stubbedBytes: number;
|
|
153
|
+
/** Folded bodies this turn added to the ledger — the summarize calls a cache saved, and the
|
|
154
|
+
* signal that a durable fold has new state to checkpoint (plan 086 T3). Zero on a turn that
|
|
155
|
+
* only re-applied bodies the ledger already held. */
|
|
156
|
+
readonly newFoldedBodies: number;
|
|
62
157
|
/** True when the gate stopped with eligible rows left: the sticky frontier is partial. */
|
|
63
158
|
readonly truncated: boolean;
|
|
64
159
|
readonly runId?: string;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Moved verbatim from contracts-core.ts; public surface unchanged behind the barrel. */
|
|
3
3
|
import type { AudioContent, DocumentContent, FileContent } from "../content.js";
|
|
4
4
|
import type { ModelCacheCapabilities } from "./provider.js";
|
|
5
|
+
import type { TokenEstimateConfidence } from "./usage.js";
|
|
5
6
|
export type JsonPrimitive = string | number | boolean | null;
|
|
6
7
|
export type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
7
8
|
export interface JsonObject {
|
|
@@ -177,6 +178,15 @@ export interface Usage {
|
|
|
177
178
|
readonly cacheWriteTokens?: number;
|
|
178
179
|
readonly cost?: number;
|
|
179
180
|
readonly currency?: string;
|
|
181
|
+
/**
|
|
182
|
+
* True when these token counts are a harness estimate, never provider truth
|
|
183
|
+
* (plan 091 T2). Estimated usage is never priced, and every accounting export
|
|
184
|
+
* (ledger rows, run totals, turn events) keeps this flag so a billing surface
|
|
185
|
+
* can always tell an estimate from a report. Absent means reported.
|
|
186
|
+
*/
|
|
187
|
+
readonly estimated?: boolean;
|
|
188
|
+
/** Confidence label of an estimated usage; absent on reported usage. */
|
|
189
|
+
readonly confidence?: TokenEstimateConfidence;
|
|
180
190
|
}
|
|
181
191
|
/**
|
|
182
192
|
* Host-supplied pricing adapter (plan 062): quotes cost rates per model id. Core
|
|
@@ -7,6 +7,7 @@ import type { Middleware, MiddlewareHookName, MiddlewareRegistry } from "../midd
|
|
|
7
7
|
import type { AgentDefinition, CommandDefinition, ContextProvider, InputBuilder, InstructionInjector, PromptBuilder, Skill } from "./agent.js";
|
|
8
8
|
import type { CompactionStrategy, RetryPolicy } from "./compaction.js";
|
|
9
9
|
import type { ErrorInfo, ModelConfig } from "./content.js";
|
|
10
|
+
import type { StopHook } from "./loop.js";
|
|
10
11
|
import type { StoreFactory } from "./persistence.js";
|
|
11
12
|
import type { AIProvider, ProviderRequest } from "./provider.js";
|
|
12
13
|
import type { Credential, CredentialResolver, ResourceLoader, SettingsProvider } from "./resources.js";
|
|
@@ -160,4 +161,6 @@ export interface ExtensionAPI {
|
|
|
160
161
|
registerProviderRequestPolicy(policy: ProviderRequestPolicy): void;
|
|
161
162
|
registerSystemPromptContribution(contribution: SystemPromptContribution): void;
|
|
162
163
|
registerInstructionInjector(injector: InstructionInjector): void;
|
|
164
|
+
/** Contributes an inert run-end stop hook; activate it via `activateKernel()` → `AgentConfig.stopHooks` (plan 106 R1). */
|
|
165
|
+
registerStopHook(hook: StopHook): void;
|
|
163
166
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guardrail packs (plan 092 Task 2): config-declared, restrictive-only rule sets compiled once per
|
|
3
|
+
* session onto the existing tool interception seams (`tool_input` / `tool_output`). Packs can only
|
|
4
|
+
* deny, tripwire, or ask for approval — they never grant permissions, widen arguments, or add a stage.
|
|
5
|
+
*/
|
|
6
|
+
import type { JsonObject } from "./content.js";
|
|
7
|
+
export type GuardrailRuleAction = "deny" | "tripwire" | "ask";
|
|
8
|
+
/** Read-only identity view handed to a pack rule predicate (never carries a raw argument echo). */
|
|
9
|
+
export interface GuardrailRuleContext {
|
|
10
|
+
readonly toolName: string;
|
|
11
|
+
readonly toolCallId: string;
|
|
12
|
+
readonly sessionId: string;
|
|
13
|
+
readonly runId: string;
|
|
14
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
15
|
+
/** Pack-local state shared with the pack's result observer; treat as read-only. */
|
|
16
|
+
readonly state: Readonly<Record<string, unknown>>;
|
|
17
|
+
}
|
|
18
|
+
export interface GuardrailRule {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
/** Tool names this rule applies to; omitted matches every tool. */
|
|
21
|
+
readonly tool?: string | readonly string[];
|
|
22
|
+
/** Regex source, compiled once; tested against matched argument strings. Exactly one of `pattern` / `deny`. */
|
|
23
|
+
readonly pattern?: string | RegExp;
|
|
24
|
+
/** Dot path(s) of arguments to test (e.g. `command`, `["from", "to"]`); omitted deep-scans argument strings. */
|
|
25
|
+
readonly argPath?: string | readonly string[];
|
|
26
|
+
/** Typed predicate escape hatch (host-trusted like all host code); deny when it returns true. Exactly one of `pattern` / `deny`. */
|
|
27
|
+
readonly deny?: (args: JsonObject, context: GuardrailRuleContext) => boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Defaults to `deny`. `tripwire` also rejects the enclosing run. `ask` suspends a durable run
|
|
30
|
+
* before the call dispatches (the pending decision names this rule) and blocks the call in a run
|
|
31
|
+
* that cannot suspend; it requires `pattern` — an opaque predicate cannot raise an approval
|
|
32
|
+
* (plan 104 Task 3).
|
|
33
|
+
*/
|
|
34
|
+
readonly action?: GuardrailRuleAction;
|
|
35
|
+
/** Bounded, redacted record reason; defaults to the pack/rule id. */
|
|
36
|
+
readonly reason?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Built-in pack selection by `id` (optional `options`), or an inline pack when `rules` is present. */
|
|
39
|
+
export interface GuardrailPackInput {
|
|
40
|
+
readonly id: string;
|
|
41
|
+
readonly version?: number;
|
|
42
|
+
readonly options?: Readonly<Record<string, unknown>>;
|
|
43
|
+
readonly rules?: readonly GuardrailRule[];
|
|
44
|
+
}
|
|
45
|
+
/** A session's `guardrailPacks` entry: built-in pack id, or an inline/built-in pack input object. */
|
|
46
|
+
export type GuardrailPackRef = string | GuardrailPackInput;
|
|
@@ -46,6 +46,36 @@ export interface TurnPolicyOptions {
|
|
|
46
46
|
*/
|
|
47
47
|
readonly stop?: (context: TurnBoundaryContext) => TurnStopDecision;
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Run-end stop-hook contract (plan 106 R1). Stop hooks run at a natural loop end — never after a
|
|
51
|
+
* loop ceiling, a host turn-policy stop, or an artifact failure — and decide whether the run is
|
|
52
|
+
* done. The first `continue` queues `reason` (plus optional `steer`) through the same steer path a
|
|
53
|
+
* host would use and re-enters the loop; `stop` (or no hook continuing) ends the run normally.
|
|
54
|
+
*/
|
|
55
|
+
export interface StopHookContext {
|
|
56
|
+
readonly sessionId: string;
|
|
57
|
+
readonly runId: string;
|
|
58
|
+
/** Provider turns already assembled in this run (resumption continues the run's counter). */
|
|
59
|
+
readonly turn: number;
|
|
60
|
+
/** Live transcript at loop end; hooks read it, never mutate it. */
|
|
61
|
+
readonly history: readonly Message[];
|
|
62
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
63
|
+
readonly signal: AbortSignal;
|
|
64
|
+
/** True on every invocation after the first continuation in this run (Claude Code `stop_hook_active`). */
|
|
65
|
+
readonly stopHookActive: boolean;
|
|
66
|
+
}
|
|
67
|
+
/** `continue` re-enters the loop with `reason` queued as a steer (optional extra `steer` message follows it). */
|
|
68
|
+
export type StopHookDecision = {
|
|
69
|
+
readonly action: "stop";
|
|
70
|
+
} | {
|
|
71
|
+
readonly action: "continue";
|
|
72
|
+
readonly reason: string;
|
|
73
|
+
readonly steer?: string | Message;
|
|
74
|
+
};
|
|
75
|
+
export interface StopHook {
|
|
76
|
+
readonly name: string;
|
|
77
|
+
decide(context: StopHookContext): StopHookDecision | Promise<StopHookDecision>;
|
|
78
|
+
}
|
|
49
79
|
export interface LoopContext {
|
|
50
80
|
readonly sessionId: string;
|
|
51
81
|
readonly runId: string;
|
|
@@ -54,6 +84,12 @@ export interface LoopContext {
|
|
|
54
84
|
readonly history: Message[];
|
|
55
85
|
readonly input: AgentInput;
|
|
56
86
|
readonly inputMessages: readonly Message[];
|
|
87
|
+
/**
|
|
88
|
+
* True when this `run()` call is a stop-hook continuation re-entry (plan 106 R1): `input` and
|
|
89
|
+
* `inputMessages` are empty because the continuation message is already in `history`. Custom
|
|
90
|
+
* strategies must not replay run-start input when this is set.
|
|
91
|
+
*/
|
|
92
|
+
readonly continuation?: boolean;
|
|
57
93
|
readonly maxToolRounds: number;
|
|
58
94
|
/**
|
|
59
95
|
* Why the loop stopped, when a limit/ceiling ends the run cleanly (F4). Strategies set
|
|
@@ -62,6 +62,36 @@ export interface AIProvider {
|
|
|
62
62
|
readonly id: string;
|
|
63
63
|
generate(request: ProviderRequest): AsyncIterable<ProviderEvent>;
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Closed taxonomy for why a provider turn stopped (plan 087 T1). Adapters map native wire
|
|
67
|
+
* reasons (`finish_reason`, `stop_reason`, `finishReason`, Converse `stopReason`) through the
|
|
68
|
+
* shared `mapProviderStopReason` table; `unknown` is the escape hatch for a new wire value.
|
|
69
|
+
*/
|
|
70
|
+
export type ProviderStopReason = "end_turn" | "tool_calls" | "max_output_tokens" | "content_filter" | "abort" | "provider_error" | "unknown";
|
|
71
|
+
/**
|
|
72
|
+
* Effective budget snapshot at provider-turn end (plan 087 T1): current-turn input tokens
|
|
73
|
+
* against the per-request input cap, cumulative run input against its budget, and the turn
|
|
74
|
+
* axis, so a host can see which limit was closest without instrumenting the session.
|
|
75
|
+
*/
|
|
76
|
+
export interface TurnBudgets {
|
|
77
|
+
/** Input tokens charged for this turn: provider-reported, or a labeled fallback estimate when the
|
|
78
|
+
* provider reported none; absent when neither exists. See `inputTokensSource`. */
|
|
79
|
+
readonly inputTokens?: number;
|
|
80
|
+
/** Provenance of `inputTokens`: `"reported"` from the provider, `"estimated"` from the
|
|
81
|
+
* `usageEstimation: "fallback"` seam. Absent together with `inputTokens`; `usage.estimated` stays
|
|
82
|
+
* the authoritative label for the turn's usage. */
|
|
83
|
+
readonly inputTokensSource?: "reported" | "estimated";
|
|
84
|
+
/** Resolved per-request input cap (attention compiler when enabled); absent when no cap derivable. */
|
|
85
|
+
readonly inputCap?: number;
|
|
86
|
+
/** Cumulative run input budget (`RunLimits.maxInputTokens`); absent when the axis is disabled. */
|
|
87
|
+
readonly runInputBudget?: number;
|
|
88
|
+
/** Cumulative input tokens charged this run (all provider turns). */
|
|
89
|
+
readonly runInputUsed: number;
|
|
90
|
+
/** Provider turns started this run (1-based current turn at turn end). */
|
|
91
|
+
readonly turns: number;
|
|
92
|
+
/** Resolved clean turn cap; `null` when disabled. */
|
|
93
|
+
readonly maxTurns: number | null;
|
|
94
|
+
}
|
|
65
95
|
export type ProviderResolver = (model: ModelConfig) => AIProvider | undefined;
|
|
66
96
|
/** Realtime audio/session event. Realtime is a bidirectional session, not a request/response
|
|
67
97
|
* stream, so it is a separate neutral seam from `AIProvider.generate()`. Credentials are
|
|
@@ -22,6 +22,12 @@ export interface RunLimits {
|
|
|
22
22
|
readonly amount: number;
|
|
23
23
|
readonly currency: string;
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Clean cap on stop-hook continuations in one run (plan 106 R1). Default 3; `0` observes stop
|
|
27
|
+
* hooks but never continues; `null` disables the cap. Layers narrow by min like every other
|
|
28
|
+
* policy axis, and the cap ends the run with `stopReason: "hook_limit"` (no limit breach).
|
|
29
|
+
*/
|
|
30
|
+
readonly maxStopContinuations?: number | null;
|
|
25
31
|
}
|
|
26
32
|
/** Fully resolved limits after `resolveRunLimits`: every policy axis is a finite cap or `null` (disabled). */
|
|
27
33
|
export interface ResolvedRunLimits {
|
|
@@ -39,8 +45,11 @@ export interface ResolvedRunLimits {
|
|
|
39
45
|
readonly amount: number;
|
|
40
46
|
readonly currency: string;
|
|
41
47
|
};
|
|
48
|
+
/** Stop-hook continuation cap (plan 106 R1); not a run-limit counter axis. */
|
|
49
|
+
readonly maxStopContinuations: number | null;
|
|
42
50
|
}
|
|
43
|
-
|
|
51
|
+
/** Counter-backed limit axes; `maxStopContinuations` caps a clean stop instead of a breach. */
|
|
52
|
+
export type RunLimitName = Exclude<keyof Required<RunLimits>, "maxStopContinuations">;
|
|
44
53
|
export interface RunLimitCounters {
|
|
45
54
|
readonly turns: number;
|
|
46
55
|
readonly providerAttempts: number;
|
|
@@ -60,6 +69,25 @@ export interface RunLimitBreach {
|
|
|
60
69
|
readonly observed: number;
|
|
61
70
|
readonly currency?: string;
|
|
62
71
|
}
|
|
72
|
+
/** One dispatched host tool call, bounded to id + name + argument hash (plan 087 T2). */
|
|
73
|
+
export interface ToolCallSummary {
|
|
74
|
+
readonly id: string;
|
|
75
|
+
readonly name: string;
|
|
76
|
+
/** `sha256:<64 hex>` over the canonicalized arguments; raw arguments never enter events. */
|
|
77
|
+
readonly argHash: string;
|
|
78
|
+
}
|
|
79
|
+
/** One run-limit axis and how close it came to its cap: `used / cap` in [0, 1] (plan 087 T2). */
|
|
80
|
+
export interface BudgetAxisUsage {
|
|
81
|
+
readonly axis: RunLimitName;
|
|
82
|
+
readonly usedRatio: number;
|
|
83
|
+
}
|
|
84
|
+
/** Run counters at exhaustion (plan 087 T2): the axes a host reads first when attributing a death. */
|
|
85
|
+
export interface BudgetConsumedCounters {
|
|
86
|
+
readonly turns: number;
|
|
87
|
+
readonly inputTokens: number;
|
|
88
|
+
readonly providerAttempts: number;
|
|
89
|
+
readonly requestBytes: number;
|
|
90
|
+
}
|
|
63
91
|
export type GuardrailStage = "input" | "output" | "tool_input" | "tool_output";
|
|
64
92
|
export type GuardrailAction = "allow" | "block" | "tripwire" | "interrupt";
|
|
65
93
|
export type GuardrailValue<S extends GuardrailStage> = S extends "input" ? readonly Message[] : S extends "output" ? ProviderTurnResult : S extends "tool_input" ? ToolCallContent : ToolResult;
|
|
@@ -35,8 +35,8 @@ export interface SessionStore {
|
|
|
35
35
|
/**
|
|
36
36
|
* Optional bounded session search. Prefer implementing this **or** returning a companion
|
|
37
37
|
* `SessionIndex` from the adapter factory — hosts must not need both. Call
|
|
38
|
-
* `resolveSessionSearchQuery` before scan/query. Memory
|
|
39
|
-
* search (`sessionSearchMode: "unsupported"` throws)
|
|
38
|
+
* `resolveSessionSearchQuery` before scan/query. Memory and JSONL default to capped linear
|
|
39
|
+
* search (memory `sessionSearchMode: "unsupported"` throws); DB adapters index.
|
|
40
40
|
*/
|
|
41
41
|
searchSessions?(query: SessionSearchQuery): Promise<PersistencePage<SessionSearchHit>>;
|
|
42
42
|
}
|
|
@@ -58,11 +58,18 @@ export declare const DEFAULT_MAX_SESSION_SEARCH_LINEAR_BYTES: number;
|
|
|
58
58
|
export declare const HARD_MAX_SESSION_SEARCH_LINEAR_BYTES: number;
|
|
59
59
|
export declare const DEFAULT_MAX_SESSION_SEARCH_FTS_CANDIDATES = 1000;
|
|
60
60
|
export declare const HARD_MAX_SESSION_SEARCH_FTS_CANDIDATES = 5000;
|
|
61
|
+
/** Entry-kind filter for `SessionSearchQuery.kind`; `"any"` (the default) matches every kind. */
|
|
62
|
+
export type SessionSearchKind = SessionEntryKind | "any";
|
|
61
63
|
/** Bounded session search filters. Workspace matches host-written `metadata.workspaceRoot`. */
|
|
62
64
|
export interface SessionSearchQuery extends PersistenceQuery, OwnershipScope {
|
|
63
65
|
readonly workspaceRoot?: string;
|
|
64
66
|
/** Optional full-text / message+summary query (adapter-defined matching). */
|
|
65
67
|
readonly query?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Restrict the text `query` to entries of these kinds (one kind or a list). Omitted or `"any"`
|
|
70
|
+
* matches every kind. Annotation search is `kind: ["label", "summary", "metadata", "custom"]`.
|
|
71
|
+
*/
|
|
72
|
+
readonly kind?: SessionSearchKind | readonly SessionSearchKind[];
|
|
66
73
|
readonly provider?: string;
|
|
67
74
|
readonly model?: string;
|
|
68
75
|
readonly label?: string;
|
|
@@ -73,11 +80,20 @@ export interface SessionSearchQuery extends PersistenceQuery, OwnershipScope {
|
|
|
73
80
|
}
|
|
74
81
|
/**
|
|
75
82
|
* Safe search hit for resume/checkout. Never includes credentials or raw full transcripts.
|
|
76
|
-
* `leafId` is the branch tip for `session.checkout` when known
|
|
83
|
+
* `leafId` is the branch tip for `session.checkout` when known; when a text `query` matched,
|
|
84
|
+
* `entryId`/`runId`/`turn`/`score` point at the matched entry and `snippet` is its matched text.
|
|
77
85
|
*/
|
|
78
86
|
export interface SessionSearchHit {
|
|
79
87
|
readonly sessionId: string;
|
|
80
88
|
readonly leafId?: string;
|
|
89
|
+
/** Transcript entry that matched the text `query` (absent for filter-only searches). */
|
|
90
|
+
readonly entryId?: string;
|
|
91
|
+
/** Run that wrote the matched entry. */
|
|
92
|
+
readonly runId?: string;
|
|
93
|
+
/** 1-based position of the matched entry in the session transcript (`(timestamp, id)` order). */
|
|
94
|
+
readonly turn?: number;
|
|
95
|
+
/** Matched-entry relevance from the store's full-text index; higher is better (0 is a valid score). */
|
|
96
|
+
readonly score?: number;
|
|
81
97
|
readonly updatedAt?: string;
|
|
82
98
|
readonly label?: string;
|
|
83
99
|
readonly summary?: string;
|
|
@@ -89,10 +105,12 @@ export interface SessionSearchHit {
|
|
|
89
105
|
export interface SessionIndex {
|
|
90
106
|
search(query: SessionSearchQuery): Promise<PersistencePage<SessionSearchHit>>;
|
|
91
107
|
}
|
|
92
|
-
/** Validated search query with finite `limit` / `order` filled in. */
|
|
108
|
+
/** Validated search query with finite `limit` / `order` filled in and `kind` normalized. */
|
|
93
109
|
export interface ResolvedSessionSearchQuery extends SessionSearchQuery {
|
|
94
110
|
readonly limit: number;
|
|
95
111
|
readonly order: "asc" | "desc";
|
|
112
|
+
/** Concrete kinds to match, or `undefined` for "any". */
|
|
113
|
+
readonly kind?: readonly SessionEntryKind[];
|
|
96
114
|
}
|
|
97
115
|
/**
|
|
98
116
|
* O(1) validation before any scan/query. Applies default page limit; rejects NaN,
|
|
@@ -100,7 +118,7 @@ export interface ResolvedSessionSearchQuery extends SessionSearchQuery {
|
|
|
100
118
|
*/
|
|
101
119
|
export declare function resolveSessionSearchQuery(query: SessionSearchQuery): ResolvedSessionSearchQuery;
|
|
102
120
|
export declare const SESSION_SEARCH_UNSUPPORTED_CODE: "session_search_unsupported";
|
|
103
|
-
/** Thrown when a store opts out of `searchSessions` (memory `unsupported
|
|
121
|
+
/** Thrown when a store opts out of `searchSessions` (memory `sessionSearchMode: "unsupported"`). */
|
|
104
122
|
export declare class SessionSearchUnsupportedError extends Error {
|
|
105
123
|
readonly code: "session_search_unsupported";
|
|
106
124
|
constructor(message?: string);
|