@arnilo/prism 0.9.0 → 0.11.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 +50 -1
- package/README.md +19 -16
- package/dist/agent-approval.d.ts +7 -1
- package/dist/agent-approval.js +15 -6
- package/dist/agent-run-lifecycle.d.ts +2 -1
- package/dist/agent-run-lifecycle.js +20 -6
- package/dist/agent-run-state.d.ts +26 -5
- package/dist/agent-run-state.js +97 -1
- package/dist/agent-session/event-subscriber.d.ts +2 -0
- package/dist/agent-session/event-subscriber.js +3 -0
- package/dist/agent-session/session/assemble.js +165 -16
- package/dist/agent-session/session/persist.js +11 -5
- package/dist/agent-session/session/provider-round.js +54 -13
- package/dist/agent-session/session/tool-round.d.ts +2 -2
- package/dist/agent-session/session/tool-round.js +86 -23
- package/dist/agent-session/session/types.d.ts +21 -2
- package/dist/agent-session/session.d.ts +66 -4
- package/dist/agent-session/session.js +159 -18
- package/dist/checkpoint-restore.d.ts +50 -14
- package/dist/checkpoint-restore.js +104 -28
- package/dist/context-budget.d.ts +11 -0
- package/dist/context-budget.js +33 -2
- package/dist/contracts-core/agent.d.ts +26 -5
- package/dist/contracts-core/extensions.d.ts +3 -0
- package/dist/contracts-core/guardrail-packs.d.ts +8 -3
- package/dist/contracts-core/loop.d.ts +36 -0
- package/dist/contracts-core/provider.d.ts +6 -1
- package/dist/contracts-core/run-limits.d.ts +10 -1
- package/dist/contracts-core/session.d.ts +2 -1
- package/dist/contracts-protocol.d.ts +6 -4
- package/dist/contracts-run-state.d.ts +48 -6
- 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/types.d.ts +10 -0
- package/dist/guardrail-packs/validation-respect.js +16 -0
- package/dist/guardrails.d.ts +42 -1
- package/dist/guardrails.js +124 -15
- package/dist/index.d.ts +7 -7
- package/dist/index.js +4 -4
- package/dist/leases.js +32 -6
- package/dist/middleware.d.ts +1 -1
- package/dist/node/contribution-discovery.d.ts +16 -1
- package/dist/node/contribution-discovery.js +47 -0
- package/dist/node/session-store-jsonl.js +67 -17
- package/dist/run-bundle.d.ts +6 -1
- package/dist/run-bundle.js +4 -1
- package/dist/run-limits.d.ts +11 -5
- package/dist/run-limits.js +13 -0
- package/dist/session-stores.js +61 -12
- package/dist/testing/prefix-stability-conformance.d.ts +73 -1
- package/dist/testing/prefix-stability-conformance.js +158 -27
- package/dist/tools.js +10 -3
- package/dist/usage-estimation.d.ts +7 -1
- package/dist/usage-estimation.js +16 -10
- package/docs/acp.md +2 -2
- package/docs/agent-events.md +15 -10
- package/docs/agent-session-runtime.md +10 -7
- package/docs/coding-agent-tools.md +1 -1
- package/docs/coding-tools.md +7 -11
- package/docs/compaction-llm.md +2 -0
- package/docs/compaction-observational-memory.md +21 -1
- package/docs/context-and-skills.md +6 -7
- package/docs/contribution-discovery.md +13 -0
- package/docs/durable-runs.md +14 -6
- package/docs/embeddings.md +7 -1
- package/docs/execution-timeline.md +9 -2
- package/docs/extensions.md +21 -5
- package/docs/guardrails.md +16 -6
- package/docs/hooks.md +282 -0
- package/docs/impeccable.md +1 -2
- package/docs/index.md +28 -21
- package/docs/input-and-prompt-assembly.md +1 -1
- package/docs/instruction-injection.md +1 -0
- package/docs/live-testing.md +3 -2
- package/docs/memory-fabric.md +29 -0
- package/docs/middleware-hooks.md +54 -4
- package/docs/migrate-to-0.11.md +65 -0
- package/docs/migration.md +24 -0
- package/docs/node-jsonl-session-store.md +4 -3
- package/docs/operations.md +1 -1
- package/docs/options-index.md +3 -1
- package/docs/peer-dependencies.md +3 -5
- package/docs/policy-and-audit.md +15 -2
- package/docs/prefix-stability-conformance.md +82 -9
- package/docs/provider-packages.md +20 -20
- package/docs/public-contracts.md +2 -1
- package/docs/rag.md +94 -7
- package/docs/release-and-install.md +62 -59
- package/docs/runs-and-usage.md +21 -10
- package/docs/scoped-agent-memory.md +17 -9
- package/docs/scoped-memory.md +138 -0
- package/docs/session-stores.md +2 -2
- package/docs/supervisors.md +14 -6
- package/docs/testing.md +17 -9
- package/docs/tools.md +1 -1
- package/docs/wiki.md +4 -2
- package/docs/workflows.md +2 -2
- package/package.json +8 -5
- package/docs/caveman.md +0 -130
- package/docs/graft.md +0 -149
- package/docs/ponytail.md +0 -129
|
@@ -1,53 +1,129 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Checkpoint restore hooks (plan 094 Task 3). A hook restores
|
|
3
|
-
* document version, workspace fingerprint) recorded in a
|
|
2
|
+
* Checkpoint restore hooks (plan 094 Task 3; reverse compensation plan 109 Task 2). A hook restores
|
|
3
|
+
* one external layer (git commit, document version, workspace fingerprint) recorded in a
|
|
4
|
+
* checkpoint's sidecar metadata.
|
|
4
5
|
*
|
|
5
|
-
* All-or-nothing: hooks run before the resume claims the checkpoint. The first hook that fails
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* All-or-nothing: hooks run before the resume claims the checkpoint. The first hook that fails or
|
|
7
|
+
* times out aborts the resume with `CheckpointRestoreError` naming that hook, so the conversation
|
|
8
|
+
* restore never applies on top of a half-restored external world. A handler may also declare a
|
|
9
|
+
* `compensate` direction: on failure the applied layers — including the failing one, which may be
|
|
10
|
+
* half-applied — are undone in reverse order and the error carries a best-effort
|
|
11
|
+
* `CheckpointRestoreCompensation` report. Compensation never runs after the caller aborted, never
|
|
12
|
+
* masks the original failure, and the checkpoint stays resumable either way.
|
|
9
13
|
*/
|
|
10
14
|
/** Per-hook ceiling for a restore (plan 094 Task 3 default). */
|
|
11
15
|
export const DEFAULT_CHECKPOINT_RESTORE_TIMEOUT_MS = 10_000;
|
|
12
16
|
/** Thrown when a restore hook fails or times out; the checkpoint and conversation are untouched. */
|
|
13
17
|
export class CheckpointRestoreError extends Error {
|
|
14
18
|
code = "ERR_PRISM_CHECKPOINT_RESTORE";
|
|
15
|
-
/** Name of the failing hook (`
|
|
19
|
+
/** Name of the failing hook (`id`, `hook.name`, or `hook[i]`). */
|
|
16
20
|
hook;
|
|
17
|
-
constructor(hook, cause) {
|
|
21
|
+
constructor(hook, cause, compensation) {
|
|
18
22
|
super(`Checkpoint restore hook ${hook} failed: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
19
23
|
this.name = "CheckpointRestoreError";
|
|
20
24
|
this.hook = hook;
|
|
25
|
+
if (compensation)
|
|
26
|
+
this.compensation = compensation;
|
|
21
27
|
}
|
|
22
28
|
}
|
|
29
|
+
/** Compensation reasons are operator hints, not log lines: capped at this many UTF-8 bytes. */
|
|
30
|
+
const MAX_COMPENSATION_REASON_BYTES = 1_024;
|
|
31
|
+
/** One handler identity per restore, resolved once at the executor boundary (plan 109 Task 2). */
|
|
32
|
+
function normalizeRestoreHandler(handler, index) {
|
|
33
|
+
if (typeof handler === "function")
|
|
34
|
+
return { id: handler.name || `hook[${index}]`, restore: handler };
|
|
35
|
+
return {
|
|
36
|
+
id: handler.id ?? handler.restore.name ?? `hook[${index}]`,
|
|
37
|
+
restore: handler.restore,
|
|
38
|
+
...(handler.compensate ? { compensate: handler.compensate } : {}),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Run one direction of one handler under the per-hook timeout, reporting failure instead of throwing. */
|
|
42
|
+
async function invokeRestoreHandler(handler, context, timeoutMs, callerSignal) {
|
|
43
|
+
const controller = new AbortController();
|
|
44
|
+
const timer = setTimeout(() => controller.abort(new Error(`timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
45
|
+
const signal = callerSignal ? AbortSignal.any([callerSignal, controller.signal]) : controller.signal;
|
|
46
|
+
const started = Date.now();
|
|
47
|
+
try {
|
|
48
|
+
await handler(context, signal);
|
|
49
|
+
return { ok: true, durationMs: Date.now() - started };
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
// Our own abort means the hook either ignored the signal or lost the race; name the timeout.
|
|
53
|
+
const timedOut = controller.signal.aborted && !callerSignal?.aborted;
|
|
54
|
+
return { ok: false, cause: timedOut ? controller.signal.reason : error };
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
clearTimeout(timer);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** UTF-8-safe truncation; no suffix, so the cap is exact. */
|
|
61
|
+
function truncateUtf8Bytes(text, maxBytes) {
|
|
62
|
+
if (Buffer.byteLength(text, "utf8") <= maxBytes)
|
|
63
|
+
return text;
|
|
64
|
+
let bytes = 0;
|
|
65
|
+
let end = 0;
|
|
66
|
+
for (const char of text) {
|
|
67
|
+
const size = Buffer.byteLength(char, "utf8");
|
|
68
|
+
if (bytes + size > maxBytes)
|
|
69
|
+
break;
|
|
70
|
+
bytes += size;
|
|
71
|
+
end += char.length;
|
|
72
|
+
}
|
|
73
|
+
return text.slice(0, end);
|
|
74
|
+
}
|
|
75
|
+
/** Redacted, byte-bounded operator hint; hook arguments are never copied into it. */
|
|
76
|
+
function compensationReason(error, redactor) {
|
|
77
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
78
|
+
return truncateUtf8Bytes(redactor ? redactor.redact(message) : message, MAX_COMPENSATION_REASON_BYTES);
|
|
79
|
+
}
|
|
23
80
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
81
|
+
* Reverse pass over the applied layers (`failedIndex`…0, failing hook first). Best-effort: a
|
|
82
|
+
* failing compensation is recorded once and the pass continues; a caller abort stops the pass and
|
|
83
|
+
* rethrows the abort reason unchanged, so a cancel still reads as cancelled.
|
|
84
|
+
*/
|
|
85
|
+
async function compensateRestoreHandlers(handlers, failedIndex, context, timeoutMs, options) {
|
|
86
|
+
const ran = [];
|
|
87
|
+
let failed;
|
|
88
|
+
for (let index = failedIndex; index >= 0; index -= 1) {
|
|
89
|
+
const handler = handlers[index];
|
|
90
|
+
if (!handler?.compensate)
|
|
91
|
+
continue;
|
|
92
|
+
options.signal?.throwIfAborted();
|
|
93
|
+
const outcome = await invokeRestoreHandler(handler.compensate, context, timeoutMs, options.signal);
|
|
94
|
+
options.signal?.throwIfAborted();
|
|
95
|
+
ran.push(handler.id);
|
|
96
|
+
if (!outcome.ok && failed === undefined)
|
|
97
|
+
failed = { hook: handler.id, reason: compensationReason(outcome.cause, options.redactor) };
|
|
98
|
+
}
|
|
99
|
+
if (ran.length === 0)
|
|
100
|
+
return undefined;
|
|
101
|
+
return { ran, ...(failed ? { failed } : {}) };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Run restore handlers sequentially and report the audit. A handler failure throws
|
|
105
|
+
* `CheckpointRestoreError` immediately (later handlers do not run) after a best-effort reverse
|
|
106
|
+
* compensation pass over the applied layers; with no `compensate` declared anywhere, the failure
|
|
107
|
+
* shape is exactly plan 094's. An already-aborted caller signal throws its own abort reason so the
|
|
108
|
+
* resume reads as cancelled rather than as a restore failure, and a caller abort during the pass
|
|
109
|
+
* stops it before the next handler runs.
|
|
27
110
|
*/
|
|
28
111
|
export async function runCheckpointRestoreHooks(hooks, context, options = {}) {
|
|
29
112
|
const timeoutMs = options.timeoutMs ?? DEFAULT_CHECKPOINT_RESTORE_TIMEOUT_MS;
|
|
30
113
|
const started = Date.now();
|
|
31
114
|
const entries = [];
|
|
32
|
-
|
|
115
|
+
const handlers = hooks.map((handler, index) => normalizeRestoreHandler(handler, index));
|
|
116
|
+
for (const [index, handler] of handlers.entries()) {
|
|
33
117
|
options.signal?.throwIfAborted();
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
// Our own abort means the hook either ignored the signal or lost the race; name the timeout.
|
|
44
|
-
const timedOut = controller.signal.aborted && !options.signal?.aborted;
|
|
45
|
-
throw new CheckpointRestoreError(name, timedOut ? controller.signal.reason : error);
|
|
46
|
-
}
|
|
47
|
-
finally {
|
|
48
|
-
clearTimeout(timer);
|
|
118
|
+
const outcome = await invokeRestoreHandler(handler.restore, context, timeoutMs, options.signal);
|
|
119
|
+
if (!outcome.ok) {
|
|
120
|
+
// Security: never run host compensation code once the caller has aborted.
|
|
121
|
+
const compensation = options.signal?.aborted
|
|
122
|
+
? undefined
|
|
123
|
+
: await compensateRestoreHandlers(handlers, index, context, timeoutMs, options);
|
|
124
|
+
throw new CheckpointRestoreError(handler.id, outcome.cause, compensation);
|
|
49
125
|
}
|
|
50
|
-
entries.push({ hook:
|
|
126
|
+
entries.push({ hook: handler.id, durationMs: outcome.durationMs });
|
|
51
127
|
}
|
|
52
128
|
return { hooks: entries, durationMs: Date.now() - started };
|
|
53
129
|
}
|
package/dist/context-budget.d.ts
CHANGED
|
@@ -96,3 +96,14 @@ export declare function measureInputCost(options: MeasureInputCostOptions): {
|
|
|
96
96
|
tokens: number;
|
|
97
97
|
bytes: number;
|
|
98
98
|
};
|
|
99
|
+
/** Plan 103 T6: the host's `contextBudget.tokenEstimator`, validated exactly like the budget pass
|
|
100
|
+
* validates it (a non-function, or a non-finite/negative count, fails closed with `TypeError`).
|
|
101
|
+
* `undefined` when no host estimator is configured, so callers can fall through to the built-in
|
|
102
|
+
* heuristic. Exported for the usage seam (`provider-round.ts`) — deliberately not re-exported by
|
|
103
|
+
* `src/index.ts`, so the public surface is unchanged. */
|
|
104
|
+
export declare function resolveHostTokenEstimator(budget: ContextBudget | undefined): TokenEstimator | undefined;
|
|
105
|
+
/** Plan 103 T6: tool declarations and context blocks projected with the assembler's own
|
|
106
|
+
* `measureAll` text shapes, so the usage-fallback estimate and the budget pass cannot drift
|
|
107
|
+
* (never `JSON.stringify` of the raw schemas). Exported for the usage seam — deliberately not
|
|
108
|
+
* re-exported by `src/index.ts`. */
|
|
109
|
+
export declare function estimateRequestExtrasTokens(tools: readonly ToolDefinition[] | undefined, context: readonly ContextBlock[] | undefined, estimateTokens: TokenEstimator): number;
|
package/dist/context-budget.js
CHANGED
|
@@ -246,7 +246,7 @@ function measureAll(groups, context, skills, tools, skillContext, demotedBodies,
|
|
|
246
246
|
for (const message of groups.toolResults)
|
|
247
247
|
addMessage(message);
|
|
248
248
|
for (const block of context) {
|
|
249
|
-
const text =
|
|
249
|
+
const text = contextBlockMeasureText(block);
|
|
250
250
|
tokens += estimateTokens(text);
|
|
251
251
|
bytes += estimateTextBytes(text);
|
|
252
252
|
}
|
|
@@ -256,12 +256,35 @@ function measureAll(groups, context, skills, tools, skillContext, demotedBodies,
|
|
|
256
256
|
bytes += estimateTextBytes(text);
|
|
257
257
|
}
|
|
258
258
|
if (tools?.length) {
|
|
259
|
-
const text =
|
|
259
|
+
const text = toolsMeasureText(tools);
|
|
260
260
|
tokens += estimateTokens(text);
|
|
261
261
|
bytes += estimateTextBytes(text);
|
|
262
262
|
}
|
|
263
263
|
return { tokens, bytes };
|
|
264
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
|
+
}
|
|
265
288
|
function overBudget(cost, budget) {
|
|
266
289
|
if (budget.maxInputTokens !== undefined && cost.tokens > budget.maxInputTokens)
|
|
267
290
|
return true;
|
|
@@ -342,4 +365,12 @@ function contextBlockText(block) {
|
|
|
342
365
|
})
|
|
343
366
|
.join("\n");
|
|
344
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
|
+
}
|
|
345
376
|
//# sourceMappingURL=context-budget.js.map
|
|
@@ -11,7 +11,7 @@ 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
13
|
import type { GuardrailPackRef } from "./guardrail-packs.js";
|
|
14
|
-
import type { AgentLoopOptions, AgentLoopStrategy } from "./loop.js";
|
|
14
|
+
import type { AgentLoopOptions, AgentLoopStrategy, StopHook } from "./loop.js";
|
|
15
15
|
import type { OwnershipScope } from "./persistence.js";
|
|
16
16
|
import type { AIProvider, ProviderRequestOptions, ProviderResolver } from "./provider.js";
|
|
17
17
|
import type { ResourceLoader } from "./resources.js";
|
|
@@ -86,11 +86,24 @@ export interface AgentConfig {
|
|
|
86
86
|
* Omitted keeps today's request bytes; per-run options may only relax this setting. */
|
|
87
87
|
readonly attentionCompiler?: import("./attention.js").AttentionCompilerSetting;
|
|
88
88
|
/**
|
|
89
|
-
* Missing-usage
|
|
90
|
-
* estimate when a provider turn reports no usage; `"off"` leaves usage absent —
|
|
91
|
-
*
|
|
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.
|
|
92
95
|
*/
|
|
93
|
-
readonly usageEstimation?: "fallback" | "off";
|
|
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;
|
|
94
107
|
readonly inputBuilder?: InputBuilder;
|
|
95
108
|
readonly promptBuilder?: PromptBuilder;
|
|
96
109
|
readonly middleware?: MiddlewareRegistry;
|
|
@@ -124,6 +137,8 @@ export interface AgentConfig {
|
|
|
124
137
|
readonly inputLayout?: InputAssemblyLayout;
|
|
125
138
|
readonly loop?: AgentLoopStrategy | AgentLoopOptions;
|
|
126
139
|
readonly guardrails?: Guardrails;
|
|
140
|
+
/** Run-end stop hooks (plan 106 R1); `RunOptions.stopHooks` appends to this list. */
|
|
141
|
+
readonly stopHooks?: readonly StopHook[];
|
|
127
142
|
/** Opt-in durable interruption/checkpointing default for this agent. */
|
|
128
143
|
readonly runState?: AgentRunStateOptions;
|
|
129
144
|
/** Internal marker set by createSecureAgent(); makes security defaults immutable per run. */
|
|
@@ -183,6 +198,12 @@ export interface AgentSessionCloneOptions {
|
|
|
183
198
|
}
|
|
184
199
|
export type SubscriberOverflowPolicy = "close" | "drop_oldest" | "drop_newest";
|
|
185
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;
|
|
186
207
|
/** Maximum queued events for a subscriber that is not actively awaiting `next()`. Defaults to 1024. */
|
|
187
208
|
readonly maxQueuedEvents?: number;
|
|
188
209
|
/** What to do when `maxQueuedEvents` is reached. Defaults to `close`. */
|
|
@@ -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
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Guardrail packs (plan 092 Task 2): config-declared, restrictive-only rule sets compiled once per
|
|
3
3
|
* session onto the existing tool interception seams (`tool_input` / `tool_output`). Packs can only
|
|
4
|
-
* deny or
|
|
4
|
+
* deny, tripwire, or ask for approval — they never grant permissions, widen arguments, or add a stage.
|
|
5
5
|
*/
|
|
6
6
|
import type { JsonObject } from "./content.js";
|
|
7
|
-
export type GuardrailRuleAction = "deny" | "tripwire";
|
|
7
|
+
export type GuardrailRuleAction = "deny" | "tripwire" | "ask";
|
|
8
8
|
/** Read-only identity view handed to a pack rule predicate (never carries a raw argument echo). */
|
|
9
9
|
export interface GuardrailRuleContext {
|
|
10
10
|
readonly toolName: string;
|
|
@@ -25,7 +25,12 @@ export interface GuardrailRule {
|
|
|
25
25
|
readonly argPath?: string | readonly string[];
|
|
26
26
|
/** Typed predicate escape hatch (host-trusted like all host code); deny when it returns true. Exactly one of `pattern` / `deny`. */
|
|
27
27
|
readonly deny?: (args: JsonObject, context: GuardrailRuleContext) => boolean;
|
|
28
|
-
/**
|
|
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
|
+
*/
|
|
29
34
|
readonly action?: GuardrailRuleAction;
|
|
30
35
|
/** Bounded, redacted record reason; defaults to the pack/rule id. */
|
|
31
36
|
readonly reason?: string;
|
|
@@ -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
|
|
@@ -74,8 +74,13 @@ export type ProviderStopReason = "end_turn" | "tool_calls" | "max_output_tokens"
|
|
|
74
74
|
* axis, so a host can see which limit was closest without instrumenting the session.
|
|
75
75
|
*/
|
|
76
76
|
export interface TurnBudgets {
|
|
77
|
-
/**
|
|
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`. */
|
|
78
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";
|
|
79
84
|
/** Resolved per-request input cap (attention compiler when enabled); absent when no cap derivable. */
|
|
80
85
|
readonly inputCap?: number;
|
|
81
86
|
/** Cumulative run input budget (`RunLimits.maxInputTokens`); absent when the axis is disabled. */
|
|
@@ -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;
|
|
@@ -30,7 +30,8 @@ export interface SessionStore {
|
|
|
30
30
|
get?(id: string): Promise<SessionEntry | undefined>;
|
|
31
31
|
/** DB-friendly branch read: return one branch's ancestor chain as a page so adapters
|
|
32
32
|
* avoid `list(sessionId)` (full-session scan) + in-memory rebuild. Optional — the
|
|
33
|
-
* built-in
|
|
33
|
+
* built-in JSONL store omits it and the runtime falls back to `list()`. The memory
|
|
34
|
+
* store implements it. */
|
|
34
35
|
readBranchPath?(query: SessionBranchRead): Promise<PersistencePage<SessionEntry>>;
|
|
35
36
|
/**
|
|
36
37
|
* Optional bounded session search. Prefer implementing this **or** returning a companion
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { AgentLoopOptions, AgentLoopStrategy, ArtifactValidation, BudgetAxisUsage, BudgetConsumedCounters, CompactionOptions, ContentBlock, ErrorInfo, GuardrailRecord, Guardrails, InstructionInjector, JsonObject, Message, ModelConfig, OwnershipScope, ProviderRequestOptions, ProviderRequestPolicy, ProviderResolver, ProviderStopReason, RetryOptions, RunLimitBreach, RunLimitName, RunLimits, Skill, SubscriberOverflowPolicy, SystemPromptConfig, ToolCallAuthority, ToolCallContent, ToolCallSummary, TurnBudgets, TurnPolicyOptions, Usage } from "./contracts-core.js";
|
|
2
1
|
import type { CacheUsageReport } from "./cache-helpers.js";
|
|
3
2
|
import type { CheckpointRestoreAudit } from "./checkpoint-restore.js";
|
|
3
|
+
import type { AgentLoopOptions, AgentLoopStrategy, ArtifactValidation, BudgetAxisUsage, BudgetConsumedCounters, CompactionOptions, ContentBlock, ErrorInfo, GuardrailRecord, Guardrails, InstructionInjector, JsonObject, Message, ModelConfig, OwnershipScope, ProviderRequestOptions, ProviderRequestPolicy, ProviderResolver, ProviderStopReason, RetryOptions, RunLimitBreach, RunLimitName, RunLimits, Skill, StopHook, SubscriberOverflowPolicy, SystemPromptConfig, ToolCallAuthority, ToolCallContent, ToolCallSummary, TurnBudgets, TurnPolicyOptions, Usage } from "./contracts-core.js";
|
|
4
4
|
import type { AgentRunInterruption, AgentRunStateOptions } from "./contracts-run-state.js";
|
|
5
5
|
import type { SecretRedactor } from "./redaction.js";
|
|
6
6
|
import type { ToolValidator } from "./tools.js";
|
|
@@ -137,6 +137,8 @@ export interface RunOptions {
|
|
|
137
137
|
* evaluated before every provider request. Omitted → no callback runs.
|
|
138
138
|
*/
|
|
139
139
|
readonly turnPolicy?: TurnPolicyOptions;
|
|
140
|
+
/** Appended to agent-level stop hooks for this run (plan 106 R1). */
|
|
141
|
+
readonly stopHooks?: readonly StopHook[];
|
|
140
142
|
}
|
|
141
143
|
export interface ProviderTurnMetadata {
|
|
142
144
|
readonly providerId: string;
|
|
@@ -193,8 +195,8 @@ export interface DelegatedAgentStep {
|
|
|
193
195
|
readonly label?: string;
|
|
194
196
|
};
|
|
195
197
|
}
|
|
196
|
-
/** Why a run stopped cleanly. `host_policy` is a `RunOptions.turnPolicy` stop; the rest are loop ceilings (F4). */
|
|
197
|
-
export type AgentFinishReason = "turn_limit" | "token_limit" | "refusal" | "host_policy";
|
|
198
|
+
/** Why a run stopped cleanly. `host_policy` is a `RunOptions.turnPolicy` stop, `hook_limit` a stop-hook continuation cap; the rest are loop ceilings (F4). */
|
|
199
|
+
export type AgentFinishReason = "turn_limit" | "token_limit" | "refusal" | "host_policy" | "hook_limit";
|
|
198
200
|
/**
|
|
199
201
|
* Origin of an agent event forwarded from a delegated child (supervisor child-event passthrough).
|
|
200
202
|
* Present only on child events routed onto a parent stream; absent on a session's own events.
|
|
@@ -215,7 +217,7 @@ type AgentEventPayload = {
|
|
|
215
217
|
readonly sessionId: string;
|
|
216
218
|
readonly runId: string;
|
|
217
219
|
readonly usage?: Usage;
|
|
218
|
-
/** Why the loop stopped, when a limit/ceiling
|
|
220
|
+
/** Why the loop stopped, when a limit/ceiling, a host turn policy, or a stop-hook continuation cap ended the run cleanly (F4). Absent = natural end. */
|
|
219
221
|
readonly finishReason?: AgentFinishReason;
|
|
220
222
|
/** Host stop detail from `TurnPolicyOptions.stop` (≤256 bytes, redacted). Present only with `finishReason: "host_policy"`. */
|
|
221
223
|
readonly stopDetail?: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CheckpointRestoreHandler } from "./checkpoint-restore.js";
|
|
2
|
+
import type { AgentSessionCloneOptions, AgentSessionForkOptions, CheckpointRecord, CheckpointStore, CompactionOptions, CompactionResult, ContentBlock, ContextMeter, ErrorInfo, GuardrailPackRef, JsonObject, JsonValue, Message, ModelConfig, OwnershipScope, RunLimitBreach, SessionEntry, SubscribeOptions, ToolCallContent, Usage } from "./contracts-core.js";
|
|
2
3
|
import type { AgentEvent, AgentFinishReason, RunOptions, ToolEffectKind } from "./contracts-protocol.js";
|
|
3
|
-
import type {
|
|
4
|
+
import type { BudgetExhaustionAttribution } from "./run-limits.js";
|
|
4
5
|
export type AgentRunStatus = "succeeded" | "failed" | "aborted" | "suspended" | "denied";
|
|
5
6
|
export type AgentRunInterruptionKind = "input_guardrail" | "tool_approval" | "elicitation";
|
|
6
7
|
export type ApprovalOutcome = "allow_once" | "allow_for_run" | "reject_once" | "reject_for_run";
|
|
@@ -27,6 +28,16 @@ export interface PendingDecision {
|
|
|
27
28
|
readonly reason: string;
|
|
28
29
|
/** Typed payload contract for elicitation decisions. */
|
|
29
30
|
readonly elicitationSchema?: JsonObject;
|
|
31
|
+
/**
|
|
32
|
+
* Plan 104 T3: pack `ask` rule that gated this call as `pack:<pack>/<rule>` (bounded by the
|
|
33
|
+
* compile-time id limits), present only when a pack rule raised the decision.
|
|
34
|
+
*/
|
|
35
|
+
readonly guardrail?: string;
|
|
36
|
+
/** Plan 104 T3: machine-readable ids behind `guardrail`, so a host never parses the name. */
|
|
37
|
+
readonly guardrailRule?: {
|
|
38
|
+
readonly pack: string;
|
|
39
|
+
readonly rule: string;
|
|
40
|
+
};
|
|
30
41
|
/** Delegation chain, root-first; core-written, never client-supplied. */
|
|
31
42
|
readonly attribution?: {
|
|
32
43
|
readonly path: readonly string[];
|
|
@@ -38,6 +49,8 @@ export interface AgentRunInterruption {
|
|
|
38
49
|
readonly reason: string;
|
|
39
50
|
readonly toolCallId?: string;
|
|
40
51
|
readonly toolName?: string;
|
|
52
|
+
/** Plan 104 T3: the pack rule that raised this suspension (`pack:<pack>/<rule>`), when one did. */
|
|
53
|
+
readonly guardrail?: string;
|
|
41
54
|
/** All unresolved approval requests of this suspension; absent for legacy single approvals. */
|
|
42
55
|
readonly pendingDecisions?: readonly PendingDecision[];
|
|
43
56
|
}
|
|
@@ -235,8 +248,8 @@ export interface AgentCheckpointRestoreContext {
|
|
|
235
248
|
readonly metadata?: AgentRunCheckpointMetadata;
|
|
236
249
|
readonly checkpoint: CheckpointRecord;
|
|
237
250
|
}
|
|
238
|
-
/** Host code restoring one external layer before a durable resume applies. */
|
|
239
|
-
export type AgentCheckpointRestoreHook =
|
|
251
|
+
/** Host code restoring or compensating one external layer before a durable resume applies. */
|
|
252
|
+
export type AgentCheckpointRestoreHook = CheckpointRestoreHandler<AgentCheckpointRestoreContext>;
|
|
240
253
|
export interface AgentRunResumeOptions {
|
|
241
254
|
readonly checkpoints: CheckpointStore;
|
|
242
255
|
/** Current host-authored revision; must exactly match the checkpoint. */
|
|
@@ -266,7 +279,9 @@ export interface AgentRunResumeOptions {
|
|
|
266
279
|
* Plan 094 Task 3: external-state restore hooks. Every hook must succeed (sequentially, each
|
|
267
280
|
* within `restoreHookTimeoutMs`) before the claim write and the conversation restore apply;
|
|
268
281
|
* the first failure throws `CheckpointRestoreError` naming the hook and leaves the checkpoint
|
|
269
|
-
* suspended.
|
|
282
|
+
* suspended. Plan 109 Task 2: an entry may be `{ id?, restore, compensate? }`, and on failure the
|
|
283
|
+
* applied layers are compensated in reverse order (best-effort) before the throw. Hosts that
|
|
284
|
+
* register hooks on the lifecycle instead pass them once there.
|
|
270
285
|
*/
|
|
271
286
|
readonly restoreHooks?: readonly AgentCheckpointRestoreHook[];
|
|
272
287
|
/** Per-hook restore ceiling in ms; defaults to `DEFAULT_CHECKPOINT_RESTORE_TIMEOUT_MS`. */
|
|
@@ -313,6 +328,11 @@ export interface AgentRunResult {
|
|
|
313
328
|
readonly usage?: Usage;
|
|
314
329
|
/** Present when the run hit a configured resource ceiling. */
|
|
315
330
|
readonly limit?: RunLimitBreach;
|
|
331
|
+
/**
|
|
332
|
+
* Present with `limit` when the run died on a ceiling: the same plan-087 attribution payload the
|
|
333
|
+
* `budget_exhausted` event carries (`limit` stays on {@link AgentRunResult.limit}).
|
|
334
|
+
*/
|
|
335
|
+
readonly attribution?: BudgetExhaustionAttribution;
|
|
316
336
|
/** Present when `status` is `"failed"` or when a failed attempt still produced partial output. */
|
|
317
337
|
readonly error?: ErrorInfo;
|
|
318
338
|
/** String form of the abort reason when `status` is `"aborted"`. */
|
|
@@ -350,6 +370,12 @@ export interface SteerOptions {
|
|
|
350
370
|
}
|
|
351
371
|
export interface AgentSession {
|
|
352
372
|
readonly id: string;
|
|
373
|
+
/**
|
|
374
|
+
* Plan 104 Task 2: guardrail pack refs this session enforces (the restored rows after a durable
|
|
375
|
+
* resume); `undefined` when it enforces none. Pass to `snapshotRunBundle({ packs })` for the
|
|
376
|
+
* recorded identity that matches enforcement.
|
|
377
|
+
*/
|
|
378
|
+
readonly guardrailPackRefs?: readonly GuardrailPackRef[];
|
|
353
379
|
/** Current branch leaf entry id; advances on every append/run and is re-pointed by `checkout`.
|
|
354
380
|
* Undefined until the first entry lands (a fresh session with no history). */
|
|
355
381
|
readonly leafId: string | undefined;
|
|
@@ -361,10 +387,26 @@ export interface AgentSession {
|
|
|
361
387
|
* Fails closed when no run is active or the pending queue exceeds caps.
|
|
362
388
|
*/
|
|
363
389
|
steer(input: string | Message | readonly Message[], options?: SteerOptions): void;
|
|
364
|
-
/**
|
|
390
|
+
/**
|
|
391
|
+
* Subscribe first, then start exactly one run and yield only that run's events until it terminates.
|
|
392
|
+
* This subscription belongs to `stream()`: it is closed when the owned run settles (so a pre-flight
|
|
393
|
+
* rejection unblocks the consumer instead of parking it behind a run that never emits).
|
|
394
|
+
*/
|
|
365
395
|
stream(input: string | Message | readonly Message[], options?: RunOptions & SubscribeOptions): AsyncIterable<AgentEvent>;
|
|
366
396
|
compact(options?: CompactionOptions): Promise<CompactionResult>;
|
|
397
|
+
/**
|
|
398
|
+
* Subscribe to this session's live events. A run-scoped subscriber (default) is closed when the run
|
|
399
|
+
* ends, suspends, or is denied; `SubscribeOptions.acrossRuns: true` keeps it open across runs until
|
|
400
|
+
* `subscription.close()`, `closeSubscribers()`, or a queue overflow closes it.
|
|
401
|
+
*/
|
|
367
402
|
subscribe(options?: SubscribeOptions): AsyncIterable<AgentEvent>;
|
|
403
|
+
/**
|
|
404
|
+
* Plan 106 R2: session teardown. Dispatches `session_shutdown` middleware once (idempotent), then
|
|
405
|
+
* closes every subscriber (`acrossRuns` included); calling it twice is a no-op. Call after the
|
|
406
|
+
* active run settles. Subscriber-only teardown stays `break`ing the `for await` (or calling the
|
|
407
|
+
* iterator's `return()`). See [Agent/session runtime](agent-session-runtime.md).
|
|
408
|
+
*/
|
|
409
|
+
close(): Promise<void>;
|
|
368
410
|
abort(reason?: unknown): void;
|
|
369
411
|
entries(): Promise<readonly SessionEntry[]>;
|
|
370
412
|
checkout(leafId?: string): Promise<void>;
|
package/dist/contributions.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentDefinition, AuthMethod, CommandDefinition, CompactionStrategy, ContextProvider, CredentialResolver, DiscoveredContribution, InputBuilder, InstructionInjector, PromptBuilder, ProviderPackage, ProviderRequestPolicy, ResourceLoader, RetryPolicy, SettingsProvider, Skill, StoreFactory, SystemPromptContribution, ToolDefinition } from "./contracts.js";
|
|
1
|
+
import type { AgentDefinition, AuthMethod, CommandDefinition, CompactionStrategy, ContextProvider, CredentialResolver, DiscoveredContribution, InputBuilder, InstructionInjector, PromptBuilder, ProviderPackage, ProviderRequestPolicy, ResourceLoader, RetryPolicy, SettingsProvider, Skill, StopHook, StoreFactory, SystemPromptContribution, ToolDefinition } from "./contracts.js";
|
|
2
2
|
import { type ModelRegistry } from "./models.js";
|
|
3
3
|
import { type ProviderRegistry } from "./providers.js";
|
|
4
4
|
import { type DuplicateRegistrationOptions } from "./registry-options.js";
|
|
@@ -35,6 +35,7 @@ export interface ContributionRegistries {
|
|
|
35
35
|
readonly providerRequestPolicies: ContributionRegistry<ProviderRequestPolicy>;
|
|
36
36
|
readonly systemPromptContributions: ContributionRegistry<SystemPromptContribution>;
|
|
37
37
|
readonly instructionInjectors: ContributionRegistry<InstructionInjector>;
|
|
38
|
+
readonly stopHooks: ContributionRegistry<StopHook>;
|
|
38
39
|
}
|
|
39
40
|
export interface ContributionRegistriesOptions extends DuplicateRegistrationOptions {
|
|
40
41
|
}
|
package/dist/contributions.js
CHANGED
|
@@ -49,6 +49,7 @@ export function createContributionRegistries(options = {}) {
|
|
|
49
49
|
providerRequestPolicies: createContributionRegistry(registryOptions("provider request policy")),
|
|
50
50
|
systemPromptContributions: createContributionRegistry(registryOptions("system prompt contribution")),
|
|
51
51
|
instructionInjectors: createContributionRegistry(registryOptions("instruction injector")),
|
|
52
|
+
stopHooks: createContributionRegistry(registryOptions("stop hook")),
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
55
|
/** Register discovered contributions into the given registries. Inert: skill
|