@arnilo/prism 0.7.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 +73 -0
- package/README.md +12 -11
- package/dist/agent-approval.d.ts +15 -2
- package/dist/agent-approval.js +5 -1
- 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 +91 -10
- package/dist/agent-run-state.d.ts +34 -2
- package/dist/agent-run-state.js +68 -6
- package/dist/agent-session/helpers.js +20 -1
- package/dist/agent-session/session/assemble.js +250 -27
- package/dist/agent-session/session/persist.d.ts +27 -0
- package/dist/agent-session/session/persist.js +94 -12
- package/dist/agent-session/session/provider-round.d.ts +14 -4
- package/dist/agent-session/session/provider-round.js +197 -25
- package/dist/agent-session/session/tool-round.js +24 -2
- package/dist/agent-session/session/types.d.ts +36 -2
- package/dist/agent-session/session.d.ts +40 -4
- package/dist/agent-session/session.js +78 -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/checkpoints.js +7 -11
- 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 +15 -0
- package/dist/contracts-core/guardrail-packs.d.ts +41 -0
- package/dist/contracts-core/guardrail-packs.js +2 -0
- package/dist/contracts-core/loop.d.ts +42 -0
- package/dist/contracts-core/provider.d.ts +25 -0
- package/dist/contracts-core/run-limits.d.ts +21 -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 +90 -4
- package/dist/contracts-run-state.d.ts +82 -6
- package/dist/evidence-grounding.d.ts +29 -0
- package/dist/evidence-grounding.js +162 -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 +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/host-composition.d.ts +13 -0
- package/dist/host-composition.js +33 -2
- package/dist/index.d.ts +19 -10
- package/dist/index.js +11 -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 +11 -3
- package/dist/provider-events.js +62 -4
- package/dist/providers/openai-compatible.js +6 -3
- package/dist/providers/transport.d.ts +3 -1
- package/dist/providers/transport.js +36 -0
- package/dist/redaction.js +18 -2
- package/dist/run-bundle.d.ts +89 -0
- package/dist/run-bundle.js +150 -0
- 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/testing/state-concurrency-conformance.js +5 -12
- 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/ag-ui.md +5 -0
- package/docs/agent-events.md +68 -1
- package/docs/agent-loops.md +33 -0
- package/docs/agent-session-runtime.md +5 -3
- package/docs/attention-compiler.md +89 -8
- package/docs/coding-agent-tools.md +1 -1
- package/docs/coding-security.md +1 -0
- package/docs/coding-tools.md +0 -1
- package/docs/compaction-and-retry.md +1 -1
- package/docs/compaction-observational-memory.md +34 -7
- package/docs/connected-apps.md +116 -0
- package/docs/context-and-skills.md +13 -0
- package/docs/core.md +1 -1
- package/docs/diagrams.md +6 -6
- package/docs/document-reader.md +9 -9
- package/docs/documents.md +32 -11
- package/docs/durable-runs.md +129 -0
- package/docs/embeddings.md +5 -0
- package/docs/enterprise-postgres-state.md +4 -0
- package/docs/evaluations.md +5 -0
- package/docs/execution-timeline.md +84 -1
- package/docs/guardrails.md +71 -2
- package/docs/history/079-messaging-primitive-review.md +391 -0
- package/docs/history/080-messaging-followon-primitive-review.md +234 -0
- package/docs/history/081-connected-apps-primitive-review.md +74 -0
- package/docs/history/083-prism-work-primitive-review.md +84 -0
- package/docs/history/084-primitive-review.md +96 -0
- package/docs/history/085-honesty-and-cut-primitive-review.md +91 -0
- package/docs/history/README.md +5 -0
- package/docs/history/release-handoffs.md +38 -0
- package/docs/host-compositions.md +8 -6
- package/docs/host-security.md +2 -2
- package/docs/index.md +66 -29
- package/docs/input-and-prompt-assembly.md +3 -3
- package/docs/knowledge-sync.md +4 -0
- package/docs/live-testing.md +5 -3
- package/docs/mcp-tools.md +1 -0
- package/docs/messaging-channel-operations.md +166 -0
- package/docs/messaging-channels.md +150 -0
- package/docs/middleware-hooks.md +38 -2
- package/docs/migrate-to-0.8.md +124 -0
- package/docs/migrate-to-0.9.md +210 -0
- package/docs/migration.md +43 -0
- package/docs/model-registry.md +12 -2
- 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/openapi-tools.md +1 -1
- package/docs/operations.md +1 -3
- package/docs/options-index.md +36 -3
- package/docs/peer-dependencies.md +6 -6
- package/docs/policy-and-audit.md +13 -1
- package/docs/postgres-persistence.md +1 -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-layer.md +2 -2
- package/docs/provider-packages.md +20 -20
- package/docs/providers/neuralwatt.md +5 -1
- package/docs/public-contracts.md +2 -2
- package/docs/rag.md +102 -4
- package/docs/release-and-install.md +55 -47
- package/docs/run-bundle.md +92 -0
- package/docs/runs-and-usage.md +57 -6
- package/docs/scoped-agent-memory.md +262 -0
- package/docs/server.md +2 -0
- package/docs/session-store-conformance.md +1 -2
- package/docs/session-stores.md +17 -17
- package/docs/sheets.md +9 -9
- package/docs/signal-channel.md +112 -0
- package/docs/speech.md +5 -1
- package/docs/sqlite-persistence.md +1 -1
- package/docs/supervisors.md +32 -12
- package/docs/telegram-channel.md +157 -0
- package/docs/testing.md +2 -2
- package/docs/tools.md +17 -0
- package/docs/wiki.md +1 -1
- package/docs/work-artifacts-and-review.md +1 -1
- package/docs/work-connectors.md +9 -9
- package/docs/work-sandbox.md +115 -0
- package/docs/work-tools.md +38 -16
- package/docs/workflows.md +5 -0
- package/package.json +9 -3
- package/templates/business-worker/manifest.json +2 -1
- package/templates/business-worker/src/agent.ts.tmpl +1 -1
- package/templates/business-worker/src/tests/agent.test.ts.tmpl +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Finalize/persist phase of runInternal (plan 059). */
|
|
2
|
-
import { boundedLoopSnapshot, initialAgentRunState, publicState, saveAgentRunState } from "../../agent-run-state.js";
|
|
2
|
+
import { boundedLoopSnapshot, initialAgentRunState, publicState, resolveCheckpointMetadata, saveAgentRunState, } from "../../agent-run-state.js";
|
|
3
3
|
import { AgentRunStateError } from "../../contracts.js";
|
|
4
4
|
import { redactRunLedgerRecord } from "../../redaction.js";
|
|
5
5
|
import { isFlushableRunLedger } from "../../run-ledger.js";
|
|
@@ -10,13 +10,16 @@ export async function persistDurable(session, state) {
|
|
|
10
10
|
if (!durable)
|
|
11
11
|
throw new AgentRunStateError("Durable run state is not configured");
|
|
12
12
|
const withGrant = session.activeToolNames !== undefined ? { ...state, toolNames: session.activeToolNames } : state;
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
const persistSessionState = durable.options.persistSessionState === true;
|
|
14
|
+
// Plan 086 T3: durable folding owns its two keys. A run that opted into `durable` writes the
|
|
15
|
+
// fold ledger and its frontier even when the broader session-state bag stays off; a run that
|
|
16
|
+
// did not keeps exactly today's bytes, where the frontier rides `persistSessionState`.
|
|
17
|
+
const attentionSticky = persistSessionState || session.attentionDurable ? session.serializedAttentionSticky() : undefined;
|
|
18
|
+
const attentionFold = session.attentionDurable ? session.serializedAttentionFold() : undefined;
|
|
19
|
+
const sessionState = {
|
|
20
|
+
...(persistSessionState
|
|
21
|
+
? {
|
|
18
22
|
loadedSkillNames: session.loadedSkills.list(),
|
|
19
|
-
...(attentionSticky ? { attentionSticky } : {}),
|
|
20
23
|
...(session.activatedTools.list().length ? { activatedToolNames: session.activatedTools.list() } : {}),
|
|
21
24
|
...(durable.options.includeSkillBodies
|
|
22
25
|
? {
|
|
@@ -25,9 +28,13 @@ export async function persistDurable(session, state) {
|
|
|
25
28
|
: undefined),
|
|
26
29
|
}
|
|
27
30
|
: {}),
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
:
|
|
31
|
+
}
|
|
32
|
+
: {}),
|
|
33
|
+
...(attentionSticky ? { attentionSticky } : {}),
|
|
34
|
+
...(attentionFold ? { attentionFold } : {}),
|
|
35
|
+
};
|
|
36
|
+
const persisted = Object.keys(sessionState).length > 0 ? { ...withGrant, sessionState } : withGrant;
|
|
37
|
+
const metadata = resolveCheckpointMetadata(durable.options.checkpointMetadata) ?? durable.checkpointMetadata;
|
|
31
38
|
const saved = await saveAgentRunState({
|
|
32
39
|
checkpoints: durable.options.checkpoints,
|
|
33
40
|
state: persisted,
|
|
@@ -36,6 +43,7 @@ export async function persistDurable(session, state) {
|
|
|
36
43
|
fencingToken: durable.options.fencingToken,
|
|
37
44
|
redactor: session.activeRedactor,
|
|
38
45
|
maxStateBytes: durable.options.maxStateBytes,
|
|
46
|
+
...(metadata ? { metadata } : {}),
|
|
39
47
|
});
|
|
40
48
|
durable.state = saved.state;
|
|
41
49
|
durable.version = saved.record.version;
|
|
@@ -77,8 +85,67 @@ export async function suspendDurable(session, input) {
|
|
|
77
85
|
counters: input.limits.snapshot(),
|
|
78
86
|
});
|
|
79
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Turn-boundary crash-recovery checkpoint (plan 084 Task 1). Called before each provider
|
|
90
|
+
* request when `checkpointPolicy: "every-turn"`; a no-op otherwise, so default-policy runs keep
|
|
91
|
+
* the 0.8.x checkpoint shape and write count unchanged. Pending-decision markers are dropped:
|
|
92
|
+
* at a turn boundary every gated call has been resolved or the run already suspended, and a
|
|
93
|
+
* stale marker must never replay. The recorded `checkpointPolicy` makes the cadence survive
|
|
94
|
+
* into a resumed run, and loop-local state rides along exactly as it does at suspension.
|
|
95
|
+
*/
|
|
96
|
+
export async function checkpointDurableTurn(session, input) {
|
|
97
|
+
if (session.activeDurable?.options.checkpointPolicy !== "every-turn")
|
|
98
|
+
return;
|
|
99
|
+
await writeRunningCheckpoint(session, input);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Fold-boundary checkpoint (plan 086 T3). Called once per turn that added folded bodies — never
|
|
103
|
+
* per turn — when the resolved compiler is durable, so a crash after a fold resumes with the
|
|
104
|
+
* ledger and frontier already on disk. Independent of `checkpointPolicy`: the fold is the
|
|
105
|
+
* durability point that matters for a long single run, not the turn boundary.
|
|
106
|
+
*/
|
|
107
|
+
export async function checkpointDurableFold(session, input) {
|
|
108
|
+
if (!session.attentionDurable)
|
|
109
|
+
return;
|
|
110
|
+
await writeRunningCheckpoint(session, input);
|
|
111
|
+
}
|
|
112
|
+
/** Shared running-checkpoint write for the turn-boundary and fold-boundary triggers. */
|
|
113
|
+
async function writeRunningCheckpoint(session, input) {
|
|
114
|
+
const durable = session.activeDurable;
|
|
115
|
+
if (!durable)
|
|
116
|
+
return;
|
|
117
|
+
const loop = session.activeLoop;
|
|
118
|
+
const loopState = loop?.snapshot ? boundedLoopSnapshot(loop.name, loop.revision ?? "1", loop.snapshot()) : undefined;
|
|
119
|
+
const state = durable.state ??
|
|
120
|
+
initialAgentRunState({
|
|
121
|
+
agent: session.agent,
|
|
122
|
+
options: durable.options,
|
|
123
|
+
runId: input.runId,
|
|
124
|
+
sessionId: session.id,
|
|
125
|
+
leafId: session.currentLeafId,
|
|
126
|
+
model: input.model,
|
|
127
|
+
counters: input.limits.snapshot(),
|
|
128
|
+
deadlineAt: input.limits.deadlineAt,
|
|
129
|
+
status: "running",
|
|
130
|
+
interruptBeforeTool: durable.options.interruptBeforeTool,
|
|
131
|
+
});
|
|
132
|
+
await persistDurable(session, {
|
|
133
|
+
...state,
|
|
134
|
+
leafId: session.currentLeafId,
|
|
135
|
+
status: "running",
|
|
136
|
+
interruption: undefined,
|
|
137
|
+
// The input messages are already in the session store by the time a turn boundary is
|
|
138
|
+
// reached; keeping them would re-append them on a later resume.
|
|
139
|
+
input: undefined,
|
|
140
|
+
pending: undefined,
|
|
141
|
+
pendingCalls: undefined,
|
|
142
|
+
...(loopState ? { loopState } : {}),
|
|
143
|
+
counters: input.limits.snapshot(),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
80
146
|
export async function persistSucceeded(ctx, loopUsage) {
|
|
81
147
|
const { session, runId, runUsage } = ctx;
|
|
148
|
+
const stop = ctx.runStop;
|
|
82
149
|
const usage = runUsage.value() ?? loopUsage;
|
|
83
150
|
if (usage && session.activeLedger) {
|
|
84
151
|
const usageRecord = {
|
|
@@ -97,12 +164,15 @@ export async function persistSucceeded(ctx, loopUsage) {
|
|
|
97
164
|
? await persistDurable(session, {
|
|
98
165
|
...session.activeDurable.state,
|
|
99
166
|
status: "succeeded",
|
|
167
|
+
// Plan 084 Task 2: a host-policy stop is terminal for the run but leaves the frontier
|
|
168
|
+
// intact — the loop state is kept and the state is marked continuable.
|
|
169
|
+
...(stop ? { stopReason: "host_policy", leafId: session.currentLeafId } : {}),
|
|
100
170
|
pending: undefined,
|
|
101
171
|
pendingCalls: undefined,
|
|
102
172
|
nestedRuns: undefined,
|
|
103
173
|
stickyDecisions: undefined,
|
|
104
174
|
interruption: undefined,
|
|
105
|
-
loopState: undefined,
|
|
175
|
+
...(stop ? {} : { loopState: undefined }),
|
|
106
176
|
})
|
|
107
177
|
: undefined;
|
|
108
178
|
session.emit({
|
|
@@ -111,8 +181,17 @@ export async function persistSucceeded(ctx, loopUsage) {
|
|
|
111
181
|
runId,
|
|
112
182
|
usage,
|
|
113
183
|
...(ctx.loopCtx.finishReason ? { finishReason: ctx.loopCtx.finishReason } : {}),
|
|
184
|
+
...(stop?.detail ? { stopDetail: stop.detail } : {}),
|
|
185
|
+
});
|
|
186
|
+
const stopReason = ctx.runStop?.reason ?? ctx.loopCtx.finishReason;
|
|
187
|
+
return session.buildRunResult({
|
|
188
|
+
runId,
|
|
189
|
+
status: "succeeded",
|
|
190
|
+
usage,
|
|
191
|
+
runState,
|
|
192
|
+
...(stopReason ? { stopReason } : {}),
|
|
193
|
+
...(stop?.detail ? { stopDetail: stop.detail } : {}),
|
|
114
194
|
});
|
|
115
|
-
return session.buildRunResult({ runId, status: "succeeded", usage, runState });
|
|
116
195
|
}
|
|
117
196
|
export async function cleanupRun(input) {
|
|
118
197
|
const { session, controller, cleanupSignal, runId, model, startedAt, runStatus, runError } = input;
|
|
@@ -138,6 +217,8 @@ export async function cleanupRun(input) {
|
|
|
138
217
|
status: runStatus,
|
|
139
218
|
startedAt,
|
|
140
219
|
finishedAt: new Date().toISOString(),
|
|
220
|
+
...(input.runStatus === "succeeded" && input.stopReason ? { stopReason: input.stopReason } : {}),
|
|
221
|
+
...(input.runStatus === "succeeded" && input.stopDetail ? { stopDetail: input.stopDetail } : {}),
|
|
141
222
|
abortReason: controller.signal.aborted ? String(controller.signal.reason) : undefined,
|
|
142
223
|
error: runError,
|
|
143
224
|
...(session.activePromptVersion ? { promptVersion: session.activePromptVersion } : {}),
|
|
@@ -160,6 +241,7 @@ export async function cleanupRun(input) {
|
|
|
160
241
|
session.activeLimits?.dispose();
|
|
161
242
|
session.activeToolNames = undefined;
|
|
162
243
|
session.activeLimits = undefined;
|
|
244
|
+
session.activeRecentToolCalls = undefined;
|
|
163
245
|
session.activeLimitOutputBuffer = false;
|
|
164
246
|
session.activeRedactor = undefined;
|
|
165
247
|
session.activeProvider = undefined;
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
/** Provider-round phase of runInternal (plan 059). */
|
|
2
|
-
import type { ProviderRequest, ProviderTurnResult, RunOptions, Usage } from "../../contracts.js";
|
|
2
|
+
import type { ModelConfig, ProviderRequest, ProviderTurnResult, RunOptions, ToolResult, Usage } from "../../contracts.js";
|
|
3
3
|
import type { RoundContext, SessionHost } from "./types.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
/** Resolve the per-request input cap for turn-budget metadata (plan 087 T1). A model without a
|
|
5
|
+
* derivable cap (or a bad attention setting on an unrelated run) omits the field instead of
|
|
6
|
+
* failing an emitting turn; the attention compiler, when enabled, is the cap authority. */
|
|
7
|
+
export declare function resolveTurnInputCap(session: SessionHost, model: ModelConfig): number | undefined;
|
|
8
|
+
export declare function recordProviderUsage(ctx: RoundContext, turnUsage: Usage | undefined, turn: number, attempt: number, request?: ProviderRequest): Promise<Usage | undefined>;
|
|
9
|
+
/**
|
|
10
|
+
* Plan 096: host middleware may answer the turn deterministically at the `beforeProviderTurn` seam —
|
|
11
|
+
* no provider request, no usage, mandatory provenance. `undefined` sends the turn to the provider
|
|
12
|
+
* unchanged; a malformed answer fails the run closed instead of falling through to the provider.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveDeterministicTurn(session: SessionHost, request: ProviderRequest, runId: string, turn: number, signal: AbortSignal, toolResults?: readonly ToolResult[]): Promise<ProviderTurnResult | undefined>;
|
|
15
|
+
export declare function generateWithRetry(session: SessionHost, request: ProviderRequest, runId: string, options: RunOptions, signal: AbortSignal, requestSecrets?: readonly (string | undefined)[], turn?: number, recordUsage?: (usage: Usage | undefined, turn: number, attempt: number) => Promise<Usage | undefined>, toolResults?: readonly ToolResult[]): Promise<ProviderTurnResult>;
|
|
16
|
+
export declare function generateProviderTurn(session: SessionHost, request: ProviderRequest, runId: string, signal: AbortSignal, secrets?: readonly (string | undefined)[], turn?: number, attempt?: number, recordUsage?: (usage: Usage | undefined, turn: number, attempt: number) => Promise<Usage | undefined>, toolResults?: readonly ToolResult[]): Promise<ProviderTurnResult>;
|
|
@@ -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
|
-
import { providerToolCallDeltaContent } from "../../provider-events.js";
|
|
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,19 +117,111 @@ 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
|
-
export async function generateWithRetry(session, request, runId, options, signal, requestSecrets = [], turn = 1, recordUsage) {
|
|
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);
|
|
75
220
|
const secrets = [...requestSecrets, ...(retry?.secrets ?? [])];
|
|
76
221
|
const policy = retry?.policy ?? (retry ? createDefaultRetryPolicy(retry) : undefined);
|
|
77
222
|
for (let attempt = 1;; attempt += 1) {
|
|
78
223
|
try {
|
|
79
|
-
return await generateProviderTurn(session, request, runId, signal, secrets, turn, attempt, recordUsage);
|
|
224
|
+
return await generateProviderTurn(session, request, runId, signal, secrets, turn, attempt, recordUsage, toolResults);
|
|
80
225
|
}
|
|
81
226
|
catch (error) {
|
|
82
227
|
if (error instanceof GuardrailError || isSteerSoftInterrupt(error))
|
|
@@ -100,7 +245,7 @@ export async function generateWithRetry(session, request, runId, options, signal
|
|
|
100
245
|
}
|
|
101
246
|
}
|
|
102
247
|
}
|
|
103
|
-
export async function generateProviderTurn(session, request, runId, signal, secrets = [], turn = 1, attempt = 1, recordUsage) {
|
|
248
|
+
export async function generateProviderTurn(session, request, runId, signal, secrets = [], turn = 1, attempt = 1, recordUsage, toolResults = []) {
|
|
104
249
|
session.activeLimits.charge("maxProviderAttempts");
|
|
105
250
|
session.activeLimits.charge("maxRequestBytes", jsonBytes(request));
|
|
106
251
|
const startedAt = performance.now();
|
|
@@ -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") {
|
|
@@ -189,7 +339,13 @@ export async function generateProviderTurn(session, request, runId, signal, secr
|
|
|
189
339
|
stage: "output",
|
|
190
340
|
guardrails: session.activeGuardrails,
|
|
191
341
|
value: { content, calls, messageId, started, usage },
|
|
192
|
-
context: {
|
|
342
|
+
context: {
|
|
343
|
+
sessionId: session.id,
|
|
344
|
+
runId,
|
|
345
|
+
metadata: session.activeMetadata ?? {},
|
|
346
|
+
signal: turnAbort.signal,
|
|
347
|
+
toolResults,
|
|
348
|
+
},
|
|
193
349
|
redactor: session.activeRedactor,
|
|
194
350
|
emit: (event) => session.emit(event),
|
|
195
351
|
}));
|
|
@@ -203,10 +359,15 @@ export async function generateProviderTurn(session, request, runId, signal, secr
|
|
|
203
359
|
sessionId: session.id,
|
|
204
360
|
runId,
|
|
205
361
|
turn,
|
|
206
|
-
metadata: buildMetadata({
|
|
207
|
-
|
|
362
|
+
metadata: buildMetadata({
|
|
363
|
+
latencyMs,
|
|
364
|
+
stopReason: normalizeTurnStopReason(nativeStopReason, calls),
|
|
365
|
+
budgets: turnBudgets(session, request.model, effectiveUsage),
|
|
366
|
+
...cacheMetadata(effectiveUsage),
|
|
367
|
+
}),
|
|
368
|
+
usage: effectiveUsage,
|
|
208
369
|
});
|
|
209
|
-
return { content, calls, messageId, started, usage };
|
|
370
|
+
return { content, calls, messageId, started, usage: effectiveUsage };
|
|
210
371
|
}
|
|
211
372
|
catch (error) {
|
|
212
373
|
if (isSteerSoftInterrupt(error) || isSteerSoftInterrupt(turnAbort.signal.reason)) {
|
|
@@ -217,21 +378,32 @@ export async function generateProviderTurn(session, request, runId, signal, secr
|
|
|
217
378
|
sessionId: session.id,
|
|
218
379
|
runId,
|
|
219
380
|
turn,
|
|
220
|
-
metadata: buildMetadata({
|
|
221
|
-
|
|
381
|
+
metadata: buildMetadata({
|
|
382
|
+
latencyMs,
|
|
383
|
+
stopReason: "abort",
|
|
384
|
+
budgets: turnBudgets(session, request.model, effectiveUsage),
|
|
385
|
+
...cacheMetadata(effectiveUsage),
|
|
386
|
+
}),
|
|
387
|
+
usage: effectiveUsage,
|
|
222
388
|
});
|
|
223
389
|
throw new SteerSoftInterrupt();
|
|
224
390
|
}
|
|
225
391
|
const latencyMs = Math.round(performance.now() - startedAt);
|
|
226
|
-
const info = error instanceof ProviderTurnFailure ? redactSecrets(error.info, secrets) :
|
|
392
|
+
const info = error instanceof ProviderTurnFailure ? redactSecrets(error.info, secrets) : providerError(error, secrets).error;
|
|
227
393
|
await recordTurnUsage();
|
|
228
394
|
session.emit({
|
|
229
395
|
type: "provider_turn_finished",
|
|
230
396
|
sessionId: session.id,
|
|
231
397
|
runId,
|
|
232
398
|
turn,
|
|
233
|
-
metadata: buildMetadata({
|
|
234
|
-
|
|
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,
|
|
235
407
|
error: info,
|
|
236
408
|
});
|
|
237
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);
|
|
@@ -251,8 +269,10 @@ export function bindDispatchToolCall(ctx) {
|
|
|
251
269
|
if (ctx.session.activeGatedRound?.has(call.id)) {
|
|
252
270
|
return { toolCallId: call.id, name: call.name, metadata: { approvalPending: true } };
|
|
253
271
|
}
|
|
272
|
+
ctx.toolCalls += 1;
|
|
273
|
+
recordRecentToolCall(ctx.session, call);
|
|
254
274
|
try {
|
|
255
|
-
|
|
275
|
+
const result = await dispatchToolCall({
|
|
256
276
|
call,
|
|
257
277
|
registry: ctx.registry,
|
|
258
278
|
context: {
|
|
@@ -278,7 +298,7 @@ export function bindDispatchToolCall(ctx) {
|
|
|
278
298
|
ownership: ctx.session.activeOwnership,
|
|
279
299
|
identity: ctx.session.activeIdentity,
|
|
280
300
|
guardrails: ctx.session.activeGuardrails,
|
|
281
|
-
...(ctx
|
|
301
|
+
...dispatchFilter(ctx),
|
|
282
302
|
limitTracker: ctx.limits,
|
|
283
303
|
beforeExecute: async (mediatedCall) => {
|
|
284
304
|
const durable = ctx.session.activeDurable;
|
|
@@ -329,6 +349,8 @@ export function bindDispatchToolCall(ctx) {
|
|
|
329
349
|
},
|
|
330
350
|
validate: ctx.validate,
|
|
331
351
|
});
|
|
352
|
+
ctx.toolResults.push(result);
|
|
353
|
+
return result;
|
|
332
354
|
}
|
|
333
355
|
catch (error) {
|
|
334
356
|
if (error instanceof AgentDelegationSuspendedError && !error.toolCall)
|
|
@@ -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, AgentLoopStrategy, AgentRunResult, AIProvider, ErrorInfo, Guardrails, LoopContext, Message, ModelConfig, OwnershipScope, PendingDecision, PromptVersionRef, ProviderRequest, RunLedger, RunOptions, SessionEntry, SessionStore, Skill, ToolDefinition, ToolEffectStore, ToolRegistry, 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;
|
|
@@ -87,6 +108,11 @@ export type SessionHost = {
|
|
|
87
108
|
snapshot(): Promise<SessionContextSnapshot>;
|
|
88
109
|
};
|
|
89
110
|
export declare function asSessionHost(session: unknown): SessionHost;
|
|
111
|
+
/** Why a run's loop ended, plus the host's stop detail when `RunOptions.turnPolicy` stopped it. */
|
|
112
|
+
export type RunStopInfo = {
|
|
113
|
+
readonly reason: AgentFinishReason;
|
|
114
|
+
readonly detail?: string;
|
|
115
|
+
};
|
|
90
116
|
export type RoundContext = {
|
|
91
117
|
session: SessionHost;
|
|
92
118
|
input: AgentInput;
|
|
@@ -111,12 +137,20 @@ export type RoundContext = {
|
|
|
111
137
|
loop: AgentLoopStrategy;
|
|
112
138
|
toolConcurrency: number;
|
|
113
139
|
toolsDisclosure: import("../../tool-search.js").ToolsDisclosure;
|
|
140
|
+
/** Per-turn dispatch overlay; undefined when `toolNarrowing` is unset. */
|
|
141
|
+
turnAllow?: readonly string[];
|
|
114
142
|
assembledTurn: boolean;
|
|
115
143
|
artifactFinished: boolean;
|
|
116
144
|
artifactFailedInfo: {
|
|
117
145
|
message: string;
|
|
118
146
|
code?: string | number;
|
|
119
147
|
} | undefined;
|
|
148
|
+
/** Host tool calls dispatched in this run; the turn-boundary context's `toolCalls` (plan 084 Task 2). */
|
|
149
|
+
toolCalls: number;
|
|
150
|
+
/** Completed host tool results from this run, for output evidence guardrails (plan 084 Task 5). */
|
|
151
|
+
toolResults: ToolResult[];
|
|
152
|
+
/** Set when a `RunOptions.turnPolicy` stop ended the loop (plan 084 Task 2). */
|
|
153
|
+
runStop?: RunStopInfo;
|
|
120
154
|
runUsage: {
|
|
121
155
|
add(usage: Usage): void;
|
|
122
156
|
value(): Usage | undefined;
|