@superdurable/dex-agents 0.3.0 → 0.5.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 +598 -45
- package/dist/src/agent-context-compaction.d.ts +1 -1
- package/dist/src/agent-framework-runner.d.ts +210 -10
- package/dist/src/agent-framework-runner.js +30 -0
- package/dist/src/agent-framework-runner.js.map +1 -1
- package/dist/src/agent-local-directory-media-store.d.ts +111 -0
- package/dist/src/agent-local-directory-media-store.js +417 -0
- package/dist/src/agent-local-directory-media-store.js.map +1 -0
- package/dist/src/agent-media.d.ts +279 -0
- package/dist/src/agent-media.js +457 -0
- package/dist/src/agent-media.js.map +1 -0
- package/dist/src/agent-session-codecs.d.ts +3 -1
- package/dist/src/agent-session-codecs.js +53 -4
- package/dist/src/agent-session-codecs.js.map +1 -1
- package/dist/src/agent-session-failure.d.ts +4 -2
- package/dist/src/agent-session-failure.js +6 -2
- package/dist/src/agent-session-failure.js.map +1 -1
- package/dist/src/agent-session-flow-graph.d.ts +46 -0
- package/dist/src/agent-session-flow-graph.js +51 -0
- package/dist/src/agent-session-flow-graph.js.map +1 -1
- package/dist/src/agent-session-flow-graph.json +98 -81
- package/dist/src/agent-session-flow.d.ts +5 -3
- package/dist/src/agent-session-flow.js +10 -1
- package/dist/src/agent-session-flow.js.map +1 -1
- package/dist/src/agent-session-start.d.ts +1 -1
- package/dist/src/agent-session-start.js +2 -2
- package/dist/src/agent-session-start.js.map +1 -1
- package/dist/src/agent-session-steps.d.ts +9 -0
- package/dist/src/agent-session-steps.js +219 -34
- package/dist/src/agent-session-steps.js.map +1 -1
- package/dist/src/agent-session-tracer.js +1 -1
- package/dist/src/agent-session-tracer.js.map +1 -1
- package/dist/src/agent-session-transitions.d.ts +4 -0
- package/dist/src/agent-session-transitions.js +29 -1
- package/dist/src/agent-session-transitions.js.map +1 -1
- package/dist/src/agent-session-values.d.ts +112 -1
- 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 +17 -5
- package/dist/src/agent-session-wait-steps.js.map +1 -1
- package/dist/src/ai-sdk/ai-sdk-model-client.d.ts +15 -3
- package/dist/src/ai-sdk/ai-sdk-model-client.js +36 -7
- package/dist/src/ai-sdk/ai-sdk-model-client.js.map +1 -1
- package/dist/src/ai-sdk/index.d.ts +1 -1
- package/dist/src/ai-sdk/index.js +1 -1
- package/dist/src/ai-sdk/index.js.map +1 -1
- package/dist/src/{stepwise → builtin-loop}/agent-definition.d.ts +120 -5
- package/dist/src/builtin-loop/agent-definition.js.map +1 -0
- package/dist/src/builtin-loop/builtin-agent-session-flow.d.ts +69 -0
- package/dist/src/{stepwise/stepwise-agent-session-flow.js → builtin-loop/builtin-agent-session-flow.js} +15 -9
- package/dist/src/builtin-loop/builtin-agent-session-flow.js.map +1 -0
- package/dist/src/{stepwise/stepwise-agent-runner.d.ts → builtin-loop/builtin-loop-agent-runner.d.ts} +85 -26
- package/dist/src/{stepwise/stepwise-agent-runner.js → builtin-loop/builtin-loop-agent-runner.js} +320 -213
- package/dist/src/builtin-loop/builtin-loop-agent-runner.js.map +1 -0
- package/dist/src/{stepwise/stepwise-input-items.d.ts → builtin-loop/builtin-loop-input-items.d.ts} +7 -3
- package/dist/src/{stepwise/stepwise-input-items.js → builtin-loop/builtin-loop-input-items.js} +57 -10
- package/dist/src/builtin-loop/builtin-loop-input-items.js.map +1 -0
- package/dist/src/builtin-loop/function-tool.d.ts +282 -0
- package/dist/src/{stepwise → builtin-loop}/function-tool.js +63 -3
- package/dist/src/builtin-loop/function-tool.js.map +1 -0
- package/dist/src/builtin-loop/index.d.ts +8 -0
- package/dist/src/builtin-loop/index.js +13 -0
- package/dist/src/builtin-loop/index.js.map +1 -0
- package/dist/src/builtin-loop/json-schema-validation.js.map +1 -0
- package/dist/src/{stepwise → builtin-loop}/model-client.d.ts +36 -7
- package/dist/src/builtin-loop/model-client.js.map +1 -0
- package/dist/src/{stepwise → builtin-loop}/scripted-model-client.d.ts +8 -5
- package/dist/src/{stepwise → builtin-loop}/scripted-model-client.js +8 -5
- package/dist/src/builtin-loop/scripted-model-client.js.map +1 -0
- package/dist/src/{stepwise → builtin-loop}/tool-source.d.ts +13 -3
- package/dist/src/builtin-loop/tool-source.js.map +1 -0
- 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 +94 -0
- package/dist/src/connectors/connector-step-context.js +180 -0
- package/dist/src/connectors/connector-step-context.js.map +1 -0
- package/dist/src/connectors/connector-tool-source.d.ts +401 -0
- package/dist/src/connectors/connector-tool-source.js +628 -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 +7 -3
- package/dist/src/index.js +6 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/index.d.ts +1 -0
- package/dist/src/mcp/index.js +1 -0
- package/dist/src/mcp/index.js.map +1 -1
- package/dist/src/mcp/mcp-dex-conventions.d.ts +57 -0
- package/dist/src/mcp/mcp-dex-conventions.js +90 -0
- package/dist/src/mcp/mcp-dex-conventions.js.map +1 -0
- package/dist/src/mcp/mcp-image-content.d.ts +20 -0
- package/dist/src/mcp/mcp-image-content.js +82 -0
- package/dist/src/mcp/mcp-image-content.js.map +1 -0
- package/dist/src/mcp/mcp-tool-source.d.ts +178 -17
- package/dist/src/mcp/mcp-tool-source.js +237 -34
- package/dist/src/mcp/mcp-tool-source.js.map +1 -1
- package/dist/src/s3/index.d.ts +1 -0
- package/dist/src/s3/index.js +9 -0
- package/dist/src/s3/index.js.map +1 -0
- package/dist/src/s3/s3-media-store.d.ts +138 -0
- package/dist/src/s3/s3-media-store.js +255 -0
- package/dist/src/s3/s3-media-store.js.map +1 -0
- package/dist/src/stepwise/index.d.ts +41 -8
- package/dist/src/stepwise/index.js +35 -5
- package/dist/src/stepwise/index.js.map +1 -1
- package/dist/src/testing/agent-session-test-client.d.ts +6 -3
- package/dist/src/testing/agent-session-test-client.js +10 -3
- package/dist/src/testing/agent-session-test-client.js.map +1 -1
- package/dist/src/testing/scripted-model-client.d.ts +1 -1
- package/dist/src/testing/scripted-model-client.js +2 -2
- package/dist/src/testing/scripted-model-client.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-json.d.ts +2 -1
- package/dist/src/ui-stream/agent-event-json.js +3 -1
- package/dist/src/ui-stream/agent-event-json.js.map +1 -1
- package/dist/src/ui-stream/agent-ui-messages.d.ts +11 -3
- package/dist/src/ui-stream/agent-ui-messages.js +29 -5
- package/dist/src/ui-stream/agent-ui-messages.js.map +1 -1
- package/package.json +25 -3
- package/dist/src/stepwise/agent-definition.js.map +0 -1
- package/dist/src/stepwise/function-tool.d.ts +0 -130
- package/dist/src/stepwise/function-tool.js.map +0 -1
- package/dist/src/stepwise/json-schema-validation.js.map +0 -1
- package/dist/src/stepwise/model-client.js.map +0 -1
- package/dist/src/stepwise/scripted-model-client.js.map +0 -1
- package/dist/src/stepwise/stepwise-agent-runner.js.map +0 -1
- package/dist/src/stepwise/stepwise-agent-session-flow.d.ts +0 -35
- package/dist/src/stepwise/stepwise-agent-session-flow.js.map +0 -1
- package/dist/src/stepwise/stepwise-input-items.js.map +0 -1
- package/dist/src/stepwise/tool-source.js.map +0 -1
- /package/dist/src/{stepwise → builtin-loop}/agent-definition.js +0 -0
- /package/dist/src/{stepwise → builtin-loop}/json-schema-validation.d.ts +0 -0
- /package/dist/src/{stepwise → builtin-loop}/json-schema-validation.js +0 -0
- /package/dist/src/{stepwise → builtin-loop}/model-client.js +0 -0
- /package/dist/src/{stepwise → builtin-loop}/tool-source.js +0 -0
|
@@ -2,7 +2,7 @@ import type { AgentEventWriter, AgentFrameworkRunner, AgentTurnContext, Deferred
|
|
|
2
2
|
import type { AgentMessage, AgentUsage, ContextSummary, SessionSettings } from "./agent-session-values.js";
|
|
3
3
|
/**
|
|
4
4
|
* When a session summarizes its earlier messages so the model input stays under the context window, passed
|
|
5
|
-
* as {@link AgentSessionOptions.compaction} or as `AgentDefinition.compaction` for a
|
|
5
|
+
* as {@link AgentSessionOptions.compaction} or as `AgentDefinition.compaction` for a built-in loop agent.
|
|
6
6
|
*
|
|
7
7
|
* Before each model call, `RunModel` asks the runner for the size of the next model input. When it reaches
|
|
8
8
|
* {@link triggerRatio} of {@link contextWindowTokens}, `RunModel` makes no model call and moves to
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { AsyncContext, RetryPolicy } from "@superdurable/dex";
|
|
1
2
|
import type { BuiltInTool } from "./agent-built-in-tools.js";
|
|
2
3
|
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";
|
|
4
|
+
import type { AgentImageReference, AgentMessage, AgentPlan, AgentToolCall, AgentToolCallRecord, AgentToolCallStatus, AgentUsage, ContextSummary, SessionSettings, FrameworkMessage, InteractionMode, QuestionAnswer, ToolEffect } from "./agent-session-values.js";
|
|
4
5
|
/**
|
|
5
6
|
* Per-tool override of the effect and approval defaults.
|
|
6
7
|
*
|
|
@@ -134,11 +135,14 @@ export interface AgentTurnContext {
|
|
|
134
135
|
*/
|
|
135
136
|
readonly messages: readonly AgentMessage[];
|
|
136
137
|
/**
|
|
137
|
-
* Framework run state from this turn's previous {@link ToolCallsRequested}
|
|
138
|
-
* the turn's first model call.
|
|
138
|
+
* Framework run state from this turn's previous {@link ToolCallsRequested} or {@link TurnContinued} outcome,
|
|
139
|
+
* or `null` for the turn's first model call.
|
|
139
140
|
*/
|
|
140
141
|
readonly frameworkRunState: string | null;
|
|
141
|
-
/**
|
|
142
|
+
/**
|
|
143
|
+
* Whether this model call continues the turn after tool calls or after a {@link TurnContinued} outcome, that
|
|
144
|
+
* is, `frameworkRunState` is set.
|
|
145
|
+
*/
|
|
142
146
|
readonly isResuming: boolean;
|
|
143
147
|
/**
|
|
144
148
|
* Tool call records of this turn, in deferral order; every record is final. Give the framework the
|
|
@@ -241,6 +245,15 @@ export interface DeferredToolCall {
|
|
|
241
245
|
* the tool without listing it again. Omit it to store nothing.
|
|
242
246
|
*/
|
|
243
247
|
readonly toolSourceReference?: string;
|
|
248
|
+
/**
|
|
249
|
+
* Whether the call is a write that runs in the model's order after the turn's earlier ordered calls.
|
|
250
|
+
* The session starts one ordered call at a time, raises its approval only when its turn comes, and
|
|
251
|
+
* records later ordered calls as skipped once one does not succeed. `read` calls ignore it. When
|
|
252
|
+
* omitted, the call runs in parallel with the turn's other calls. `ConnectorToolSource` sets it for
|
|
253
|
+
* connector writes.
|
|
254
|
+
* @since 0.4.0
|
|
255
|
+
*/
|
|
256
|
+
readonly ordered?: boolean;
|
|
244
257
|
}
|
|
245
258
|
/**
|
|
246
259
|
* Model and response of one model call, returned in {@link TurnCompleted} or {@link ToolCallsRequested}
|
|
@@ -297,6 +310,62 @@ export interface TurnCompleted {
|
|
|
297
310
|
readonly usage: AgentUsage;
|
|
298
311
|
/** Model and response of this model call, for the `chat` span. When omitted, the span is named `chat`. */
|
|
299
312
|
readonly modelCallMetadata?: ModelCallMetadata;
|
|
313
|
+
/**
|
|
314
|
+
* Error text that ends the turn as failed instead of completed.
|
|
315
|
+
*
|
|
316
|
+
* When it is set, the session still stores {@link newMessages} and records {@link usage} in the same commit.
|
|
317
|
+
* It then sets the turn's `lastTurnError` to this text and writes a `turn_failed` event instead of
|
|
318
|
+
* `turn_completed`. No retry follows, so use it only for a deliberate stop that a retry would repeat, such as a
|
|
319
|
+
* limit the runner enforces. Throw instead for a failure that a retry may fix. Omit it, the default, to complete
|
|
320
|
+
* the turn. Snapshots and the UI stream show the text, so keep secrets out of it.
|
|
321
|
+
*
|
|
322
|
+
* @since 0.5.0
|
|
323
|
+
*/
|
|
324
|
+
readonly turnError?: string;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Outcome of a model call that answered without tool calls, after which the turn continues with another model
|
|
328
|
+
* call.
|
|
329
|
+
*
|
|
330
|
+
* The session stores {@link newMessages}, records {@link usage}, keeps {@link frameworkRunState}, and moves to
|
|
331
|
+
* `RunModel` again, all in one commit, within the same turn. That next `RunModel` is its own Step, so a retry there
|
|
332
|
+
* repeats only its own model call. Its {@link AgentTurnContext.messages} include these messages. End them with a
|
|
333
|
+
* user message when the next request must end with one, as Anthropic models from Claude 4.6 on require. The
|
|
334
|
+
* built-in loop returns this outcome when `AgentDefinition.decideTurnContinuation` returns a continuation, with its
|
|
335
|
+
* message as the last of {@link newMessages}.
|
|
336
|
+
*
|
|
337
|
+
* A runner that returns it with messages must implement {@link AgentFrameworkRunner.buildUnfinishedTurnMessages},
|
|
338
|
+
* as for {@link ToolCallsRequested.newMessages}; the session fails the turn otherwise. A runner that never returns
|
|
339
|
+
* it needs no change.
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* ```ts
|
|
343
|
+
* return {
|
|
344
|
+
* kind: "turn_continued",
|
|
345
|
+
* frameworkRunState: JSON.stringify({ model_calls: modelCalls + 1 }),
|
|
346
|
+
* newMessages: [...previousToolResults, ...thisResponse, continuationUserMessage],
|
|
347
|
+
* usage,
|
|
348
|
+
* };
|
|
349
|
+
* ```
|
|
350
|
+
* @since 0.5.0
|
|
351
|
+
*/
|
|
352
|
+
export interface TurnContinued {
|
|
353
|
+
/** Discriminator. */
|
|
354
|
+
readonly kind: "turn_continued";
|
|
355
|
+
/**
|
|
356
|
+
* Non-empty serialized framework state from which the next `RunModel` continues the turn. The session keeps it
|
|
357
|
+
* opaquely in `FrameworkRunState`, as it keeps {@link ToolCallsRequested.frameworkRunState}.
|
|
358
|
+
*/
|
|
359
|
+
readonly frameworkRunState: string;
|
|
360
|
+
/**
|
|
361
|
+
* Messages of the turn to store now: the previous model response's unstored tool results, if any, this model
|
|
362
|
+
* response, and any user message for the next call. The next {@link AgentTurnContext.messages} include them.
|
|
363
|
+
*/
|
|
364
|
+
readonly newMessages: readonly FrameworkMessage[];
|
|
365
|
+
/** Usage of this model call only. */
|
|
366
|
+
readonly usage: AgentUsage;
|
|
367
|
+
/** Model and response of this model call, for the `chat` span. When omitted, the span is named `chat`. */
|
|
368
|
+
readonly modelCallMetadata?: ModelCallMetadata;
|
|
300
369
|
}
|
|
301
370
|
/** Outcome of a model call that requested tool calls. */
|
|
302
371
|
export interface ToolCallsRequested {
|
|
@@ -329,8 +398,12 @@ export interface ToolCallsRequested {
|
|
|
329
398
|
/** Model and response of this model call, for the `chat` span. When omitted, the span is named `chat`. */
|
|
330
399
|
readonly modelCallMetadata?: ModelCallMetadata;
|
|
331
400
|
}
|
|
332
|
-
/**
|
|
333
|
-
|
|
401
|
+
/**
|
|
402
|
+
* Result of {@link AgentFrameworkRunner.runModelStep}.
|
|
403
|
+
*
|
|
404
|
+
* Changed in 0.5.0: {@link TurnContinued} joined the union, so code that handles every kind handles it too.
|
|
405
|
+
*/
|
|
406
|
+
export type AgentTurnOutcome = TurnCompleted | ToolCallsRequested | TurnContinued;
|
|
334
407
|
/** One tool call that a tool Step asks the runner to run. */
|
|
335
408
|
export interface DeferredToolExecution {
|
|
336
409
|
/** Flow ID, which is the session ID. */
|
|
@@ -387,11 +460,66 @@ export interface DeferredToolExecution {
|
|
|
387
460
|
* @returns A Promise that resolves when the Worker accepted the heartbeat.
|
|
388
461
|
*/
|
|
389
462
|
saveHeartbeatCheckpoint?(checkpoint: string): Promise<void>;
|
|
463
|
+
/**
|
|
464
|
+
* The tool Step's live context, absent when the caller has none, such as a unit test. It gives the Step
|
|
465
|
+
* execution ID, the attempt deadline, and heartbeats. Use it only during this call and never store it.
|
|
466
|
+
* Record heartbeats only through {@link heartbeat} and {@link saveHeartbeatCheckpoint}, because a bare
|
|
467
|
+
* `context.recordHeartbeat()` would drop the checkpoint. It is never part of stored state.
|
|
468
|
+
* `ConnectorToolSource` derives the connector Call ID from its Step execution ID.
|
|
469
|
+
* @since 0.4.0
|
|
470
|
+
*/
|
|
471
|
+
readonly context?: AsyncContext;
|
|
390
472
|
}
|
|
391
473
|
/** Successful result of one deferred tool call. A result without `kind` is a `ToolExecutionResult`. */
|
|
392
474
|
export interface ToolExecutionResult {
|
|
393
475
|
/** Output text recorded on the call and shown to the model. */
|
|
394
476
|
readonly output: string;
|
|
477
|
+
/**
|
|
478
|
+
* Size in bytes of the full output when {@link output} is a truncated copy; omit it when the output is
|
|
479
|
+
* whole. The session stores it as {@link AgentToolCall.truncatedOutputBytes}.
|
|
480
|
+
* @since 0.4.0
|
|
481
|
+
*/
|
|
482
|
+
readonly truncatedOutputBytes?: number;
|
|
483
|
+
/**
|
|
484
|
+
* Images the tool returns with {@link output}, uploaded with `MediaStore.putImage` inside the call, at most
|
|
485
|
+
* `maxImagesPerMessage`. The session stores them as {@link AgentToolCall.images}; a reference that
|
|
486
|
+
* `validateImageReference` refuses fails the attempt. Upload before returning: a retried attempt uploads the same
|
|
487
|
+
* bytes to the same object. Omit it for none.
|
|
488
|
+
* @since 0.5.0
|
|
489
|
+
*/
|
|
490
|
+
readonly images?: readonly AgentImageReference[];
|
|
491
|
+
/**
|
|
492
|
+
* Opaque text the runner keeps with the call's result for its own later model calls, such as the framework
|
|
493
|
+
* state that the tool changed. The session stores it as {@link AgentToolCall.runnerToolState} of the
|
|
494
|
+
* `succeeded` record, and `runModelStep` reads it from `AgentTurnContext.toolCalls`. The session never interprets
|
|
495
|
+
* it and never shows it to the model, in the browser snapshot from `agentSnapshotToJson`, or in trace attributes.
|
|
496
|
+
* Only the attempt that commits the result stores it, so a retried attempt never adds a second copy. Omit it to
|
|
497
|
+
* store nothing.
|
|
498
|
+
* @since 0.5.0
|
|
499
|
+
*/
|
|
500
|
+
readonly runnerToolState?: string;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Timeout and retry policy of one tool call's Step, returned by
|
|
504
|
+
* {@link AgentFrameworkRunner.toolCallStepOptions}.
|
|
505
|
+
*
|
|
506
|
+
* The session applies it to the movement that starts the call's tool Step, and to no other Step. A
|
|
507
|
+
* `CallSingleAttemptTool` call takes only {@link executeMethodTimeout}; it still runs one attempt.
|
|
508
|
+
*
|
|
509
|
+
* @example
|
|
510
|
+
* ```ts
|
|
511
|
+
* const options: ToolCallStepOptions = {
|
|
512
|
+
* executeMethodTimeout: 30_000,
|
|
513
|
+
* executeRetry: { maximumAttempts: 3, totalDuration: 3_600_000 },
|
|
514
|
+
* };
|
|
515
|
+
* ```
|
|
516
|
+
* @since 0.4.0
|
|
517
|
+
*/
|
|
518
|
+
export interface ToolCallStepOptions {
|
|
519
|
+
/** Timeout of each attempt in milliseconds; omit it for the tool Step's default. */
|
|
520
|
+
readonly executeMethodTimeout?: number;
|
|
521
|
+
/** Retry policy of a `CallTool` call; omit it for the default of three attempts. */
|
|
522
|
+
readonly executeRetry?: RetryPolicy;
|
|
395
523
|
}
|
|
396
524
|
/**
|
|
397
525
|
* Result of a deferred tool call that needs an answer from the user before it can take effect.
|
|
@@ -548,6 +676,33 @@ export interface ToolTaskCancellation {
|
|
|
548
676
|
export type DeferredToolOutcome = ToolExecutionResult | ToolInputRequested | ToolTaskStarted;
|
|
549
677
|
/** Result of {@link AgentFrameworkRunner.pollToolTask}. */
|
|
550
678
|
export type ToolTaskPollOutcome = ToolExecutionResult | ToolInputRequested | ToolTaskPending;
|
|
679
|
+
/**
|
|
680
|
+
* Tool failure whose effect may or may not have happened, thrown from
|
|
681
|
+
* {@link AgentFrameworkRunner.executeDeferredToolCall}.
|
|
682
|
+
*
|
|
683
|
+
* Throw it when the tool sent a write and cannot tell whether it took effect, such as a connector
|
|
684
|
+
* operation's `uncertain` branch. The session records `outcome_unknown` with this error's message as
|
|
685
|
+
* `error`, does not retry, and the model sees {@link outcomeUnknownToolResult}. A later ordered write of
|
|
686
|
+
* the turn is skipped.
|
|
687
|
+
*
|
|
688
|
+
* {@link AgentFrameworkRunner.pollToolTask} may throw it too, for a task that ended without a known
|
|
689
|
+
* outcome. The session then records `outcome_unknown` the same way and stops polling. Changed in 0.5.0:
|
|
690
|
+
* `pollToolTask` may throw it.
|
|
691
|
+
*
|
|
692
|
+
* @example
|
|
693
|
+
* ```ts
|
|
694
|
+
* throw new ToolOutcomeUnknownError("the provider timed out after receiving the refund");
|
|
695
|
+
* ```
|
|
696
|
+
* @since 0.4.0
|
|
697
|
+
*/
|
|
698
|
+
export declare class ToolOutcomeUnknownError extends Error {
|
|
699
|
+
/**
|
|
700
|
+
* Creates an unknown-outcome failure.
|
|
701
|
+
* @param message - Error text recorded on the call.
|
|
702
|
+
* @param options - Standard error options, such as `cause`.
|
|
703
|
+
*/
|
|
704
|
+
constructor(message: string, options?: ErrorOptions);
|
|
705
|
+
}
|
|
551
706
|
/**
|
|
552
707
|
* Tool failure that the model should see, thrown from {@link AgentFrameworkRunner.executeDeferredToolCall}.
|
|
553
708
|
*
|
|
@@ -629,12 +784,35 @@ export interface AgentFrameworkRunner<ToolOutcome extends DeferredToolOutcome =
|
|
|
629
784
|
* @returns The framework message, with `role` `"user"`.
|
|
630
785
|
*/
|
|
631
786
|
buildUserMessage(text: string): FrameworkMessage;
|
|
787
|
+
/**
|
|
788
|
+
* Converts a user message with images into the framework's user message. Optional.
|
|
789
|
+
*
|
|
790
|
+
* Implement it when the runner can show images to its model. `send_user_message` accepts images only for a runner
|
|
791
|
+
* with this method, and the session calls it instead of {@link buildUserMessage} for a message with images. Put
|
|
792
|
+
* the references, never the bytes, in `frameworkItem`; read the bytes with `loadImages` when the model call
|
|
793
|
+
* builds its input. The session sets the stored message's `images` itself. It must be synchronous,
|
|
794
|
+
* deterministic, and free of side effects.
|
|
795
|
+
*
|
|
796
|
+
* @example
|
|
797
|
+
* ```ts
|
|
798
|
+
* public buildUserMessageWithImages(text: string, images: readonly AgentImageReference[]): FrameworkMessage {
|
|
799
|
+
* return { role: "user", text, toolCallId: null, toolName: null, toolArguments: null, toolOutput: null,
|
|
800
|
+
* frameworkItem: JSON.stringify({ role: "user", content: text, images }) };
|
|
801
|
+
* }
|
|
802
|
+
* ```
|
|
803
|
+
* @param text - User message text, never blank.
|
|
804
|
+
* @param images - The message's images, at least one, each valid for `validateImageReference`.
|
|
805
|
+
* @returns The framework message, with `role` `"user"`.
|
|
806
|
+
* @since 0.5.0
|
|
807
|
+
*/
|
|
808
|
+
buildUserMessageWithImages?(text: string, images: readonly AgentImageReference[]): FrameworkMessage;
|
|
632
809
|
/**
|
|
633
810
|
* Makes the turn's next model call, at most one.
|
|
634
811
|
*
|
|
635
812
|
* @param turn - Turn context; see {@link AgentTurnContext}.
|
|
636
|
-
* @returns {@link TurnCompleted} with every new message of the turn,
|
|
637
|
-
* with the framework run state and every tool call of the model response
|
|
813
|
+
* @returns {@link TurnCompleted} with every new message of the turn, {@link ToolCallsRequested}
|
|
814
|
+
* with the framework run state and every tool call of the model response, or {@link TurnContinued} to make
|
|
815
|
+
* another model call within the same turn.
|
|
638
816
|
* @throws Any error to retry the model call; after the last attempt the turn fails.
|
|
639
817
|
*/
|
|
640
818
|
runModelStep(turn: AgentTurnContext): Promise<AgentTurnOutcome>;
|
|
@@ -671,8 +849,8 @@ export interface AgentFrameworkRunner<ToolOutcome extends DeferredToolOutcome =
|
|
|
671
849
|
* Such a runner reads {@link AgentTurnContext.interactionMode} in every `runModelStep`. In a `planning`
|
|
672
850
|
* turn it offers only the `write_todos` definition from {@link builtInToolDefinitions}. It may force
|
|
673
851
|
* `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;
|
|
675
|
-
* turn it shows the plan with {@link buildPlanNote} as user text before the turn's messages. The
|
|
852
|
+
* forced tool choice; the built-in loop does with `planningToolChoice: "required"`. In every
|
|
853
|
+
* turn it shows the plan with {@link buildPlanNote} as user text before the turn's messages. The built-in loop
|
|
676
854
|
* runner implements it; a framework adapter that cannot change the tools it offers between turns leaves
|
|
677
855
|
* plan mode off.
|
|
678
856
|
*/
|
|
@@ -701,6 +879,9 @@ export interface AgentFrameworkRunner<ToolOutcome extends DeferredToolOutcome =
|
|
|
701
879
|
* the call's result.
|
|
702
880
|
* @throws {ToolExecutionError} When the task failed in a way the model should see; the call is
|
|
703
881
|
* recorded as `failed`.
|
|
882
|
+
* @throws {ToolOutcomeUnknownError} When the task ended and may or may not have taken effect; the call is
|
|
883
|
+
* recorded as `outcome_unknown` and not polled again. Changed in 0.5.0: this error is recorded instead of
|
|
884
|
+
* failing the poll attempt.
|
|
704
885
|
* @throws Any other error to fail the poll attempt; after three attempts the record becomes `failed`
|
|
705
886
|
* for a `read` call and `outcome_unknown` otherwise, because the task may still run.
|
|
706
887
|
*/
|
|
@@ -727,6 +908,25 @@ export interface AgentFrameworkRunner<ToolOutcome extends DeferredToolOutcome =
|
|
|
727
908
|
* three times, then records the call `outcome_unknown` anyway, so the turn always ends.
|
|
728
909
|
*/
|
|
729
910
|
cancelToolTask?(cancellation: ToolTaskCancellation): Promise<void>;
|
|
911
|
+
/**
|
|
912
|
+
* Returns the timeout and retry policy of one call's tool Step. Optional.
|
|
913
|
+
*
|
|
914
|
+
* Implement it when some tools need options other than the tool Steps' defaults, as the built-in loop runner
|
|
915
|
+
* does for a tool source that defines `toolCallStepOptions`. The session calls it whenever it starts a
|
|
916
|
+
* call's tool Step, including after an approval, so it must answer from the record alone. A method that
|
|
917
|
+
* throws leaves the defaults.
|
|
918
|
+
*
|
|
919
|
+
* @example
|
|
920
|
+
* ```ts
|
|
921
|
+
* public toolCallStepOptions(toolCall: AgentToolCall): ToolCallStepOptions | undefined {
|
|
922
|
+
* return toolCall.toolName === "export_report" ? { executeMethodTimeout: 120_000 } : undefined;
|
|
923
|
+
* }
|
|
924
|
+
* ```
|
|
925
|
+
* @param toolCall - The record whose tool Step starts.
|
|
926
|
+
* @returns The options, or `undefined` for the defaults.
|
|
927
|
+
* @since 0.4.0
|
|
928
|
+
*/
|
|
929
|
+
toolCallStepOptions?(toolCall: AgentToolCall): ToolCallStepOptions | undefined;
|
|
730
930
|
/**
|
|
731
931
|
* Estimates the size of the model input that the next {@link runModelStep} sends. Optional; one of the
|
|
732
932
|
* three compaction methods that {@link AgentSessionOptions.compaction} requires.
|
|
@@ -29,6 +29,36 @@ export function resolveToolPolicy(toolName, toolPolicies, defaultToolEffect, fra
|
|
|
29
29
|
const requiresApproval = policy?.requiresApproval ?? (effect === "non_idempotent_write" || effect === "unclassified");
|
|
30
30
|
return { effect, requiresApproval };
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Tool failure whose effect may or may not have happened, thrown from
|
|
34
|
+
* {@link AgentFrameworkRunner.executeDeferredToolCall}.
|
|
35
|
+
*
|
|
36
|
+
* Throw it when the tool sent a write and cannot tell whether it took effect, such as a connector
|
|
37
|
+
* operation's `uncertain` branch. The session records `outcome_unknown` with this error's message as
|
|
38
|
+
* `error`, does not retry, and the model sees {@link outcomeUnknownToolResult}. A later ordered write of
|
|
39
|
+
* the turn is skipped.
|
|
40
|
+
*
|
|
41
|
+
* {@link AgentFrameworkRunner.pollToolTask} may throw it too, for a task that ended without a known
|
|
42
|
+
* outcome. The session then records `outcome_unknown` the same way and stops polling. Changed in 0.5.0:
|
|
43
|
+
* `pollToolTask` may throw it.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* throw new ToolOutcomeUnknownError("the provider timed out after receiving the refund");
|
|
48
|
+
* ```
|
|
49
|
+
* @since 0.4.0
|
|
50
|
+
*/
|
|
51
|
+
export class ToolOutcomeUnknownError extends Error {
|
|
52
|
+
/**
|
|
53
|
+
* Creates an unknown-outcome failure.
|
|
54
|
+
* @param message - Error text recorded on the call.
|
|
55
|
+
* @param options - Standard error options, such as `cause`.
|
|
56
|
+
*/
|
|
57
|
+
constructor(message, options) {
|
|
58
|
+
super(message, options);
|
|
59
|
+
this.name = "ToolOutcomeUnknownError";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
32
62
|
/**
|
|
33
63
|
* Tool failure that the model should see, thrown from {@link AgentFrameworkRunner.executeDeferredToolCall}.
|
|
34
64
|
*
|
|
@@ -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;AAsD1D;;;;;;;;;;;;;;;;;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;AAqoBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAChD;;;;OAIG;IACH,YAAmB,OAAe,EAAE,OAAsB;QACxD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED;;;;;;;;;;;;;;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;AA4QD;;;;;;;;;;;;;;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,111 @@
|
|
|
1
|
+
import { type MediaStore } from "./agent-media.js";
|
|
2
|
+
import type { AgentImageReference } from "./agent-session-values.js";
|
|
3
|
+
/**
|
|
4
|
+
* Keeps image bytes in a local directory, one file per distinct image.
|
|
5
|
+
*
|
|
6
|
+
* Use it when every client and Worker of a session runs on one machine, such as a command-line tool in local mode;
|
|
7
|
+
* use `S3MediaStore` from `@superdurable/dex-agents/s3` when they run on different machines.
|
|
8
|
+
*
|
|
9
|
+
* The file of an image is `<root>/sha256/<sha256>`, and a reference's `uri` is `file://<root>/sha256/<sha256>`, where
|
|
10
|
+
* `<root>` is the absolute root with every UTF-8 byte other than ASCII letters, digits, `-`, `.`, `_`, `~`, and `/`
|
|
11
|
+
* written as `%XX` in uppercase hex. The root is made absolute as text: `.` and `..` segments and repeated or trailing
|
|
12
|
+
* `/` characters are resolved without reading the file system, symbolic links are not resolved, and Unicode is not
|
|
13
|
+
* normalized. A client and a Worker that pass the same root therefore build the same references, in every core.
|
|
14
|
+
*
|
|
15
|
+
* `putImage` copies the bytes into a temporary file in the same directory, syncs it, and renames it into place, so a
|
|
16
|
+
* reader never sees a partial image. An existing file with the same bytes is success, so retried and concurrent uploads
|
|
17
|
+
* of the same bytes leave one file; an existing file with other bytes is replaced. Directories the store creates get
|
|
18
|
+
* mode `0700` and image files mode `0600`, narrowed further by the process umask. When `putImage` writes the image, it
|
|
19
|
+
* syncs the file before the rename. Before every `putImage` returns, including when an identical file already exists
|
|
20
|
+
* and nothing is written, it syncs the `sha256` directory, the root, and the root's parent. It also syncs the parent of
|
|
21
|
+
* each directory it creates. Directories above the root's parent must already be durable: a concurrent creator of a
|
|
22
|
+
* deeper missing ancestor is out of scope.
|
|
23
|
+
*
|
|
24
|
+
* The store refuses a `sha256` directory or an image file that is a symbolic link or not a regular file, and an image
|
|
25
|
+
* file with more than one hard link, with `MediaStoreError`, on both upload and read. The root itself may be a symbolic
|
|
26
|
+
* link. Node.js has no `openat`, so this store opens files by path and checks before and after each operation: it
|
|
27
|
+
* checks the `sha256` directory with `lstat` and opens the file with `O_NOFOLLOW`, then confirms that the real path of
|
|
28
|
+
* the `sha256` directory is still the root's and that the path still names the opened or written file. A read that
|
|
29
|
+
* fails the check returns nothing, and a write that fails it removes the file it wrote when it can still find it. A
|
|
30
|
+
* process of the same user that can write the `0700` root can still race a directory swap between these checks; the
|
|
31
|
+
* Python core opens every path relative to an open directory and has no such window. `getImage` reads only
|
|
32
|
+
* references under this store's root, refuses a file whose size differs from the reference before reading it, reads at
|
|
33
|
+
* most one byte more than `sizeBytes`, and checks the bytes with `verifyImageBytes`. It needs a POSIX file system; on
|
|
34
|
+
* Windows the constructor throws.
|
|
35
|
+
*
|
|
36
|
+
* Session deletion does not delete files. A runner reads a session's images again whenever a model call replays them,
|
|
37
|
+
* so keep every file at least as long as any session that references it can still run a turn or replay its history. A
|
|
38
|
+
* missing file makes those turns fail with `MediaStoreError`.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* import { LocalDirectoryMediaStore } from "@superdurable/dex-agents";
|
|
43
|
+
*
|
|
44
|
+
* const store = new LocalDirectoryMediaStore("/var/lib/my-agent/media");
|
|
45
|
+
* const reference = await store.putImage(screenshotPng);
|
|
46
|
+
* // reference.uri === "file:///var/lib/my-agent/media/sha256/9f2c..."
|
|
47
|
+
* ```
|
|
48
|
+
* @since 0.5.0
|
|
49
|
+
*/
|
|
50
|
+
export declare class LocalDirectoryMediaStore implements MediaStore {
|
|
51
|
+
/** The absolute root directory, made absolute as text, without a trailing `/`. */
|
|
52
|
+
readonly root: string;
|
|
53
|
+
/** The location that every reference of this store starts with: `"file://<root>"`, with the root percent-encoded. */
|
|
54
|
+
readonly storeUri: string;
|
|
55
|
+
/**
|
|
56
|
+
* Creates a store; it touches no file until the first upload or read.
|
|
57
|
+
*
|
|
58
|
+
* @param root - Absolute path of the directory that holds the images, such as `"/var/lib/my-agent/media"`. The first
|
|
59
|
+
* upload creates it and any missing parent directory with mode `0700`.
|
|
60
|
+
* @throws {TypeError} When `root` is not absolute, is not well-formed Unicode, contains NUL, or is the file system
|
|
61
|
+
* root.
|
|
62
|
+
* @throws {RangeError} When `root` makes image URIs longer than `maxImageUriLength`.
|
|
63
|
+
* @throws {Error} On a system without POSIX file access, such as Windows.
|
|
64
|
+
*/
|
|
65
|
+
constructor(root: string);
|
|
66
|
+
/**
|
|
67
|
+
* Returns the path of the file of the image with this SHA-256.
|
|
68
|
+
*
|
|
69
|
+
* @param sha256 - SHA-256 of the bytes as 64 lowercase hex digits.
|
|
70
|
+
* @returns `"<root>/sha256/<sha256>"`.
|
|
71
|
+
*/
|
|
72
|
+
imagePath(sha256: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* Stores one image unless the directory already has it, and returns its reference.
|
|
75
|
+
*
|
|
76
|
+
* @param data - PNG, JPEG, GIF, or WebP bytes, at most `maxImageBytes`.
|
|
77
|
+
* @returns The reference.
|
|
78
|
+
* @throws {ImageValidationError} When the bytes are not a valid image for `buildImageReference`. Nothing is written.
|
|
79
|
+
* @throws {MediaStoreError} When the `sha256` directory or the image's file is a symbolic link or not a directory or
|
|
80
|
+
* regular file, the image's file has more than one hard link, or the `sha256` directory changed during the write.
|
|
81
|
+
* @throws A Node.js system error (`NodeJS.ErrnoException`) when the file system refuses a write, such as for missing
|
|
82
|
+
* permissions or a full disk. Retrying is safe.
|
|
83
|
+
*/
|
|
84
|
+
putImage(data: Uint8Array): Promise<AgentImageReference>;
|
|
85
|
+
/**
|
|
86
|
+
* Returns the bytes of one image in this store.
|
|
87
|
+
*
|
|
88
|
+
* @param reference - A reference under this store's root.
|
|
89
|
+
* @returns The exact bytes, checked with `verifyImageBytes`.
|
|
90
|
+
* @throws {ImageValidationError} When the reference's fields are invalid.
|
|
91
|
+
* @throws {MediaStoreError} When the reference is outside this store's root, the file is missing, is a symbolic link
|
|
92
|
+
* or not a regular file, has more than one hard link, moved during the read, or its bytes do not match.
|
|
93
|
+
* @throws A Node.js system error (`NodeJS.ErrnoException`) when the file system refuses the read for another reason.
|
|
94
|
+
*/
|
|
95
|
+
getImage(reference: AgentImageReference): Promise<Uint8Array>;
|
|
96
|
+
private imageDirectory;
|
|
97
|
+
/** Creates the root and its missing parents with mode `0700`, syncing the parent of each. */
|
|
98
|
+
private makeRoot;
|
|
99
|
+
/** Throws `MediaStoreError` unless the `sha256` directory is a real directory, not a symbolic link. */
|
|
100
|
+
private requireImageDirectory;
|
|
101
|
+
/** Returns whether the image's file exists and holds exactly `data`. */
|
|
102
|
+
private hasImageFile;
|
|
103
|
+
/** Opens the reference's image file, refusing symbolic links, special files, hard links, and moved files. */
|
|
104
|
+
private openImageFile;
|
|
105
|
+
/** Returns the open file, or `undefined` when a rename replaced it after the open. */
|
|
106
|
+
private openImageFileOnce;
|
|
107
|
+
/** Returns whether the `sha256` directory is a real directory whose real path is the root's. */
|
|
108
|
+
private isImageDirectoryInStore;
|
|
109
|
+
private directoryChanged;
|
|
110
|
+
private replaceImageFile;
|
|
111
|
+
}
|