@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.
Files changed (168) hide show
  1. package/README.md +1608 -64
  2. package/dist/src/agent-built-in-tools.d.ts +81 -0
  3. package/dist/src/agent-built-in-tools.js +246 -0
  4. package/dist/src/agent-built-in-tools.js.map +1 -0
  5. package/dist/src/agent-context-compaction.d.ts +254 -0
  6. package/dist/src/agent-context-compaction.js +287 -0
  7. package/dist/src/agent-context-compaction.js.map +1 -0
  8. package/dist/src/agent-framework-runner.d.ts +456 -16
  9. package/dist/src/agent-framework-runner.js +4 -3
  10. package/dist/src/agent-framework-runner.js.map +1 -1
  11. package/dist/src/agent-plans.d.ts +48 -0
  12. package/dist/src/agent-plans.js +86 -0
  13. package/dist/src/agent-plans.js.map +1 -0
  14. package/dist/src/agent-session-cancellation-steps.d.ts +28 -0
  15. package/dist/src/agent-session-cancellation-steps.js +154 -0
  16. package/dist/src/agent-session-cancellation-steps.js.map +1 -0
  17. package/dist/src/agent-session-codecs.d.ts +65 -4
  18. package/dist/src/agent-session-codecs.js +343 -8
  19. package/dist/src/agent-session-codecs.js.map +1 -1
  20. package/dist/src/agent-session-failure.d.ts +58 -0
  21. package/dist/src/agent-session-failure.js +126 -0
  22. package/dist/src/agent-session-failure.js.map +1 -0
  23. package/dist/src/agent-session-flow-graph-cli.d.ts +2 -0
  24. package/dist/src/agent-session-flow-graph-cli.js +47 -0
  25. package/dist/src/agent-session-flow-graph-cli.js.map +1 -0
  26. package/dist/src/agent-session-flow-graph.d.ts +38 -0
  27. package/dist/src/agent-session-flow-graph.js +54 -0
  28. package/dist/src/agent-session-flow-graph.js.map +1 -0
  29. package/dist/src/agent-session-flow-graph.json +2187 -0
  30. package/dist/src/agent-session-flow.d.ts +317 -28
  31. package/dist/src/agent-session-flow.js +373 -21
  32. package/dist/src/agent-session-flow.js.map +1 -1
  33. package/dist/src/agent-session-persistence.d.ts +81 -4
  34. package/dist/src/agent-session-persistence.js +33 -2
  35. package/dist/src/agent-session-persistence.js.map +1 -1
  36. package/dist/src/agent-session-settings.d.ts +58 -0
  37. package/dist/src/agent-session-settings.js +81 -0
  38. package/dist/src/agent-session-settings.js.map +1 -0
  39. package/dist/src/agent-session-spend-limit.d.ts +156 -0
  40. package/dist/src/agent-session-spend-limit.js +42 -0
  41. package/dist/src/agent-session-spend-limit.js.map +1 -0
  42. package/dist/src/agent-session-start.d.ts +49 -0
  43. package/dist/src/agent-session-start.js +67 -0
  44. package/dist/src/agent-session-start.js.map +1 -0
  45. package/dist/src/agent-session-step-options.d.ts +78 -0
  46. package/dist/src/agent-session-step-options.js +71 -0
  47. package/dist/src/agent-session-step-options.js.map +1 -0
  48. package/dist/src/agent-session-step-types.d.ts +20 -0
  49. package/dist/src/agent-session-step-types.js +28 -0
  50. package/dist/src/agent-session-step-types.js.map +1 -0
  51. package/dist/src/agent-session-steps.d.ts +103 -8
  52. package/dist/src/agent-session-steps.js +997 -197
  53. package/dist/src/agent-session-steps.js.map +1 -1
  54. package/dist/src/agent-session-tracer.d.ts +61 -0
  55. package/dist/src/agent-session-tracer.js +608 -0
  56. package/dist/src/agent-session-tracer.js.map +1 -0
  57. package/dist/src/agent-session-transitions.d.ts +200 -26
  58. package/dist/src/agent-session-transitions.js +732 -32
  59. package/dist/src/agent-session-transitions.js.map +1 -1
  60. package/dist/src/agent-session-values.d.ts +696 -30
  61. package/dist/src/agent-session-values.js +39 -4
  62. package/dist/src/agent-session-values.js.map +1 -1
  63. package/dist/src/agent-session-wait-steps.d.ts +53 -0
  64. package/dist/src/agent-session-wait-steps.js +389 -0
  65. package/dist/src/agent-session-wait-steps.js.map +1 -0
  66. package/dist/src/agent-tracing-options.d.ts +107 -0
  67. package/dist/src/agent-tracing-options.js +20 -0
  68. package/dist/src/agent-tracing-options.js.map +1 -0
  69. package/dist/src/ai-sdk/ai-sdk-model-client.d.ts +40 -0
  70. package/dist/src/ai-sdk/ai-sdk-model-client.js +235 -0
  71. package/dist/src/ai-sdk/ai-sdk-model-client.js.map +1 -0
  72. package/dist/src/ai-sdk/index.d.ts +1 -0
  73. package/dist/src/ai-sdk/index.js +9 -0
  74. package/dist/src/ai-sdk/index.js.map +1 -0
  75. package/dist/src/index.d.ts +14 -3
  76. package/dist/src/index.js +12 -2
  77. package/dist/src/index.js.map +1 -1
  78. package/dist/src/mcp/index.d.ts +3 -0
  79. package/dist/src/mcp/index.js +10 -0
  80. package/dist/src/mcp/index.js.map +1 -0
  81. package/dist/src/mcp/mcp-resource-and-prompt-tools.d.ts +29 -0
  82. package/dist/src/mcp/mcp-resource-and-prompt-tools.js +185 -0
  83. package/dist/src/mcp/mcp-resource-and-prompt-tools.js.map +1 -0
  84. package/dist/src/mcp/mcp-server-config.d.ts +86 -0
  85. package/dist/src/mcp/mcp-server-config.js +38 -0
  86. package/dist/src/mcp/mcp-server-config.js.map +1 -0
  87. package/dist/src/mcp/mcp-tool-source.d.ts +470 -0
  88. package/dist/src/mcp/mcp-tool-source.js +1204 -0
  89. package/dist/src/mcp/mcp-tool-source.js.map +1 -0
  90. package/dist/src/stepwise/agent-definition.d.ts +166 -0
  91. package/dist/src/stepwise/agent-definition.js +9 -0
  92. package/dist/src/stepwise/agent-definition.js.map +1 -0
  93. package/dist/src/stepwise/function-tool.d.ts +130 -0
  94. package/dist/src/stepwise/function-tool.js +75 -0
  95. package/dist/src/stepwise/function-tool.js.map +1 -0
  96. package/dist/src/stepwise/index.d.ts +8 -0
  97. package/dist/src/stepwise/index.js +13 -0
  98. package/dist/src/stepwise/index.js.map +1 -0
  99. package/dist/src/stepwise/json-schema-validation.d.ts +9 -0
  100. package/dist/src/stepwise/json-schema-validation.js +141 -0
  101. package/dist/src/stepwise/json-schema-validation.js.map +1 -0
  102. package/dist/src/stepwise/model-client.d.ts +194 -0
  103. package/dist/src/stepwise/model-client.js +9 -0
  104. package/dist/src/stepwise/model-client.js.map +1 -0
  105. package/dist/src/stepwise/scripted-model-client.d.ts +99 -0
  106. package/dist/src/stepwise/scripted-model-client.js +156 -0
  107. package/dist/src/stepwise/scripted-model-client.js.map +1 -0
  108. package/dist/src/stepwise/stepwise-agent-runner.d.ts +171 -0
  109. package/dist/src/stepwise/stepwise-agent-runner.js +777 -0
  110. package/dist/src/stepwise/stepwise-agent-runner.js.map +1 -0
  111. package/dist/src/stepwise/stepwise-agent-session-flow.d.ts +35 -0
  112. package/dist/src/stepwise/stepwise-agent-session-flow.js +57 -0
  113. package/dist/src/stepwise/stepwise-agent-session-flow.js.map +1 -0
  114. package/dist/src/stepwise/stepwise-input-items.d.ts +12 -0
  115. package/dist/src/stepwise/stepwise-input-items.js +172 -0
  116. package/dist/src/stepwise/stepwise-input-items.js.map +1 -0
  117. package/dist/src/stepwise/tool-source.d.ts +103 -0
  118. package/dist/src/stepwise/tool-source.js +9 -0
  119. package/dist/src/stepwise/tool-source.js.map +1 -0
  120. package/dist/src/testing/agent-session-test-client.d.ts +65 -8
  121. package/dist/src/testing/agent-session-test-client.js +92 -22
  122. package/dist/src/testing/agent-session-test-client.js.map +1 -1
  123. package/dist/src/testing/context-window.d.ts +194 -0
  124. package/dist/src/testing/context-window.js +360 -0
  125. package/dist/src/testing/context-window.js.map +1 -0
  126. package/dist/src/testing/index.d.ts +2 -0
  127. package/dist/src/testing/index.js +2 -0
  128. package/dist/src/testing/index.js.map +1 -1
  129. package/dist/src/testing/private-dex-engine.d.ts +9 -0
  130. package/dist/src/testing/private-dex-engine.js +9 -1
  131. package/dist/src/testing/private-dex-engine.js.map +1 -1
  132. package/dist/src/testing/scripted-model-client.d.ts +1 -0
  133. package/dist/src/testing/scripted-model-client.js +10 -0
  134. package/dist/src/testing/scripted-model-client.js.map +1 -0
  135. package/dist/src/ui-stream/agent-event-json.d.ts +30 -0
  136. package/dist/src/ui-stream/agent-event-json.js +64 -0
  137. package/dist/src/ui-stream/agent-event-json.js.map +1 -0
  138. package/dist/src/ui-stream/agent-event-sse.d.ts +155 -0
  139. package/dist/src/ui-stream/agent-event-sse.js +167 -0
  140. package/dist/src/ui-stream/agent-event-sse.js.map +1 -0
  141. package/dist/src/ui-stream/agent-event-stream-positions.d.ts +42 -0
  142. package/dist/src/ui-stream/agent-event-stream-positions.js +153 -0
  143. package/dist/src/ui-stream/agent-event-stream-positions.js.map +1 -0
  144. package/dist/src/ui-stream/agent-session-record-reader.d.ts +74 -0
  145. package/dist/src/ui-stream/agent-session-record-reader.js +246 -0
  146. package/dist/src/ui-stream/agent-session-record-reader.js.map +1 -0
  147. package/dist/src/ui-stream/agent-ui-message-stream-responses.d.ts +219 -0
  148. package/dist/src/ui-stream/agent-ui-message-stream-responses.js +441 -0
  149. package/dist/src/ui-stream/agent-ui-message-stream-responses.js.map +1 -0
  150. package/dist/src/ui-stream/agent-ui-message-stream.d.ts +138 -0
  151. package/dist/src/ui-stream/agent-ui-message-stream.js +695 -0
  152. package/dist/src/ui-stream/agent-ui-message-stream.js.map +1 -0
  153. package/dist/src/ui-stream/agent-ui-message-types.d.ts +238 -0
  154. package/dist/src/ui-stream/agent-ui-message-types.js +57 -0
  155. package/dist/src/ui-stream/agent-ui-message-types.js.map +1 -0
  156. package/dist/src/ui-stream/agent-ui-messages.d.ts +68 -0
  157. package/dist/src/ui-stream/agent-ui-messages.js +222 -0
  158. package/dist/src/ui-stream/agent-ui-messages.js.map +1 -0
  159. package/dist/src/ui-stream/agent-ui-stream-cursor.d.ts +64 -0
  160. package/dist/src/ui-stream/agent-ui-stream-cursor.js +186 -0
  161. package/dist/src/ui-stream/agent-ui-stream-cursor.js.map +1 -0
  162. package/dist/src/ui-stream/index.d.ts +14 -0
  163. package/dist/src/ui-stream/index.js +22 -0
  164. package/dist/src/ui-stream/index.js.map +1 -0
  165. package/dist/src/ui-stream/server-sent-event-responses.d.ts +6 -0
  166. package/dist/src/ui-stream/server-sent-event-responses.js +34 -0
  167. package/dist/src/ui-stream/server-sent-event-responses.js.map +1 -0
  168. package/package.json +44 -5
@@ -1,8 +1,29 @@
1
1
  import { type Context, type Flow, type RPCResult } from "@superdurable/dex";
2
- import type { AgentFrameworkRunner, ToolPolicy } from "./agent-framework-runner.js";
2
+ import { type BuiltInTool } from "./agent-built-in-tools.js";
3
+ import { type CompactionPolicy, type ResolvedCompactionPolicy } from "./agent-context-compaction.js";
4
+ import type { AgentFrameworkRunner, DeferredToolOutcome, ToolPolicy } from "./agent-framework-runner.js";
3
5
  import { type AgentSessionPersistence } from "./agent-session-persistence.js";
4
- import type { AgentMessagesPage, AgentSessionStartInput, AgentSnapshot, AgentUserMessage, ListAgentMessagesInput, ResolveInterruptInput, ToolEffect } from "./agent-session-values.js";
5
- /** Tool policies, live events, and approval deadline of one agent, passed to {@link createAgentSessionFlow}. */
6
+ import type { ModelSpendLimit } from "./agent-session-spend-limit.js";
7
+ import { type ResolvedRunModelLimit, type RunModelLimit } from "./agent-session-step-options.js";
8
+ import { messageRolloverMaxBytesPerCommit, messageRolloverMaxChunksPerCommit } from "./agent-session-transitions.js";
9
+ import type { AgentMessagesPage, AgentSessionStartInput, AgentSnapshot, AgentUserMessage, AnswerQuestionRequest, CancelTurnRequest, DeleteQueuedMessageRequest, ExecutePlanRequest, ListAgentMessagesInput, ResolveInterruptInput, SteerUserMessageRequest, ToolEffect, UpdateSessionSettingsRequest } from "./agent-session-values.js";
10
+ import { type AgentTracingOptions, type ResolvedAgentTracingOptions } from "./agent-tracing-options.js";
11
+ export declare const snapshotMessageLimit = 200;
12
+ export declare const defaultMaxDurableWaitMs: number;
13
+ export declare const messagePageLimit = 200;
14
+ /** Default {@link AgentSessionOptions.messageWindowSize}. */
15
+ export declare const defaultMessageWindowSize = 64;
16
+ /** Default {@link AgentSessionOptions.messageChunkSize}. */
17
+ export declare const defaultMessageChunkSize = 32;
18
+ /** Default {@link AgentSessionOptions.messageChunkMaxBytes}: 1 MiB. */
19
+ export declare const defaultMessageChunkMaxBytes = 1048576;
20
+ /** Default {@link AgentSessionOptions.retainedMessageLimit}. */
21
+ export declare const defaultRetainedMessageLimit = 1000;
22
+ export { messageRolloverMaxBytesPerCommit, messageRolloverMaxChunksPerCommit };
23
+ /**
24
+ * Tool policies, built-in tools, live events, interrupt deadline, tracing, and compaction of one agent,
25
+ * passed to {@link createAgentSessionFlow}.
26
+ */
6
27
  export interface AgentSessionOptions {
7
28
  /**
8
29
  * Policies by tool name. A policy overrides framework metadata and {@link defaultToolEffect}.
@@ -20,10 +41,91 @@ export interface AgentSessionOptions {
20
41
  */
21
42
  readonly eventStreamCapacityBytes?: number;
22
43
  /**
23
- * Milliseconds an approval may stay pending before `AwaitToolApproval` rejects it with
24
- * `"approval deadline passed"`. Defaults to no deadline: approvals wait indefinitely.
44
+ * Milliseconds an approval or a question may stay pending before the session rejects it with
45
+ * `"approval deadline passed"` or `"question deadline passed"`. Defaults to no deadline: interrupts wait
46
+ * indefinitely.
25
47
  */
26
48
  readonly interruptDeadlineMs?: number;
49
+ /**
50
+ * OpenTelemetry GenAI span options. Defaults to spans through the global tracer provider when
51
+ * `@opentelemetry/api` is installed, and nothing otherwise. See {@link AgentTracingOptions}.
52
+ */
53
+ readonly tracing?: AgentTracingOptions;
54
+ /**
55
+ * Built-in tools the session handles, such as `["ask_user", "durable_wait"]`. Defaults to none.
56
+ *
57
+ * The runner offers the enabled ones to its model from {@link builtInToolDefinitions}; see
58
+ * {@link BuiltInTool}. An enabled built-in name is reserved: a tool policy for it is refused here, and
59
+ * the session routes every call with that name to the built-in tool. Enable a built-in tool only after
60
+ * every Worker of the Flow type runs a release that supports it.
61
+ */
62
+ readonly builtInTools?: readonly BuiltInTool[];
63
+ /**
64
+ * Longest `durable_wait` in milliseconds; a longer `duration_seconds` fails the call at once.
65
+ * Defaults to 365 days. It must be a positive multiple of 1,000, because Dex Timers take whole seconds.
66
+ * The Python core's `max_durable_wait` is a `timedelta`; this option is the same limit in milliseconds.
67
+ */
68
+ readonly maxDurableWaitMs?: number;
69
+ /**
70
+ * Whether `send_user_message` accepts a message with `planMode`, which starts a `planning` turn that drafts
71
+ * a plan for `execute_plan`. A `draft` plan makes every new turn a `planning` turn until it runs. Defaults
72
+ * to `false`.
73
+ *
74
+ * It requires `write_todos` in {@link builtInTools} and a runner whose
75
+ * {@link AgentFrameworkRunner.supportsPlanMode} is `true`, such as the Stepwise runner.
76
+ */
77
+ readonly planModeEnabled?: boolean;
78
+ /**
79
+ * When to summarize earlier messages so the model input stays under the context window. Defaults to no
80
+ * compaction. It needs a runner that implements {@link AgentFrameworkRunner.estimateInputTokens},
81
+ * {@link AgentFrameworkRunner.selectCompactionCutoff}, and {@link AgentFrameworkRunner.summarizeContext}.
82
+ * The summarized messages stay stored until {@link retainedMessageLimit} deletes them. Enable it only after
83
+ * every Worker of the Flow type runs a release with the `CompactContext` Step. See {@link CompactionPolicy}.
84
+ */
85
+ readonly compaction?: CompactionPolicy;
86
+ /**
87
+ * Most messages the `AgentMessages` window holds. Defaults to 64. When an append takes the window past it,
88
+ * its oldest messages move into immutable `AgentMessageChunks` instances in the same commit, at most
89
+ * {@link messageRolloverMaxChunksPerCommit} chunks per commit. Every Step that stores messages loads the
90
+ * whole window, so it bounds that load. It must be at least {@link messageChunkSize}.
91
+ */
92
+ readonly messageWindowSize?: number;
93
+ /** Most messages one archive chunk holds. Defaults to 32. A change applies to the next chunk written. */
94
+ readonly messageChunkSize?: number;
95
+ /**
96
+ * Most bytes one archive chunk holds, measured on the JSON this core writes. Defaults to 1 MiB, between 1 and
97
+ * 8,388,608. A chunk closes at {@link messageChunkSize} messages or at this size, whichever comes first. A
98
+ * message whose chunk of one, the message plus 15 bytes, would pass it never enters the window: the Step that
99
+ * stores it writes it straight into its own chunk, so a message too large for the server's
100
+ * `values.maxValueBytes` fails that Step instead of a later rollover. Keep it well under that limit.
101
+ */
102
+ readonly messageChunkMaxBytes?: number;
103
+ /**
104
+ * Retention of summarized messages: the session deletes its oldest archive chunk once every message in it is
105
+ * at or before `ContextSummary.lastSequence` and at least this many stored messages come after the chunk.
106
+ * Defaults to 1,000. `null` keeps every message. It applies only with {@link compaction}, so Flow state stays
107
+ * bounded however long the session runs.
108
+ *
109
+ * The newest `retainedMessageLimit` messages and every message after the summary always stay. Deleted
110
+ * messages leave `list_agent_messages` and `get_agent_snapshot`, and each `list_agent_messages` page then
111
+ * carries `deletedBeforeSequence`. An application that keeps the full transcript copies new messages with
112
+ * `list_agent_messages` before more than `retainedMessageLimit` messages follow them.
113
+ */
114
+ readonly retainedMessageLimit?: number | null;
115
+ /**
116
+ * Method timeout and attempts of `RunModel`, for a runner whose `RunModel` takes longer than one model call, such as
117
+ * a harness. Defaults to 15 minutes and 3 attempts in 30 minutes. See {@link RunModelLimit}.
118
+ *
119
+ * @since 0.3.0
120
+ */
121
+ readonly runModelLimit?: RunModelLimit;
122
+ /**
123
+ * The application's spend limit, called before and after each model call of `RunModel` and `CompactContext`.
124
+ * Omit it to make no checks. See {@link ModelSpendLimit}.
125
+ *
126
+ * @since 0.3.0
127
+ */
128
+ readonly spendLimit?: ModelSpendLimit;
27
129
  }
28
130
  /** Options applied by an {@link AgentSessionFlow}, with every default filled in. */
29
131
  export interface ResolvedAgentSessionOptions {
@@ -33,17 +135,51 @@ export interface ResolvedAgentSessionOptions {
33
135
  readonly defaultToolEffect: ToolEffect;
34
136
  /** Byte budget of the `AgentEvents` Stream. */
35
137
  readonly eventStreamCapacityBytes: number;
36
- /** Approval deadline in milliseconds, or `undefined` for none. */
138
+ /** Approval and question deadline in milliseconds, or `undefined` for none. */
37
139
  readonly interruptDeadlineMs: number | undefined;
140
+ /**
141
+ * Tracing options. A Flow always sets this field; it is optional so that 0.1.0 code that builds these
142
+ * options keeps compiling.
143
+ */
144
+ readonly tracing?: ResolvedAgentTracingOptions;
145
+ /**
146
+ * Enabled built-in tools, in {@link builtInToolDefinitions} order. A Flow always sets this field and
147
+ * the one below; they are optional so that 0.1.0 code that builds these options keeps compiling.
148
+ */
149
+ readonly builtInTools?: readonly BuiltInTool[];
150
+ /** Longest `durable_wait` in milliseconds. */
151
+ readonly maxDurableWaitMs?: number;
152
+ /** Whether plan mode is enabled. A Flow always sets it; it is optional for the same reason. */
153
+ readonly planModeEnabled?: boolean;
154
+ /** The compaction policy with its defaults, or `undefined` when the session never compacts. */
155
+ readonly compaction?: ResolvedCompactionPolicy;
156
+ /** Most messages the `AgentMessages` window holds. A Flow always sets it; optional for 0.1.0 code. */
157
+ readonly messageWindowSize?: number;
158
+ /** Most messages per archive chunk. A Flow always sets it; optional for 0.1.0 code. */
159
+ readonly messageChunkSize?: number;
160
+ /** Most bytes per archive chunk. A Flow always sets it; optional for 0.1.0 code. */
161
+ readonly messageChunkMaxBytes?: number;
162
+ /** The retention limit, or `null` to keep every message. A Flow always sets it; optional for 0.1.0 code. */
163
+ readonly retainedMessageLimit?: number | null;
164
+ /** The `RunModel` limit and its retry budget. A Flow always sets it; optional for 0.2.0 code. */
165
+ readonly runModelLimit?: ResolvedRunModelLimit;
166
+ /** The application's spend limit, or `undefined` for none. */
167
+ readonly spendLimit?: ModelSpendLimit;
38
168
  }
39
169
  /**
40
170
  * Durable agent session Flow: one Flow execution is one agent session, and its Flow ID is the session ID.
41
171
  *
42
172
  * Create one per agent with {@link createAgentSessionFlow}, register it in the process `Registry`, and
43
- * call its RPCs with `Client.invokeRPC`. The RPC names are `send_user_message`, `resolve_interrupt`,
44
- * `get_agent_snapshot`, and `list_agent_messages`, the same as the Python core. The session never
45
- * completes on its own: it waits for the next user message after every turn. Stop it with
46
- * `Client.stopFlow`.
173
+ * call its RPCs with `Client.invokeRPC`. The RPC names are `send_user_message`, `steer_user_message`,
174
+ * `delete_queued_message`, `cancel_turn`, `resolve_interrupt`, `answer_question`, `execute_plan`,
175
+ * `update_session_settings`, `get_agent_snapshot`, and `list_agent_messages`, the same as the Python core. The session never completes on its
176
+ * own: it waits for the next user message after every turn. Stop it with `Client.stopFlow`.
177
+ *
178
+ * `steer_user_message` ends the running turn at its next safe Step boundary. It never interrupts a model call or a
179
+ * tool call that has already started. `cancel_turn` aborts the running model call and every wait for a person, a
180
+ * Timer, or a remote task too, but a tool call Step that has started still runs to the end. The calls that have
181
+ * not started record `rejected` with a `cancellationReason`, an abandoned task records `outcome_unknown`, and
182
+ * `ApplyTurnControl` ends the turn. A steered turn is followed by a new turn with the steered messages.
47
183
  *
48
184
  * The Flow's persistence definitions are properties of the Flow; pass them to `Client.getAttributes`
49
185
  * or the Stream reads.
@@ -53,7 +189,7 @@ export interface ResolvedAgentSessionOptions {
53
189
  * const flow = createAgentSessionFlow(runner, "SupportAgent");
54
190
  * const registry = new Registry([flow]);
55
191
  * // ... start a Worker and a Client with this registry ...
56
- * await client.startFlow(flow, sessionId, { initialMessage: null });
192
+ * await startAgentSession(client, flow, sessionId);
57
193
  * await client.invokeRPC(flow.sendUserMessage, sessionId, { text: "Where is order 42?" });
58
194
  * const snapshot = await client.invokeRPC(flow.getAgentSnapshot, sessionId);
59
195
  * for (const interrupt of snapshot.pendingInterrupts) {
@@ -61,10 +197,11 @@ export interface ResolvedAgentSessionOptions {
61
197
  * interruptId: interrupt.interruptId, approved: true, rejectionMessage: null });
62
198
  * }
63
199
  * ```
200
+ * @typeParam Runner - Type of {@link runner}. It defaults to {@link AgentFrameworkRunner}.
64
201
  */
65
- export interface AgentSessionFlow extends Flow<AgentSessionStartInput>, AgentSessionPersistence {
202
+ export interface AgentSessionFlow<Runner extends AgentFrameworkRunner<DeferredToolOutcome> = AgentFrameworkRunner> extends Flow<AgentSessionStartInput>, AgentSessionPersistence {
66
203
  /** The framework runner passed to {@link createAgentSessionFlow}. */
67
- readonly runner: AgentFrameworkRunner;
204
+ readonly runner: Runner;
68
205
  /** The options this Flow applies, with defaults filled in. */
69
206
  readonly options: ResolvedAgentSessionOptions;
70
207
  /**
@@ -75,45 +212,191 @@ export interface AgentSessionFlow extends Flow<AgentSessionStartInput>, AgentSes
75
212
  *
76
213
  * @param context - RPC Context supplied by Dex.
77
214
  * @param message - Message to queue.
78
- * @returns `true` when queued; `false` when the text is blank.
215
+ * @returns `true` when queued; `false` when the text is blank, or for a `planMode` message when
216
+ * {@link AgentSessionOptions.planModeEnabled} is not set.
79
217
  */
80
218
  sendUserMessage(context: Context, message: AgentUserMessage): RPCResult<boolean>;
81
219
  /**
82
- * RPC `resolve_interrupt`: approves or rejects one pending interrupt.
220
+ * RPC `execute_plan`: approves one plan revision, so the session starts a turn that runs it.
221
+ *
222
+ * Call it after the user reviewed the `draft` plan that a `planMode` message drafted, or to run an `active`
223
+ * plan again. The next `AwaitUserMessage` starts an `executing` turn with every tool, whose user message is
224
+ * `[Dex] The user approved plan revision <n>. Execute it and keep the task statuses current with
225
+ * write_todos.`. A queued message that the session took first runs its turn first; when that turn changes
226
+ * the plan, the approval is stale and never runs.
227
+ *
228
+ * The RPC records the approval in `PendingPlanExecution` until the session starts the turn, so a revision
229
+ * runs once per approval. It locks `PendingPlanExecution`: a concurrent `execute_plan` can make it fail with
230
+ * `RpcLockConflictError`, which is safe to retry.
231
+ *
232
+ * @example
233
+ * ```ts
234
+ * const snapshot = await client.invokeRPC(flow.getAgentSnapshot, sessionId);
235
+ * if (snapshot.plan?.status === "draft") {
236
+ * await client.invokeRPC(flow.executePlan, sessionId, { revision: snapshot.plan.revision });
237
+ * }
238
+ * ```
239
+ * @param context - RPC Context supplied by Dex.
240
+ * @param input - The plan revision the user reviewed.
241
+ * @returns `true` when the execution is accepted; `false` unless the session waits for a user message, the
242
+ * plan has this revision and is `draft` or `active`, no execution of it is pending, and no queued or steered
243
+ * message or interrupt is pending.
244
+ */
245
+ executePlan(context: Context, input: ExecutePlanRequest): RPCResult<boolean>;
246
+ /**
247
+ * RPC `steer_user_message`: steers the running turn with new text or with a queued message.
248
+ *
249
+ * A steered message applies at the turn's next safe Step boundary. The session never interrupts a model call or
250
+ * a tool call that has started. It records the calls that have not started as `rejected` with
251
+ * `cancellationReason` `"steered"`, ends the turn, and starts a new turn whose user messages are every steered
252
+ * message, in order.
253
+ *
254
+ * While no turn is active, there is nothing to steer: new `text` is queued like `send_user_message`, so it
255
+ * starts the next turn at once, and a `messageId` that is still queued stays queued. A turn that a Worker
256
+ * without steering started or advanced cannot be steered; see {@link AgentState.acceptsTurnControl}.
257
+ *
258
+ * With `messageId`, the RPC moves that queued message: it deletes it from `QueuedUserMessages` and publishes it
259
+ * to `SteeredUserMessages` in one commit. It locks nothing. When another Step or RPC consumes the message
260
+ * between the RPC's read and its commit, the RPC fails with `ChannelMessageNotFoundError` and commits nothing;
261
+ * reload the snapshot and let the user choose again.
262
+ *
263
+ * @example
264
+ * ```ts
265
+ * const [queued] = (await client.invokeRPC(flow.getAgentSnapshot, sessionId)).queuedMessages ?? [];
266
+ * if (queued !== undefined) {
267
+ * await client.invokeRPC(flow.steerUserMessage, sessionId, { messageId: queued.messageId, text: null });
268
+ * }
269
+ * ```
270
+ * @param context - RPC Context supplied by Dex.
271
+ * @param input - Exactly one of a queued message ID and new text.
272
+ * @returns `true` when the message is steered, or queued while no turn is active; `false` when both or neither
273
+ * field is set, the text is blank, the message is no longer queued, or the active turn does not accept steering.
274
+ */
275
+ steerUserMessage(context: Context, input: SteerUserMessageRequest): RPCResult<boolean>;
276
+ /**
277
+ * RPC `delete_queued_message`: deletes one queued user message before it starts a turn.
278
+ *
279
+ * It locks nothing. When the session consumes the message between the RPC's read and its commit, the RPC fails
280
+ * with `ChannelMessageNotFoundError` and commits nothing.
281
+ *
282
+ * @param context - RPC Context supplied by Dex.
283
+ * @param input - {@link PendingUserMessage.messageId} from `get_agent_snapshot`.
284
+ * @returns `true` when the message was deleted; `false` when it is no longer queued.
285
+ */
286
+ deleteQueuedMessage(context: Context, input: DeleteQueuedMessageRequest): RPCResult<boolean>;
287
+ /**
288
+ * RPC `cancel_turn`: stops the running turn now, with no new turn.
289
+ *
290
+ * The RPC cancels the turn's running model call or compaction, and every Step that waits for an approval, an
291
+ * answer, a `durable_wait` Timer, or a remote task's next poll. A cancelled model call's `cancellationSignal`
292
+ * aborts at once and its answer is dropped. A tool call Step that has started runs to the end, and the turn ends
293
+ * after it. The calls that have not started record `rejected` with `cancellationReason` `"turn_cancelled"`. A
294
+ * started remote task is abandoned: the call records `outcome_unknown`, and a runner that implements
295
+ * {@link AgentFrameworkRunner.cancelToolTask} is asked to cancel the task. Then the session waits for the next
296
+ * user message.
297
+ *
298
+ * The RPC locks `TurnCancellationRequest` and `PendingInterrupts`. No long-running Step locks them, so it never
299
+ * waits for a model call. It can fail with `RpcLockConflictError` while a short Step holds a lock, which is safe
300
+ * to retry. A second call for the same turn changes nothing and returns `true`.
301
+ *
302
+ * @param context - RPC Context supplied by Dex.
303
+ * @param input - The turn to stop, or `turnId` `null` for the active turn.
304
+ * @returns `true` when the request is recorded, although a turn whose model call already committed its final
305
+ * answer completes instead; `false` when no turn is active, `turnId` names another turn, or the active turn does
306
+ * not accept cancellation.
307
+ */
308
+ cancelTurn(context: Context, input: CancelTurnRequest): RPCResult<boolean>;
309
+ /**
310
+ * RPC `update_session_settings`: replaces the session's settings from the next turn on.
311
+ *
312
+ * The new settings apply when the next turn starts, the same boundary at which a `planMode` message takes
313
+ * effect. A running turn keeps the settings it started with for every model call, retry, and compaction, so one
314
+ * turn never mixes two models. The settings replace the old ones; nothing is merged, and `{}` clears them, so
315
+ * `get_agent_snapshot` returns `null`.
316
+ *
317
+ * Settings are stored in the session and returned by `get_agent_snapshot`, and the browser snapshot JSON of
318
+ * `@superdurable/dex-agents/ui-stream` includes them. Never put a secret or anything a browser must not see in
319
+ * them; put a reference, such as a credential name, that the Worker resolves. Call the RPC only after every
320
+ * Worker of the Flow type runs dex-agents 0.2.0.
321
+ *
322
+ * The RPC locks nothing. When two updates race, the one that commits last wins. A turn that starts between
323
+ * this RPC's read and its commit runs with the earlier settings, and the next turn gets these.
324
+ *
325
+ * @example
326
+ * ```ts
327
+ * await client.invokeRPC(flow.updateSessionSettings, sessionId, { sessionSettings: { model: "gpt-5" } });
328
+ * ```
329
+ * @param context - RPC Context supplied by Dex.
330
+ * @param input - The complete new settings.
331
+ * @returns `true` when the settings are stored; `false` before `StartAgentSession` committed, or when the
332
+ * settings are `null` (a missing or `null` field), are not a JSON object, or are larger than
333
+ * `MAX_SESSION_SETTINGS_BYTES` plus `SESSION_SETTINGS_SIZE_TOLERANCE_BYTES`.
334
+ */
335
+ updateSessionSettings(context: Context, input: UpdateSessionSettingsRequest): RPCResult<boolean>;
336
+ /**
337
+ * RPC `resolve_interrupt`: approves or rejects one pending tool approval, or declines one question.
83
338
  *
84
339
  * It removes the interrupt from `PendingInterrupts` and publishes the answer in one commit, so only
85
340
  * one call succeeds per interrupt. It locks `PendingInterrupts`, so a call that races
86
- * `AwaitToolApproval` can fail with `RpcLockConflictError`, which is safe to retry. The
87
- * rejection message is dropped when `approved` is `true`.
341
+ * `AwaitToolApproval`, `AwaitQuestionAnswer`, `ResumeTurn`, `FinishTurnCancellation`, or `cancel_turn` can fail
342
+ * with `RpcLockConflictError`, which is safe to retry. The caller sends the RPC's locks: SDK clients and Dex Web do,
343
+ * but a raw `InvokeRPC` request without them runs unlocked, and then more than one call can succeed. The rejection message is dropped when `approved` is `true`. A question needs an answer, so
344
+ * `approved` `true` on a `question` interrupt is refused; answer it with {@link answerQuestion}.
88
345
  *
89
346
  * @param context - RPC Context supplied by Dex.
90
347
  * @param input - Interrupt ID and decision.
91
348
  * @returns `true` when the interrupt was pending and is now resolved; `false` when it is unknown,
92
- * already resolved, or past its deadline.
349
+ * already resolved, past its deadline, or a question with `approved` `true`.
93
350
  */
94
351
  resolveInterrupt(context: Context, input: ResolveInterruptInput): RPCResult<boolean>;
352
+ /**
353
+ * RPC `answer_question`: answers one pending `question` interrupt.
354
+ *
355
+ * The answer becomes the result of the `ask_user` call, `{"status":"answered","answer":"<text>"}`, so
356
+ * the model continues the same turn. For a tool's question, the tool runs again with the answer. The
357
+ * RPC removes the interrupt and publishes the answer in one commit, so only one call succeeds per
358
+ * question. It locks `PendingInterrupts` and can fail with `RpcLockConflictError`, which is safe to
359
+ * retry. Decline a question with {@link resolveInterrupt} and `approved` `false`.
360
+ *
361
+ * @example
362
+ * ```ts
363
+ * const snapshot = await client.invokeRPC(flow.getAgentSnapshot, sessionId);
364
+ * const question = snapshot.pendingInterrupts.find((interrupt) => interrupt.kind === "question");
365
+ * if (question !== undefined) {
366
+ * await client.invokeRPC(flow.answerQuestion, sessionId, { interruptId: question.interruptId, answer: "blue" });
367
+ * }
368
+ * ```
369
+ * @param context - RPC Context supplied by Dex.
370
+ * @param input - Interrupt ID and answer.
371
+ * @returns `true` when the question was pending and is now answered; `false` when the interrupt is
372
+ * not pending, is not a question, or is past its deadline, and when the answer is blank or is not one
373
+ * of the choices while free text is not allowed.
374
+ */
375
+ answerQuestion(context: Context, input: AnswerQuestionRequest): RPCResult<boolean>;
95
376
  /**
96
377
  * RPC `get_agent_snapshot`: returns the durable session view a UI renders.
97
378
  *
98
379
  * It reads committed state without locks, so it also serves a retained closed session. It loads the
99
- * whole `AgentMessages` map.
380
+ * `AgentMessages` window and every retained `AgentMessageChunks` instance.
100
381
  *
101
382
  * @param context - RPC Context supplied by Dex.
102
- * @returns State, the last 200 messages, pending interrupts, the active turn's tool calls, usage,
103
- * and the queued message count. Before `StartAgentSession` commits, `state` is `null` and the lists
104
- * are empty.
383
+ * @returns State, the last 200 messages, pending interrupts, the active turn's tool calls, usage, the queued
384
+ * message count, the plan, the queued and steered messages with their Channel message IDs, and the context
385
+ * summary; summarized messages stay in `messages` until retention deletes them. Before `StartAgentSession` commits, `state` is `null` and
386
+ * the lists are empty.
105
387
  */
106
388
  getAgentSnapshot(context: Context): RPCResult<AgentSnapshot>;
107
389
  /**
108
390
  * RPC `list_agent_messages`: returns one page of stored messages, oldest first.
109
391
  *
110
392
  * Start with `beforeSequence` `null` for the newest page, then pass each page's
111
- * `nextBeforeSequence` to walk back. It also serves a retained closed session.
393
+ * `nextBeforeSequence` to walk back. It also serves a retained closed session. Messages that retention
394
+ * deleted are gone: the oldest page starts at the oldest stored message.
112
395
  *
113
396
  * @param context - RPC Context supplied by Dex.
114
397
  * @param input - Exclusive upper sequence bound, or `null`, and a page size clamped to 1..200.
115
398
  * @returns Up to `limit` messages below `beforeSequence` in ascending order, and the bound of the
116
- * next older page, or `null` when the page starts at the first message.
399
+ * next older page, or `null` when the page starts at the oldest stored message.
117
400
  */
118
401
  listAgentMessages(context: Context, input: ListAgentMessagesInput): RPCResult<AgentMessagesPage>;
119
402
  }
@@ -137,12 +420,18 @@ export interface AgentSessionFlow extends Flow<AgentSessionStartInput>, AgentSes
137
420
  * const billing = createAgentSessionFlow(billingRunner, "BillingAgent");
138
421
  * const registry = new Registry([triage, billing]);
139
422
  * ```
423
+ * @typeParam Runner - Type of the runner, kept as the Flow's `runner` property type.
140
424
  * @param runner - Framework runner; the Flow owns no other dependency.
141
425
  * @param flowType - Flow type, unique within the Registry, such as `"TriageAgent"`. Keep it stable:
142
426
  * running sessions resume by it.
143
- * @param options - Tool policies, Stream capacity, and approval deadline. Defaults to all defaults.
427
+ * @param options - Tool policies, Stream capacity, approval deadline, and tracing. Defaults to all
428
+ * defaults.
144
429
  * @returns A new Flow to register in one Registry.
145
- * @throws {TypeError} When `flowType` is blank, the runner is incomplete, or an effect is unknown.
146
- * @throws {RangeError} When `eventStreamCapacityBytes` or `interruptDeadlineMs` is not positive.
430
+ * @throws {TypeError} When `flowType` is blank, the runner is incomplete, an effect or built-in tool is
431
+ * unknown, a tool policy names an enabled built-in tool, a tracing option is invalid, `planModeEnabled`
432
+ * is set without `write_todos` or for a runner without {@link AgentFrameworkRunner.supportsPlanMode}, or
433
+ * `compaction` is set for a runner without the compaction methods.
434
+ * @throws {RangeError} When `eventStreamCapacityBytes` or `interruptDeadlineMs` is not positive,
435
+ * `maxDurableWaitMs` is not a positive whole number of seconds, or the compaction policy is out of range.
147
436
  */
148
- export declare function createAgentSessionFlow(runner: AgentFrameworkRunner, flowType: string, options?: AgentSessionOptions): AgentSessionFlow;
437
+ export declare function createAgentSessionFlow<Runner extends AgentFrameworkRunner<DeferredToolOutcome>>(runner: Runner, flowType: string, options?: AgentSessionOptions): AgentSessionFlow<Runner>;