@arnilo/prism 0.8.0 → 0.9.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 +38 -0
- package/README.md +11 -11
- package/dist/agent-approval.d.ts +11 -2
- 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 +63 -6
- package/dist/agent-run-state.d.ts +22 -2
- package/dist/agent-run-state.js +57 -5
- package/dist/agent-session/helpers.js +14 -0
- package/dist/agent-session/session/assemble.js +126 -24
- package/dist/agent-session/session/persist.d.ts +11 -0
- package/dist/agent-session/session/persist.js +37 -11
- package/dist/agent-session/session/provider-round.d.ts +14 -4
- package/dist/agent-session/session/provider-round.js +185 -19
- package/dist/agent-session/session/tool-round.js +20 -1
- package/dist/agent-session/session/types.d.ts +25 -2
- package/dist/agent-session/session.d.ts +38 -4
- package/dist/agent-session/session.js +76 -5
- 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 +2 -1
- package/dist/context-budget.js +24 -2
- package/dist/contracts-core/agent.d.ts +30 -0
- package/dist/contracts-core/attention.d.ts +95 -0
- package/dist/contracts-core/content.d.ts +10 -0
- package/dist/contracts-core/guardrail-packs.d.ts +41 -0
- package/dist/contracts-core/guardrail-packs.js +2 -0
- package/dist/contracts-core/provider.d.ts +25 -0
- package/dist/contracts-core/run-limits.d.ts +19 -0
- 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 +76 -2
- package/dist/contracts-run-state.d.ts +56 -1
- 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 +16 -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 +53 -0
- package/dist/guardrails.d.ts +20 -1
- package/dist/guardrails.js +268 -0
- package/dist/index.d.ts +14 -9
- package/dist/index.js +9 -6
- 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.js +2 -1
- package/dist/run-limits.d.ts +11 -1
- package/dist/run-limits.js +46 -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 +30 -0
- package/dist/testing/prefix-stability-conformance.js +104 -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 +11 -3
- package/dist/usage-estimation.d.ts +29 -0
- package/dist/usage-estimation.js +79 -0
- package/docs/agent-events.md +68 -1
- package/docs/agent-session-runtime.md +1 -0
- package/docs/attention-compiler.md +89 -8
- package/docs/coding-agent-tools.md +1 -1
- package/docs/compaction-and-retry.md +1 -1
- package/docs/compaction-observational-memory.md +33 -6
- package/docs/durable-runs.md +42 -0
- package/docs/embeddings.md +5 -0
- package/docs/evaluations.md +5 -0
- package/docs/execution-timeline.md +78 -1
- package/docs/guardrails.md +38 -2
- package/docs/index.md +32 -13
- package/docs/input-and-prompt-assembly.md +3 -3
- package/docs/knowledge-sync.md +4 -0
- package/docs/middleware-hooks.md +38 -2
- package/docs/migrate-to-0.9.md +210 -0
- package/docs/migration.md +13 -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 +2 -1
- package/docs/policy-and-audit.md +13 -1
- package/docs/prefix-stability-conformance.md +93 -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 +2 -2
- package/docs/rag.md +101 -3
- package/docs/release-and-install.md +39 -37
- package/docs/runs-and-usage.md +43 -6
- package/docs/scoped-agent-memory.md +262 -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 +17 -0
- package/docs/workflows.md +5 -0
- package/package.json +5 -1
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
/** Provider-round phase of runInternal (plan 059). */
|
|
2
|
+
import { resolveInputCap } from "../../attention-compiler.js";
|
|
3
|
+
import { cacheUsageReport } from "../../cache-helpers.js";
|
|
4
|
+
import { estimateMessageTokens } from "../../context-budget.js";
|
|
2
5
|
import { assertGuardrailsAllowed, GuardrailError, runGuardrails } from "../../guardrails.js";
|
|
6
|
+
import { validateDeterministicTurnAnswer } from "../../middleware.js";
|
|
3
7
|
import { createProviderTurnMetadata, readProviderHttpStatus } from "../../observability.js";
|
|
4
8
|
import { providerError, providerToolCallDeltaContent } from "../../provider-events.js";
|
|
5
9
|
import { errorToErrorInfo, redactRunLedgerRecord, redactSecrets } from "../../redaction.js";
|
|
6
10
|
import { createDefaultRetryPolicy, waitForRetry } from "../../retry.js";
|
|
11
|
+
import { estimateTextTokensForFamily } from "../../usage-estimation.js";
|
|
7
12
|
import { bridgeAbort, errorFromInfo, isSteerSoftInterrupt, jsonBytes, mergeRetry, ProviderTurnFailure, providerContent, randomId, reconstructMissingToolCalls, SteerSoftInterrupt, throwIfAborted, } from "../helpers.js";
|
|
8
13
|
function pushCoalescedContent(content, block) {
|
|
9
14
|
const last = content.at(-1);
|
|
@@ -21,6 +26,49 @@ function pushCoalescedContent(content, block) {
|
|
|
21
26
|
}
|
|
22
27
|
content.push(block);
|
|
23
28
|
}
|
|
29
|
+
/** Resolve the per-request input cap for turn-budget metadata (plan 087 T1). A model without a
|
|
30
|
+
* derivable cap (or a bad attention setting on an unrelated run) omits the field instead of
|
|
31
|
+
* failing an emitting turn; the attention compiler, when enabled, is the cap authority. */
|
|
32
|
+
export function resolveTurnInputCap(session, model) {
|
|
33
|
+
const setting = session.agent.config.attentionCompiler;
|
|
34
|
+
const options = typeof setting === "object" && setting !== null ? setting : undefined;
|
|
35
|
+
try {
|
|
36
|
+
return resolveInputCap(options ? { maxInputTokens: options.maxInputTokens, reserveTokens: options.reserveTokens } : {}, model);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Effective budget snapshot at turn end (plan 087 T1): O(1) from the run limit tracker. */
|
|
43
|
+
function turnBudgets(session, model, usage) {
|
|
44
|
+
const tracker = session.activeLimits;
|
|
45
|
+
if (!tracker)
|
|
46
|
+
return undefined;
|
|
47
|
+
const snapshot = tracker.snapshot();
|
|
48
|
+
const inputCap = resolveTurnInputCap(session, model);
|
|
49
|
+
const runInputBudget = tracker.limits.maxInputTokens;
|
|
50
|
+
return {
|
|
51
|
+
...(usage?.inputTokens === undefined ? {} : { inputTokens: usage.inputTokens }),
|
|
52
|
+
...(inputCap === undefined ? {} : { inputCap }),
|
|
53
|
+
...(runInputBudget === null ? {} : { runInputBudget }),
|
|
54
|
+
runInputUsed: snapshot.inputTokens,
|
|
55
|
+
turns: snapshot.turns,
|
|
56
|
+
maxTurns: tracker.limits.maxTurns,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function cacheMetadata(usage) {
|
|
60
|
+
const cache = cacheUsageReport(usage);
|
|
61
|
+
return cache === undefined ? {} : { cache };
|
|
62
|
+
}
|
|
63
|
+
/** Native reason wins, except a generic `end_turn` on a turn that produced tool calls: protocols
|
|
64
|
+
* with one generic completion value (Google `STOP`) are tool-call turns by content (plan 087 T1). */
|
|
65
|
+
function normalizeTurnStopReason(native, calls) {
|
|
66
|
+
if (native === undefined)
|
|
67
|
+
return calls.length > 0 ? "tool_calls" : "end_turn";
|
|
68
|
+
if (native === "end_turn" && calls.length > 0)
|
|
69
|
+
return "tool_calls";
|
|
70
|
+
return native;
|
|
71
|
+
}
|
|
24
72
|
/**
|
|
25
73
|
* Plan 062: price usage through the host's {@link CostCatalog} when the provider
|
|
26
74
|
* did not report a cost itself. Stale/unknown quotes, catalog failures, or
|
|
@@ -46,17 +94,22 @@ async function withCatalogCost(catalog, model, usage, signal) {
|
|
|
46
94
|
return usage; // catalog failure degrades to usage-only
|
|
47
95
|
}
|
|
48
96
|
}
|
|
49
|
-
export async function recordProviderUsage(ctx, turnUsage, turn, attempt) {
|
|
97
|
+
export async function recordProviderUsage(ctx, turnUsage, turn, attempt, request) {
|
|
50
98
|
const { session, limits, runUsage, runId } = ctx;
|
|
51
|
-
const usage = turnUsage
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
99
|
+
const usage = turnUsage ?? estimateTurnUsage(session, ctx.model, request);
|
|
100
|
+
// An estimate is never priced: a catalog quote on estimated tokens would invent billing.
|
|
101
|
+
const effective = usage && usage.estimated !== true
|
|
102
|
+
? await withCatalogCost(session.agent.config.costCatalog, ctx.model, usage, ctx.controller.signal)
|
|
103
|
+
: usage;
|
|
104
|
+
limits.recordUsage(effective);
|
|
105
|
+
if (!effective)
|
|
106
|
+
return undefined;
|
|
107
|
+
if (effective.inputTokens !== undefined) {
|
|
108
|
+
session.activeInputMeter = { tokens: effective.inputTokens, source: effective.estimated === true ? "estimated" : "reported" };
|
|
109
|
+
}
|
|
110
|
+
runUsage.add(effective);
|
|
58
111
|
if (!session.activeLedger)
|
|
59
|
-
return;
|
|
112
|
+
return effective;
|
|
60
113
|
const usageRecord = {
|
|
61
114
|
id: randomId("usage"),
|
|
62
115
|
sessionId: session.id,
|
|
@@ -64,11 +117,103 @@ export async function recordProviderUsage(ctx, turnUsage, turn, attempt) {
|
|
|
64
117
|
scope: "provider_turn",
|
|
65
118
|
turn,
|
|
66
119
|
attempt,
|
|
67
|
-
usage,
|
|
120
|
+
usage: effective,
|
|
68
121
|
recordedAt: new Date().toISOString(),
|
|
69
122
|
...session.activeOwnership,
|
|
70
123
|
};
|
|
71
124
|
await session.activeLedger.appendUsage(redactRunLedgerRecord(usageRecord, session.activeRedactor));
|
|
125
|
+
return effective;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Plan 091 T2 missing-usage fallback: when the provider reported nothing and the
|
|
129
|
+
* agent did not turn estimation off, label an estimate of the turn's own request
|
|
130
|
+
* (messages + tool declarations + context blocks). Returns `undefined` when
|
|
131
|
+
* estimation is off or the request is unavailable — absent stays absent.
|
|
132
|
+
*/
|
|
133
|
+
function estimateTurnUsage(session, model, request) {
|
|
134
|
+
if (!request || session.agent.config.usageEstimation === "off")
|
|
135
|
+
return undefined;
|
|
136
|
+
const estimate = estimateMessageTokens(request.messages, model.model);
|
|
137
|
+
const extras = request.tools?.length || request.context?.length ? JSON.stringify({ tools: request.tools, context: request.context }) : undefined;
|
|
138
|
+
return {
|
|
139
|
+
inputTokens: estimate.tokens + (extras === undefined ? 0 : estimateTextTokensForFamily(extras, model.model)),
|
|
140
|
+
estimated: true,
|
|
141
|
+
confidence: estimate.confidence,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/** Latest user-role text in the assembled request; steered messages included. */
|
|
145
|
+
function lastUserText(messages) {
|
|
146
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
147
|
+
const message = messages[i];
|
|
148
|
+
if (message?.role !== "user")
|
|
149
|
+
continue;
|
|
150
|
+
return message.content.map((block) => (block.type === "text" ? block.text : "")).join("");
|
|
151
|
+
}
|
|
152
|
+
return "";
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Plan 096: host middleware may answer the turn deterministically at the `beforeProviderTurn` seam —
|
|
156
|
+
* no provider request, no usage, mandatory provenance. `undefined` sends the turn to the provider
|
|
157
|
+
* unchanged; a malformed answer fails the run closed instead of falling through to the provider.
|
|
158
|
+
*/
|
|
159
|
+
export async function resolveDeterministicTurn(session, request, runId, turn, signal, toolResults = []) {
|
|
160
|
+
const middleware = session.agent.config.middleware;
|
|
161
|
+
if (!middleware)
|
|
162
|
+
return undefined;
|
|
163
|
+
const payload = await middleware.run("beforeProviderTurn", {
|
|
164
|
+
sessionId: session.id,
|
|
165
|
+
runId,
|
|
166
|
+
turn,
|
|
167
|
+
userText: lastUserText(request.messages),
|
|
168
|
+
});
|
|
169
|
+
const answer = payload?.answer;
|
|
170
|
+
if (answer === undefined)
|
|
171
|
+
return undefined;
|
|
172
|
+
const validated = validateDeterministicTurnAnswer(answer);
|
|
173
|
+
throwIfAborted(signal);
|
|
174
|
+
const messageId = randomId("msg");
|
|
175
|
+
// Same response-byte axis as provider output: a host answer must not bypass a run ceiling.
|
|
176
|
+
session.activeLimits?.charge("maxResponseBytes", jsonBytes(validated.content));
|
|
177
|
+
if (session.activeGuardrails?.output?.length) {
|
|
178
|
+
assertGuardrailsAllowed(await runGuardrails({
|
|
179
|
+
stage: "output",
|
|
180
|
+
guardrails: session.activeGuardrails,
|
|
181
|
+
value: { content: validated.content, calls: [], messageId, started: true, usage: undefined },
|
|
182
|
+
context: {
|
|
183
|
+
sessionId: session.id,
|
|
184
|
+
runId,
|
|
185
|
+
metadata: session.activeMetadata ?? {},
|
|
186
|
+
signal,
|
|
187
|
+
toolResults,
|
|
188
|
+
},
|
|
189
|
+
redactor: session.activeRedactor,
|
|
190
|
+
emit: (event) => session.emit(event),
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
193
|
+
session.emit({
|
|
194
|
+
type: "deterministic_turn",
|
|
195
|
+
sessionId: session.id,
|
|
196
|
+
runId,
|
|
197
|
+
turn,
|
|
198
|
+
middleware: validated.provenance.middleware,
|
|
199
|
+
});
|
|
200
|
+
session.emit({
|
|
201
|
+
type: "message_started",
|
|
202
|
+
sessionId: session.id,
|
|
203
|
+
runId,
|
|
204
|
+
message: { id: messageId, role: "assistant", content: [] },
|
|
205
|
+
});
|
|
206
|
+
for (const block of validated.content)
|
|
207
|
+
session.emit({ type: "message_delta", sessionId: session.id, runId, content: block });
|
|
208
|
+
// Provenance rides the message into the store (plan 096 Task 2): the transcript alone proves no model ran.
|
|
209
|
+
return {
|
|
210
|
+
content: validated.content,
|
|
211
|
+
calls: [],
|
|
212
|
+
messageId,
|
|
213
|
+
started: true,
|
|
214
|
+
usage: undefined,
|
|
215
|
+
metadata: { deterministic: validated.provenance },
|
|
216
|
+
};
|
|
72
217
|
}
|
|
73
218
|
export async function generateWithRetry(session, request, runId, options, signal, requestSecrets = [], turn = 1, recordUsage, toolResults = []) {
|
|
74
219
|
const retry = mergeRetry(session.agent.config.retry, options.retry);
|
|
@@ -119,7 +264,9 @@ export async function generateProviderTurn(session, request, runId, signal, secr
|
|
|
119
264
|
let messageId;
|
|
120
265
|
let started = false;
|
|
121
266
|
let usage;
|
|
267
|
+
let nativeStopReason;
|
|
122
268
|
let usageRecorded = false;
|
|
269
|
+
let effectiveUsage;
|
|
123
270
|
const bufferedOutput = [];
|
|
124
271
|
const bufferOutput = Boolean(session.activeGuardrails?.output?.length || session.activeLimitOutputBuffer);
|
|
125
272
|
const emitOutput = (event) => {
|
|
@@ -130,9 +277,11 @@ export async function generateProviderTurn(session, request, runId, signal, secr
|
|
|
130
277
|
};
|
|
131
278
|
const recordTurnUsage = async () => {
|
|
132
279
|
if (usageRecorded)
|
|
133
|
-
return;
|
|
280
|
+
return effectiveUsage;
|
|
134
281
|
usageRecorded = true;
|
|
135
|
-
|
|
282
|
+
// The seam may return a labeled estimate (plan 091 T2); without a callback the reported value stands.
|
|
283
|
+
effectiveUsage = (await recordUsage?.(usage, turn, attempt)) ?? usage;
|
|
284
|
+
return effectiveUsage;
|
|
136
285
|
};
|
|
137
286
|
const turnAbort = new AbortController();
|
|
138
287
|
const cleanupTurn = bridgeAbort(signal, turnAbort);
|
|
@@ -153,6 +302,7 @@ export async function generateProviderTurn(session, request, runId, signal, secr
|
|
|
153
302
|
usage = event.usage;
|
|
154
303
|
if (event.type === "done") {
|
|
155
304
|
usage = event.usage ?? usage;
|
|
305
|
+
nativeStopReason = event.stopReason;
|
|
156
306
|
break;
|
|
157
307
|
}
|
|
158
308
|
if (event.type === "message_start") {
|
|
@@ -209,10 +359,15 @@ export async function generateProviderTurn(session, request, runId, signal, secr
|
|
|
209
359
|
sessionId: session.id,
|
|
210
360
|
runId,
|
|
211
361
|
turn,
|
|
212
|
-
metadata: buildMetadata({
|
|
213
|
-
|
|
362
|
+
metadata: buildMetadata({
|
|
363
|
+
latencyMs,
|
|
364
|
+
stopReason: normalizeTurnStopReason(nativeStopReason, calls),
|
|
365
|
+
budgets: turnBudgets(session, request.model, effectiveUsage),
|
|
366
|
+
...cacheMetadata(effectiveUsage),
|
|
367
|
+
}),
|
|
368
|
+
usage: effectiveUsage,
|
|
214
369
|
});
|
|
215
|
-
return { content, calls, messageId, started, usage };
|
|
370
|
+
return { content, calls, messageId, started, usage: effectiveUsage };
|
|
216
371
|
}
|
|
217
372
|
catch (error) {
|
|
218
373
|
if (isSteerSoftInterrupt(error) || isSteerSoftInterrupt(turnAbort.signal.reason)) {
|
|
@@ -223,8 +378,13 @@ export async function generateProviderTurn(session, request, runId, signal, secr
|
|
|
223
378
|
sessionId: session.id,
|
|
224
379
|
runId,
|
|
225
380
|
turn,
|
|
226
|
-
metadata: buildMetadata({
|
|
227
|
-
|
|
381
|
+
metadata: buildMetadata({
|
|
382
|
+
latencyMs,
|
|
383
|
+
stopReason: "abort",
|
|
384
|
+
budgets: turnBudgets(session, request.model, effectiveUsage),
|
|
385
|
+
...cacheMetadata(effectiveUsage),
|
|
386
|
+
}),
|
|
387
|
+
usage: effectiveUsage,
|
|
228
388
|
});
|
|
229
389
|
throw new SteerSoftInterrupt();
|
|
230
390
|
}
|
|
@@ -236,8 +396,14 @@ export async function generateProviderTurn(session, request, runId, signal, secr
|
|
|
236
396
|
sessionId: session.id,
|
|
237
397
|
runId,
|
|
238
398
|
turn,
|
|
239
|
-
metadata: buildMetadata({
|
|
240
|
-
|
|
399
|
+
metadata: buildMetadata({
|
|
400
|
+
latencyMs,
|
|
401
|
+
httpStatus: readProviderHttpStatus(info),
|
|
402
|
+
stopReason: signal.aborted || turnAbort.signal.aborted ? "abort" : "provider_error",
|
|
403
|
+
budgets: turnBudgets(session, request.model, effectiveUsage),
|
|
404
|
+
...cacheMetadata(effectiveUsage),
|
|
405
|
+
}),
|
|
406
|
+
usage: effectiveUsage,
|
|
241
407
|
error: info,
|
|
242
408
|
});
|
|
243
409
|
if (error instanceof GuardrailError || error instanceof ProviderTurnFailure)
|
|
@@ -238,6 +238,24 @@ export function bindChargeToolRound(ctx) {
|
|
|
238
238
|
}
|
|
239
239
|
};
|
|
240
240
|
}
|
|
241
|
+
/** Last-N dispatched tool calls kept for `budget_exhausted` attribution (plan 087 T2); the hash
|
|
242
|
+
* is the same canonical arguments hash the effect store uses, so raw args never enter events. */
|
|
243
|
+
const RECENT_TOOL_CALL_LIMIT = 10;
|
|
244
|
+
function recordRecentToolCall(session, call) {
|
|
245
|
+
const recent = (session.activeRecentToolCalls ??= []);
|
|
246
|
+
recent.push({ id: call.id, name: call.name, argHash: `sha256:${toolEffectArgumentsHash(call.arguments)}` });
|
|
247
|
+
if (recent.length > RECENT_TOOL_CALL_LIMIT)
|
|
248
|
+
recent.shift();
|
|
249
|
+
}
|
|
250
|
+
function dispatchFilter(ctx) {
|
|
251
|
+
const hiddenOk = ctx.options.allowHiddenToolCalls ?? ctx.session.agent.config.allowHiddenToolCalls;
|
|
252
|
+
if (hiddenOk || ctx.turnAllow === undefined) {
|
|
253
|
+
return ctx.tools.length > 0 ? { filter: { allow: ctx.tools.map((tool) => tool.name) } } : {};
|
|
254
|
+
}
|
|
255
|
+
if (ctx.turnAllow.length > 0)
|
|
256
|
+
return { filter: { allow: ctx.turnAllow } };
|
|
257
|
+
return ctx.tools.length > 0 ? { filter: { deny: ctx.tools.map((tool) => tool.name) } } : {};
|
|
258
|
+
}
|
|
241
259
|
export function bindDispatchToolCall(ctx) {
|
|
242
260
|
return async (call) => {
|
|
243
261
|
const sticky = matchStickyDecision(ctx.session, call, ctx.registry);
|
|
@@ -252,6 +270,7 @@ export function bindDispatchToolCall(ctx) {
|
|
|
252
270
|
return { toolCallId: call.id, name: call.name, metadata: { approvalPending: true } };
|
|
253
271
|
}
|
|
254
272
|
ctx.toolCalls += 1;
|
|
273
|
+
recordRecentToolCall(ctx.session, call);
|
|
255
274
|
try {
|
|
256
275
|
const result = await dispatchToolCall({
|
|
257
276
|
call,
|
|
@@ -279,7 +298,7 @@ export function bindDispatchToolCall(ctx) {
|
|
|
279
298
|
ownership: ctx.session.activeOwnership,
|
|
280
299
|
identity: ctx.session.activeIdentity,
|
|
281
300
|
guardrails: ctx.session.activeGuardrails,
|
|
282
|
-
...(ctx
|
|
301
|
+
...dispatchFilter(ctx),
|
|
283
302
|
limitTracker: ctx.limits,
|
|
284
303
|
beforeExecute: async (mediatedCall) => {
|
|
285
304
|
const durable = ctx.session.activeDurable;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/** Shared host/round types for runInternal phase split (plan 059). Internal only. */
|
|
2
2
|
import type { ActiveDurableRun } from "../../agent-approval.js";
|
|
3
3
|
import type { PendingToolCall } from "../../agent-run-state.js";
|
|
4
|
-
import type { AttentionStickyFrontier, PersistedAttentionStickyFrontier } from "../../attention-compiler.js";
|
|
5
|
-
import type { Agent, AgentEvent, AgentFinishReason, AgentLoopStrategy, AgentRunResult, AIProvider, ErrorInfo, Guardrails, LoopContext, Message, ModelConfig, OwnershipScope, PendingDecision, PromptVersionRef, ProviderRequest, RunLedger, RunOptions, SessionEntry, SessionStore, Skill, ToolDefinition, ToolEffectStore, ToolRegistry, ToolResult, Usage } from "../../contracts.js";
|
|
4
|
+
import type { AttentionFoldLedger, AttentionStickyFrontier, PersistedAttentionFoldLedger, PersistedAttentionStickyFrontier } from "../../attention-compiler.js";
|
|
5
|
+
import type { Agent, AgentEvent, AgentFinishReason, AgentLoopStrategy, AgentRunResult, AIProvider, ErrorInfo, Guardrails, LoopContext, Message, ModelConfig, OwnershipScope, PendingDecision, PromptVersionRef, ProviderRequest, RunLedger, RunOptions, SessionEntry, SessionStore, Skill, ToolCallSummary, ToolDefinition, ToolEffectStore, ToolRegistry, ToolResult, Usage } from "../../contracts.js";
|
|
6
6
|
import type { AgentIdentity } from "../../identity.js";
|
|
7
7
|
import type { AgentInput } from "../../input.js";
|
|
8
8
|
import type { SecretRedactor } from "../../redaction.js";
|
|
@@ -33,9 +33,19 @@ export type SessionHost = {
|
|
|
33
33
|
activeIdentity?: AgentIdentity;
|
|
34
34
|
activeIdempotencyKey?: string;
|
|
35
35
|
activeGuardrails?: Guardrails;
|
|
36
|
+
/** Plan 092 Task 2: packs compiled once at session construction; read-only for phases. */
|
|
37
|
+
readonly packGuardrails?: Guardrails;
|
|
36
38
|
activeMetadata?: Readonly<Record<string, unknown>>;
|
|
37
39
|
activePromptVersion?: PromptVersionRef;
|
|
38
40
|
activeLimits?: RunLimitTracker;
|
|
41
|
+
/** Plan 091 T2: input tokens of the latest provider turn plus whether the
|
|
42
|
+
* provider reported them. Set by the usage seam; read by `contextMeter()`. */
|
|
43
|
+
activeInputMeter?: {
|
|
44
|
+
readonly tokens: number;
|
|
45
|
+
readonly source: "reported" | "estimated";
|
|
46
|
+
};
|
|
47
|
+
/** Bounded last-N tool-call summaries of the active run (plan 087 T2): ids, names, arg hashes. */
|
|
48
|
+
activeRecentToolCalls?: ToolCallSummary[];
|
|
39
49
|
activeLimitOutputBuffer: boolean;
|
|
40
50
|
activeDurable?: ActiveDurableRun;
|
|
41
51
|
activeLoop?: AgentLoopStrategy;
|
|
@@ -45,6 +55,8 @@ export type SessionHost = {
|
|
|
45
55
|
}>;
|
|
46
56
|
activeLoopTurn: number;
|
|
47
57
|
readonly loadedSkills: LoadedSkillSet;
|
|
58
|
+
/** Run-owned monotonic prompt tail; cleared before each new run. */
|
|
59
|
+
readonly tailSegments: Map<string, Message>;
|
|
48
60
|
readonly activatedTools: ActiveToolSet;
|
|
49
61
|
restoredSkillBodies: readonly LoadedSkillBodiesEntry[];
|
|
50
62
|
activeRunSkills: readonly Skill[];
|
|
@@ -57,6 +69,15 @@ export type SessionHost = {
|
|
|
57
69
|
serializedAttentionSticky(): PersistedAttentionStickyFrontier | undefined;
|
|
58
70
|
/** Plan 074 P3: restore a frontier that was validated when the checkpoint was loaded. */
|
|
59
71
|
restoreAttentionSticky(persisted: PersistedAttentionStickyFrontier): void;
|
|
72
|
+
/** Folded bodies for this session (plan 086 T3); session-owned so a resumed fold re-applies
|
|
73
|
+
* the same stub bytes instead of calling the host `summarize` again. Lazily created. */
|
|
74
|
+
attentionFoldFor(): AttentionFoldLedger;
|
|
75
|
+
/** Plan 086 T3: bounded ledger snapshot for a durable checkpoint (undefined before any fold). */
|
|
76
|
+
serializedAttentionFold(): PersistedAttentionFoldLedger | undefined;
|
|
77
|
+
/** Plan 086 T3: adopt a ledger validated when the checkpoint was loaded. */
|
|
78
|
+
restoreAttentionFold(ledger: AttentionFoldLedger): void;
|
|
79
|
+
/** Plan 086 T3: `attention.compiler.durable` for the current run; set by the run assembler. */
|
|
80
|
+
attentionDurable: boolean;
|
|
60
81
|
invalidateSnapshot(): void;
|
|
61
82
|
resolveRunProvider(options: RunOptions): void;
|
|
62
83
|
emit(event: AgentEvent): void;
|
|
@@ -116,6 +137,8 @@ export type RoundContext = {
|
|
|
116
137
|
loop: AgentLoopStrategy;
|
|
117
138
|
toolConcurrency: number;
|
|
118
139
|
toolsDisclosure: import("../../tool-search.js").ToolsDisclosure;
|
|
140
|
+
/** Per-turn dispatch overlay; undefined when `toolNarrowing` is unset. */
|
|
141
|
+
turnAllow?: readonly string[];
|
|
119
142
|
assembledTurn: boolean;
|
|
120
143
|
artifactFinished: boolean;
|
|
121
144
|
artifactFailedInfo: {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/** session (0.2.5 plan 025 Task 1 split). Moved verbatim from agent-session.ts; public surface unchanged behind the barrel. */
|
|
2
|
-
import { ActiveDurableRun } from "../agent-approval.js";
|
|
2
|
+
import { ActiveDurableRun, ActiveDurableRunExtras } from "../agent-approval.js";
|
|
3
3
|
import type { PendingToolCall, StoredAgentRunState } from "../agent-run-state.js";
|
|
4
|
-
import { type AttentionStickyFrontier, type PersistedAttentionStickyFrontier } from "../attention-compiler.js";
|
|
5
|
-
import type { Agent, AgentEvent, AgentRunResult, AgentRunState, AgentRunStateOptions, AgentSession, AgentSessionConfig, AIProvider, CompactionOptions, CompactionResult, ErrorInfo, Message, OwnershipScope, PendingDecision, PromptVersionRef, ProviderRequest, RunDecision, RunOptions, SessionEntry, Skill, SteerOptions, SubscribeOptions, ToolDefinition, ToolEffectStore, Usage } from "../contracts.js";
|
|
4
|
+
import { type AttentionFoldLedger, type AttentionStickyFrontier, type PersistedAttentionFoldLedger, type PersistedAttentionStickyFrontier } from "../attention-compiler.js";
|
|
5
|
+
import type { Agent, AgentEvent, AgentRunResult, AgentRunState, AgentRunStateOptions, AgentSession, AgentSessionConfig, AIProvider, CompactionOptions, CompactionResult, ContextMeter, ErrorInfo, Guardrails, Message, OwnershipScope, PendingDecision, PromptVersionRef, ProviderRequest, RunDecision, RunOptions, SessionEntry, Skill, SteerOptions, SubscribeOptions, ToolCallSummary, ToolDefinition, ToolEffectStore, Usage } from "../contracts.js";
|
|
6
6
|
import type { AgentIdentity } from "../identity.js";
|
|
7
7
|
import type { AgentInput } from "../input.js";
|
|
8
8
|
import type { RunLimitTracker } from "../run-limits.js";
|
|
@@ -30,9 +30,21 @@ export declare class RuntimeAgentSession implements AgentSession {
|
|
|
30
30
|
activeIdentity?: AgentIdentity;
|
|
31
31
|
private activeIdempotencyKey?;
|
|
32
32
|
private activeGuardrails?;
|
|
33
|
+
/** Plan 092 Task 2: guardrail packs compiled once in the constructor; merged into every run's `activeGuardrails`. */
|
|
34
|
+
readonly packGuardrails?: Guardrails;
|
|
35
|
+
/** Original pack refs, carried into `fork()`/`clone()` so a branch cannot silently lose its policy. */
|
|
36
|
+
private readonly guardrailPackRefs?;
|
|
33
37
|
activeMetadata?: Readonly<Record<string, unknown>>;
|
|
34
38
|
activePromptVersion?: PromptVersionRef;
|
|
35
39
|
activeLimits?: RunLimitTracker;
|
|
40
|
+
/** Plan 091 T2: input tokens of the latest provider turn plus whether the provider reported
|
|
41
|
+
* them; set by the usage seam, read by `contextMeter()`. */
|
|
42
|
+
activeInputMeter?: {
|
|
43
|
+
readonly tokens: number;
|
|
44
|
+
readonly source: "reported" | "estimated";
|
|
45
|
+
};
|
|
46
|
+
/** Bounded last-N tool-call summaries of the active run (plan 087 T2): ids, names, arg hashes. */
|
|
47
|
+
activeRecentToolCalls?: ToolCallSummary[];
|
|
36
48
|
activeLimitOutputBuffer: boolean;
|
|
37
49
|
activeDurable?: ActiveDurableRun;
|
|
38
50
|
activeLoop?: import("../contracts.js").AgentLoopStrategy;
|
|
@@ -43,6 +55,8 @@ export declare class RuntimeAgentSession implements AgentSession {
|
|
|
43
55
|
}>;
|
|
44
56
|
activeLoopTurn: number;
|
|
45
57
|
private readonly loadedSkills;
|
|
58
|
+
/** Run-owned only: loaded bodies and URI resources retain first insertion order within one provider loop. */
|
|
59
|
+
readonly tailSegments: Map<string, Message>;
|
|
46
60
|
/** Tools activated via `search_tools` this session (plan 041); names-only in persistence. */
|
|
47
61
|
readonly activatedTools: import("../tool-search.js").ActiveToolSet;
|
|
48
62
|
/** Plan 018 Task 6 (closeout `checkpoint-bodies`): persisted exact instructions, registry-independent. */
|
|
@@ -62,6 +76,17 @@ export declare class RuntimeAgentSession implements AgentSession {
|
|
|
62
76
|
/** Plan 074 P3: restore a frontier validated at checkpoint load, so a resumed run keeps its
|
|
63
77
|
* stubs instead of re-deciding its first turn from the ratio. */
|
|
64
78
|
restoreAttentionSticky(persisted: PersistedAttentionStickyFrontier): void;
|
|
79
|
+
/** Session-owned folded bodies (plan 086 T3); created on first use like the frontier, so a
|
|
80
|
+
* compiler-off session allocates nothing. */
|
|
81
|
+
private attentionFold?;
|
|
82
|
+
/** Set per run from the resolved compiler: `durable: true` opts the fold ledger and its
|
|
83
|
+
* frontier into checkpoints even when `persistSessionState` is off. */
|
|
84
|
+
attentionDurable: boolean;
|
|
85
|
+
attentionFoldFor(): AttentionFoldLedger;
|
|
86
|
+
/** Plan 086 T3: bounded ledger snapshot for a durable checkpoint; `undefined` before any fold. */
|
|
87
|
+
serializedAttentionFold(): PersistedAttentionFoldLedger | undefined;
|
|
88
|
+
/** Plan 086 T3: adopt a ledger validated at checkpoint load, so a resumed fold is byte-identical. */
|
|
89
|
+
restoreAttentionFold(ledger: AttentionFoldLedger): void;
|
|
65
90
|
/** Plan 015 Task 4: re-add persisted loaded-skill names (names only; bodies re-resolve on demand). */
|
|
66
91
|
restoreLoadedSkills(names: readonly string[]): void;
|
|
67
92
|
/** Plan 041: re-add persisted activated-tool names (names only; inert for absent tools). */
|
|
@@ -79,10 +104,19 @@ export declare class RuntimeAgentSession implements AgentSession {
|
|
|
79
104
|
readonly agent: Agent;
|
|
80
105
|
});
|
|
81
106
|
get leafId(): string | undefined;
|
|
107
|
+
/**
|
|
108
|
+
* Context-fill read (plan 091 T2): the latest provider turn's input tokens —
|
|
109
|
+
* provider-reported when it reported, else a labeled estimate — plus the
|
|
110
|
+
* per-request cap and cumulative run input budget, resolved exactly as
|
|
111
|
+
* `provider_turn_finished.budgets` resolves them. Before any provider turn in
|
|
112
|
+
* this session it estimates stored history, so a non-reporting model still
|
|
113
|
+
* shows a working meter instead of zero. Never billing; estimates are labeled.
|
|
114
|
+
*/
|
|
115
|
+
contextMeter(): ContextMeter;
|
|
82
116
|
subscribe(options?: SubscribeOptions): AsyncIterable<AgentEvent>;
|
|
83
117
|
run(input: AgentInput, options?: RunOptions): Promise<AgentRunResult>;
|
|
84
118
|
steer(input: AgentInput, options?: SteerOptions): void;
|
|
85
|
-
resumeDurable(state: StoredAgentRunState, runState: AgentRunStateOptions, ownership?: OwnershipScope, signal?: AbortSignal, decisions?: ReadonlyMap<string, RunDecision
|
|
119
|
+
resumeDurable(state: StoredAgentRunState, runState: AgentRunStateOptions, ownership?: OwnershipScope, signal?: AbortSignal, decisions?: ReadonlyMap<string, RunDecision>, extras?: ActiveDurableRunExtras): Promise<AgentRunResult>;
|
|
86
120
|
recordDurableResumption(runId: string, interruption: import("../contracts.js").AgentRunInterruption, version: number, ownership?: OwnershipScope): Promise<void>;
|
|
87
121
|
recordDurableDenial(runId: string, interruption: import("../contracts.js").AgentRunInterruption, version: number, ownership?: OwnershipScope): Promise<void>;
|
|
88
122
|
private runInternal;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/** session (0.2.5 plan 025 Task 1 split). Moved verbatim from agent-session.ts; public surface unchanged behind the barrel. */
|
|
2
2
|
import { policyList } from "../agent-tool-dispatch.js";
|
|
3
|
-
import { createAttentionStickyFrontier, resolveInputCap, restoreAttentionStickyFrontier, serializeAttentionStickyFrontier, } from "../attention-compiler.js";
|
|
3
|
+
import { createAttentionFoldLedger, createAttentionStickyFrontier, resolveInputCap, restoreAttentionStickyFrontier, serializeAttentionFoldLedger, serializeAttentionStickyFrontier, } from "../attention-compiler.js";
|
|
4
4
|
import { createDefaultCompactionStrategy, isCompactionEntryData } from "../compaction.js";
|
|
5
|
-
import { estimateAssemblyTokens, estimateTextTokens } from "../context-budget.js";
|
|
5
|
+
import { estimateAssemblyTokens, estimateMessageTokens, estimateTextTokens } from "../context-budget.js";
|
|
6
6
|
import { DEFAULT_MAX_PENDING_STEER_BYTES, DEFAULT_MAX_PENDING_STEERS, DEFAULT_SNAPSHOT_CACHE_TTL_MS, HARD_MAX_SNAPSHOT_CACHE_TTL_MS, resolveShouldCompact, } from "../contracts.js";
|
|
7
|
-
import { GuardrailError, runGuardrails } from "../guardrails.js";
|
|
7
|
+
import { compileGuardrailPacks, GuardrailError, runGuardrails } from "../guardrails.js";
|
|
8
8
|
import { applyDefaultProviderRequestOptions, createProviderRequestPolicyChain, normalizeProviderRequestPolicyResult, } from "../provider-request-policy.js";
|
|
9
9
|
import { redactAgentEvent, redactProviderRequest, redactRunLedgerRecord, redactSecrets, redactSessionEntry } from "../redaction.js";
|
|
10
10
|
import { createMemorySessionStore, createSessionEntry, getSessionBranchEntries, rebuildSessionContext } from "../session-stores.js";
|
|
@@ -39,9 +39,18 @@ export class RuntimeAgentSession {
|
|
|
39
39
|
activeIdentity;
|
|
40
40
|
activeIdempotencyKey;
|
|
41
41
|
activeGuardrails;
|
|
42
|
+
/** Plan 092 Task 2: guardrail packs compiled once in the constructor; merged into every run's `activeGuardrails`. */
|
|
43
|
+
packGuardrails;
|
|
44
|
+
/** Original pack refs, carried into `fork()`/`clone()` so a branch cannot silently lose its policy. */
|
|
45
|
+
guardrailPackRefs;
|
|
42
46
|
activeMetadata;
|
|
43
47
|
activePromptVersion;
|
|
44
48
|
activeLimits;
|
|
49
|
+
/** Plan 091 T2: input tokens of the latest provider turn plus whether the provider reported
|
|
50
|
+
* them; set by the usage seam, read by `contextMeter()`. */
|
|
51
|
+
activeInputMeter;
|
|
52
|
+
/** Bounded last-N tool-call summaries of the active run (plan 087 T2): ids, names, arg hashes. */
|
|
53
|
+
activeRecentToolCalls;
|
|
45
54
|
activeLimitOutputBuffer = false;
|
|
46
55
|
activeDurable;
|
|
47
56
|
activeLoop;
|
|
@@ -49,6 +58,8 @@ export class RuntimeAgentSession {
|
|
|
49
58
|
activeGatedRound;
|
|
50
59
|
activeLoopTurn = 1;
|
|
51
60
|
loadedSkills = createLoadedSkillSet();
|
|
61
|
+
/** Run-owned only: loaded bodies and URI resources retain first insertion order within one provider loop. */
|
|
62
|
+
tailSegments = new Map();
|
|
52
63
|
/** Tools activated via `search_tools` this session (plan 041); names-only in persistence. */
|
|
53
64
|
activatedTools = createActiveToolSet();
|
|
54
65
|
/** Plan 018 Task 6 (closeout `checkpoint-bodies`): persisted exact instructions, registry-independent. */
|
|
@@ -77,6 +88,24 @@ export class RuntimeAgentSession {
|
|
|
77
88
|
restoreAttentionSticky(persisted) {
|
|
78
89
|
this.attentionSticky = restoreAttentionStickyFrontier(persisted);
|
|
79
90
|
}
|
|
91
|
+
/** Session-owned folded bodies (plan 086 T3); created on first use like the frontier, so a
|
|
92
|
+
* compiler-off session allocates nothing. */
|
|
93
|
+
attentionFold;
|
|
94
|
+
/** Set per run from the resolved compiler: `durable: true` opts the fold ledger and its
|
|
95
|
+
* frontier into checkpoints even when `persistSessionState` is off. */
|
|
96
|
+
attentionDurable = false;
|
|
97
|
+
attentionFoldFor() {
|
|
98
|
+
this.attentionFold ??= createAttentionFoldLedger();
|
|
99
|
+
return this.attentionFold;
|
|
100
|
+
}
|
|
101
|
+
/** Plan 086 T3: bounded ledger snapshot for a durable checkpoint; `undefined` before any fold. */
|
|
102
|
+
serializedAttentionFold() {
|
|
103
|
+
return this.attentionFold && this.attentionFold.bodies.size > 0 ? serializeAttentionFoldLedger(this.attentionFold) : undefined;
|
|
104
|
+
}
|
|
105
|
+
/** Plan 086 T3: adopt a ledger validated at checkpoint load, so a resumed fold is byte-identical. */
|
|
106
|
+
restoreAttentionFold(ledger) {
|
|
107
|
+
this.attentionFold = ledger;
|
|
108
|
+
}
|
|
80
109
|
/** Plan 015 Task 4: re-add persisted loaded-skill names (names only; bodies re-resolve on demand). */
|
|
81
110
|
restoreLoadedSkills(names) {
|
|
82
111
|
for (const name of names)
|
|
@@ -110,10 +139,46 @@ export class RuntimeAgentSession {
|
|
|
110
139
|
this.store = config.store ?? config.agent.config.store ?? createMemorySessionStore();
|
|
111
140
|
this.currentLeafId = config.leafId;
|
|
112
141
|
this.snapshotCacheTtlMs = resolveSnapshotCacheTtlMs(config.snapshotCacheTtlMs);
|
|
142
|
+
this.packGuardrails = compileGuardrailPacks(config.guardrailPacks);
|
|
143
|
+
this.guardrailPackRefs = config.guardrailPacks;
|
|
144
|
+
const usageEstimation = config.agent.config.usageEstimation;
|
|
145
|
+
if (usageEstimation !== undefined && usageEstimation !== "fallback" && usageEstimation !== "off") {
|
|
146
|
+
throw new TypeError('usageEstimation must be "fallback" or "off"');
|
|
147
|
+
}
|
|
113
148
|
}
|
|
114
149
|
get leafId() {
|
|
115
150
|
return this.currentLeafId;
|
|
116
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Context-fill read (plan 091 T2): the latest provider turn's input tokens —
|
|
154
|
+
* provider-reported when it reported, else a labeled estimate — plus the
|
|
155
|
+
* per-request cap and cumulative run input budget, resolved exactly as
|
|
156
|
+
* `provider_turn_finished.budgets` resolves them. Before any provider turn in
|
|
157
|
+
* this session it estimates stored history, so a non-reporting model still
|
|
158
|
+
* shows a working meter instead of zero. Never billing; estimates are labeled.
|
|
159
|
+
*/
|
|
160
|
+
contextMeter() {
|
|
161
|
+
const model = this.agent.config.model;
|
|
162
|
+
const inputTokens = this.activeInputMeter?.tokens ?? estimateMessageTokens(this.history, model.model).tokens;
|
|
163
|
+
const source = this.activeInputMeter?.source ?? "estimated";
|
|
164
|
+
let inputCap;
|
|
165
|
+
try {
|
|
166
|
+
const setting = this.agent.config.attentionCompiler;
|
|
167
|
+
const options = typeof setting === "object" && setting !== null ? setting : undefined;
|
|
168
|
+
inputCap = resolveInputCap(options ? { maxInputTokens: options.maxInputTokens, reserveTokens: options.reserveTokens } : {}, model);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
inputCap = undefined; // undialed model: omit instead of throwing a state read
|
|
172
|
+
}
|
|
173
|
+
const runInputBudget = this.activeLimits?.limits.maxInputTokens ?? undefined;
|
|
174
|
+
return {
|
|
175
|
+
inputTokens,
|
|
176
|
+
source,
|
|
177
|
+
...(inputCap === undefined ? {} : { inputCap }),
|
|
178
|
+
...(runInputBudget == null ? {} : { runInputBudget }),
|
|
179
|
+
...(inputCap === undefined ? {} : { usedRatio: inputTokens / inputCap }),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
117
182
|
subscribe(options = {}) {
|
|
118
183
|
const subscriber = new EventSubscriber(this.id, options, () => this.subscribers.delete(subscriber));
|
|
119
184
|
this.subscribers.add(subscriber);
|
|
@@ -147,12 +212,13 @@ export class RuntimeAgentSession {
|
|
|
147
212
|
this.pendingSoftInterrupt = true;
|
|
148
213
|
}
|
|
149
214
|
}
|
|
150
|
-
async resumeDurable(state, runState, ownership, signal, decisions) {
|
|
215
|
+
async resumeDurable(state, runState, ownership, signal, decisions, extras) {
|
|
151
216
|
return this.runInternal(state.input ?? [], { runState, ownership, signal }, state.runId, {
|
|
152
217
|
options: runState,
|
|
153
218
|
state,
|
|
154
219
|
version: state.version,
|
|
155
220
|
decisions,
|
|
221
|
+
...extras,
|
|
156
222
|
});
|
|
157
223
|
}
|
|
158
224
|
async recordDurableResumption(runId, interruption, version, ownership) {
|
|
@@ -241,7 +307,10 @@ export class RuntimeAgentSession {
|
|
|
241
307
|
async compact(options = {}) {
|
|
242
308
|
if (this.activeRun)
|
|
243
309
|
throw new Error("Agent session already has an active run");
|
|
244
|
-
|
|
310
|
+
const result = await this.compactBranch(options, undefined, options.signal, "manual");
|
|
311
|
+
// Plan 091 T2: history changed, so a pre-compaction meter reading would overstate the context.
|
|
312
|
+
this.activeInputMeter = undefined;
|
|
313
|
+
return result;
|
|
245
314
|
}
|
|
246
315
|
abort(reason) {
|
|
247
316
|
this.activeRun?.abort(reason);
|
|
@@ -264,6 +333,7 @@ export class RuntimeAgentSession {
|
|
|
264
333
|
store: this.store,
|
|
265
334
|
leafId: options.leafId ?? this.currentLeafId,
|
|
266
335
|
metadata: this.metadata,
|
|
336
|
+
...(this.guardrailPackRefs ? { guardrailPacks: this.guardrailPackRefs } : {}),
|
|
267
337
|
});
|
|
268
338
|
}
|
|
269
339
|
async clone(options = {}) {
|
|
@@ -286,6 +356,7 @@ export class RuntimeAgentSession {
|
|
|
286
356
|
store: this.store,
|
|
287
357
|
leafId: branch.length ? remap.get(branch[branch.length - 1].id) : undefined,
|
|
288
358
|
metadata: this.metadata,
|
|
359
|
+
...(this.guardrailPackRefs ? { guardrailPacks: this.guardrailPackRefs } : {}),
|
|
289
360
|
});
|
|
290
361
|
}
|
|
291
362
|
branchReader() {
|