@superdurable/dex-agents 0.2.0 → 0.4.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 +143 -6
- package/dist/src/agent-context-compaction.d.ts +150 -4
- package/dist/src/agent-context-compaction.js +253 -5
- package/dist/src/agent-context-compaction.js.map +1 -1
- package/dist/src/agent-framework-runner.d.ts +89 -0
- package/dist/src/agent-framework-runner.js +26 -0
- package/dist/src/agent-framework-runner.js.map +1 -1
- package/dist/src/agent-session-codecs.js +9 -0
- 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 +2204 -0
- package/dist/src/agent-session-flow.d.ts +23 -2
- package/dist/src/agent-session-flow.js +5 -0
- package/dist/src/agent-session-flow.js.map +1 -1
- 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 +52 -1
- package/dist/src/agent-session-step-options.js +34 -2
- package/dist/src/agent-session-step-options.js.map +1 -1
- package/dist/src/agent-session-steps.d.ts +9 -0
- package/dist/src/agent-session-steps.js +247 -50
- package/dist/src/agent-session-steps.js.map +1 -1
- package/dist/src/agent-session-transitions.d.ts +14 -1
- package/dist/src/agent-session-transitions.js +61 -1
- package/dist/src/agent-session-transitions.js.map +1 -1
- package/dist/src/agent-session-values.d.ts +43 -2
- package/dist/src/agent-session-values.js +6 -0
- package/dist/src/agent-session-values.js.map +1 -1
- package/dist/src/agent-session-wait-steps.js +3 -3
- package/dist/src/agent-session-wait-steps.js.map +1 -1
- package/dist/src/connectors/connector-input-schema.d.ts +19 -0
- package/dist/src/connectors/connector-input-schema.js +228 -0
- package/dist/src/connectors/connector-input-schema.js.map +1 -0
- package/dist/src/connectors/connector-step-context.d.ts +77 -0
- package/dist/src/connectors/connector-step-context.js +124 -0
- package/dist/src/connectors/connector-step-context.js.map +1 -0
- package/dist/src/connectors/connector-tool-source.d.ts +353 -0
- package/dist/src/connectors/connector-tool-source.js +541 -0
- package/dist/src/connectors/connector-tool-source.js.map +1 -0
- package/dist/src/connectors/index.d.ts +3 -0
- package/dist/src/connectors/index.js +11 -0
- package/dist/src/connectors/index.js.map +1 -0
- package/dist/src/index.d.ts +10 -3
- package/dist/src/index.js +8 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/stepwise/agent-definition.d.ts +8 -0
- package/dist/src/stepwise/index.d.ts +2 -1
- package/dist/src/stepwise/index.js +2 -1
- package/dist/src/stepwise/index.js.map +1 -1
- package/dist/src/stepwise/stepwise-agent-runner.d.ts +15 -32
- package/dist/src/stepwise/stepwise-agent-runner.js +37 -200
- package/dist/src/stepwise/stepwise-agent-runner.js.map +1 -1
- package/dist/src/stepwise/stepwise-agent-session-flow.js +1 -0
- package/dist/src/stepwise/stepwise-agent-session-flow.js.map +1 -1
- package/dist/src/stepwise/tool-source.d.ts +11 -1
- package/dist/src/testing/agent-session-test-client.js +2 -5
- 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 +1 -0
- package/dist/src/testing/index.js +1 -0
- package/dist/src/testing/index.js.map +1 -1
- package/dist/src/tool-source-router.d.ts +211 -0
- package/dist/src/tool-source-router.js +380 -0
- package/dist/src/tool-source-router.js.map +1 -0
- package/dist/src/ui-stream/agent-event-sse.d.ts +3 -2
- package/dist/src/ui-stream/agent-event-sse.js +11 -3
- package/dist/src/ui-stream/agent-event-sse.js.map +1 -1
- package/dist/src/ui-stream/agent-session-record-reader.d.ts +2 -0
- package/dist/src/ui-stream/agent-session-record-reader.js +5 -0
- package/dist/src/ui-stream/agent-session-record-reader.js.map +1 -1
- package/dist/src/ui-stream/agent-ui-message-stream-responses.js +3 -2
- package/dist/src/ui-stream/agent-ui-message-stream-responses.js.map +1 -1
- package/dist/src/ui-stream/agent-ui-message-stream.js +17 -3
- package/dist/src/ui-stream/agent-ui-message-stream.js.map +1 -1
- package/dist/src/ui-stream/agent-ui-messages.d.ts +2 -0
- package/dist/src/ui-stream/agent-ui-messages.js +5 -3
- package/dist/src/ui-stream/agent-ui-messages.js.map +1 -1
- package/package.json +15 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-session-step-options.js","sourceRoot":"","sources":["../../src/agent-session-step-options.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,kDAAkD;AAClD,mEAAmE;AACnE,+CAA+C;AAC/C,EAAE;AACF,0DAA0D;AAE1D,OAAO,EAAE,cAAc,EAAE,OAAO,EAA6D,MAAM,mBAAmB,CAAC;AAGvH,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC;AAC/B,qFAAqF;AACrF,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,sBAAsB,EAAE,EAAE,GAAG,QAAQ;IACrC,kBAAkB,EAAE,CAAC,GAAG,QAAQ;IAChC,YAAY,EAAE,EAAE,eAAe,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,GAAG,QAAQ,EAAE;IACpE,cAAc,EAAE,cAAc,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,CAAC;CAChE,CAAC;AACjC,qGAAqG;AACrG,MAAM,CAAC,MAAM,aAAa,GAAgB,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC;AACvE,mGAAmG;AACnG,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAW,CAAC;AAWhG,sGAAsG;AACtG,MAAM,UAAU,kBAAkB,CAChC,WAAoC,EACpC,QAAgB,EAChB,UAA6B;
|
|
1
|
+
{"version":3,"file":"agent-session-step-options.js","sourceRoot":"","sources":["../../src/agent-session-step-options.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,6 +34,8 @@ export declare class RunModelStep implements Step<void> {
|
|
|
34
34
|
getStepType(): string;
|
|
35
35
|
getStepOptions(): StepOptions;
|
|
36
36
|
execute(context: AsyncContext): Promise<StepDecision>;
|
|
37
|
+
/** Starts the next queued write or skips the rest; `null` lets a cancelled turn end here. */
|
|
38
|
+
private continueOrderedWrites;
|
|
37
39
|
/** Returns RunModel's move instead of a model call, or `null` to call the model. */
|
|
38
40
|
private decideBeforeModelCall;
|
|
39
41
|
private completeTurn;
|
|
@@ -140,6 +142,8 @@ export declare class RecordTurnFailureStep implements Step<CompactContextInput |
|
|
|
140
142
|
getStepOptions(): StepOptions;
|
|
141
143
|
execute(context: Context): StepDecision;
|
|
142
144
|
}
|
|
145
|
+
/** Reports whether a Step failed because its commit would exceed the Flow's state limit. */
|
|
146
|
+
export declare function isStateLimitFailure(recoveryError: RecoveryErrorInfo | undefined): boolean;
|
|
143
147
|
/** `last_turn_error` of a turn whose runner stored messages incrementally without the builder. */
|
|
144
148
|
export declare const missingUnfinishedTurnMessageBuilder = "a runner that sets ToolCallsRequested.newMessages must implement buildUnfinishedTurnMessages";
|
|
145
149
|
/**
|
|
@@ -148,6 +152,11 @@ export declare const missingUnfinishedTurnMessageBuilder = "a runner that sets T
|
|
|
148
152
|
*/
|
|
149
153
|
export declare function toolStepOptions(persistence: AgentSessionPersistence, stepType: string, toolCallId?: string): StepOptions;
|
|
150
154
|
export declare function toolStepMovement(persistence: AgentSessionPersistence, stepType: string, toolCallId: string): StepMovement<string>;
|
|
155
|
+
/**
|
|
156
|
+
* Returns the movement that starts an approved call's tool Step, with the runner's timeout and retry policy.
|
|
157
|
+
* Only `CallTool` takes the retry policy; `CallSingleAttemptTool` keeps one attempt.
|
|
158
|
+
*/
|
|
159
|
+
export declare function toolCallMovement(transitions: AgentSessionTransitions, toolCall: AgentToolCallRecord): StepMovement<string>;
|
|
151
160
|
/** Moves to `PollToolTask`; a poll that keeps failing leaves the task running, so the call is recorded by effect. */
|
|
152
161
|
export declare function toolTaskPollMovement(persistence: AgentSessionPersistence, toolCall: AgentToolCallRecord): StepMovement<string>;
|
|
153
162
|
/** Returns the record of a tool's question: `awaiting_answer`, or `failed` when it is blank. */
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
import { ExecuteFailure, StepMovement, int64Codec, StepRef, StepAttemptProgress, Timer, Wait, deadEnd, forceFail, goTo, goToMany, stringCodec, voidCodec, } from "@superdurable/dex";
|
|
9
9
|
import { buildPlanClearedOutput, buildPlanUpdatedOutput, isBlankText, validateAskUserArguments, validateDurableWaitArguments, validateWriteTodosArguments, writeTodosCalledMoreThanOnce, } from "./agent-built-in-tools.js";
|
|
10
10
|
import { isCompactionTriggered, isContextCompactionRunner, readRetainedTokenBudget, } from "./agent-context-compaction.js";
|
|
11
|
-
import { ToolExecutionError, } from "./agent-framework-runner.js";
|
|
11
|
+
import { ToolExecutionError, ToolOutcomeUnknownError, } from "./agent-framework-runner.js";
|
|
12
12
|
import { buildPlanExecutionMessage, planningTurnToolRejection, planStatusAfterWrite } from "./agent-plans.js";
|
|
13
13
|
import { agentSessionStartInputCodec, turnFailureRouteInputCodec } from "./agent-session-codecs.js";
|
|
14
14
|
import { messageStepOptions, minuteMs, modelCallStepOptions, recoveryRetry, syncDurability, } from "./agent-session-step-options.js";
|
|
15
15
|
import { agentSessionStepTypes, allPendingMessages, cancelledToolCall, isAbandonedToolTask, isCancellableByTurnControl, readRecoveryDetail, recoveryErrorDetail, toRunnerToolCall, toolStepTypeForEffect, ToolStepHeartbeats, writePlanUpdated, } from "./agent-session-transitions.js";
|
|
16
16
|
import { messageSequenceKey, planExecutionKey, } from "./agent-session-persistence.js";
|
|
17
17
|
import { checkStoredSessionSettings } from "./agent-session-settings.js";
|
|
18
|
-
import { approvalDeadlinePassed, blankToolTaskId, buildTurnFailureNote, emptyAgentUsage, invalidToolTaskPollInterval, isFinalToolCallStatus, missingToolTaskPoller, toolCallNotRunErrorPrefix, toolTaskAbandonedError, } from "./agent-session-values.js";
|
|
18
|
+
import { approvalDeadlinePassed, blankToolTaskId, buildTurnFailureNote, emptyAgentUsage, invalidToolTaskPollInterval, isFinalToolCallStatus, missingToolTaskPoller, toolCallNotRunErrorPrefix, toolCallSkippedAfterWriteDetail, toolTaskAbandonedError, } from "./agent-session-values.js";
|
|
19
19
|
/** Longest wait between two polls of a tool task, as in the Python core; a longer interval is shortened. */
|
|
20
20
|
const maximumToolTaskPollIntervalSeconds = 86_400;
|
|
21
21
|
// An int64 Value, as the Python core's Step[int] encodes it.
|
|
@@ -159,7 +159,7 @@ export class RunModelStep {
|
|
|
159
159
|
}
|
|
160
160
|
getStepOptions() {
|
|
161
161
|
// Each movement into RunModel adds the archive chunks of the model input.
|
|
162
|
-
return messageStepOptions(this.transitions.persistence, this.getStepType(), staticMessageChunkLoads(this.transitions));
|
|
162
|
+
return messageStepOptions(this.transitions.persistence, this.getStepType(), staticMessageChunkLoads(this.transitions), this.transitions.config.runModelLimit);
|
|
163
163
|
}
|
|
164
164
|
async execute(context) {
|
|
165
165
|
const transitions = this.transitions;
|
|
@@ -168,7 +168,14 @@ export class RunModelStep {
|
|
|
168
168
|
if (turnId === null) {
|
|
169
169
|
throw new Error(`the agent session ${context.flowId} has no active turn`);
|
|
170
170
|
}
|
|
171
|
-
|
|
171
|
+
let toolCalls = transitions.readTurnToolCalls(context, turnId);
|
|
172
|
+
if (toolCalls.some((toolCall) => toolCall.writeQueued === true)) {
|
|
173
|
+
const writeDecision = this.continueOrderedWrites(context, state, turnId, toolCalls);
|
|
174
|
+
if (writeDecision !== null) {
|
|
175
|
+
return writeDecision;
|
|
176
|
+
}
|
|
177
|
+
toolCalls = transitions.readTurnToolCalls(context, turnId);
|
|
178
|
+
}
|
|
172
179
|
const openToolCall = toolCalls.find((toolCall) => !isFinalToolCallStatus(toolCall.status));
|
|
173
180
|
if (openToolCall !== undefined) {
|
|
174
181
|
throw new Error(`RunModel for ${turnId} started before tool call ${openToolCall.toolCallId} finished`);
|
|
@@ -184,8 +191,18 @@ export class RunModelStep {
|
|
|
184
191
|
if (throughSequence !== null) {
|
|
185
192
|
return this.startCompaction(context, state, turnContext.contextSummary ?? null, throughSequence);
|
|
186
193
|
}
|
|
194
|
+
const refusal = await transitions.checkSpendLimit(context, state, turnId, this.getStepType());
|
|
195
|
+
if (refusal !== null) {
|
|
196
|
+
return refusal;
|
|
197
|
+
}
|
|
187
198
|
return await transitions.tracer.traceModelCall(context, this.getStepType(), turnContext, async (modelCallSpan) => {
|
|
188
|
-
const outcome = await transitions.runWithHeartbeats(context, () =>
|
|
199
|
+
const outcome = await transitions.runWithHeartbeats(context, async () => {
|
|
200
|
+
const result = await transitions.runner.runModelStep(turnContext);
|
|
201
|
+
if (result?.kind === "completed" || result?.kind === "tool_calls_requested") {
|
|
202
|
+
await transitions.reportModelUsage(context, turnId, this.getStepType(), result.usage);
|
|
203
|
+
}
|
|
204
|
+
return result;
|
|
205
|
+
});
|
|
189
206
|
switch (outcome?.kind) {
|
|
190
207
|
case "completed": {
|
|
191
208
|
modelCallSpan.recordOutcome(outcome, appendedMessageKeys(state, outcome.newMessages));
|
|
@@ -211,6 +228,61 @@ export class RunModelStep {
|
|
|
211
228
|
events.close();
|
|
212
229
|
}
|
|
213
230
|
}
|
|
231
|
+
/** Starts the next queued write or skips the rest; `null` lets a cancelled turn end here. */
|
|
232
|
+
continueOrderedWrites(context, state, turnId, toolCalls) {
|
|
233
|
+
const transitions = this.transitions;
|
|
234
|
+
const queued = toolCalls.filter((toolCall) => toolCall.writeQueued === true);
|
|
235
|
+
const reason = transitions.readTurnControlReason(context, turnId);
|
|
236
|
+
if (reason !== null) {
|
|
237
|
+
transitions.writeEvents(context, turnId, (events) => {
|
|
238
|
+
for (const toolCall of queued) {
|
|
239
|
+
transitions.finishUnscheduledToolCall(context, { ...cancelledToolCall(toolCall, reason), writeQueued: false }, events);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
const openToolCall = toolCalls.find((toolCall) => toolCall.writeQueued !== true && !isFinalToolCallStatus(toolCall.status));
|
|
245
|
+
if (openToolCall !== undefined) {
|
|
246
|
+
throw new Error(`RunModel for ${turnId} started before tool call ${openToolCall.toolCallId} finished`);
|
|
247
|
+
}
|
|
248
|
+
const nextWrite = queued[0];
|
|
249
|
+
const previousWrite = toolCalls
|
|
250
|
+
.filter((toolCall) => toolCall.orderedWrite === true &&
|
|
251
|
+
toolCall.writeQueued !== true &&
|
|
252
|
+
toolCall.deferralOrder < nextWrite.deferralOrder)
|
|
253
|
+
.at(-1);
|
|
254
|
+
if (previousWrite !== undefined && previousWrite.status !== "succeeded") {
|
|
255
|
+
transitions.writeEvents(context, turnId, (events) => {
|
|
256
|
+
for (const toolCall of queued) {
|
|
257
|
+
transitions.finishUnscheduledToolCall(context, skippedToolCall(toolCall), events);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
// The skips commit before the model call, so readers see them while the model runs.
|
|
261
|
+
return transitions.goToRunModel(context);
|
|
262
|
+
}
|
|
263
|
+
const createdAt = new Date();
|
|
264
|
+
const traceContext = transitions.tracer.readActivationTraceparent(context);
|
|
265
|
+
const { traceContext: _queuedTraceContext, ...queuedWrite } = nextWrite;
|
|
266
|
+
const started = {
|
|
267
|
+
...queuedWrite,
|
|
268
|
+
writeQueued: false,
|
|
269
|
+
status: nextWrite.requiresApproval ? "awaiting_approval" : "approved",
|
|
270
|
+
...(traceContext === null ? {} : { traceContext }),
|
|
271
|
+
};
|
|
272
|
+
transitions.writeToolCall(context, started);
|
|
273
|
+
let movement;
|
|
274
|
+
if (started.requiresApproval) {
|
|
275
|
+
const interrupt = toolApprovalInterrupt(started, createdAt.toISOString(), interruptDeadline(transitions, createdAt));
|
|
276
|
+
transitions.persistence.pendingInterrupts.set(context, [...transitions.readPendingInterrupts(context), interrupt]);
|
|
277
|
+
transitions.writeEvents(context, turnId, (events) => transitions.writeInterruptRaised(events, interrupt));
|
|
278
|
+
movement = toolStepMovement(transitions.persistence, agentSessionStepTypes.awaitToolApproval, started.toolCallId);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
movement = toolCallMovement(transitions, started);
|
|
282
|
+
}
|
|
283
|
+
transitions.writeAgentState(context, { ...state, status: "running_tools" });
|
|
284
|
+
return goToMany(movement, StepMovement.of(new StepRef(agentSessionStepTypes.resumeTurn), 1));
|
|
285
|
+
}
|
|
214
286
|
/** Returns RunModel's move instead of a model call, or `null` to call the model. */
|
|
215
287
|
decideBeforeModelCall(context, turnId) {
|
|
216
288
|
// Execute state is fixed at the first attempt, so this and the compaction check are RunModel's decision points.
|
|
@@ -290,15 +362,15 @@ export class RunModelStep {
|
|
|
290
362
|
context,
|
|
291
363
|
turnId,
|
|
292
364
|
createdAt: createdAt.toISOString(),
|
|
293
|
-
interruptDeadline: transitions
|
|
294
|
-
? null
|
|
295
|
-
: new Date(createdAt.getTime() + transitions.config.interruptDeadlineMs).toISOString(),
|
|
365
|
+
interruptDeadline: interruptDeadline(transitions, createdAt),
|
|
296
366
|
interrupts: [],
|
|
297
367
|
traceContext: transitions.tracer.readActivationTraceparent(context),
|
|
298
368
|
movements: [],
|
|
299
369
|
events,
|
|
300
370
|
interactionMode: state.interactionMode ?? "chat",
|
|
301
371
|
writeTodosCallCount: outcome.toolCalls.filter((toolCall) => toolCall.toolName === "write_todos" && transitions.isEnabledBuiltInTool(toolCall.toolName)).length,
|
|
372
|
+
hasStartedOrderedWrite: false,
|
|
373
|
+
queuedCount: 0,
|
|
302
374
|
};
|
|
303
375
|
for (const [index, requestedToolCall] of outcome.toolCalls.entries()) {
|
|
304
376
|
const deferralOrder = toolCalls.length + index;
|
|
@@ -316,7 +388,7 @@ export class RunModelStep {
|
|
|
316
388
|
transitions.persistence.pendingInterrupts.set(context, batch.interrupts);
|
|
317
389
|
transitions.recordUsage(context, outcome.usage, events);
|
|
318
390
|
transitions.writeAgentState(context, { ...stateWithMessages, status: "running_tools" });
|
|
319
|
-
batch.movements.push(StepMovement.of(new StepRef(agentSessionStepTypes.resumeTurn), outcome.toolCalls.length));
|
|
391
|
+
batch.movements.push(StepMovement.of(new StepRef(agentSessionStepTypes.resumeTurn), outcome.toolCalls.length - batch.queuedCount));
|
|
320
392
|
return goToMany(...batch.movements);
|
|
321
393
|
}
|
|
322
394
|
/** A planning turn hides executable tools; a call to one never runs. */
|
|
@@ -330,31 +402,27 @@ export class RunModelStep {
|
|
|
330
402
|
const transitions = this.transitions;
|
|
331
403
|
const requiresApproval = requestedToolCall.policy.requiresApproval;
|
|
332
404
|
const effect = requestedToolCall.policy.effect;
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
...
|
|
336
|
-
|
|
337
|
-
}
|
|
405
|
+
const isOrderedWrite = requestedToolCall.ordered === true && effect !== "read";
|
|
406
|
+
const record = {
|
|
407
|
+
...createToolCallRecord(batch, requestedToolCall, effect, requiresApproval, deferralOrder),
|
|
408
|
+
orderedWrite: isOrderedWrite,
|
|
409
|
+
};
|
|
338
410
|
writeToolCallDeferred(batch.events, record);
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
:
|
|
342
|
-
|
|
411
|
+
if (isOrderedWrite && batch.hasStartedOrderedWrite) {
|
|
412
|
+
// Started by RunModel once every earlier ordered write of the turn succeeded.
|
|
413
|
+
transitions.writeToolCall(batch.context, { ...record, status: "approved", writeQueued: true });
|
|
414
|
+
batch.queuedCount += 1;
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
batch.hasStartedOrderedWrite ||= isOrderedWrite;
|
|
418
|
+
const deferred = { ...record, status: requiresApproval ? "awaiting_approval" : "approved" };
|
|
419
|
+
transitions.writeToolCall(batch.context, deferred);
|
|
343
420
|
if (!requiresApproval) {
|
|
421
|
+
batch.movements.push(toolCallMovement(transitions, deferred));
|
|
344
422
|
return;
|
|
345
423
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
kind: "tool_approval",
|
|
349
|
-
toolCallId: requestedToolCall.toolCallId,
|
|
350
|
-
toolName: requestedToolCall.toolName,
|
|
351
|
-
arguments: requestedToolCall.arguments,
|
|
352
|
-
createdAt: batch.createdAt,
|
|
353
|
-
deadline: batch.interruptDeadline,
|
|
354
|
-
question: null,
|
|
355
|
-
choices: [],
|
|
356
|
-
allowsFreeText: true,
|
|
357
|
-
};
|
|
424
|
+
batch.movements.push(toolStepMovement(transitions.persistence, agentSessionStepTypes.awaitToolApproval, requestedToolCall.toolCallId));
|
|
425
|
+
const interrupt = toolApprovalInterrupt(record, batch.createdAt, batch.interruptDeadline);
|
|
358
426
|
batch.interrupts.push(interrupt);
|
|
359
427
|
transitions.writeInterruptRaised(batch.events, interrupt);
|
|
360
428
|
}
|
|
@@ -477,6 +545,10 @@ export class CompactContextStep {
|
|
|
477
545
|
if (!isContextCompactionRunner(runner)) {
|
|
478
546
|
throw new TypeError("CompactContext needs a runner that implements the compaction methods");
|
|
479
547
|
}
|
|
548
|
+
const refusal = await transitions.checkSpendLimit(context, state, turnId, this.getStepType());
|
|
549
|
+
if (refusal !== null) {
|
|
550
|
+
return refusal;
|
|
551
|
+
}
|
|
480
552
|
const events = transitions.createEventWriter(context, turnId);
|
|
481
553
|
try {
|
|
482
554
|
events.writeEvent("compaction_started", { through_sequence: throughSequence });
|
|
@@ -511,21 +583,27 @@ export class CompactContextStep {
|
|
|
511
583
|
const messages = transitions.readMessages(context, firstSequence, throughSequence + 1);
|
|
512
584
|
const policy = transitions.config.compaction;
|
|
513
585
|
return transitions.tracer.traceContextSummary(context, this.getStepType(), turnId, throughSequence, messages, async (summarySpan) => {
|
|
514
|
-
const result = await transitions.runWithHeartbeats(context, () =>
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
586
|
+
const result = await transitions.runWithHeartbeats(context, async () => {
|
|
587
|
+
const summaryResult = await runner.summarizeContext({
|
|
588
|
+
flowId: context.flowId,
|
|
589
|
+
turnId,
|
|
590
|
+
attempt: context.attempt,
|
|
591
|
+
stepExecutionId: context.stepExecutionId,
|
|
592
|
+
previousSummary,
|
|
593
|
+
messages,
|
|
594
|
+
throughSequence,
|
|
595
|
+
events,
|
|
596
|
+
cancellationSignal: context.cancellationSignal,
|
|
597
|
+
deadline: context.deadline,
|
|
598
|
+
...(policy === undefined ? {} : { inputTokenBudget: policy.contextWindowTokens }),
|
|
599
|
+
sessionSettings: transitions.readTurnSessionSettings(context),
|
|
600
|
+
heartbeat: () => transitions.recordHeartbeat(context),
|
|
601
|
+
});
|
|
602
|
+
if (typeof summaryResult?.usage === "object") {
|
|
603
|
+
await transitions.reportModelUsage(context, turnId, this.getStepType(), summaryResult.usage);
|
|
604
|
+
}
|
|
605
|
+
return summaryResult;
|
|
606
|
+
});
|
|
529
607
|
if (typeof result?.text !== "string" || result.text.trim() === "" || typeof result.usage !== "object") {
|
|
530
608
|
throw new TypeError("summarizeContext must return summary text and usage");
|
|
531
609
|
}
|
|
@@ -610,7 +688,7 @@ export class AwaitToolApprovalStep {
|
|
|
610
688
|
isAnswered: false,
|
|
611
689
|
rejectionMessage: null,
|
|
612
690
|
});
|
|
613
|
-
return goToMany(
|
|
691
|
+
return goToMany(toolCallMovement(this.transitions, { ...toolCall, status: "approved" }));
|
|
614
692
|
});
|
|
615
693
|
}
|
|
616
694
|
rejectToolCall(context, toolCall, rejectionMessage) {
|
|
@@ -680,12 +758,19 @@ export class ToolCallStep {
|
|
|
680
758
|
heartbeat: () => heartbeats.record(),
|
|
681
759
|
...(heartbeats.previousCheckpoint === undefined ? {} : { heartbeatCheckpoint: heartbeats.previousCheckpoint }),
|
|
682
760
|
saveHeartbeatCheckpoint: (checkpoint) => heartbeats.saveCheckpoint(checkpoint),
|
|
761
|
+
context,
|
|
683
762
|
};
|
|
684
763
|
let outcome;
|
|
685
764
|
try {
|
|
686
765
|
outcome = await transitions.runWithHeartbeats(context, () => transitions.runner.executeDeferredToolCall(execution), () => heartbeats.record());
|
|
687
766
|
}
|
|
688
767
|
catch (error) {
|
|
768
|
+
if (error instanceof ToolOutcomeUnknownError) {
|
|
769
|
+
const unknown = { ...toolCall, status: "outcome_unknown", error: error.message };
|
|
770
|
+
toolCallSpan.recordFinished(unknown);
|
|
771
|
+
transitions.finishToolCall(context, unknown, events);
|
|
772
|
+
return deadEnd();
|
|
773
|
+
}
|
|
689
774
|
if (!(error instanceof ToolExecutionError)) {
|
|
690
775
|
throw error;
|
|
691
776
|
}
|
|
@@ -703,7 +788,12 @@ export class ToolCallStep {
|
|
|
703
788
|
if (typeof outcome?.output !== "string") {
|
|
704
789
|
throw new TypeError(`executeDeferredToolCall returned no output for ${toolCallId}`);
|
|
705
790
|
}
|
|
706
|
-
const succeeded = {
|
|
791
|
+
const succeeded = {
|
|
792
|
+
...toolCall,
|
|
793
|
+
status: "succeeded",
|
|
794
|
+
output: outcome.output,
|
|
795
|
+
truncatedOutputBytes: outcome.truncatedOutputBytes ?? null,
|
|
796
|
+
};
|
|
707
797
|
toolCallSpan.recordFinished(succeeded);
|
|
708
798
|
transitions.finishToolCall(context, succeeded, events);
|
|
709
799
|
return deadEnd();
|
|
@@ -786,6 +876,9 @@ export class ToolCallFailureRecordingStep {
|
|
|
786
876
|
}
|
|
787
877
|
execute(context, toolCallId) {
|
|
788
878
|
const transitions = this.transitions;
|
|
879
|
+
if (isStateLimitFailure(context.recoveryError)) {
|
|
880
|
+
return recordFailedSession(transitions, context, readRecoveryDetail(context));
|
|
881
|
+
}
|
|
789
882
|
const toolCall = transitions.readToolCall(context, toolCallId);
|
|
790
883
|
if (isFinalToolCallStatus(toolCall.status)) {
|
|
791
884
|
return deadEnd();
|
|
@@ -855,12 +948,17 @@ export class ResumeTurnStep {
|
|
|
855
948
|
// The results did not all arrive, so wait again for the same count.
|
|
856
949
|
return goTo(new StepRef(agentSessionStepTypes.resumeTurn), expectedResultCount);
|
|
857
950
|
}
|
|
858
|
-
const unfinishedCount = toolCalls.filter((toolCall) => !isFinalToolCallStatus(toolCall.status)).length;
|
|
951
|
+
const unfinishedCount = toolCalls.filter((toolCall) => !isFinalToolCallStatus(toolCall.status) && toolCall.writeQueued !== true).length;
|
|
859
952
|
if (unfinishedCount > 0) {
|
|
860
953
|
// A consumed result from an earlier turn must not resume this one early.
|
|
861
954
|
return goTo(new StepRef(agentSessionStepTypes.resumeTurn), unfinishedCount);
|
|
862
955
|
}
|
|
863
956
|
if (reason !== null) {
|
|
957
|
+
transitions.writeEvents(context, turnId, (events) => {
|
|
958
|
+
for (const toolCall of toolCalls.filter((queued) => queued.writeQueued === true)) {
|
|
959
|
+
transitions.finishUnscheduledToolCall(context, { ...cancelledToolCall(toolCall, reason), writeQueued: false }, events);
|
|
960
|
+
}
|
|
961
|
+
});
|
|
864
962
|
return transitions.goToApplyTurnControl(context);
|
|
865
963
|
}
|
|
866
964
|
transitions.writeAgentState(context, { ...state, status: "running_model" });
|
|
@@ -912,7 +1010,7 @@ export class ApplyTurnControlStep {
|
|
|
912
1010
|
// Each movement into ApplyTurnControl adds the archive chunks of the model input.
|
|
913
1011
|
// The lock keeps a turn from starting while cancel_turn decides about the last one.
|
|
914
1012
|
return {
|
|
915
|
-
...messageStepOptions(this.transitions.persistence, this.getStepType(), staticMessageChunkLoads(this.transitions)),
|
|
1013
|
+
...messageStepOptions(this.transitions.persistence, this.getStepType(), staticMessageChunkLoads(this.transitions), this.transitions.config.runModelLimit),
|
|
916
1014
|
executeLockAttributes: [this.transitions.persistence.turnCancellationRequest.lock()],
|
|
917
1015
|
};
|
|
918
1016
|
}
|
|
@@ -935,6 +1033,11 @@ export class ApplyTurnControlStep {
|
|
|
935
1033
|
return transitions.beginTurn(context, state, steeredMessages, this.getStepType(), transitions.decideInteractionMode(context, steeredMessages));
|
|
936
1034
|
}
|
|
937
1035
|
}
|
|
1036
|
+
// server-zd reports a Step whose commit would pass limits.maxFlowStateBytes with this type and text:
|
|
1037
|
+
// "run state of <X> bytes exceeds the maximum of <Y> bytes", or "active run state of ..." since the limit
|
|
1038
|
+
// counts only active state.
|
|
1039
|
+
const stateLimitErrorType = "ValueTooLarge";
|
|
1040
|
+
const stateLimitErrorText = "run state of ";
|
|
938
1041
|
/** Ends a failed turn; it is the failure route of `RunModel` and `CompactContext`, so it takes either's input. */
|
|
939
1042
|
export class RecordTurnFailureStep {
|
|
940
1043
|
transitions;
|
|
@@ -959,15 +1062,48 @@ export class RecordTurnFailureStep {
|
|
|
959
1062
|
}
|
|
960
1063
|
execute(context) {
|
|
961
1064
|
const transitions = this.transitions;
|
|
1065
|
+
if (isStateLimitFailure(context.recoveryError)) {
|
|
1066
|
+
return recordFailedSession(transitions, context, readRecoveryDetail(context));
|
|
1067
|
+
}
|
|
962
1068
|
const state = transitions.readAgentState(context);
|
|
963
1069
|
const toolCalls = transitions.readTurnToolCalls(context, state.activeTurnId);
|
|
964
1070
|
const finalToolCalls = toolCalls.filter((toolCall) => isFinalToolCallStatus(toolCall.status));
|
|
965
1071
|
const unfinishedTurnMessages = state.activeTurnId === null
|
|
966
1072
|
? null
|
|
967
1073
|
: transitions.buildUnfinishedTurnMessages(context, state, state.activeTurnId, finalToolCalls);
|
|
968
|
-
|
|
1074
|
+
// A refused model call moves here on purpose, with its reason already in the state.
|
|
1075
|
+
const error = context.recoveryError === undefined && state.lastTurnError ? state.lastTurnError : readRecoveryDetail(context);
|
|
1076
|
+
return recordFailedTurn(transitions, context, state, toolCalls, unfinishedTurnMessages ?? [], error);
|
|
969
1077
|
}
|
|
970
1078
|
}
|
|
1079
|
+
/** Reports whether a Step failed because its commit would exceed the Flow's state limit. */
|
|
1080
|
+
export function isStateLimitFailure(recoveryError) {
|
|
1081
|
+
// The Server gives this failure no code of its own; a value over its own limit shares the type.
|
|
1082
|
+
return recoveryError?.errorType === stateLimitErrorType && recoveryError.detail.includes(stateLimitErrorText);
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* Ends a session whose Flow reached the state limit, in one commit with the Flow's close. This commit is checked
|
|
1086
|
+
* against the same limit, so it stores no turn messages and keeps the turn's tool call records. When it does not
|
|
1087
|
+
* fit, Dex fails the Flow with the same text and `AgentState` stays as it was; see `agent-session-failure.ts`.
|
|
1088
|
+
*/
|
|
1089
|
+
function recordFailedSession(transitions, context, error) {
|
|
1090
|
+
const persistence = transitions.persistence;
|
|
1091
|
+
const state = transitions.readAgentState(context);
|
|
1092
|
+
persistence.frameworkRunState.delete(context);
|
|
1093
|
+
if (transitions.readPendingInterrupts(context).length > 0) {
|
|
1094
|
+
persistence.pendingInterrupts.set(context, []);
|
|
1095
|
+
}
|
|
1096
|
+
transitions.writeAgentState(context, {
|
|
1097
|
+
...state,
|
|
1098
|
+
status: "failed",
|
|
1099
|
+
turnCount: state.turnCount + (state.activeTurnId === null ? 0 : 1),
|
|
1100
|
+
activeTurnId: null,
|
|
1101
|
+
lastTurnError: error,
|
|
1102
|
+
acceptsTurnControl: false,
|
|
1103
|
+
});
|
|
1104
|
+
transitions.writeEvents(context, state.activeTurnId, (events) => events.writeEvent("turn_failed", { error }));
|
|
1105
|
+
return forceFail(error);
|
|
1106
|
+
}
|
|
971
1107
|
/**
|
|
972
1108
|
* Ends the active turn as failed in the current commit: appends the unfinished-turn messages, then the
|
|
973
1109
|
* turn-failure note when the turn has final records, and clears the turn.
|
|
@@ -1106,6 +1242,63 @@ export function toolStepOptions(persistence, stepType, toolCallId) {
|
|
|
1106
1242
|
export function toolStepMovement(persistence, stepType, toolCallId) {
|
|
1107
1243
|
return StepMovement.of(new StepRef(stepType), toolCallId, toolStepOptions(persistence, stepType, toolCallId));
|
|
1108
1244
|
}
|
|
1245
|
+
/**
|
|
1246
|
+
* Returns the movement that starts an approved call's tool Step, with the runner's timeout and retry policy.
|
|
1247
|
+
* Only `CallTool` takes the retry policy; `CallSingleAttemptTool` keeps one attempt.
|
|
1248
|
+
*/
|
|
1249
|
+
export function toolCallMovement(transitions, toolCall) {
|
|
1250
|
+
const stepType = toolStepTypeForEffect(toolCall.effect);
|
|
1251
|
+
const options = toolStepOptions(transitions.persistence, stepType, toolCall.toolCallId);
|
|
1252
|
+
const overrides = readToolCallStepOptions(transitions, toolCall);
|
|
1253
|
+
return StepMovement.of(new StepRef(stepType), toolCall.toolCallId, {
|
|
1254
|
+
...options,
|
|
1255
|
+
...(overrides?.executeMethodTimeout === undefined ? {} : { executeMethodTimeoutMs: overrides.executeMethodTimeout }),
|
|
1256
|
+
...(overrides?.executeRetry === undefined || stepType !== agentSessionStepTypes.callTool
|
|
1257
|
+
? {}
|
|
1258
|
+
: { executeRetry: overrides.executeRetry }),
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
function readToolCallStepOptions(transitions, toolCall) {
|
|
1262
|
+
const provide = transitions.runner.toolCallStepOptions;
|
|
1263
|
+
if (provide === undefined) {
|
|
1264
|
+
return undefined;
|
|
1265
|
+
}
|
|
1266
|
+
try {
|
|
1267
|
+
return provide.call(transitions.runner, toRunnerToolCall(toolCall));
|
|
1268
|
+
}
|
|
1269
|
+
catch (error) {
|
|
1270
|
+
// The call then runs with the defaults; a missing tool fails by its effect class.
|
|
1271
|
+
console.warn(`dex-agents: toolCallStepOptions failed for ${toolCall.toolName}:`, error);
|
|
1272
|
+
return undefined;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
function toolApprovalInterrupt(toolCall, createdAt, deadline) {
|
|
1276
|
+
return {
|
|
1277
|
+
interruptId: toolCall.toolCallId,
|
|
1278
|
+
kind: "tool_approval",
|
|
1279
|
+
toolCallId: toolCall.toolCallId,
|
|
1280
|
+
toolName: toolCall.toolName,
|
|
1281
|
+
arguments: toolCall.arguments,
|
|
1282
|
+
createdAt,
|
|
1283
|
+
deadline,
|
|
1284
|
+
question: null,
|
|
1285
|
+
choices: [],
|
|
1286
|
+
allowsFreeText: true,
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
function interruptDeadline(transitions, createdAt) {
|
|
1290
|
+
const deadlineMs = transitions.config.interruptDeadlineMs;
|
|
1291
|
+
return deadlineMs === undefined ? null : new Date(createdAt.getTime() + deadlineMs).toISOString();
|
|
1292
|
+
}
|
|
1293
|
+
function skippedToolCall(toolCall) {
|
|
1294
|
+
return {
|
|
1295
|
+
...toolCall,
|
|
1296
|
+
status: "failed",
|
|
1297
|
+
writeQueued: false,
|
|
1298
|
+
skipped: true,
|
|
1299
|
+
error: `${toolCallNotRunErrorPrefix}: ${toolCallSkippedAfterWriteDetail}`,
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1109
1302
|
/**
|
|
1110
1303
|
* Returns the options of `PollToolTask`. It takes no lock and never waits on a cancellation: it owns the
|
|
1111
1304
|
* record, and a started task runs on.
|
|
@@ -1193,6 +1386,10 @@ function createToolCallRecord(batch, requestedToolCall, effect, requiresApproval
|
|
|
1193
1386
|
taskId: null,
|
|
1194
1387
|
taskPollIntervalSeconds: null,
|
|
1195
1388
|
taskAnswerPending: false,
|
|
1389
|
+
orderedWrite: false,
|
|
1390
|
+
writeQueued: false,
|
|
1391
|
+
skipped: false,
|
|
1392
|
+
truncatedOutputBytes: null,
|
|
1196
1393
|
};
|
|
1197
1394
|
}
|
|
1198
1395
|
function writeToolCallDeferred(events, record) {
|