@superdurable/dex-agents 0.1.0 → 0.3.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/README.md +1608 -64
- package/dist/src/agent-built-in-tools.d.ts +81 -0
- package/dist/src/agent-built-in-tools.js +246 -0
- package/dist/src/agent-built-in-tools.js.map +1 -0
- package/dist/src/agent-context-compaction.d.ts +254 -0
- package/dist/src/agent-context-compaction.js +287 -0
- package/dist/src/agent-context-compaction.js.map +1 -0
- package/dist/src/agent-framework-runner.d.ts +456 -16
- package/dist/src/agent-framework-runner.js +4 -3
- package/dist/src/agent-framework-runner.js.map +1 -1
- package/dist/src/agent-plans.d.ts +48 -0
- package/dist/src/agent-plans.js +86 -0
- package/dist/src/agent-plans.js.map +1 -0
- package/dist/src/agent-session-cancellation-steps.d.ts +28 -0
- package/dist/src/agent-session-cancellation-steps.js +154 -0
- package/dist/src/agent-session-cancellation-steps.js.map +1 -0
- package/dist/src/agent-session-codecs.d.ts +65 -4
- package/dist/src/agent-session-codecs.js +343 -8
- package/dist/src/agent-session-codecs.js.map +1 -1
- package/dist/src/agent-session-failure.d.ts +58 -0
- package/dist/src/agent-session-failure.js +126 -0
- package/dist/src/agent-session-failure.js.map +1 -0
- package/dist/src/agent-session-flow-graph-cli.d.ts +2 -0
- package/dist/src/agent-session-flow-graph-cli.js +47 -0
- package/dist/src/agent-session-flow-graph-cli.js.map +1 -0
- package/dist/src/agent-session-flow-graph.d.ts +38 -0
- package/dist/src/agent-session-flow-graph.js +54 -0
- package/dist/src/agent-session-flow-graph.js.map +1 -0
- package/dist/src/agent-session-flow-graph.json +2187 -0
- package/dist/src/agent-session-flow.d.ts +317 -28
- package/dist/src/agent-session-flow.js +373 -21
- package/dist/src/agent-session-flow.js.map +1 -1
- package/dist/src/agent-session-persistence.d.ts +81 -4
- package/dist/src/agent-session-persistence.js +33 -2
- package/dist/src/agent-session-persistence.js.map +1 -1
- package/dist/src/agent-session-settings.d.ts +58 -0
- package/dist/src/agent-session-settings.js +81 -0
- package/dist/src/agent-session-settings.js.map +1 -0
- package/dist/src/agent-session-spend-limit.d.ts +156 -0
- package/dist/src/agent-session-spend-limit.js +42 -0
- package/dist/src/agent-session-spend-limit.js.map +1 -0
- package/dist/src/agent-session-start.d.ts +49 -0
- package/dist/src/agent-session-start.js +67 -0
- package/dist/src/agent-session-start.js.map +1 -0
- package/dist/src/agent-session-step-options.d.ts +78 -0
- package/dist/src/agent-session-step-options.js +71 -0
- package/dist/src/agent-session-step-options.js.map +1 -0
- package/dist/src/agent-session-step-types.d.ts +20 -0
- package/dist/src/agent-session-step-types.js +28 -0
- package/dist/src/agent-session-step-types.js.map +1 -0
- package/dist/src/agent-session-steps.d.ts +103 -8
- package/dist/src/agent-session-steps.js +997 -197
- package/dist/src/agent-session-steps.js.map +1 -1
- package/dist/src/agent-session-tracer.d.ts +61 -0
- package/dist/src/agent-session-tracer.js +608 -0
- package/dist/src/agent-session-tracer.js.map +1 -0
- package/dist/src/agent-session-transitions.d.ts +200 -26
- package/dist/src/agent-session-transitions.js +732 -32
- package/dist/src/agent-session-transitions.js.map +1 -1
- package/dist/src/agent-session-values.d.ts +696 -30
- package/dist/src/agent-session-values.js +39 -4
- package/dist/src/agent-session-values.js.map +1 -1
- package/dist/src/agent-session-wait-steps.d.ts +53 -0
- package/dist/src/agent-session-wait-steps.js +389 -0
- package/dist/src/agent-session-wait-steps.js.map +1 -0
- package/dist/src/agent-tracing-options.d.ts +107 -0
- package/dist/src/agent-tracing-options.js +20 -0
- package/dist/src/agent-tracing-options.js.map +1 -0
- package/dist/src/ai-sdk/ai-sdk-model-client.d.ts +40 -0
- package/dist/src/ai-sdk/ai-sdk-model-client.js +235 -0
- package/dist/src/ai-sdk/ai-sdk-model-client.js.map +1 -0
- package/dist/src/ai-sdk/index.d.ts +1 -0
- package/dist/src/ai-sdk/index.js +9 -0
- package/dist/src/ai-sdk/index.js.map +1 -0
- package/dist/src/index.d.ts +14 -3
- package/dist/src/index.js +12 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/index.d.ts +3 -0
- package/dist/src/mcp/index.js +10 -0
- package/dist/src/mcp/index.js.map +1 -0
- package/dist/src/mcp/mcp-resource-and-prompt-tools.d.ts +29 -0
- package/dist/src/mcp/mcp-resource-and-prompt-tools.js +185 -0
- package/dist/src/mcp/mcp-resource-and-prompt-tools.js.map +1 -0
- package/dist/src/mcp/mcp-server-config.d.ts +86 -0
- package/dist/src/mcp/mcp-server-config.js +38 -0
- package/dist/src/mcp/mcp-server-config.js.map +1 -0
- package/dist/src/mcp/mcp-tool-source.d.ts +470 -0
- package/dist/src/mcp/mcp-tool-source.js +1204 -0
- package/dist/src/mcp/mcp-tool-source.js.map +1 -0
- package/dist/src/stepwise/agent-definition.d.ts +166 -0
- package/dist/src/stepwise/agent-definition.js +9 -0
- package/dist/src/stepwise/agent-definition.js.map +1 -0
- package/dist/src/stepwise/function-tool.d.ts +130 -0
- package/dist/src/stepwise/function-tool.js +75 -0
- package/dist/src/stepwise/function-tool.js.map +1 -0
- package/dist/src/stepwise/index.d.ts +8 -0
- package/dist/src/stepwise/index.js +13 -0
- package/dist/src/stepwise/index.js.map +1 -0
- package/dist/src/stepwise/json-schema-validation.d.ts +9 -0
- package/dist/src/stepwise/json-schema-validation.js +141 -0
- package/dist/src/stepwise/json-schema-validation.js.map +1 -0
- package/dist/src/stepwise/model-client.d.ts +194 -0
- package/dist/src/stepwise/model-client.js +9 -0
- package/dist/src/stepwise/model-client.js.map +1 -0
- package/dist/src/stepwise/scripted-model-client.d.ts +99 -0
- package/dist/src/stepwise/scripted-model-client.js +156 -0
- package/dist/src/stepwise/scripted-model-client.js.map +1 -0
- package/dist/src/stepwise/stepwise-agent-runner.d.ts +171 -0
- package/dist/src/stepwise/stepwise-agent-runner.js +777 -0
- package/dist/src/stepwise/stepwise-agent-runner.js.map +1 -0
- package/dist/src/stepwise/stepwise-agent-session-flow.d.ts +35 -0
- package/dist/src/stepwise/stepwise-agent-session-flow.js +57 -0
- package/dist/src/stepwise/stepwise-agent-session-flow.js.map +1 -0
- package/dist/src/stepwise/stepwise-input-items.d.ts +12 -0
- package/dist/src/stepwise/stepwise-input-items.js +172 -0
- package/dist/src/stepwise/stepwise-input-items.js.map +1 -0
- package/dist/src/stepwise/tool-source.d.ts +103 -0
- package/dist/src/stepwise/tool-source.js +9 -0
- package/dist/src/stepwise/tool-source.js.map +1 -0
- package/dist/src/testing/agent-session-test-client.d.ts +65 -8
- package/dist/src/testing/agent-session-test-client.js +92 -22
- package/dist/src/testing/agent-session-test-client.js.map +1 -1
- package/dist/src/testing/context-window.d.ts +194 -0
- package/dist/src/testing/context-window.js +360 -0
- package/dist/src/testing/context-window.js.map +1 -0
- package/dist/src/testing/index.d.ts +2 -0
- package/dist/src/testing/index.js +2 -0
- package/dist/src/testing/index.js.map +1 -1
- package/dist/src/testing/private-dex-engine.d.ts +9 -0
- package/dist/src/testing/private-dex-engine.js +9 -1
- package/dist/src/testing/private-dex-engine.js.map +1 -1
- package/dist/src/testing/scripted-model-client.d.ts +1 -0
- package/dist/src/testing/scripted-model-client.js +10 -0
- package/dist/src/testing/scripted-model-client.js.map +1 -0
- package/dist/src/ui-stream/agent-event-json.d.ts +30 -0
- package/dist/src/ui-stream/agent-event-json.js +64 -0
- package/dist/src/ui-stream/agent-event-json.js.map +1 -0
- package/dist/src/ui-stream/agent-event-sse.d.ts +155 -0
- package/dist/src/ui-stream/agent-event-sse.js +167 -0
- package/dist/src/ui-stream/agent-event-sse.js.map +1 -0
- package/dist/src/ui-stream/agent-event-stream-positions.d.ts +42 -0
- package/dist/src/ui-stream/agent-event-stream-positions.js +153 -0
- package/dist/src/ui-stream/agent-event-stream-positions.js.map +1 -0
- package/dist/src/ui-stream/agent-session-record-reader.d.ts +74 -0
- package/dist/src/ui-stream/agent-session-record-reader.js +246 -0
- package/dist/src/ui-stream/agent-session-record-reader.js.map +1 -0
- package/dist/src/ui-stream/agent-ui-message-stream-responses.d.ts +219 -0
- package/dist/src/ui-stream/agent-ui-message-stream-responses.js +441 -0
- package/dist/src/ui-stream/agent-ui-message-stream-responses.js.map +1 -0
- package/dist/src/ui-stream/agent-ui-message-stream.d.ts +138 -0
- package/dist/src/ui-stream/agent-ui-message-stream.js +695 -0
- package/dist/src/ui-stream/agent-ui-message-stream.js.map +1 -0
- package/dist/src/ui-stream/agent-ui-message-types.d.ts +238 -0
- package/dist/src/ui-stream/agent-ui-message-types.js +57 -0
- package/dist/src/ui-stream/agent-ui-message-types.js.map +1 -0
- package/dist/src/ui-stream/agent-ui-messages.d.ts +68 -0
- package/dist/src/ui-stream/agent-ui-messages.js +222 -0
- package/dist/src/ui-stream/agent-ui-messages.js.map +1 -0
- package/dist/src/ui-stream/agent-ui-stream-cursor.d.ts +64 -0
- package/dist/src/ui-stream/agent-ui-stream-cursor.js +186 -0
- package/dist/src/ui-stream/agent-ui-stream-cursor.js.map +1 -0
- package/dist/src/ui-stream/index.d.ts +14 -0
- package/dist/src/ui-stream/index.js +22 -0
- package/dist/src/ui-stream/index.js.map +1 -0
- package/dist/src/ui-stream/server-sent-event-responses.d.ts +6 -0
- package/dist/src/ui-stream/server-sent-event-responses.js +34 -0
- package/dist/src/ui-stream/server-sent-event-responses.js.map +1 -0
- package/package.json +44 -5
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BuiltInTool } from "./agent-built-in-tools.js";
|
|
2
|
+
import type { ContextSummaryRequest, ContextSummaryResult } from "./agent-context-compaction.js";
|
|
3
|
+
import type { AgentMessage, AgentPlan, AgentToolCall, AgentToolCallRecord, AgentToolCallStatus, AgentUsage, ContextSummary, SessionSettings, FrameworkMessage, InteractionMode, QuestionAnswer, ToolEffect } from "./agent-session-values.js";
|
|
2
4
|
/**
|
|
3
5
|
* Per-tool override of the effect and approval defaults.
|
|
4
6
|
*
|
|
@@ -113,13 +115,22 @@ export interface AgentTurnContext {
|
|
|
113
115
|
/** Turn ID, `turn-<n>`. */
|
|
114
116
|
readonly turnId: string;
|
|
115
117
|
/**
|
|
116
|
-
* One-based `RunModel` attempt. A rerun after a Worker crash
|
|
117
|
-
*
|
|
118
|
+
* One-based `RunModel` attempt. A rerun after a Worker crash gets the next attempt, but an attempt whose
|
|
119
|
+
* stream half-closed before any output returns as not run and keeps its number, so do not rely on it to
|
|
120
|
+
* detect reruns.
|
|
118
121
|
*/
|
|
119
122
|
readonly attempt: number;
|
|
123
|
+
/**
|
|
124
|
+
* Dex Step execution ID of this `RunModel` Step, shared by all of its attempts.
|
|
125
|
+
*
|
|
126
|
+
* The session always sets this field. It is optional only so that code that builds a context by hand
|
|
127
|
+
* keeps compiling.
|
|
128
|
+
*/
|
|
129
|
+
readonly stepExecutionId?: string;
|
|
120
130
|
/**
|
|
121
131
|
* Every stored session message in ascending sequence order, including the user message that
|
|
122
|
-
* started this turn. Replay each `frameworkItem` to the framework unchanged.
|
|
132
|
+
* started this turn. Replay each `frameworkItem` to the framework unchanged. After compaction, only the
|
|
133
|
+
* messages after {@link contextSummary}.
|
|
123
134
|
*/
|
|
124
135
|
readonly messages: readonly AgentMessage[];
|
|
125
136
|
/**
|
|
@@ -141,6 +152,52 @@ export interface AgentTurnContext {
|
|
|
141
152
|
readonly cancellationSignal: AbortSignal;
|
|
142
153
|
/** Absolute deadline of the current attempt, or `undefined` when Dex supplied none. */
|
|
143
154
|
readonly deadline: Date | undefined;
|
|
155
|
+
/**
|
|
156
|
+
* Built-in tools enabled for this session through {@link AgentSessionOptions.builtInTools}. Offer
|
|
157
|
+
* their definitions from {@link builtInToolDefinitions} to the model; the session handles their calls.
|
|
158
|
+
*
|
|
159
|
+
* The session always sets this field. It is optional only so that code that builds a context by hand,
|
|
160
|
+
* such as a unit test, keeps compiling; treat `undefined` as no built-in tools.
|
|
161
|
+
*/
|
|
162
|
+
readonly enabledBuiltInTools?: ReadonlySet<BuiltInTool>;
|
|
163
|
+
/**
|
|
164
|
+
* Explicit policies by tool name from {@link AgentSessionOptions.toolPolicies}, the same map
|
|
165
|
+
* {@link resolveToolPolicy} applies first. A runner whose framework sets its own approval default, such as
|
|
166
|
+
* a tool's `requiresApproval`, applies that default only to tools without an explicit policy here.
|
|
167
|
+
* Optional for the same reason as {@link enabledBuiltInTools}; treat `undefined` as no policies.
|
|
168
|
+
*/
|
|
169
|
+
readonly toolPolicies?: Readonly<Record<string, ToolPolicy>>;
|
|
170
|
+
/**
|
|
171
|
+
* {@link AgentSessionOptions.defaultToolEffect}, the effect of a tool without a policy or framework
|
|
172
|
+
* metadata. Optional for the same reason as {@link enabledBuiltInTools}.
|
|
173
|
+
*/
|
|
174
|
+
readonly defaultToolEffect?: ToolEffect;
|
|
175
|
+
/**
|
|
176
|
+
* The turn's {@link AgentState.interactionMode}. A runner with {@link AgentFrameworkRunner.supportsPlanMode}
|
|
177
|
+
* offers only `write_todos` in a `planning` turn. The session always sets it; treat `undefined` as `chat`.
|
|
178
|
+
*/
|
|
179
|
+
readonly interactionMode?: InteractionMode;
|
|
180
|
+
/**
|
|
181
|
+
* The {@link AgentPlan} as committed before this model call, or `null` before `write_todos` first
|
|
182
|
+
* succeeded. Show it to the model with {@link buildPlanNote}. The session always sets it; treat
|
|
183
|
+
* `undefined` as `null`.
|
|
184
|
+
*/
|
|
185
|
+
readonly plan?: AgentPlan | null;
|
|
186
|
+
/**
|
|
187
|
+
* The summary of the messages before {@link messages}, or `null`. Only a runner that implements the
|
|
188
|
+
* compaction methods, such as {@link AgentFrameworkRunner.summarizeContext}, receives one; put its text
|
|
189
|
+
* before {@link messages} in the model input. Optional for the same reason as {@link enabledBuiltInTools};
|
|
190
|
+
* treat `undefined` as no summary.
|
|
191
|
+
*/
|
|
192
|
+
readonly contextSummary?: ContextSummary | null;
|
|
193
|
+
/**
|
|
194
|
+
* The {@link SessionSettings} this turn started with, such as `{ model: "gpt-5-mini" }`. Use them to choose
|
|
195
|
+
* the model or the instructions of each model call. `update_session_settings` changes them from the next turn
|
|
196
|
+
* on, so every model call of one turn sees the same value, retries included. Empty when the session has no
|
|
197
|
+
* settings, such as a session started on dex-agents 0.1.0. The session always sets it; it is optional for the
|
|
198
|
+
* same reason as {@link enabledBuiltInTools}, so treat `undefined` as `{}`.
|
|
199
|
+
*/
|
|
200
|
+
readonly sessionSettings?: SessionSettings;
|
|
144
201
|
/**
|
|
145
202
|
* Returns the effective policy of a tool; see {@link resolveToolPolicy} for the precedence.
|
|
146
203
|
* Pass it unchanged in {@link DeferredToolCall.policy}.
|
|
@@ -178,30 +235,89 @@ export interface DeferredToolCall {
|
|
|
178
235
|
readonly arguments: string;
|
|
179
236
|
/** Policy from {@link AgentTurnContext.resolveToolPolicy}; it decides approval and the tool Step. */
|
|
180
237
|
readonly policy: ResolvedToolPolicy;
|
|
238
|
+
/**
|
|
239
|
+
* Opaque text that the tool's source stores on the call's record, such as which MCP server and tool
|
|
240
|
+
* to call. The tool Step returns it in {@link DeferredToolExecution.toolCall}, so the source resolves
|
|
241
|
+
* the tool without listing it again. Omit it to store nothing.
|
|
242
|
+
*/
|
|
243
|
+
readonly toolSourceReference?: string;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Model and response of one model call, returned in {@link TurnCompleted} or {@link ToolCallsRequested}
|
|
247
|
+
* for tracing.
|
|
248
|
+
*
|
|
249
|
+
* The session never stores it: it only names the `chat` span and sets its GenAI attributes. Omit a
|
|
250
|
+
* field when the framework does not expose it.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```ts
|
|
254
|
+
* const modelCallMetadata: ModelCallMetadata = {
|
|
255
|
+
* requestModel: "gpt-5",
|
|
256
|
+
* responseModel: "gpt-5-2026-08-07",
|
|
257
|
+
* providerName: "openai",
|
|
258
|
+
* responseId: "resp_123",
|
|
259
|
+
* finishReasons: ["tool_calls"],
|
|
260
|
+
* };
|
|
261
|
+
* return { kind: "tool_calls_requested", frameworkRunState, toolCalls, usage, modelCallMetadata };
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
export interface ModelCallMetadata {
|
|
265
|
+
/**
|
|
266
|
+
* Model name the call requested, such as `"gpt-5"`. It becomes `gen_ai.request.model` and the span
|
|
267
|
+
* name `chat <requestModel>`.
|
|
268
|
+
*/
|
|
269
|
+
readonly requestModel?: string;
|
|
270
|
+
/** Model name the provider reported. */
|
|
271
|
+
readonly responseModel?: string;
|
|
272
|
+
/**
|
|
273
|
+
* GenAI provider, such as `"openai"`, `"anthropic"`, or `"gcp.gemini"`. Use the well-known
|
|
274
|
+
* `gen_ai.provider.name` value when one applies.
|
|
275
|
+
*/
|
|
276
|
+
readonly providerName?: string;
|
|
277
|
+
/** Provider response ID. */
|
|
278
|
+
readonly responseId?: string;
|
|
279
|
+
/** Provider finish reasons, one per returned choice. */
|
|
280
|
+
readonly finishReasons?: readonly string[];
|
|
181
281
|
}
|
|
182
282
|
/** Outcome of a model call that produced the turn's final answer. */
|
|
183
283
|
export interface TurnCompleted {
|
|
184
284
|
/** Discriminator. */
|
|
185
285
|
readonly kind: "completed";
|
|
186
286
|
/**
|
|
187
|
-
* Every message the turn
|
|
188
|
-
*
|
|
189
|
-
*
|
|
287
|
+
* Every message of the turn that the session has not stored yet, in order: model output, tool
|
|
288
|
+
* requests, tool results, and the final answer. The session appends them in one commit and deletes the
|
|
289
|
+
* turn's tool call records.
|
|
290
|
+
*
|
|
291
|
+
* A runner that never sets {@link ToolCallsRequested.newMessages} returns every message the turn
|
|
292
|
+
* produced after its user message, across all of its model calls. A runner that stores messages
|
|
293
|
+
* incrementally returns only the messages after the ones it already returned.
|
|
190
294
|
*/
|
|
191
295
|
readonly newMessages: readonly FrameworkMessage[];
|
|
192
296
|
/** Usage of this model call only; the session adds it to the cumulative usage. */
|
|
193
297
|
readonly usage: AgentUsage;
|
|
298
|
+
/** Model and response of this model call, for the `chat` span. When omitted, the span is named `chat`. */
|
|
299
|
+
readonly modelCallMetadata?: ModelCallMetadata;
|
|
194
300
|
}
|
|
195
301
|
/** Outcome of a model call that requested tool calls. */
|
|
196
302
|
export interface ToolCallsRequested {
|
|
197
303
|
/** Discriminator. */
|
|
198
304
|
readonly kind: "tool_calls_requested";
|
|
199
305
|
/**
|
|
200
|
-
* Non-empty serialized framework state from which the next `RunModel` continues the turn
|
|
201
|
-
*
|
|
202
|
-
*
|
|
306
|
+
* Non-empty serialized framework state from which the next `RunModel` continues the turn. The
|
|
307
|
+
* session keeps this value opaquely in `FrameworkRunState`. A runner without
|
|
308
|
+
* {@link newMessages} includes the messages this turn has produced so far; a runner with them keeps
|
|
309
|
+
* only what the stored messages cannot rebuild, so the value does not grow with the turn.
|
|
203
310
|
*/
|
|
204
311
|
readonly frameworkRunState: string;
|
|
312
|
+
/**
|
|
313
|
+
* Messages of the turn to store now, in the same commit that records the tool calls. Defaults to none.
|
|
314
|
+
*
|
|
315
|
+
* Return the previous model response's tool results and this model response, so the turn's
|
|
316
|
+
* transcript is stored while its tools run. A runner that sets this field must implement
|
|
317
|
+
* {@link AgentFrameworkRunner.buildUnfinishedTurnMessages}; the session fails the model call
|
|
318
|
+
* otherwise. The next {@link AgentTurnContext.messages} include these messages.
|
|
319
|
+
*/
|
|
320
|
+
readonly newMessages?: readonly FrameworkMessage[];
|
|
205
321
|
/**
|
|
206
322
|
* Every tool call of the model response, at least one. Each runs in its own Step, in parallel. Do not
|
|
207
323
|
* repeat a call that already has a record in {@link AgentTurnContext.toolCalls}; the session rejects
|
|
@@ -210,6 +326,8 @@ export interface ToolCallsRequested {
|
|
|
210
326
|
readonly toolCalls: readonly DeferredToolCall[];
|
|
211
327
|
/** Usage of this model call only. */
|
|
212
328
|
readonly usage: AgentUsage;
|
|
329
|
+
/** Model and response of this model call, for the `chat` span. When omitted, the span is named `chat`. */
|
|
330
|
+
readonly modelCallMetadata?: ModelCallMetadata;
|
|
213
331
|
}
|
|
214
332
|
/** Result of {@link AgentFrameworkRunner.runModelStep}. */
|
|
215
333
|
export type AgentTurnOutcome = TurnCompleted | ToolCallsRequested;
|
|
@@ -236,17 +354,200 @@ export interface DeferredToolExecution {
|
|
|
236
354
|
readonly cancellationSignal: AbortSignal;
|
|
237
355
|
/** Absolute deadline of the current attempt, or `undefined`. */
|
|
238
356
|
readonly deadline: Date | undefined;
|
|
357
|
+
/**
|
|
358
|
+
* Answers to the questions this call asked by returning {@link ToolInputRequested}, oldest first, or
|
|
359
|
+
* empty. The opaque continuation of the last question is in `toolCall.inputContinuation`.
|
|
360
|
+
*
|
|
361
|
+
* The session always sets this field. It is optional only so that code that builds an execution by
|
|
362
|
+
* hand, such as a unit test, keeps compiling; treat `undefined` as no answers.
|
|
363
|
+
*/
|
|
364
|
+
readonly inputAnswers?: readonly QuestionAnswer[];
|
|
365
|
+
/**
|
|
366
|
+
* Whether the runner implements {@link AgentFrameworkRunner.pollToolTask}, so the tool may return
|
|
367
|
+
* {@link ToolTaskStarted}. When it is not `true`, run remote work to its end inside the call instead.
|
|
368
|
+
* Optional for the same reason as {@link inputAnswers}; treat `undefined` as `false`.
|
|
369
|
+
*/
|
|
370
|
+
readonly supportsToolTasks?: boolean;
|
|
239
371
|
/**
|
|
240
372
|
* Records a heartbeat. The session already records one every 20 seconds.
|
|
241
373
|
* @returns A Promise that resolves when the Worker accepted the heartbeat.
|
|
242
374
|
*/
|
|
243
375
|
heartbeat(): Promise<void>;
|
|
376
|
+
/**
|
|
377
|
+
* The checkpoint an earlier attempt of this call saved with {@link saveHeartbeatCheckpoint}, absent
|
|
378
|
+
* when none did. Use it to resume work that the earlier attempt started, such as polling a
|
|
379
|
+
* long-running job, instead of starting it again.
|
|
380
|
+
*/
|
|
381
|
+
readonly heartbeatCheckpoint?: string;
|
|
382
|
+
/**
|
|
383
|
+
* Records a heartbeat carrying a checkpoint. Every later heartbeat of the attempt, including the
|
|
384
|
+
* session's background heartbeats, carries it too, so the next attempt reads it as
|
|
385
|
+
* {@link heartbeatCheckpoint}. Absent when the caller cannot save checkpoints.
|
|
386
|
+
* @param checkpoint - Text to hand to the next attempt.
|
|
387
|
+
* @returns A Promise that resolves when the Worker accepted the heartbeat.
|
|
388
|
+
*/
|
|
389
|
+
saveHeartbeatCheckpoint?(checkpoint: string): Promise<void>;
|
|
244
390
|
}
|
|
245
|
-
/** Successful result of one deferred tool call. */
|
|
391
|
+
/** Successful result of one deferred tool call. A result without `kind` is a `ToolExecutionResult`. */
|
|
246
392
|
export interface ToolExecutionResult {
|
|
247
393
|
/** Output text recorded on the call and shown to the model. */
|
|
248
394
|
readonly output: string;
|
|
249
395
|
}
|
|
396
|
+
/**
|
|
397
|
+
* Result of a deferred tool call that needs an answer from the user before it can take effect.
|
|
398
|
+
*
|
|
399
|
+
* Return it from {@link AgentFrameworkRunner.executeDeferredToolCall} only when the call has had no
|
|
400
|
+
* effect yet. The tool Step records `awaiting_answer` and stores {@link continuation}. `AwaitQuestionAnswer`
|
|
401
|
+
* then raises a `question` interrupt with ID `<toolCallId>-input-<n>`, where `n` counts the call's
|
|
402
|
+
* questions from 1. After `answer_question`, the record returns to `approved` and the same tool Step
|
|
403
|
+
* type runs the call again, with every answer in {@link DeferredToolExecution.inputAnswers} and the
|
|
404
|
+
* continuation in `toolCall.inputContinuation`. The tool's later output, not the answer, is the result.
|
|
405
|
+
* A declined question or a passed deadline records `rejected`, and the tool never runs again.
|
|
406
|
+
*
|
|
407
|
+
* Because the call took no effect, a single-attempt tool that runs again after an answer still never
|
|
408
|
+
* repeats an effect. A crash during the second run records `outcome_unknown`, as for any run.
|
|
409
|
+
*
|
|
410
|
+
* @example
|
|
411
|
+
* ```ts
|
|
412
|
+
* public async executeDeferredToolCall(call: DeferredToolExecution): Promise<DeferredToolOutcome> {
|
|
413
|
+
* const confirmation = call.inputAnswers?.at(-1)?.answer;
|
|
414
|
+
* if (confirmation === undefined) {
|
|
415
|
+
* return { kind: "tool_input_requested", question: "Ship to the saved address?", choices: ["yes", "no"],
|
|
416
|
+
* allowsFreeText: false, continuation: null };
|
|
417
|
+
* }
|
|
418
|
+
* return { output: confirmation === "yes" ? await shipOrder(call.idempotencyKey) : "not shipped" };
|
|
419
|
+
* }
|
|
420
|
+
* ```
|
|
421
|
+
*/
|
|
422
|
+
export interface ToolInputRequested {
|
|
423
|
+
/** Discriminator. */
|
|
424
|
+
readonly kind: "tool_input_requested";
|
|
425
|
+
/** Question for the user; it must not be blank. */
|
|
426
|
+
readonly question: string;
|
|
427
|
+
/** Answers to offer. Defaults to none, which makes the question free text. */
|
|
428
|
+
readonly choices?: readonly string[];
|
|
429
|
+
/** Whether an answer outside {@link choices} is accepted. Defaults to `true`; ignored without choices. */
|
|
430
|
+
readonly allowsFreeText?: boolean;
|
|
431
|
+
/** Opaque text returned to the tool with the answer, such as a server request ID, or `null`. */
|
|
432
|
+
readonly continuation: string | null;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Result of a deferred tool call that started remote work and returned a handle to poll.
|
|
436
|
+
*
|
|
437
|
+
* Return it from {@link AgentFrameworkRunner.executeDeferredToolCall} when the tool's work runs
|
|
438
|
+
* elsewhere and outlives the call, such as an MCP task. The tool Step records `waiting_for_task` with
|
|
439
|
+
* {@link taskId} and the poll interval, writes `tool_task_started`, and ends. `PollToolTask` then waits
|
|
440
|
+
* on a Timer for the interval and calls {@link AgentFrameworkRunner.pollToolTask} once per execution, so
|
|
441
|
+
* no Step or connection is held while the work runs, and a Worker restart only delays the next poll. The
|
|
442
|
+
* runner must implement `pollToolTask`; without it the session records the call `failed` for a `read`
|
|
443
|
+
* tool and `outcome_unknown` otherwise.
|
|
444
|
+
*
|
|
445
|
+
* The tool Step commits the handle with its result. A `CallTool` attempt that dies after the remote work
|
|
446
|
+
* started runs again, so save the handle with {@link DeferredToolExecution.saveHeartbeatCheckpoint}
|
|
447
|
+
* before you return it, and return the saved handle when {@link DeferredToolExecution.heartbeatCheckpoint}
|
|
448
|
+
* holds one. Once the checkpoint has reached Dex, a retried attempt resumes the same work. Dex may drop a
|
|
449
|
+
* heartbeat checkpoint, though, so an attempt that dies before its checkpoint is saved and before the tool
|
|
450
|
+
* Step commits can still start the work a second time on a `CallTool` retry; pass the idempotency key to
|
|
451
|
+
* the remote system so it can drop the duplicate. Steering waits for a started task. `cancel_turn` abandons
|
|
452
|
+
* it: the session records `outcome_unknown` and asks {@link AgentFrameworkRunner.cancelToolTask} to cancel it.
|
|
453
|
+
*
|
|
454
|
+
* @example
|
|
455
|
+
* ```ts
|
|
456
|
+
* public async executeDeferredToolCall(call: DeferredToolExecution): Promise<DeferredToolOutcome> {
|
|
457
|
+
* if (call.heartbeatCheckpoint !== undefined) {
|
|
458
|
+
* return { kind: "tool_task_started", taskId: call.heartbeatCheckpoint, pollIntervalSeconds: 5 };
|
|
459
|
+
* }
|
|
460
|
+
* const jobId = await reports.start(call.idempotencyKey);
|
|
461
|
+
* await call.saveHeartbeatCheckpoint?.(jobId);
|
|
462
|
+
* return { kind: "tool_task_started", taskId: jobId, pollIntervalSeconds: 5 };
|
|
463
|
+
* }
|
|
464
|
+
* ```
|
|
465
|
+
*/
|
|
466
|
+
export interface ToolTaskStarted {
|
|
467
|
+
/** Discriminator. */
|
|
468
|
+
readonly kind: "tool_task_started";
|
|
469
|
+
/** Handle of the remote work; it must not be blank. The session stores it as the record's `taskId`. */
|
|
470
|
+
readonly taskId: string;
|
|
471
|
+
/**
|
|
472
|
+
* Seconds to wait before the first poll. The session rounds it up to whole seconds, at least 1,
|
|
473
|
+
* because Dex Timers take whole seconds, and shortens it to at most a day.
|
|
474
|
+
*/
|
|
475
|
+
readonly pollIntervalSeconds: number;
|
|
476
|
+
}
|
|
477
|
+
/** Result of {@link AgentFrameworkRunner.pollToolTask} while the polled task still runs. */
|
|
478
|
+
export interface ToolTaskPending {
|
|
479
|
+
/** Discriminator. */
|
|
480
|
+
readonly kind: "tool_task_pending";
|
|
481
|
+
/** Seconds to wait before the next poll. The session rounds it up to whole seconds, from 1 to a day. */
|
|
482
|
+
readonly pollIntervalSeconds: number;
|
|
483
|
+
/**
|
|
484
|
+
* Text the next poll reads as `toolCall.inputContinuation`, such as which question the task took an answer
|
|
485
|
+
* to and when. Omitted or `null` clears it: keep what the next poll needs, and drop a question's
|
|
486
|
+
* continuation once the task took its answer, so an identical later question reads as new.
|
|
487
|
+
*/
|
|
488
|
+
readonly continuation?: string | null;
|
|
489
|
+
}
|
|
490
|
+
/** One task that `PollToolTask` asks the runner to poll. */
|
|
491
|
+
export interface ToolTaskPoll {
|
|
492
|
+
/** Flow ID, which is the session ID. */
|
|
493
|
+
readonly flowId: string;
|
|
494
|
+
/** The call's record, `waiting_for_task`, with `taskId`, `taskPollIntervalSeconds`, and `toolSourceReference`. */
|
|
495
|
+
readonly toolCall: AgentToolCallRecord;
|
|
496
|
+
/** `<flowId>/<turnId>/<toolCallId>`, the key the tool Step passed when it started the task. */
|
|
497
|
+
readonly idempotencyKey: string;
|
|
498
|
+
/** One-based `PollToolTask` attempt. Each poll gets up to three attempts. */
|
|
499
|
+
readonly attempt: number;
|
|
500
|
+
/** How the questions this call asked were resolved, oldest first, whether its tool or its task asked them. */
|
|
501
|
+
readonly inputAnswers: readonly QuestionAnswer[];
|
|
502
|
+
/**
|
|
503
|
+
* The resolution of the task's last question, which has not reached the task yet, or `null`. It is set
|
|
504
|
+
* only on the first poll after `AwaitQuestionAnswer` resolved the question, which runs at once. Deliver it
|
|
505
|
+
* to the task: the answer when `resolution` is `answered`, a decline when it is `declined`, and a
|
|
506
|
+
* cancelled request when it is `deadline_passed`. `toolCall.inputContinuation` holds the question's
|
|
507
|
+
* continuation, so recognize the request it answers and deliver only to that request. Later polls read the
|
|
508
|
+
* continuation the last {@link ToolTaskPending} returned. A retried attempt gets it again; when it cannot
|
|
509
|
+
* tell whether an earlier attempt delivered it, return the task's question as {@link ToolInputRequested}
|
|
510
|
+
* again rather than send it to what may be a later question. When the task cannot take the resolution,
|
|
511
|
+
* cancel the task best-effort and throw an error other than {@link ToolExecutionError}, so the session
|
|
512
|
+
* records the call by its effect.
|
|
513
|
+
*/
|
|
514
|
+
readonly pendingAnswer: QuestionAnswer | null;
|
|
515
|
+
/** Events writer bound to the turn and attempt. */
|
|
516
|
+
readonly events: AgentEventWriter;
|
|
517
|
+
/** Signal aborted when Dex cancels the attempt. */
|
|
518
|
+
readonly cancellationSignal: AbortSignal;
|
|
519
|
+
/** Absolute deadline of the current attempt, or `undefined`. */
|
|
520
|
+
readonly deadline: Date | undefined;
|
|
521
|
+
/**
|
|
522
|
+
* Records a heartbeat. The session already records one every 20 seconds.
|
|
523
|
+
* @returns A Promise that resolves when the Worker accepted the heartbeat.
|
|
524
|
+
*/
|
|
525
|
+
heartbeat(): Promise<void>;
|
|
526
|
+
}
|
|
527
|
+
/** One task that `cancel_turn` abandoned, which `CancelToolTask` asks the runner to cancel. */
|
|
528
|
+
export interface ToolTaskCancellation {
|
|
529
|
+
/** Flow ID, which is the session ID. */
|
|
530
|
+
readonly flowId: string;
|
|
531
|
+
/**
|
|
532
|
+
* The call's record with `taskId` and `toolSourceReference`. Its `cancellationReason` is `turn_cancelled`.
|
|
533
|
+
*/
|
|
534
|
+
readonly toolCall: AgentToolCallRecord;
|
|
535
|
+
/** `<flowId>/<turnId>/<toolCallId>`, the key the tool Step passed when it started the task. */
|
|
536
|
+
readonly idempotencyKey: string;
|
|
537
|
+
/** One-based `CancelToolTask` attempt. Each cancellation gets up to three attempts. */
|
|
538
|
+
readonly attempt: number;
|
|
539
|
+
/** Signal aborted when Dex cancels the attempt, such as when its method timeout passes. */
|
|
540
|
+
readonly cancellationSignal: AbortSignal;
|
|
541
|
+
/**
|
|
542
|
+
* Records a heartbeat. The session already records one every 20 seconds.
|
|
543
|
+
* @returns A Promise that resolves when the Worker accepted the heartbeat.
|
|
544
|
+
*/
|
|
545
|
+
heartbeat(): Promise<void>;
|
|
546
|
+
}
|
|
547
|
+
/** Result of {@link AgentFrameworkRunner.executeDeferredToolCall}. */
|
|
548
|
+
export type DeferredToolOutcome = ToolExecutionResult | ToolInputRequested | ToolTaskStarted;
|
|
549
|
+
/** Result of {@link AgentFrameworkRunner.pollToolTask}. */
|
|
550
|
+
export type ToolTaskPollOutcome = ToolExecutionResult | ToolInputRequested | ToolTaskPending;
|
|
250
551
|
/**
|
|
251
552
|
* Tool failure that the model should see, thrown from {@link AgentFrameworkRunner.executeDeferredToolCall}.
|
|
252
553
|
*
|
|
@@ -290,6 +591,9 @@ export declare class ToolExecutionError extends Error {
|
|
|
290
591
|
* run in another Worker process.
|
|
291
592
|
* - Throwing from `runModelStep` retries the model call, up to 3 attempts within 30 minutes; then the
|
|
292
593
|
* turn fails, the session records `last_turn_error`, and it waits for the next user message.
|
|
594
|
+
* - A runner may store the turn's transcript incrementally with {@link ToolCallsRequested.newMessages};
|
|
595
|
+
* it then implements {@link buildUnfinishedTurnMessages}. A runner may offer the
|
|
596
|
+
* {@link AgentTurnContext.enabledBuiltInTools} to its model; the session handles their calls.
|
|
293
597
|
*
|
|
294
598
|
* @example
|
|
295
599
|
* ```ts
|
|
@@ -310,8 +614,11 @@ export declare class ToolExecutionError extends Error {
|
|
|
310
614
|
* }
|
|
311
615
|
* }
|
|
312
616
|
* ```
|
|
617
|
+
* @typeParam ToolOutcome - What {@link executeDeferredToolCall} returns. It defaults to
|
|
618
|
+
* {@link ToolExecutionResult}; a runner whose tools can ask the user a question first or start a remote
|
|
619
|
+
* task implements `AgentFrameworkRunner<DeferredToolOutcome>`. The session accepts both.
|
|
313
620
|
*/
|
|
314
|
-
export interface AgentFrameworkRunner {
|
|
621
|
+
export interface AgentFrameworkRunner<ToolOutcome extends DeferredToolOutcome = ToolExecutionResult> {
|
|
315
622
|
/**
|
|
316
623
|
* Converts user text into the framework's user message.
|
|
317
624
|
*
|
|
@@ -335,12 +642,144 @@ export interface AgentFrameworkRunner {
|
|
|
335
642
|
* Runs the real tool for one tool call, in `CallTool` or `CallSingleAttemptTool`.
|
|
336
643
|
*
|
|
337
644
|
* @param call - Deferred call to run.
|
|
338
|
-
* @returns The tool output text
|
|
645
|
+
* @returns The tool output text; {@link ToolInputRequested} when the tool needs an answer from the
|
|
646
|
+
* user before it takes any effect; or {@link ToolTaskStarted} when the tool started remote work that
|
|
647
|
+
* {@link pollToolTask} polls.
|
|
339
648
|
* @throws {ToolExecutionError} For a failure the model should see; the call is recorded as `failed`.
|
|
340
649
|
* @throws Any other error for an unexpected failure; after the last attempt the record becomes
|
|
341
650
|
* `failed` for a `read` tool and `outcome_unknown` for a write. See {@link ToolExecutionError}.
|
|
342
651
|
*/
|
|
343
|
-
executeDeferredToolCall(call: DeferredToolExecution): Promise<
|
|
652
|
+
executeDeferredToolCall(call: DeferredToolExecution): Promise<ToolOutcome>;
|
|
653
|
+
/**
|
|
654
|
+
* Returns the turn's messages that the session has not stored yet, when the turn ends without a final
|
|
655
|
+
* answer. Optional.
|
|
656
|
+
*
|
|
657
|
+
* Implement it when the runner sets {@link ToolCallsRequested.newMessages}. `RecordTurnFailure` calls
|
|
658
|
+
* it before it appends the turn-failure note, with every record of the turn final. Return the tool
|
|
659
|
+
* result of every tool call already stored or returned that has no stored result, so no tool call is
|
|
660
|
+
* left without a result. It must be synchronous and make no model call. When it throws, the session
|
|
661
|
+
* stores only the turn-failure note, so a runner defect never blocks the failure route.
|
|
662
|
+
*
|
|
663
|
+
* @param turn - The ended turn; {@link AgentTurnContext.toolCalls} holds its final records.
|
|
664
|
+
* @returns The messages to append, in order, possibly none.
|
|
665
|
+
*/
|
|
666
|
+
buildUnfinishedTurnMessages?(turn: AgentTurnContext): readonly FrameworkMessage[];
|
|
667
|
+
/**
|
|
668
|
+
* Whether the runner honors plan mode. Optional; {@link AgentSessionOptions.planModeEnabled} needs `true`,
|
|
669
|
+
* and `createAgentSessionFlow` throws otherwise.
|
|
670
|
+
*
|
|
671
|
+
* Such a runner reads {@link AgentTurnContext.interactionMode} in every `runModelStep`. In a `planning`
|
|
672
|
+
* turn it offers only the `write_todos` definition from {@link builtInToolDefinitions}. It may force
|
|
673
|
+
* `write_todos` on the turn's first model call while the plan is not a draft yet, where the model accepts a
|
|
674
|
+
* forced tool choice; Stepwise does with `planningToolChoice: "required"`. In every
|
|
675
|
+
* turn it shows the plan with {@link buildPlanNote} as user text before the turn's messages. The Stepwise
|
|
676
|
+
* runner implements it; a framework adapter that cannot change the tools it offers between turns leaves
|
|
677
|
+
* plan mode off.
|
|
678
|
+
*/
|
|
679
|
+
readonly supportsPlanMode?: boolean;
|
|
680
|
+
/**
|
|
681
|
+
* Polls one remote task that a tool started with {@link ToolTaskStarted}, once. Optional.
|
|
682
|
+
*
|
|
683
|
+
* Implement it when a tool returns `ToolTaskStarted`. `PollToolTask` calls it once per execution,
|
|
684
|
+
* after a Timer for the call's poll interval, until it returns a result. Polling must only read the
|
|
685
|
+
* task, and deliver `poll.pendingAnswer` when it is set, because the session may poll again after a
|
|
686
|
+
* crash. Steering never stops a poll. `cancel_turn` aborts `poll.cancellationSignal` of a running poll,
|
|
687
|
+
* and the session drops whatever it returns.
|
|
688
|
+
*
|
|
689
|
+
* @example
|
|
690
|
+
* ```ts
|
|
691
|
+
* public async pollToolTask(poll: ToolTaskPoll): Promise<ToolTaskPollOutcome> {
|
|
692
|
+
* const job = await reports.get(poll.toolCall.taskId!);
|
|
693
|
+
* return job.done ? { output: job.summary } : { kind: "tool_task_pending", pollIntervalSeconds: 10 };
|
|
694
|
+
* }
|
|
695
|
+
* ```
|
|
696
|
+
* @param poll - The call's record and its idempotency key.
|
|
697
|
+
* @returns {@link ToolExecutionResult} when the task finished, which the model sees;
|
|
698
|
+
* {@link ToolTaskPending} while it runs; or {@link ToolInputRequested} when it needs the user's answer.
|
|
699
|
+
* The session asks the question through `AwaitQuestionAnswer` and polls again at once with its
|
|
700
|
+
* resolution, answered, declined, or past its deadline, as `pendingAnswer`. The task's later result is
|
|
701
|
+
* the call's result.
|
|
702
|
+
* @throws {ToolExecutionError} When the task failed in a way the model should see; the call is
|
|
703
|
+
* recorded as `failed`.
|
|
704
|
+
* @throws Any other error to fail the poll attempt; after three attempts the record becomes `failed`
|
|
705
|
+
* for a `read` call and `outcome_unknown` otherwise, because the task may still run.
|
|
706
|
+
*/
|
|
707
|
+
pollToolTask?(poll: ToolTaskPoll): Promise<ToolTaskPollOutcome>;
|
|
708
|
+
/**
|
|
709
|
+
* Asks the remote system to stop one task that `cancel_turn` abandoned. Optional.
|
|
710
|
+
*
|
|
711
|
+
* `cancel_turn` does not wait for a started task: the session records the call `outcome_unknown` with
|
|
712
|
+
* `cancellationReason` `turn_cancelled`, and the `CancelToolTask` Step calls this method best-effort before
|
|
713
|
+
* it records the call. A runner without it leaves the task running. Steering never cancels a task. The
|
|
714
|
+
* session may call it more than once for one task, after a crash or a failed attempt, so make it idempotent
|
|
715
|
+
* by `taskId`. A task that already finished, or that the remote system no longer knows, is cancelled: return
|
|
716
|
+
* normally. The record is final whatever this method does, and a result the task returns later is dropped.
|
|
717
|
+
*
|
|
718
|
+
* @example
|
|
719
|
+
* ```ts
|
|
720
|
+
* public async cancelToolTask(cancellation: ToolTaskCancellation): Promise<void> {
|
|
721
|
+
* await reports.cancel(cancellation.toolCall.taskId!);
|
|
722
|
+
* }
|
|
723
|
+
* ```
|
|
724
|
+
* @param cancellation - The abandoned call's record and its idempotency key.
|
|
725
|
+
* @returns A Promise that resolves once the remote system took the cancellation.
|
|
726
|
+
* @throws Any error when the cancellation did not reach the remote system; the session retries it up to
|
|
727
|
+
* three times, then records the call `outcome_unknown` anyway, so the turn always ends.
|
|
728
|
+
*/
|
|
729
|
+
cancelToolTask?(cancellation: ToolTaskCancellation): Promise<void>;
|
|
730
|
+
/**
|
|
731
|
+
* Estimates the size of the model input that the next {@link runModelStep} sends. Optional; one of the
|
|
732
|
+
* three compaction methods that {@link AgentSessionOptions.compaction} requires.
|
|
733
|
+
*
|
|
734
|
+
* `RunModel` calls it before every model call of a session with a compaction policy. At the policy's
|
|
735
|
+
* threshold it calls {@link selectCompactionCutoff}, and when that returns a sequence after the current
|
|
736
|
+
* summary, `CompactContext` calls {@link summarizeContext} once and stores the result as the
|
|
737
|
+
* `ContextSummary`. From then on, {@link AgentTurnContext.messages} start after the summary and
|
|
738
|
+
* {@link AgentTurnContext.contextSummary} holds it. A runner without these methods never compacts.
|
|
739
|
+
*
|
|
740
|
+
* @example
|
|
741
|
+
* ```ts
|
|
742
|
+
* class CompactingRunner extends MyRunner {
|
|
743
|
+
* public estimateInputTokens(turn: AgentTurnContext): number {
|
|
744
|
+
* return countTokens(buildModelInput(turn));
|
|
745
|
+
* }
|
|
746
|
+
* public selectCompactionCutoff(turn: AgentTurnContext, retainedTokenBudget: number): number | null {
|
|
747
|
+
* return lastSequenceBeforeNewestMessages(turn.messages, retainedTokenBudget);
|
|
748
|
+
* }
|
|
749
|
+
* public async summarizeContext(request: ContextSummaryRequest): Promise<ContextSummaryResult> {
|
|
750
|
+
* const response = await model.summarize(request.previousSummary, request.messages);
|
|
751
|
+
* return { text: response.text, usage: response.usage };
|
|
752
|
+
* }
|
|
753
|
+
* }
|
|
754
|
+
* ```
|
|
755
|
+
* @param turn - The same context the next {@link runModelStep} receives.
|
|
756
|
+
* @returns The estimated input tokens, in the unit of `CompactionPolicy.contextWindowTokens`.
|
|
757
|
+
*/
|
|
758
|
+
estimateInputTokens?(turn: AgentTurnContext): number | Promise<number>;
|
|
759
|
+
/**
|
|
760
|
+
* Chooses the last message to summarize, so the newest messages fit a token budget. Optional; see
|
|
761
|
+
* {@link estimateInputTokens}.
|
|
762
|
+
*
|
|
763
|
+
* Never separate a tool call from its result: the messages after the cutoff must not start with a tool
|
|
764
|
+
* result or hold a result whose call is before the cutoff. Keep the turn's unstored tool results
|
|
765
|
+
* answerable.
|
|
766
|
+
*
|
|
767
|
+
* @param turn - The context of the model call that crossed the threshold.
|
|
768
|
+
* @param retainedTokenBudget - Tokens that the messages after the cutoff may use.
|
|
769
|
+
* @returns The sequence of the last message to summarize, one of {@link AgentTurnContext.messages}; or
|
|
770
|
+
* `null` when nothing can be summarized, which lets the model call proceed.
|
|
771
|
+
*/
|
|
772
|
+
selectCompactionCutoff?(turn: AgentTurnContext, retainedTokenBudget: number): number | null | Promise<number | null>;
|
|
773
|
+
/**
|
|
774
|
+
* Folds the previous summary and a range of messages into a new summary, with at most one model call.
|
|
775
|
+
* Optional; see {@link estimateInputTokens}. A crash during the call reruns only this call.
|
|
776
|
+
*
|
|
777
|
+
* @param request - The previous summary and the messages to summarize.
|
|
778
|
+
* @returns The new summary text and the usage of the call.
|
|
779
|
+
* @throws Any error to fail the `CompactContext` attempt; it retries up to 3 attempts within 30
|
|
780
|
+
* minutes, then the turn fails through `RecordTurnFailure`.
|
|
781
|
+
*/
|
|
782
|
+
summarizeContext?(request: ContextSummaryRequest): Promise<ContextSummaryResult>;
|
|
344
783
|
}
|
|
345
784
|
/** MCP tool annotations that classify a tool's side effects. */
|
|
346
785
|
export interface McpToolAnnotations {
|
|
@@ -362,7 +801,8 @@ export interface McpToolAnnotations {
|
|
|
362
801
|
* const policy = turn.resolveToolPolicy(tool.name, toolEffectFromMcpToolAnnotations(tool.annotations ?? {}));
|
|
363
802
|
* ```
|
|
364
803
|
* @param annotations - The tool's MCP annotations.
|
|
365
|
-
* @returns `read` when `readOnlyHint` is `true`; `idempotent_write` when `idempotentHint` is
|
|
366
|
-
*
|
|
804
|
+
* @returns `read` when `readOnlyHint` is `true`; otherwise `idempotent_write` when `idempotentHint` is
|
|
805
|
+
* `true`, whatever `destructiveHint` says, as in the Python core; otherwise `undefined`, so the session
|
|
806
|
+
* default applies.
|
|
367
807
|
*/
|
|
368
808
|
export declare function toolEffectFromMcpToolAnnotations(annotations: McpToolAnnotations): ToolEffect | undefined;
|
|
@@ -66,14 +66,15 @@ export class ToolExecutionError extends Error {
|
|
|
66
66
|
* const policy = turn.resolveToolPolicy(tool.name, toolEffectFromMcpToolAnnotations(tool.annotations ?? {}));
|
|
67
67
|
* ```
|
|
68
68
|
* @param annotations - The tool's MCP annotations.
|
|
69
|
-
* @returns `read` when `readOnlyHint` is `true`; `idempotent_write` when `idempotentHint` is
|
|
70
|
-
*
|
|
69
|
+
* @returns `read` when `readOnlyHint` is `true`; otherwise `idempotent_write` when `idempotentHint` is
|
|
70
|
+
* `true`, whatever `destructiveHint` says, as in the Python core; otherwise `undefined`, so the session
|
|
71
|
+
* default applies.
|
|
71
72
|
*/
|
|
72
73
|
export function toolEffectFromMcpToolAnnotations(annotations) {
|
|
73
74
|
if (annotations.readOnlyHint === true) {
|
|
74
75
|
return "read";
|
|
75
76
|
}
|
|
76
|
-
if (annotations.idempotentHint === true
|
|
77
|
+
if (annotations.idempotentHint === true) {
|
|
77
78
|
return "idempotent_write";
|
|
78
79
|
}
|
|
79
80
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-framework-runner.js","sourceRoot":"","sources":["../../src/agent-framework-runner.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,kDAAkD;AAClD,mEAAmE;AACnE,+CAA+C;AAC/C,EAAE;AACF,0DAA0D;
|
|
1
|
+
{"version":3,"file":"agent-framework-runner.js","sourceRoot":"","sources":["../../src/agent-framework-runner.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,kDAAkD;AAClD,mEAAmE;AACnE,+CAA+C;AAC/C,EAAE;AACF,0DAA0D;AAmD1D;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,YAAkD,EAClD,iBAA6B,EAC7B,eAA4B;IAE5B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1F,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,IAAI,eAAe,IAAI,iBAAiB,CAAC;IACtE,MAAM,gBAAgB,GACpB,MAAM,EAAE,gBAAgB,IAAI,CAAC,MAAM,KAAK,sBAAsB,IAAI,MAAM,KAAK,cAAc,CAAC,CAAC;IAC/F,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;AACtC,CAAC;AAogBD;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C;;;;OAIG;IACH,YAAmB,OAAe,EAAE,OAAsB;QACxD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AA+ND;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,gCAAgC,CAC9C,WAA+B;IAE/B,IAAI,WAAW,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;QACtC,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,WAAW,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;QACxC,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AgentPlan, AgentPlanTask, InteractionMode, PlanStatus } from "./agent-session-values.js";
|
|
2
|
+
/**
|
|
3
|
+
* Rejection message of a call to any tool other than `write_todos` in a `planning` turn; the same text as
|
|
4
|
+
* the Python core.
|
|
5
|
+
*/
|
|
6
|
+
export declare const planningTurnToolRejection = "The tool call was not run: a planning turn can only call write_todos.";
|
|
7
|
+
/** First line of the plan note while no plan exists; the same text as the Python core. */
|
|
8
|
+
export declare const noPlanNote = "[Dex] There is no plan yet.";
|
|
9
|
+
/** Last line of the plan note in a `planning` turn; the same text as the Python core. */
|
|
10
|
+
export declare const planningTurnInstruction: string;
|
|
11
|
+
/**
|
|
12
|
+
* Returns the user message text of a turn that `execute_plan` started.
|
|
13
|
+
*
|
|
14
|
+
* @param revision - The approved {@link AgentPlan.revision}.
|
|
15
|
+
* @returns `[Dex] The user approved plan revision <n>. Execute it and keep the task statuses current with
|
|
16
|
+
* write_todos.`, the same text as the Python core.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildPlanExecutionMessage(revision: number): string;
|
|
19
|
+
/**
|
|
20
|
+
* Returns the text that shows the model the current plan, or `undefined` for none.
|
|
21
|
+
*
|
|
22
|
+
* A runner that honors plan mode adds it to the model input of every model call, after the context summary
|
|
23
|
+
* and before the turn's messages, as user text. It is not stored as a message, so it always shows the
|
|
24
|
+
* latest plan. The text is the same as the Python core's `build_plan_note`:
|
|
25
|
+
*
|
|
26
|
+
* ```text
|
|
27
|
+
* [Dex] The current plan, revision 2, is draft:
|
|
28
|
+
* - [completed] Look up the order
|
|
29
|
+
* - [pending] Refund the order
|
|
30
|
+
* This turn only plans: write or revise the plan with write_todos, ...
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @param plan - The {@link AgentPlan}, or `null` or `undefined` when there is none.
|
|
34
|
+
* @param interactionMode - The turn's mode; `undefined` means `chat`.
|
|
35
|
+
* @returns One line for the plan and one per task, then {@link planningTurnInstruction} in a `planning`
|
|
36
|
+
* turn, joined with newlines. {@link noPlanNote} stands for a missing or cleared plan in a `planning` turn.
|
|
37
|
+
* `undefined` when there is no plan to show outside a `planning` turn.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildPlanNote(plan: AgentPlan | null | undefined, interactionMode: InteractionMode | undefined): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Returns the status of the plan that `write_todos` writes.
|
|
42
|
+
*
|
|
43
|
+
* @param tasks - The tasks written.
|
|
44
|
+
* @param interactionMode - The mode of the turn that wrote them.
|
|
45
|
+
* @returns `cleared` for no tasks, `draft` in a `planning` turn, `completed` when every task is completed,
|
|
46
|
+
* and `active` otherwise.
|
|
47
|
+
*/
|
|
48
|
+
export declare function planStatusAfterWrite(tasks: readonly AgentPlanTask[], interactionMode: InteractionMode | undefined): PlanStatus;
|