@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,5 +1,5 @@
1
1
  import { Attribute, AttributeMap, Channel, ChannelMap, Stream } from "@superdurable/dex";
2
- import type { AgentEvent, AgentInterrupt, AgentInterruptResolution, AgentMessage, AgentState, AgentToolCall, AgentUsage, AgentUserMessage, ToolCallCompleted } from "./agent-session-values.js";
2
+ import type { AgentEvent, AgentInterrupt, AgentInterruptResolution, AgentMessage, AgentMessageChunk, AgentMessageIndex, AgentPlan, AgentState, AgentToolCallRecord, AgentUsage, AgentUserMessage, PlanExecutionRequest, ContextSummary, SessionSettings, TurnReplySequence, TurnSessionSettings, ToolCallCancellation, ToolCallCompleted, TurnCancellationRequest, TurnControlRequest } from "./agent-session-values.js";
3
3
  /** Default byte budget of the `AgentEvents` Stream: 10 MiB. */
4
4
  export declare const defaultAgentEventsCapacityBytes: number;
5
5
  /**
@@ -19,12 +19,25 @@ export declare const defaultAgentEventsCapacityBytes: number;
19
19
  export interface AgentSessionPersistence {
20
20
  /** The `AgentState` Attribute. It is always set after `StartAgentSession`. */
21
21
  readonly agentState: Attribute<AgentState>;
22
- /** The `AgentMessages` AttributeMap, keyed by sequence as 12-digit zero-padded decimal. */
22
+ /**
23
+ * The `AgentMessages` AttributeMap: the window of the newest messages, one instance per message, keyed by
24
+ * {@link messageSequenceKey}. Older messages are in {@link agentMessageChunks}; see {@link agentMessageIndex}.
25
+ */
23
26
  readonly agentMessages: AttributeMap<AgentMessage>;
27
+ /**
28
+ * The `AgentMessageChunks` AttributeMap: immutable archive chunks of older messages, keyed by
29
+ * {@link messageSequenceKey} of each chunk's first sequence.
30
+ */
31
+ readonly agentMessageChunks: AttributeMap<AgentMessageChunk>;
32
+ /**
33
+ * The `AgentMessageIndex` Attribute: where the window and the retained chunks start. A session that a 0.1.0
34
+ * Worker wrote has none until its first write on this version.
35
+ */
36
+ readonly agentMessageIndex: Attribute<AgentMessageIndex>;
24
37
  /** The `FrameworkRunState` Attribute: opaque framework JSON, set only while a turn is suspended. */
25
38
  readonly frameworkRunState: Attribute<string>;
26
39
  /** The `AgentToolCalls` AttributeMap, keyed by tool call ID; holds only the active turn's records. */
27
- readonly agentToolCalls: AttributeMap<AgentToolCall>;
40
+ readonly agentToolCalls: AttributeMap<AgentToolCallRecord>;
28
41
  /** The `PendingInterrupts` Attribute: interrupts that `resolve_interrupt` still accepts. */
29
42
  readonly pendingInterrupts: Attribute<readonly AgentInterrupt[]>;
30
43
  /** The `AgentUsage` Attribute: cumulative usage of every turn. */
@@ -38,12 +51,68 @@ export interface AgentSessionPersistence {
38
51
  * record becomes final, and `ResumeTurn` consumes them. Applications never publish to it.
39
52
  */
40
53
  readonly toolCallResults: Channel<ToolCallCompleted>;
54
+ /** The `SteeredUserMessages` Channel; `steer_user_message` publishes and `ApplyTurnControl` consumes. */
55
+ readonly steeredUserMessages: Channel<AgentUserMessage>;
56
+ /**
57
+ * The internal `TurnControlRequests` Channel. `steer_user_message` and `cancel_turn` publish to it, and its
58
+ * messages only wake `ResumeTurn` or `AwaitUserMessage`.
59
+ */
60
+ readonly turnControlRequests: Channel<TurnControlRequest>;
61
+ /** The `TurnCancellationRequest` Attribute: the latest `cancel_turn` request. Only `cancel_turn` writes it. */
62
+ readonly turnCancellationRequest: Attribute<TurnCancellationRequest>;
63
+ /**
64
+ * The internal `ToolCallCancellations` ChannelMap, keyed by tool call ID. `ResumeTurn` publishes to it to wake
65
+ * the Step that waits on a call of a steered or cancelled turn.
66
+ */
67
+ readonly toolCallCancellations: ChannelMap<ToolCallCancellation>;
41
68
  /** The best-effort `AgentEvents` Stream. Rebuild durable state with `get_agent_snapshot`. */
42
69
  readonly agentEvents: Stream<AgentEvent>;
70
+ /**
71
+ * The `AgentTraceContext` Attribute: the W3C `traceparent` of the current activation's root span when
72
+ * that span has a valid context, sampled or not; an activation whose root has none, such as one without
73
+ * an OpenTelemetry SDK, deletes it. `RunModel` reads it to join the activation's trace.
74
+ */
75
+ readonly agentTraceContext: Attribute<string>;
76
+ /** The `AgentPlan` Attribute: the session's plan, unset until `write_todos` first succeeds. */
77
+ readonly agentPlan: Attribute<AgentPlan>;
78
+ /**
79
+ * The `PlanExecutions` ChannelMap, keyed by {@link planExecutionKey}: approved plan executions that
80
+ * `execute_plan` publishes and `AwaitUserMessage` consumes.
81
+ */
82
+ readonly planExecutions: ChannelMap<PlanExecutionRequest>;
83
+ /**
84
+ * The `PendingPlanExecution` Attribute: the execution `execute_plan` accepted and `AwaitUserMessage` has
85
+ * not consumed yet.
86
+ */
87
+ readonly pendingPlanExecution: Attribute<PlanExecutionRequest>;
88
+ /**
89
+ * The `ContextSummary` Attribute: the summary that replaces the earlier messages in the model input,
90
+ * set once the session compacts. Only `CompactContext` writes it.
91
+ */
92
+ readonly contextSummary: Attribute<ContextSummary>;
93
+ /**
94
+ * The `SessionSettings` Attribute: the settings the next turn starts with, from the start input and then each
95
+ * `update_session_settings`. Unset when the session has none.
96
+ */
97
+ readonly sessionSettings: Attribute<SessionSettings>;
98
+ /**
99
+ * The `TurnSessionSettings` Attribute: the settings a turn started with, tagged with its turn, copied from
100
+ * `SessionSettings` when the turn began. A copy from an earlier turn reads as no settings.
101
+ */
102
+ readonly turnSessionSettings: Attribute<TurnSessionSettings>;
103
+ /**
104
+ * The `TurnReplySequence` Attribute: where the latest turn's replies start, tagged with its turn. The Step
105
+ * that starts a turn writes it; turn events count the replies from it.
106
+ */
107
+ readonly turnReplySequence: Attribute<TurnReplySequence>;
43
108
  }
44
109
  export declare function createAgentSessionPersistence(agentEventsCapacityBytes: number): AgentSessionPersistence;
45
110
  /**
46
- * Returns the `AgentMessages` map instance of a message sequence.
111
+ * Returns the `AgentMessages` map instance of a message sequence, which is also the `AgentMessageChunks`
112
+ * instance of a chunk that starts at that sequence.
113
+ *
114
+ * A message stays in `AgentMessages` only while it is in the window; read older ones from their chunk, or
115
+ * page through all of them with `list_agent_messages`.
47
116
  *
48
117
  * @example
49
118
  * ```ts
@@ -54,3 +123,11 @@ export declare function createAgentSessionPersistence(agentEventsCapacityBytes:
54
123
  * @throws {RangeError} When `sequence` is not a positive safe integer.
55
124
  */
56
125
  export declare function messageSequenceKey(sequence: number): string;
126
+ /**
127
+ * Returns the `PlanExecutions` map instance of a plan revision.
128
+ *
129
+ * @param revision - Positive {@link AgentPlan.revision}.
130
+ * @returns The revision as a decimal, such as `"3"`.
131
+ * @throws {RangeError} When `revision` is not a positive safe integer.
132
+ */
133
+ export declare function planExecutionKey(revision: number): string;
@@ -6,13 +6,15 @@
6
6
  //
7
7
  // SPDX-License-Identifier: LicenseRef-Sustainable-Use-1.0
8
8
  import { Attribute, AttributeMap, Channel, ChannelMap, Stream, stringCodec } from "@superdurable/dex";
9
- import { agentEventCodec, agentInterruptListCodec, agentInterruptResolutionCodec, agentMessageCodec, agentStateCodec, agentToolCallCodec, agentUsageCodec, agentUserMessageCodec, toolCallCompletedCodec, } from "./agent-session-codecs.js";
9
+ import { agentEventCodec, agentInterruptListCodec, agentInterruptResolutionCodec, agentMessageChunkCodec, agentMessageCodec, agentMessageIndexCodec, agentPlanCodec, agentStateCodec, agentToolCallCodec, agentUsageCodec, agentUserMessageCodec, planExecutionRequestCodec, contextSummaryCodec, sessionSettingsCodec, turnSessionSettingsCodec, turnReplySequenceCodec, toolCallCancellationCodec, toolCallCompletedCodec, turnCancellationRequestCodec, turnControlRequestCodec, } from "./agent-session-codecs.js";
10
10
  /** Default byte budget of the `AgentEvents` Stream: 10 MiB. */
11
11
  export const defaultAgentEventsCapacityBytes = 10 * 1024 * 1024;
12
12
  export function createAgentSessionPersistence(agentEventsCapacityBytes) {
13
13
  return {
14
14
  agentState: new Attribute("AgentState", agentStateCodec),
15
15
  agentMessages: new AttributeMap("AgentMessages", agentMessageCodec),
16
+ agentMessageChunks: new AttributeMap("AgentMessageChunks", agentMessageChunkCodec),
17
+ agentMessageIndex: new Attribute("AgentMessageIndex", agentMessageIndexCodec),
16
18
  frameworkRunState: new Attribute("FrameworkRunState", stringCodec),
17
19
  agentToolCalls: new AttributeMap("AgentToolCalls", agentToolCallCodec),
18
20
  pendingInterrupts: new Attribute("PendingInterrupts", agentInterruptListCodec),
@@ -20,11 +22,27 @@ export function createAgentSessionPersistence(agentEventsCapacityBytes) {
20
22
  queuedUserMessages: new Channel("QueuedUserMessages", agentUserMessageCodec),
21
23
  interruptResolutions: new ChannelMap("InterruptResolutions", agentInterruptResolutionCodec),
22
24
  toolCallResults: new Channel("ToolCallResults", toolCallCompletedCodec),
25
+ steeredUserMessages: new Channel("SteeredUserMessages", agentUserMessageCodec),
26
+ turnControlRequests: new Channel("TurnControlRequests", turnControlRequestCodec),
27
+ turnCancellationRequest: new Attribute("TurnCancellationRequest", turnCancellationRequestCodec),
28
+ toolCallCancellations: new ChannelMap("ToolCallCancellations", toolCallCancellationCodec),
23
29
  agentEvents: new Stream("AgentEvents", agentEventCodec, agentEventsCapacityBytes),
30
+ agentTraceContext: new Attribute("AgentTraceContext", stringCodec),
31
+ agentPlan: new Attribute("AgentPlan", agentPlanCodec),
32
+ planExecutions: new ChannelMap("PlanExecutions", planExecutionRequestCodec),
33
+ pendingPlanExecution: new Attribute("PendingPlanExecution", planExecutionRequestCodec),
34
+ contextSummary: new Attribute("ContextSummary", contextSummaryCodec),
35
+ sessionSettings: new Attribute("SessionSettings", sessionSettingsCodec),
36
+ turnSessionSettings: new Attribute("TurnSessionSettings", turnSessionSettingsCodec),
37
+ turnReplySequence: new Attribute("TurnReplySequence", turnReplySequenceCodec),
24
38
  };
25
39
  }
26
40
  /**
27
- * Returns the `AgentMessages` map instance of a message sequence.
41
+ * Returns the `AgentMessages` map instance of a message sequence, which is also the `AgentMessageChunks`
42
+ * instance of a chunk that starts at that sequence.
43
+ *
44
+ * A message stays in `AgentMessages` only while it is in the window; read older ones from their chunk, or
45
+ * page through all of them with `list_agent_messages`.
28
46
  *
29
47
  * @example
30
48
  * ```ts
@@ -40,4 +58,17 @@ export function messageSequenceKey(sequence) {
40
58
  }
41
59
  return String(sequence).padStart(12, "0");
42
60
  }
61
+ /**
62
+ * Returns the `PlanExecutions` map instance of a plan revision.
63
+ *
64
+ * @param revision - Positive {@link AgentPlan.revision}.
65
+ * @returns The revision as a decimal, such as `"3"`.
66
+ * @throws {RangeError} When `revision` is not a positive safe integer.
67
+ */
68
+ export function planExecutionKey(revision) {
69
+ if (!Number.isSafeInteger(revision) || revision <= 0) {
70
+ throw new RangeError(`plan revision must be a positive integer: ${revision}`);
71
+ }
72
+ return String(revision);
73
+ }
43
74
  //# sourceMappingURL=agent-session-persistence.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-session-persistence.js","sourceRoot":"","sources":["../../src/agent-session-persistence.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,kDAAkD;AAClD,mEAAmE;AACnE,+CAA+C;AAC/C,EAAE;AACF,0DAA0D;AAE1D,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEtG,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,6BAA6B,EAC7B,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,2BAA2B,CAAC;AAanC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,+BAA+B,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AA0ChE,MAAM,UAAU,6BAA6B,CAC3C,wBAAgC;IAEhC,OAAO;QACL,UAAU,EAAE,IAAI,SAAS,CAAC,YAAY,EAAE,eAAe,CAAC;QACxD,aAAa,EAAE,IAAI,YAAY,CAAC,eAAe,EAAE,iBAAiB,CAAC;QACnE,iBAAiB,EAAE,IAAI,SAAS,CAAC,mBAAmB,EAAE,WAAW,CAAC;QAClE,cAAc,EAAE,IAAI,YAAY,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;QACtE,iBAAiB,EAAE,IAAI,SAAS,CAAC,mBAAmB,EAAE,uBAAuB,CAAC;QAC9E,UAAU,EAAE,IAAI,SAAS,CAAC,YAAY,EAAE,eAAe,CAAC;QACxD,kBAAkB,EAAE,IAAI,OAAO,CAAC,oBAAoB,EAAE,qBAAqB,CAAC;QAC5E,oBAAoB,EAAE,IAAI,UAAU,CAAC,sBAAsB,EAAE,6BAA6B,CAAC;QAC3F,eAAe,EAAE,IAAI,OAAO,CAAC,iBAAiB,EAAE,sBAAsB,CAAC;QACvE,WAAW,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,eAAe,EAAE,wBAAwB,CAAC;KAClF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,UAAU,CAAC,gDAAgD,QAAQ,EAAE,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"agent-session-persistence.js","sourceRoot":"","sources":["../../src/agent-session-persistence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { SessionSettings } from "./agent-session-values.js";
2
+ /** Largest {@link SessionSettings}, as the UTF-8 bytes of their compact JSON text: 16 KiB. Same in every core. */
3
+ export declare const MAX_SESSION_SETTINGS_BYTES: number;
4
+ /**
5
+ * Extra bytes the session's own Steps and RPC accept over {@link MAX_SESSION_SETTINGS_BYTES}.
6
+ *
7
+ * The cores write some numbers and characters differently, so settings that one core's Client accepted can
8
+ * measure a few bytes more in another core's Worker. The tolerance keeps that from failing a session.
9
+ * {@link validateSessionSettings} checks the exact limit.
10
+ */
11
+ export declare const SESSION_SETTINGS_SIZE_TOLERANCE_BYTES = 1024;
12
+ /**
13
+ * Returns the size of session settings that {@link MAX_SESSION_SETTINGS_BYTES} limits.
14
+ *
15
+ * The size is the UTF-8 byte length of `JSON.stringify(sessionSettings)`: compact, with characters outside ASCII
16
+ * written as themselves. The Python and Go cores measure their own JSON text, which is the same for strings,
17
+ * integers, booleans, `null`, objects, and arrays, with two exceptions: Python writes floats in their shortest
18
+ * form, such as `1.0` and `1e+16`, where this core writes `1` and `10000000000000000`, and Go escapes U+2028
19
+ * and U+2029. So sizes can differ by a few bytes per float or per such character. The session's Steps and RPC
20
+ * accept {@link SESSION_SETTINGS_SIZE_TOLERANCE_BYTES} more than the limit, so settings that another core's
21
+ * Client accepted never fail a session.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * sessionSettingsSize({ model: "gpt-5-mini" }); // 22
26
+ * ```
27
+ * @param sessionSettings - The settings.
28
+ * @returns The size in bytes.
29
+ * @throws {TypeError} When the settings cannot be written as JSON, such as with a cycle or a `bigint`.
30
+ */
31
+ export declare function sessionSettingsSize(sessionSettings: SessionSettings): number;
32
+ /**
33
+ * Checks that a value can be a session's settings: a JSON object whose compact JSON text fits in
34
+ * {@link MAX_SESSION_SETTINGS_BYTES}.
35
+ *
36
+ * Call it before `Client.startFlow` or the `update_session_settings` RPC, such as in a form handler. A start whose
37
+ * settings the session refuses fails the session at once, and the RPC returns `false`.
38
+ * `AgentSessionTestClient.startSession` calls it.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * validateSessionSettings({ model: "gpt-5-mini" });
43
+ * await client.startFlow(flow, sessionId, { initialMessage: null, sessionSettings: { model: "gpt-5-mini" } });
44
+ * ```
45
+ * @param sessionSettings - The candidate settings.
46
+ * @throws {TypeError} When the value is not a plain JSON object or cannot be written as JSON.
47
+ * @throws {RangeError} When its compact JSON text is larger than {@link MAX_SESSION_SETTINGS_BYTES}.
48
+ */
49
+ export declare function validateSessionSettings(sessionSettings: unknown): asserts sessionSettings is SessionSettings;
50
+ /**
51
+ * Checks settings as the session's Steps and RPC do: {@link validateSessionSettings} with a limit of
52
+ * {@link MAX_SESSION_SETTINGS_BYTES} plus {@link SESSION_SETTINGS_SIZE_TOLERANCE_BYTES}.
53
+ *
54
+ * @param sessionSettings - The candidate settings.
55
+ * @throws {TypeError} When the value is not a plain JSON object or cannot be written as JSON.
56
+ * @throws {RangeError} When its compact JSON text is larger than the session's limit.
57
+ */
58
+ export declare function checkStoredSessionSettings(sessionSettings: unknown): asserts sessionSettings is SessionSettings;
@@ -0,0 +1,81 @@
1
+ // Copyright (c) 2026 Super Durable, Inc.
2
+ //
3
+ // Licensed under the Sustainable Use License 1.0.
4
+ // You may not use this file except in compliance with the License.
5
+ // See the LICENSE file in the repository root.
6
+ //
7
+ // SPDX-License-Identifier: LicenseRef-Sustainable-Use-1.0
8
+ /** Largest {@link SessionSettings}, as the UTF-8 bytes of their compact JSON text: 16 KiB. Same in every core. */
9
+ export const MAX_SESSION_SETTINGS_BYTES = 16 * 1024;
10
+ /**
11
+ * Extra bytes the session's own Steps and RPC accept over {@link MAX_SESSION_SETTINGS_BYTES}.
12
+ *
13
+ * The cores write some numbers and characters differently, so settings that one core's Client accepted can
14
+ * measure a few bytes more in another core's Worker. The tolerance keeps that from failing a session.
15
+ * {@link validateSessionSettings} checks the exact limit.
16
+ */
17
+ export const SESSION_SETTINGS_SIZE_TOLERANCE_BYTES = 1024;
18
+ const utf8Encoder = new TextEncoder();
19
+ /**
20
+ * Returns the size of session settings that {@link MAX_SESSION_SETTINGS_BYTES} limits.
21
+ *
22
+ * The size is the UTF-8 byte length of `JSON.stringify(sessionSettings)`: compact, with characters outside ASCII
23
+ * written as themselves. The Python and Go cores measure their own JSON text, which is the same for strings,
24
+ * integers, booleans, `null`, objects, and arrays, with two exceptions: Python writes floats in their shortest
25
+ * form, such as `1.0` and `1e+16`, where this core writes `1` and `10000000000000000`, and Go escapes U+2028
26
+ * and U+2029. So sizes can differ by a few bytes per float or per such character. The session's Steps and RPC
27
+ * accept {@link SESSION_SETTINGS_SIZE_TOLERANCE_BYTES} more than the limit, so settings that another core's
28
+ * Client accepted never fail a session.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * sessionSettingsSize({ model: "gpt-5-mini" }); // 22
33
+ * ```
34
+ * @param sessionSettings - The settings.
35
+ * @returns The size in bytes.
36
+ * @throws {TypeError} When the settings cannot be written as JSON, such as with a cycle or a `bigint`.
37
+ */
38
+ export function sessionSettingsSize(sessionSettings) {
39
+ return utf8Encoder.encode(JSON.stringify(sessionSettings)).length;
40
+ }
41
+ /**
42
+ * Checks that a value can be a session's settings: a JSON object whose compact JSON text fits in
43
+ * {@link MAX_SESSION_SETTINGS_BYTES}.
44
+ *
45
+ * Call it before `Client.startFlow` or the `update_session_settings` RPC, such as in a form handler. A start whose
46
+ * settings the session refuses fails the session at once, and the RPC returns `false`.
47
+ * `AgentSessionTestClient.startSession` calls it.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * validateSessionSettings({ model: "gpt-5-mini" });
52
+ * await client.startFlow(flow, sessionId, { initialMessage: null, sessionSettings: { model: "gpt-5-mini" } });
53
+ * ```
54
+ * @param sessionSettings - The candidate settings.
55
+ * @throws {TypeError} When the value is not a plain JSON object or cannot be written as JSON.
56
+ * @throws {RangeError} When its compact JSON text is larger than {@link MAX_SESSION_SETTINGS_BYTES}.
57
+ */
58
+ export function validateSessionSettings(sessionSettings) {
59
+ checkSessionSettings(sessionSettings, MAX_SESSION_SETTINGS_BYTES);
60
+ }
61
+ /**
62
+ * Checks settings as the session's Steps and RPC do: {@link validateSessionSettings} with a limit of
63
+ * {@link MAX_SESSION_SETTINGS_BYTES} plus {@link SESSION_SETTINGS_SIZE_TOLERANCE_BYTES}.
64
+ *
65
+ * @param sessionSettings - The candidate settings.
66
+ * @throws {TypeError} When the value is not a plain JSON object or cannot be written as JSON.
67
+ * @throws {RangeError} When its compact JSON text is larger than the session's limit.
68
+ */
69
+ export function checkStoredSessionSettings(sessionSettings) {
70
+ checkSessionSettings(sessionSettings, MAX_SESSION_SETTINGS_BYTES + SESSION_SETTINGS_SIZE_TOLERANCE_BYTES);
71
+ }
72
+ function checkSessionSettings(sessionSettings, limitBytes) {
73
+ if (typeof sessionSettings !== "object" || sessionSettings === null || Array.isArray(sessionSettings)) {
74
+ throw new TypeError("session settings must be a JSON object");
75
+ }
76
+ const size = sessionSettingsSize(sessionSettings);
77
+ if (size > limitBytes) {
78
+ throw new RangeError(`session settings are ${size} bytes, more than the ${limitBytes} allowed`);
79
+ }
80
+ }
81
+ //# sourceMappingURL=agent-session-settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-session-settings.js","sourceRoot":"","sources":["../../src/agent-session-settings.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,kDAAkD;AAClD,mEAAmE;AACnE,+CAA+C;AAC/C,EAAE;AACF,0DAA0D;AAI1D,kHAAkH;AAClH,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,GAAG,IAAI,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qCAAqC,GAAG,IAAI,CAAC;AAE1D,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;AAEtC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CAAC,eAAgC;IAClE,OAAO,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC;AACpE,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,uBAAuB,CAAC,eAAwB;IAC9D,oBAAoB,CAAC,eAAe,EAAE,0BAA0B,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,0BAA0B,CAAC,eAAwB;IACjE,oBAAoB,CAAC,eAAe,EAAE,0BAA0B,GAAG,qCAAqC,CAAC,CAAC;AAC5G,CAAC;AAED,SAAS,oBAAoB,CAAC,eAAwB,EAAE,UAAkB;IACxE,IAAI,OAAO,eAAe,KAAK,QAAQ,IAAI,eAAe,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;QACtG,MAAM,IAAI,SAAS,CAAC,wCAAwC,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,IAAI,GAAG,mBAAmB,CAAC,eAAkC,CAAC,CAAC;IACrE,IAAI,IAAI,GAAG,UAAU,EAAE,CAAC;QACtB,MAAM,IAAI,UAAU,CAAC,wBAAwB,IAAI,yBAAyB,UAAU,UAAU,CAAC,CAAC;IAClG,CAAC;AACH,CAAC"}
@@ -0,0 +1,156 @@
1
+ import type { AgentUsage, SessionSettings } from "./agent-session-values.js";
2
+ /**
3
+ * How long the session waits for {@link ModelSpendLimit.checkModelCall} or {@link ModelSpendLimit.reportModelUsage},
4
+ * in milliseconds. Bound your own calls below it. A check that takes longer counts as a check that threw. A report
5
+ * that takes longer is dropped.
6
+ *
7
+ * @since 0.3.0
8
+ */
9
+ export declare const spendLimitCallTimeoutMs = 30000;
10
+ /**
11
+ * Starts `AgentState.lastTurnError` of a turn that a spend limit ended. The text goes on with `": "` and the reason
12
+ * from {@link ModelCallDecision}. Test for it to tell a refused call from a failed one.
13
+ *
14
+ * @since 0.3.0
15
+ */
16
+ export declare const modelCallRefusedErrorPrefix = "the model call was refused";
17
+ /**
18
+ * Describes one model call that is about to run. The session builds one for every attempt of `RunModel` and
19
+ * `CompactContext`, because every attempt can cost money.
20
+ *
21
+ * @since 0.3.0
22
+ */
23
+ export interface ModelCallCheck {
24
+ /** The session's Flow ID. */
25
+ readonly flowId: string;
26
+ /** The turn that makes the call. */
27
+ readonly turnId: string;
28
+ /** `"RunModel"` or `"CompactContext"`. */
29
+ readonly stepType: string;
30
+ /** One-based attempt of the Step. */
31
+ readonly attempt: number;
32
+ /** The turn's session settings. Put the account or API key reference that the limit applies to here. Never a secret. */
33
+ readonly sessionSettings: SessionSettings;
34
+ /** Committed usage of this session so far. */
35
+ readonly sessionUsage: AgentUsage;
36
+ }
37
+ /**
38
+ * Says whether a model call may run. `reason` reaches `AgentState.lastTurnError`, so people read it, and it is stored.
39
+ * Never put a secret in it.
40
+ *
41
+ * @since 0.3.0
42
+ */
43
+ export type ModelCallDecision = {
44
+ readonly isAllowed: true;
45
+ } | {
46
+ readonly isAllowed: false;
47
+ readonly reason: string;
48
+ };
49
+ /**
50
+ * Reports what one finished model call used.
51
+ *
52
+ * @since 0.3.0
53
+ */
54
+ export interface ModelUsageReport {
55
+ /**
56
+ * Stable ID of this attempt's call: `<flow>/<turn>/<step execution>/<attempt>`. Count each ID once. A retry has a new
57
+ * ID because it is a new paid call.
58
+ */
59
+ readonly reportId: string;
60
+ /** The session's Flow ID. */
61
+ readonly flowId: string;
62
+ /** The turn that made the call. */
63
+ readonly turnId: string;
64
+ /** `"RunModel"` or `"CompactContext"`. */
65
+ readonly stepType: string;
66
+ /** One-based attempt of the Step. */
67
+ readonly attempt: number;
68
+ /** The turn's session settings. */
69
+ readonly sessionSettings: SessionSettings;
70
+ /**
71
+ * What the runner reported. A harness runner, such as the Claude Agent SDK adapter, reports a whole segment here:
72
+ * several model calls in `usage.modelCalls`. Zero tokens with `modelCalls` above zero mean the framework did not
73
+ * expose token counts, not that the call was free.
74
+ */
75
+ readonly usage: AgentUsage;
76
+ /**
77
+ * `usage` added to the committed session usage. It includes a call whose report threw or timed out, for an
78
+ * application that counts per session.
79
+ */
80
+ readonly sessionUsage: AgentUsage;
81
+ }
82
+ /**
83
+ * Lets an application decide whether a session may spend on a model call.
84
+ *
85
+ * A spend limit is usually per account or per API key, across many sessions, so the counters and the limit belong to
86
+ * the application. Pass an implementation as `AgentSessionOptions.spendLimit`. Without one, the session makes no
87
+ * checks. The object lives in the Worker and is not stored.
88
+ *
89
+ * The session calls {@link checkModelCall} before each attempt of `RunModel` and `CompactContext`, and
90
+ * {@link reportModelUsage} after the attempt's model call returns. Both run inside the Step, on the Worker, so keep
91
+ * them fast and bound them below {@link spendLimitCallTimeoutMs}.
92
+ *
93
+ * A refused call ends the turn: the session records {@link modelCallRefusedErrorPrefix} and the reason in
94
+ * `AgentState.lastTurnError`, keeps the turn's finished tool results, and waits for the next user message, which is
95
+ * checked again. A check that throws or times out fails closed. It fails the attempt, Dex retries it under the Step's
96
+ * retry policy, and no model call runs without a passed check. When the retries run out the turn fails. To fail open,
97
+ * catch your own errors in `checkModelCall` and return `{ isAllowed: true }`.
98
+ *
99
+ * A report that throws or times out is logged and dropped, because failing the attempt would repeat a call that was
100
+ * already paid for.
101
+ *
102
+ * Limits to design for:
103
+ *
104
+ * - A check bounds the next call, not its cost. Sessions that pass together can overshoot a limit. A harness runner is
105
+ * checked once per segment, so the overshoot can be a whole segment. Set the harness's own budget option too, such
106
+ * as `maxBudgetUsd` for the Claude Agent SDK.
107
+ * - A call that fails, is cancelled, or is lost with its Worker reports nothing, though the provider may bill it. So
108
+ * the reports can be lower than the bill. They can also exceed `AgentUsage`: a call whose Step did not commit reports
109
+ * here and again on its retry, under a new `reportId`, while `AgentUsage` keeps only the committed attempt.
110
+ * - Reports are not durable. A report runs inside the Step, so a Worker that dies between the model's answer and the
111
+ * report loses it. That attempt never commits, so `AgentUsage` does not hold the call either, and only the provider's
112
+ * bill does. A report that threw or timed out is different: its attempt commits, so the next report's `sessionUsage`
113
+ * includes it.
114
+ *
115
+ * @example
116
+ * ```ts
117
+ * const spendLimit: ModelSpendLimit = {
118
+ * async checkModelCall(check) {
119
+ * const account = check.sessionSettings.account as string;
120
+ * return (await spentThisMonth(account)) >= limitOf(account)
121
+ * ? { isAllowed: false, reason: "account over its monthly limit" }
122
+ * : { isAllowed: true };
123
+ * },
124
+ * async reportModelUsage(report) {
125
+ * await recordOnce(report.reportId, report.usage);
126
+ * },
127
+ * };
128
+ * const flow = createAgentSessionFlow(runner, "SupportAgent", { spendLimit });
129
+ * ```
130
+ *
131
+ * @since 0.3.0
132
+ */
133
+ export interface ModelSpendLimit {
134
+ /**
135
+ * Decides whether one model call may run.
136
+ * @param check - The call that is about to run.
137
+ * @returns The decision.
138
+ * @throws Any error fails the attempt, so the call does not run.
139
+ */
140
+ checkModelCall(check: ModelCallCheck): Promise<ModelCallDecision>;
141
+ /**
142
+ * Records what one finished model call used.
143
+ * @param report - The call's usage. Count each `reportId` once.
144
+ * @returns A Promise that settles when the usage is recorded.
145
+ * @throws Any error is logged and dropped.
146
+ */
147
+ reportModelUsage(report: ModelUsageReport): Promise<void>;
148
+ }
149
+ /**
150
+ * Settles with `operation`, or rejects after {@link spendLimitCallTimeoutMs}.
151
+ * @param description - What is running, for the timeout message.
152
+ * @param operation - The application's call.
153
+ * @returns The call's result.
154
+ * @throws {Error} When the call takes too long, or what the call threw.
155
+ */
156
+ export declare function withinSpendLimitCallTimeout<Result>(description: string, operation: Promise<Result>): Promise<Result>;
@@ -0,0 +1,42 @@
1
+ // Copyright (c) 2026 Super Durable, Inc.
2
+ //
3
+ // Licensed under the Sustainable Use License 1.0.
4
+ // You may not use this file except in compliance with the License.
5
+ // See the LICENSE file in the repository root.
6
+ //
7
+ // SPDX-License-Identifier: LicenseRef-Sustainable-Use-1.0
8
+ /**
9
+ * How long the session waits for {@link ModelSpendLimit.checkModelCall} or {@link ModelSpendLimit.reportModelUsage},
10
+ * in milliseconds. Bound your own calls below it. A check that takes longer counts as a check that threw. A report
11
+ * that takes longer is dropped.
12
+ *
13
+ * @since 0.3.0
14
+ */
15
+ export const spendLimitCallTimeoutMs = 30_000;
16
+ /**
17
+ * Starts `AgentState.lastTurnError` of a turn that a spend limit ended. The text goes on with `": "` and the reason
18
+ * from {@link ModelCallDecision}. Test for it to tell a refused call from a failed one.
19
+ *
20
+ * @since 0.3.0
21
+ */
22
+ export const modelCallRefusedErrorPrefix = "the model call was refused";
23
+ /**
24
+ * Settles with `operation`, or rejects after {@link spendLimitCallTimeoutMs}.
25
+ * @param description - What is running, for the timeout message.
26
+ * @param operation - The application's call.
27
+ * @returns The call's result.
28
+ * @throws {Error} When the call takes too long, or what the call threw.
29
+ */
30
+ export async function withinSpendLimitCallTimeout(description, operation) {
31
+ let timer;
32
+ const timeout = new Promise((_, reject) => {
33
+ timer = setTimeout(() => reject(new Error(`${description} took more than ${spendLimitCallTimeoutMs} ms`)), spendLimitCallTimeoutMs);
34
+ });
35
+ try {
36
+ return await Promise.race([operation, timeout]);
37
+ }
38
+ finally {
39
+ clearTimeout(timer);
40
+ }
41
+ }
42
+ //# sourceMappingURL=agent-session-spend-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-session-spend-limit.js","sourceRoot":"","sources":["../../src/agent-session-spend-limit.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,kDAAkD;AAClD,mEAAmE;AACnE,+CAA+C;AAC/C,EAAE;AACF,0DAA0D;AAI1D;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,4BAA4B,CAAC;AAqIxE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,WAAmB,EACnB,SAA0B;IAE1B,IAAI,KAAiC,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;QAC/C,KAAK,GAAG,UAAU,CAChB,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,WAAW,mBAAmB,uBAAuB,KAAK,CAAC,CAAC,EACtF,uBAAuB,CACxB,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { ActiveStepSearchMode, type Client, type StartFlowOptions } from "@superdurable/dex";
2
+ import type { AgentFrameworkRunner, DeferredToolOutcome } from "./agent-framework-runner.js";
3
+ import type { AgentSessionFlow } from "./agent-session-flow.js";
4
+ import type { AgentSessionStartInput } from "./agent-session-values.js";
5
+ /**
6
+ * The search mode {@link startAgentSession} gives a new session.
7
+ *
8
+ * It indexes the Steps that wait, such as `AwaitToolApproval`, `AwaitQuestionAnswer`, and `AwaitUserMessage`, and
9
+ * leaves out Steps that run straight away, such as `RunModel`. So a session's search entry changes when it enters or
10
+ * leaves a wait, not on every Step.
11
+ *
12
+ * Pass it as `activeStepSearchMode` in `StartFlowOptions.configOverride` to `Client.startFlow`, in a SubFlow's
13
+ * `configOverride`, or to `Client.updateFlowConfig` for a running session.
14
+ *
15
+ * The value is `ActiveStepSearchMode.DEFAULT` because the Dex SDK this core supports has no `WITH_WAIT_FOR` value.
16
+ * It sends the unspecified mode, which the server stores on the Flow and treats as Steps with a wait.
17
+ *
18
+ * @since 0.3.0
19
+ */
20
+ export declare const agentSessionActiveStepSearchMode: ActiveStepSearchMode;
21
+ /**
22
+ * Starts one agent session, searchable by the Steps it waits in.
23
+ *
24
+ * `ActiveStepTypes = "AwaitToolApproval"` then finds the session while a tool call waits for a person. Prefer this to
25
+ * `Client.startFlow`, which leaves the session out of that search unless `configOverride` sets
26
+ * {@link agentSessionActiveStepSearchMode}.
27
+ *
28
+ * Set `configOverride.activeStepSearchMode` to choose another mode. To leave a session out of the search, start it
29
+ * with `Client.startFlow` and no mode: the Dex SDK this core supports cannot send the disabled mode. A session started
30
+ * as a SubFlow inherits its parent's mode unless its `configOverride` sets one.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * await startAgentSession(client, flow, "session-42", { initialMessage: "Refund order 7" });
35
+ * const page = await client.searchFlows('ActiveStepTypes = "AwaitToolApproval"', 50);
36
+ * ```
37
+ *
38
+ * @param client - An open Client whose Registry contains `flow`.
39
+ * @param flow - The registered agent session Flow.
40
+ * @param sessionId - Flow ID of the new session.
41
+ * @param input - The first user message and the session's settings.
42
+ * @param options - Start options, such as a Request ID for an idempotent start. `configOverride` keeps every field
43
+ * it sets.
44
+ * @returns The server-assigned run ID.
45
+ * @throws {TypeError | RangeError} From `validateSessionSettings`, before anything is sent.
46
+ * @throws {FlowAlreadyStartedError} When the Flow ID is already in use.
47
+ * @since 0.3.0
48
+ */
49
+ export declare function startAgentSession(client: Client, flow: AgentSessionFlow<AgentFrameworkRunner<DeferredToolOutcome>>, sessionId: string, input?: Partial<AgentSessionStartInput>, options?: StartFlowOptions): Promise<string>;