@superdurable/dex-agents 0.0.0-stage → 0.2.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 (171) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +1981 -2
  3. package/dist/src/agent-built-in-tools.d.ts +81 -0
  4. package/dist/src/agent-built-in-tools.js +246 -0
  5. package/dist/src/agent-built-in-tools.js.map +1 -0
  6. package/dist/src/agent-context-compaction.d.ts +108 -0
  7. package/dist/src/agent-context-compaction.js +39 -0
  8. package/dist/src/agent-context-compaction.js.map +1 -0
  9. package/dist/src/agent-event-writer.d.ts +26 -0
  10. package/dist/src/agent-event-writer.js +110 -0
  11. package/dist/src/agent-event-writer.js.map +1 -0
  12. package/dist/src/agent-framework-runner.d.ts +808 -0
  13. package/dist/src/agent-framework-runner.js +82 -0
  14. package/dist/src/agent-framework-runner.js.map +1 -0
  15. package/dist/src/agent-plans.d.ts +48 -0
  16. package/dist/src/agent-plans.js +86 -0
  17. package/dist/src/agent-plans.js.map +1 -0
  18. package/dist/src/agent-session-cancellation-steps.d.ts +28 -0
  19. package/dist/src/agent-session-cancellation-steps.js +154 -0
  20. package/dist/src/agent-session-cancellation-steps.js.map +1 -0
  21. package/dist/src/agent-session-codecs.d.ts +105 -0
  22. package/dist/src/agent-session-codecs.js +689 -0
  23. package/dist/src/agent-session-codecs.js.map +1 -0
  24. package/dist/src/agent-session-flow.d.ts +416 -0
  25. package/dist/src/agent-session-flow.js +623 -0
  26. package/dist/src/agent-session-flow.js.map +1 -0
  27. package/dist/src/agent-session-persistence.d.ts +133 -0
  28. package/dist/src/agent-session-persistence.js +74 -0
  29. package/dist/src/agent-session-persistence.js.map +1 -0
  30. package/dist/src/agent-session-settings.d.ts +58 -0
  31. package/dist/src/agent-session-settings.js +81 -0
  32. package/dist/src/agent-session-settings.js.map +1 -0
  33. package/dist/src/agent-session-step-options.d.ts +27 -0
  34. package/dist/src/agent-session-step-options.js +39 -0
  35. package/dist/src/agent-session-step-options.js.map +1 -0
  36. package/dist/src/agent-session-step-types.d.ts +20 -0
  37. package/dist/src/agent-session-step-types.js +28 -0
  38. package/dist/src/agent-session-step-types.js.map +1 -0
  39. package/dist/src/agent-session-steps.d.ts +179 -0
  40. package/dist/src/agent-session-steps.js +1272 -0
  41. package/dist/src/agent-session-steps.js.map +1 -0
  42. package/dist/src/agent-session-tracer.d.ts +61 -0
  43. package/dist/src/agent-session-tracer.js +608 -0
  44. package/dist/src/agent-session-tracer.js.map +1 -0
  45. package/dist/src/agent-session-transitions.d.ts +224 -0
  46. package/dist/src/agent-session-transitions.js +850 -0
  47. package/dist/src/agent-session-transitions.js.map +1 -0
  48. package/dist/src/agent-session-values.d.ts +998 -0
  49. package/dist/src/agent-session-values.js +162 -0
  50. package/dist/src/agent-session-values.js.map +1 -0
  51. package/dist/src/agent-session-wait-steps.d.ts +53 -0
  52. package/dist/src/agent-session-wait-steps.js +389 -0
  53. package/dist/src/agent-session-wait-steps.js.map +1 -0
  54. package/dist/src/agent-tracing-options.d.ts +107 -0
  55. package/dist/src/agent-tracing-options.js +20 -0
  56. package/dist/src/agent-tracing-options.js.map +1 -0
  57. package/dist/src/ai-sdk/ai-sdk-model-client.d.ts +40 -0
  58. package/dist/src/ai-sdk/ai-sdk-model-client.js +235 -0
  59. package/dist/src/ai-sdk/ai-sdk-model-client.js.map +1 -0
  60. package/dist/src/ai-sdk/index.d.ts +1 -0
  61. package/dist/src/ai-sdk/index.js +9 -0
  62. package/dist/src/ai-sdk/index.js.map +1 -0
  63. package/dist/src/index.d.ts +10 -0
  64. package/dist/src/index.js +17 -0
  65. package/dist/src/index.js.map +1 -0
  66. package/dist/src/mcp/index.d.ts +3 -0
  67. package/dist/src/mcp/index.js +10 -0
  68. package/dist/src/mcp/index.js.map +1 -0
  69. package/dist/src/mcp/mcp-resource-and-prompt-tools.d.ts +29 -0
  70. package/dist/src/mcp/mcp-resource-and-prompt-tools.js +185 -0
  71. package/dist/src/mcp/mcp-resource-and-prompt-tools.js.map +1 -0
  72. package/dist/src/mcp/mcp-server-config.d.ts +86 -0
  73. package/dist/src/mcp/mcp-server-config.js +38 -0
  74. package/dist/src/mcp/mcp-server-config.js.map +1 -0
  75. package/dist/src/mcp/mcp-tool-source.d.ts +470 -0
  76. package/dist/src/mcp/mcp-tool-source.js +1204 -0
  77. package/dist/src/mcp/mcp-tool-source.js.map +1 -0
  78. package/dist/src/stepwise/agent-definition.d.ts +158 -0
  79. package/dist/src/stepwise/agent-definition.js +9 -0
  80. package/dist/src/stepwise/agent-definition.js.map +1 -0
  81. package/dist/src/stepwise/function-tool.d.ts +130 -0
  82. package/dist/src/stepwise/function-tool.js +75 -0
  83. package/dist/src/stepwise/function-tool.js.map +1 -0
  84. package/dist/src/stepwise/index.d.ts +7 -0
  85. package/dist/src/stepwise/index.js +12 -0
  86. package/dist/src/stepwise/index.js.map +1 -0
  87. package/dist/src/stepwise/json-schema-validation.d.ts +9 -0
  88. package/dist/src/stepwise/json-schema-validation.js +141 -0
  89. package/dist/src/stepwise/json-schema-validation.js.map +1 -0
  90. package/dist/src/stepwise/model-client.d.ts +194 -0
  91. package/dist/src/stepwise/model-client.js +9 -0
  92. package/dist/src/stepwise/model-client.js.map +1 -0
  93. package/dist/src/stepwise/scripted-model-client.d.ts +99 -0
  94. package/dist/src/stepwise/scripted-model-client.js +156 -0
  95. package/dist/src/stepwise/scripted-model-client.js.map +1 -0
  96. package/dist/src/stepwise/stepwise-agent-runner.d.ts +189 -0
  97. package/dist/src/stepwise/stepwise-agent-runner.js +804 -0
  98. package/dist/src/stepwise/stepwise-agent-runner.js.map +1 -0
  99. package/dist/src/stepwise/stepwise-agent-session-flow.d.ts +35 -0
  100. package/dist/src/stepwise/stepwise-agent-session-flow.js +56 -0
  101. package/dist/src/stepwise/stepwise-agent-session-flow.js.map +1 -0
  102. package/dist/src/stepwise/stepwise-input-items.d.ts +12 -0
  103. package/dist/src/stepwise/stepwise-input-items.js +172 -0
  104. package/dist/src/stepwise/stepwise-input-items.js.map +1 -0
  105. package/dist/src/stepwise/tool-source.d.ts +103 -0
  106. package/dist/src/stepwise/tool-source.js +9 -0
  107. package/dist/src/stepwise/tool-source.js.map +1 -0
  108. package/dist/src/testing/agent-session-test-client.d.ts +205 -0
  109. package/dist/src/testing/agent-session-test-client.js +290 -0
  110. package/dist/src/testing/agent-session-test-client.js.map +1 -0
  111. package/dist/src/testing/agent-test-environment.d.ts +52 -0
  112. package/dist/src/testing/agent-test-environment.js +86 -0
  113. package/dist/src/testing/agent-test-environment.js.map +1 -0
  114. package/dist/src/testing/agent-worker-process.d.ts +91 -0
  115. package/dist/src/testing/agent-worker-process.js +150 -0
  116. package/dist/src/testing/agent-worker-process.js.map +1 -0
  117. package/dist/src/testing/child-process-group.d.ts +33 -0
  118. package/dist/src/testing/child-process-group.js +164 -0
  119. package/dist/src/testing/child-process-group.js.map +1 -0
  120. package/dist/src/testing/coordination.d.ts +99 -0
  121. package/dist/src/testing/coordination.js +155 -0
  122. package/dist/src/testing/coordination.js.map +1 -0
  123. package/dist/src/testing/index.d.ts +8 -0
  124. package/dist/src/testing/index.js +16 -0
  125. package/dist/src/testing/index.js.map +1 -0
  126. package/dist/src/testing/polling.d.ts +31 -0
  127. package/dist/src/testing/polling.js +51 -0
  128. package/dist/src/testing/polling.js.map +1 -0
  129. package/dist/src/testing/private-dex-engine.d.ts +101 -0
  130. package/dist/src/testing/private-dex-engine.js +223 -0
  131. package/dist/src/testing/private-dex-engine.js.map +1 -0
  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/testing/step-history.d.ts +40 -0
  136. package/dist/src/testing/step-history.js +59 -0
  137. package/dist/src/testing/step-history.js.map +1 -0
  138. package/dist/src/ui-stream/agent-event-json.d.ts +30 -0
  139. package/dist/src/ui-stream/agent-event-json.js +64 -0
  140. package/dist/src/ui-stream/agent-event-json.js.map +1 -0
  141. package/dist/src/ui-stream/agent-event-sse.d.ts +154 -0
  142. package/dist/src/ui-stream/agent-event-sse.js +159 -0
  143. package/dist/src/ui-stream/agent-event-sse.js.map +1 -0
  144. package/dist/src/ui-stream/agent-event-stream-positions.d.ts +42 -0
  145. package/dist/src/ui-stream/agent-event-stream-positions.js +153 -0
  146. package/dist/src/ui-stream/agent-event-stream-positions.js.map +1 -0
  147. package/dist/src/ui-stream/agent-session-record-reader.d.ts +72 -0
  148. package/dist/src/ui-stream/agent-session-record-reader.js +241 -0
  149. package/dist/src/ui-stream/agent-session-record-reader.js.map +1 -0
  150. package/dist/src/ui-stream/agent-ui-message-stream-responses.d.ts +219 -0
  151. package/dist/src/ui-stream/agent-ui-message-stream-responses.js +440 -0
  152. package/dist/src/ui-stream/agent-ui-message-stream-responses.js.map +1 -0
  153. package/dist/src/ui-stream/agent-ui-message-stream.d.ts +138 -0
  154. package/dist/src/ui-stream/agent-ui-message-stream.js +681 -0
  155. package/dist/src/ui-stream/agent-ui-message-stream.js.map +1 -0
  156. package/dist/src/ui-stream/agent-ui-message-types.d.ts +238 -0
  157. package/dist/src/ui-stream/agent-ui-message-types.js +57 -0
  158. package/dist/src/ui-stream/agent-ui-message-types.js.map +1 -0
  159. package/dist/src/ui-stream/agent-ui-messages.d.ts +66 -0
  160. package/dist/src/ui-stream/agent-ui-messages.js +220 -0
  161. package/dist/src/ui-stream/agent-ui-messages.js.map +1 -0
  162. package/dist/src/ui-stream/agent-ui-stream-cursor.d.ts +64 -0
  163. package/dist/src/ui-stream/agent-ui-stream-cursor.js +186 -0
  164. package/dist/src/ui-stream/agent-ui-stream-cursor.js.map +1 -0
  165. package/dist/src/ui-stream/index.d.ts +14 -0
  166. package/dist/src/ui-stream/index.js +22 -0
  167. package/dist/src/ui-stream/index.js.map +1 -0
  168. package/dist/src/ui-stream/server-sent-event-responses.d.ts +6 -0
  169. package/dist/src/ui-stream/server-sent-event-responses.js +34 -0
  170. package/dist/src/ui-stream/server-sent-event-responses.js.map +1 -0
  171. package/package.json +86 -4
@@ -0,0 +1,141 @@
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
+ /** Returns the first way `value` breaks the schema, such as `arguments.order_id must be string`, or `undefined`. */
9
+ export function findJsonSchemaViolation(value, schema, path) {
10
+ const anyOf = schema["anyOf"];
11
+ const isNoAnyOfOptionMatched = Array.isArray(anyOf) &&
12
+ anyOf.every((option) => findJsonSchemaViolation(value, option, path) !== undefined);
13
+ if (isNoAnyOfOptionMatched) {
14
+ return `${path} matches none of the allowed types`;
15
+ }
16
+ const expected = schema["type"];
17
+ if (expected !== undefined) {
18
+ const expectedTypes = (typeof expected === "string" ? [expected] : expected).map(String);
19
+ if (!expectedTypes.some((type) => matchesJsonType(type, value))) {
20
+ return `${path} must be ${expectedTypes.join(" or ")}`;
21
+ }
22
+ }
23
+ const allowedValues = schema["enum"];
24
+ if (Array.isArray(allowedValues) && !allowedValues.some((allowed) => isPythonEqual(allowed, value))) {
25
+ return `${path} must be one of ${serializeJsonWithSpacedSeparators(allowedValues)}`;
26
+ }
27
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
28
+ return findObjectViolation(value, schema, path);
29
+ }
30
+ const items = schema["items"];
31
+ if (Array.isArray(value) && typeof items === "object" && items !== null) {
32
+ for (const [index, item] of value.entries()) {
33
+ const violation = findJsonSchemaViolation(item, items, `${path}[${index}]`);
34
+ if (violation !== undefined) {
35
+ return violation;
36
+ }
37
+ }
38
+ }
39
+ if (typeof value === "number") {
40
+ if (typeof schema["minimum"] === "number" && value < schema["minimum"]) {
41
+ return `${path} must be at least ${schema["minimum"]}`;
42
+ }
43
+ if (typeof schema["maximum"] === "number" && value > schema["maximum"]) {
44
+ return `${path} must be at most ${schema["maximum"]}`;
45
+ }
46
+ }
47
+ return undefined;
48
+ }
49
+ /**
50
+ * Serializes JSON with `", "` and `": "` separators and unescaped non-ASCII text, the format of Python's
51
+ * `json.dumps`, so model-visible text matches the Python core.
52
+ */
53
+ export function serializeJsonWithSpacedSeparators(value) {
54
+ if (Array.isArray(value)) {
55
+ return `[${value.map((item) => serializeJsonWithSpacedSeparators(item === undefined ? null : item)).join(", ")}]`;
56
+ }
57
+ if (typeof value === "object" && value !== null) {
58
+ const record = typeof value.toJSON === "function"
59
+ ? value.toJSON()
60
+ : value;
61
+ if (typeof record !== "object" || record === null) {
62
+ return serializeJsonWithSpacedSeparators(record);
63
+ }
64
+ const entries = Object.entries(record).filter(([, nestedValue]) => nestedValue !== undefined);
65
+ return `{${entries
66
+ .map(([key, nestedValue]) => `${JSON.stringify(key)}: ${serializeJsonWithSpacedSeparators(nestedValue)}`)
67
+ .join(", ")}}`;
68
+ }
69
+ const text = JSON.stringify(value);
70
+ if (text === undefined) {
71
+ throw new TypeError(`a ${typeof value} value cannot be serialized as JSON`);
72
+ }
73
+ return text;
74
+ }
75
+ function findObjectViolation(value, schema, path) {
76
+ const properties = (schema["properties"] ?? {});
77
+ for (const requiredName of (schema["required"] ?? [])) {
78
+ if (!Object.hasOwn(value, requiredName)) {
79
+ return `${path}.${requiredName} is required`;
80
+ }
81
+ }
82
+ const additionalProperties = schema["additionalProperties"] ?? true;
83
+ for (const [name, propertyValue] of Object.entries(value)) {
84
+ let violation;
85
+ if (Object.hasOwn(properties, name)) {
86
+ violation = findJsonSchemaViolation(propertyValue, properties[name] ?? {}, `${path}.${name}`);
87
+ }
88
+ else if (additionalProperties === false) {
89
+ violation = `${path}.${name} is not allowed`;
90
+ }
91
+ else if (typeof additionalProperties === "object" && additionalProperties !== null) {
92
+ violation = findJsonSchemaViolation(propertyValue, additionalProperties, `${path}.${name}`);
93
+ }
94
+ if (violation !== undefined) {
95
+ return violation;
96
+ }
97
+ }
98
+ return undefined;
99
+ }
100
+ /** Python's `==` over JSON values, which the Python core's `enum` check uses: `true == 1` and `1 == 1.0`. */
101
+ function isPythonEqual(left, right) {
102
+ const isNumeric = (value) => typeof value === "number" || typeof value === "boolean";
103
+ if (isNumeric(left) || isNumeric(right)) {
104
+ return isNumeric(left) && isNumeric(right) && Number(left) === Number(right);
105
+ }
106
+ if (Array.isArray(left) || Array.isArray(right)) {
107
+ return (Array.isArray(left) &&
108
+ Array.isArray(right) &&
109
+ left.length === right.length &&
110
+ left.every((item, index) => isPythonEqual(item, right[index])));
111
+ }
112
+ if (typeof left === "object" && left !== null && typeof right === "object" && right !== null) {
113
+ const leftRecord = left;
114
+ const rightRecord = right;
115
+ const leftKeys = Object.keys(leftRecord);
116
+ return (leftKeys.length === Object.keys(rightRecord).length &&
117
+ leftKeys.every((key) => Object.hasOwn(rightRecord, key) && isPythonEqual(leftRecord[key], rightRecord[key])));
118
+ }
119
+ return left === right;
120
+ }
121
+ function matchesJsonType(type, value) {
122
+ switch (type) {
123
+ case "string":
124
+ return typeof value === "string";
125
+ case "boolean":
126
+ return typeof value === "boolean";
127
+ case "null":
128
+ return value === null;
129
+ case "array":
130
+ return Array.isArray(value);
131
+ case "object":
132
+ return typeof value === "object" && value !== null && !Array.isArray(value);
133
+ case "number":
134
+ return typeof value === "number";
135
+ case "integer":
136
+ return typeof value === "number" && Number.isInteger(value);
137
+ default:
138
+ throw new TypeError(`unsupported JSON Schema type ${type}`);
139
+ }
140
+ }
141
+ //# sourceMappingURL=json-schema-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-schema-validation.js","sourceRoot":"","sources":["../../../src/stepwise/json-schema-validation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,194 @@
1
+ import type { AgentUsage } from "../agent-session-values.js";
2
+ /**
3
+ * User text in a model input, stored for a user message and for Dex notes such as the turn-failure note.
4
+ * Wire shape: `{"type":"user_text","text"}`.
5
+ */
6
+ export interface ModelUserTextItem {
7
+ /** Discriminator. Wire field: `type`. */
8
+ readonly type: "user_text";
9
+ /** The text. Wire field: `text`. */
10
+ readonly text: string;
11
+ }
12
+ /** One tool call of a model response, in provider-neutral form. */
13
+ export interface ModelToolCall {
14
+ /** Provider tool call ID. Wire field: `tool_call_id`. */
15
+ readonly toolCallId: string;
16
+ /** Tool name. Wire field: `tool_name`. */
17
+ readonly toolName: string;
18
+ /** Tool arguments as JSON text, exactly as the model produced them. Wire field: `arguments`. */
19
+ readonly arguments: string;
20
+ }
21
+ /**
22
+ * One output item exactly as a provider returned it, with provider-neutral projections.
23
+ *
24
+ * Wire shape: `{"type":"model_output","provider","api","item","text","tool_calls"}`. A client returns one
25
+ * item per provider output item, such as one AI SDK assistant message. {@link item} is the provider's
26
+ * JSON text, opaque to Dex, so its bytes survive storage: opaque fields such as thinking signatures and
27
+ * encrypted reasoning stay the exact strings the provider sent. A {@link ModelClient} replays the item
28
+ * unchanged when {@link provider} and {@link api} match its own. Otherwise it replays {@link text} and
29
+ * {@link toolCalls} and drops the rest, such as reasoning, so a session can change model between turns.
30
+ */
31
+ export interface ModelOutputItem {
32
+ /** Discriminator. Wire field: `type`. */
33
+ readonly type: "model_output";
34
+ /** Provider that produced the item, such as `"openai.responses"`. Wire field: `provider`. */
35
+ readonly provider: string;
36
+ /** Provider API that produced the item, such as `"ai-sdk"`. Wire field: `api`. */
37
+ readonly api: string;
38
+ /** Provider JSON text of the item. Wire field: `item`. */
39
+ readonly item: string;
40
+ /** Visible text of the item, or `null` when it has none. Wire field: `text`. */
41
+ readonly text: string | null;
42
+ /** Tool calls the item asks for, in model order. Wire field: `tool_calls`. */
43
+ readonly toolCalls: readonly ModelToolCall[];
44
+ }
45
+ /**
46
+ * The result of one tool call in a model input, in provider-neutral form.
47
+ * Wire shape: `{"type":"tool_result","tool_call_id","tool_name","output"}`.
48
+ */
49
+ export interface ModelToolResultItem {
50
+ /** Discriminator. Wire field: `type`. */
51
+ readonly type: "tool_result";
52
+ /** Tool call this result answers. Wire field: `tool_call_id`. */
53
+ readonly toolCallId: string;
54
+ /** Tool name. Wire field: `tool_name`. */
55
+ readonly toolName: string;
56
+ /** Model-visible result text, from `describeToolCallOutcome`. Wire field: `output`. */
57
+ readonly output: string;
58
+ }
59
+ /**
60
+ * One item of a model input. The Stepwise runner stores each one as the `framework_item` of an
61
+ * `AgentMessage`, as snake_case JSON.
62
+ */
63
+ export type ModelInputItem = ModelUserTextItem | ModelOutputItem | ModelToolResultItem;
64
+ /** Definition of one tool offered to the model. */
65
+ export interface ModelToolDefinition {
66
+ /** Tool name. */
67
+ readonly name: string;
68
+ /** Tool description for the model. */
69
+ readonly description: string;
70
+ /** JSON Schema of the arguments, an object schema. */
71
+ readonly parameters: Readonly<Record<string, unknown>>;
72
+ }
73
+ /**
74
+ * How the model may use the offered tools: `auto` lets it choose, `none` forbids tool calls, `required`
75
+ * forces at least one, and `{ toolName }` forces that tool.
76
+ */
77
+ export type ModelToolChoice = "auto" | "none" | "required" | {
78
+ readonly toolName: string;
79
+ };
80
+ /** Settings of every model call of an agent; a {@link ModelClient} passes them to its provider. */
81
+ export interface ModelSettings {
82
+ /** Sampling temperature; the provider's default when omitted. */
83
+ readonly temperature?: number;
84
+ /** Maximum output tokens; the provider's default when omitted. */
85
+ readonly maxOutputTokens?: number;
86
+ /** Reasoning effort, such as `"low"` or `"high"`; the provider's default when omitted. */
87
+ readonly reasoningEffort?: string;
88
+ /** Provider-specific options by provider name, passed through unchanged. */
89
+ readonly providerOptions?: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
90
+ }
91
+ /** Identifies the `RunModel` attempt that makes a model call. */
92
+ export interface ModelRequestMetadata {
93
+ /** Flow ID, which is the session ID. */
94
+ readonly flowId: string;
95
+ /** Turn ID. */
96
+ readonly turnId: string;
97
+ /** Dex Step execution ID of the `RunModel` Step. */
98
+ readonly stepExecutionId: string;
99
+ /** One-based attempt of the `RunModel` Step. */
100
+ readonly attempt: number;
101
+ }
102
+ /** One model call, built by the Stepwise runner from committed session state only. */
103
+ export interface ModelRequest {
104
+ /** System instructions for this call. */
105
+ readonly instructions: string;
106
+ /** The conversation, oldest first; every tool call is followed by its result. */
107
+ readonly inputItems: readonly ModelInputItem[];
108
+ /** Tools the model may call; empty when the call must answer. */
109
+ readonly tools: readonly ModelToolDefinition[];
110
+ /** How the model may use {@link tools}. */
111
+ readonly toolChoice: ModelToolChoice;
112
+ /** Settings from the agent definition. */
113
+ readonly settings: ModelSettings;
114
+ /** The `RunModel` attempt making the call. */
115
+ readonly metadata: ModelRequestMetadata;
116
+ /** Signal aborted when Dex cancels the attempt; pass it to the provider request. */
117
+ readonly cancellationSignal: AbortSignal;
118
+ }
119
+ /** Result of one model call. */
120
+ export interface ModelResponse {
121
+ /** Provider-exact output items of the response; the session stores them in order. */
122
+ readonly outputItems: readonly ModelOutputItem[];
123
+ /** Visible text of the response, a display projection. */
124
+ readonly text: string;
125
+ /** Tool calls the model requested, in model order; empty for a final answer. */
126
+ readonly toolCalls: readonly ModelToolCall[];
127
+ /** Usage of this one call; `modelCalls` is 1. */
128
+ readonly usage: AgentUsage;
129
+ /** Model that answered, as the provider reported it. */
130
+ readonly responseModel: string;
131
+ /** Provider finish reason, such as `"stop"` or `"tool-calls"`. */
132
+ readonly finishReason: string;
133
+ }
134
+ /** Receives the live text of one model call; the Stepwise runner forwards it to `AgentEvents`. */
135
+ export interface ModelOutputWriter {
136
+ /**
137
+ * Writes visible text as a `text_delta` event.
138
+ * @param text - Text chunk; empty chunks are ignored.
139
+ */
140
+ writeTextDelta(text: string): void;
141
+ /**
142
+ * Writes a provider-authored reasoning summary chunk as a `reasoning_delta` event.
143
+ * @param text - Text chunk; empty chunks are ignored.
144
+ */
145
+ writeReasoningDelta(text: string): void;
146
+ }
147
+ /**
148
+ * Makes one model call for the Stepwise runner.
149
+ *
150
+ * Use `createAiSdkModelClient` from `@superdurable/dex-agents/ai-sdk` for any AI SDK provider, or
151
+ * implement this interface for another model API. Every client follows these rules:
152
+ * - One request per call. The client makes no retries of its own; retries are `RunModel` attempts, so
153
+ * each one is visible in the Flow history.
154
+ * - Dex owns the conversation. The client sends the whole input every time and uses no provider-side
155
+ * conversation state, such as a previous response ID.
156
+ * - Provider-exact transcript. The client returns each output item as the provider returned it and
157
+ * replays items of its own provider and API unchanged. It never rebuilds opaque fields, such as
158
+ * thinking signatures or encrypted reasoning, from display text.
159
+ * - Dex-authored items, {@link ModelUserTextItem} and {@link ModelToolResultItem}, are converted at call
160
+ * time. An item from another provider or API is replayed as its text and tool calls.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * const echoModel: ModelClient = {
165
+ * async callModel(request, output) {
166
+ * const text = `echo: ${request.inputItems.length} items`;
167
+ * output.writeTextDelta(text);
168
+ * return {
169
+ * outputItems: [{ type: "model_output", provider: "echo", api: "echo", item: JSON.stringify({ text }),
170
+ * text, toolCalls: [] }],
171
+ * text, toolCalls: [], responseModel: "echo-1", finishReason: "stop",
172
+ * usage: { modelCalls: 1, inputTokens: 0, outputTokens: 0, cachedInputTokens: 0, reasoningTokens: 0 },
173
+ * };
174
+ * },
175
+ * estimateInputTokens: (request) => JSON.stringify(request.inputItems).length / 4,
176
+ * };
177
+ * ```
178
+ */
179
+ export interface ModelClient {
180
+ /**
181
+ * Makes exactly one model call and streams its text to `output`.
182
+ * @param request - The call; see {@link ModelRequest}.
183
+ * @param output - Receives text and reasoning deltas while the call streams.
184
+ * @returns The provider-exact output items, projections, and usage of the call.
185
+ * @throws Any error to fail the `RunModel` attempt, which Dex retries up to 3 times.
186
+ */
187
+ callModel(request: ModelRequest, output: ModelOutputWriter): Promise<ModelResponse>;
188
+ /**
189
+ * Estimates the input tokens of a request without a model call.
190
+ * @param request - The request to measure.
191
+ * @returns An estimate of its input tokens.
192
+ */
193
+ estimateInputTokens(request: ModelRequest): number;
194
+ }
@@ -0,0 +1,9 @@
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
+ export {};
9
+ //# sourceMappingURL=model-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-client.js","sourceRoot":"","sources":["../../../src/stepwise/model-client.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,kDAAkD;AAClD,mEAAmE;AACnE,+CAA+C;AAC/C,EAAE;AACF,0DAA0D"}
@@ -0,0 +1,99 @@
1
+ import type { AgentUsage } from "../agent-session-values.js";
2
+ import type { ModelClient, ModelOutputWriter, ModelRequest, ModelResponse, ModelToolResultItem } from "./model-client.js";
3
+ /** {@link ModelOutputItem.provider} of every item {@link ScriptedModelClient} returns. */
4
+ export declare const scriptedModelProvider = "dex-scripted";
5
+ /** {@link ModelOutputItem.api} of every item {@link ScriptedModelClient} returns. */
6
+ export declare const scriptedModelApi = "scripted";
7
+ /** Default number of latest requests {@link ScriptedModelClient.requests} keeps. */
8
+ export declare const defaultMaxRecordedRequests = 100;
9
+ /** One tool call of a {@link ScriptedModelReply}. */
10
+ export interface ScriptedToolCall {
11
+ /** Tool name. */
12
+ readonly toolName: string;
13
+ /** Arguments as JSON text, or an object encoded as JSON. Defaults to `{}`. */
14
+ readonly arguments?: string | Readonly<Record<string, unknown>>;
15
+ /** Tool call ID. Defaults to `<stepExecutionId>-<index>`, which is unique in the session. */
16
+ readonly toolCallId?: string;
17
+ }
18
+ /** What one scripted model call returns. */
19
+ export interface ScriptedModelReply {
20
+ /** Visible text, streamed as one `text_delta`. Defaults to none. */
21
+ readonly text?: string;
22
+ /** Tool calls, in order. Defaults to none. */
23
+ readonly toolCalls?: readonly ScriptedToolCall[];
24
+ /** Reasoning summary, streamed as one `reasoning_delta` and stored as a reasoning item. Defaults to none. */
25
+ readonly reasoning?: string | null;
26
+ /** Usage of the call. Defaults to one model call with 10 input and 5 output tokens. */
27
+ readonly usage?: AgentUsage;
28
+ }
29
+ /** The script: a function from the whole request to the reply. */
30
+ export type ScriptedModelResponder = (request: ModelRequest) => ScriptedModelReply | Promise<ScriptedModelReply>;
31
+ /**
32
+ * A Stepwise {@link ModelClient} that answers every model call from a script, for demos and tests without a
33
+ * model key. It mirrors the Python core's `ScriptedModelClient`.
34
+ *
35
+ * Use it as `AgentDefinition.model` to run a Stepwise agent with no provider account: a local demo
36
+ * mode of an application, a tutorial, or an integration test. It is a supported part of
37
+ * `@superdurable/dex-agents/stepwise` and needs no optional peer. `@superdurable/dex-agents/testing`
38
+ * exports the same class.
39
+ *
40
+ * The script is a function of the whole {@link ModelRequest}, so it can read the user text, with
41
+ * {@link ScriptedModelClient.userTexts}, and the tool results the runner replays, with
42
+ * {@link ScriptedModelClient.toolResults}, and it can call any offered tool, including built-in and tool
43
+ * source tools. Keep it deterministic: a Worker that crashes mid-call reruns it in a new process. Its output
44
+ * items use {@link scriptedModelProvider} and {@link scriptedModelApi}, so a session can switch to a real
45
+ * model later; that model sees the scripted replies as text.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const model = new ScriptedModelClient((request) =>
50
+ * ScriptedModelClient.toolResults(request).length > 0
51
+ * ? { text: "done" }
52
+ * : { toolCalls: [{ toolName: "lookup_order", arguments: { order_id: "7" } }] });
53
+ * const flow = createStepwiseAgentSessionFlow(
54
+ * { name: "demo", instructions: "Help.", model, tools: [lookupOrder] }, "DemoAgent");
55
+ * ```
56
+ */
57
+ export declare class ScriptedModelClient implements ModelClient {
58
+ private readonly respond;
59
+ private readonly receivedRequests;
60
+ private readonly maxRecordedRequests;
61
+ /**
62
+ * Creates a client around a script.
63
+ * @param respond - Function that returns the reply for a request.
64
+ * @param options - `maxRecordedRequests`: how many of the latest requests {@link requests} keeps, so a
65
+ * long-running demo Worker does not keep every transcript. `0` records none. Defaults to
66
+ * {@link defaultMaxRecordedRequests}.
67
+ * @throws {RangeError} When `maxRecordedRequests` is not a non-negative integer.
68
+ */
69
+ constructor(respond: ScriptedModelResponder, options?: {
70
+ readonly maxRecordedRequests?: number;
71
+ });
72
+ /** The latest requests this client received in this process, up to `maxRecordedRequests`, oldest first. */
73
+ get requests(): readonly ModelRequest[];
74
+ /**
75
+ * Runs the script for one request and streams its reply.
76
+ * @param request - The request.
77
+ * @param output - Writer for text and reasoning deltas.
78
+ * @returns One reasoning item, one message item, and one item per tool call, for the parts the reply has.
79
+ */
80
+ callModel(request: ModelRequest, output: ModelOutputWriter): Promise<ModelResponse>;
81
+ /**
82
+ * Estimates four characters per token over the request text.
83
+ * @param request - The request.
84
+ * @returns The estimate.
85
+ */
86
+ estimateInputTokens(request: ModelRequest): number;
87
+ /**
88
+ * Returns the text of every user item in a request, oldest first.
89
+ * @param request - The request.
90
+ * @returns User texts, including Dex notes stored as user text.
91
+ */
92
+ static userTexts(request: ModelRequest): string[];
93
+ /**
94
+ * Returns the tool results after the last user item of a request.
95
+ * @param request - The request.
96
+ * @returns The current turn's tool results, oldest first.
97
+ */
98
+ static toolResults(request: ModelRequest): ModelToolResultItem[];
99
+ }
@@ -0,0 +1,156 @@
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
+ import { serializeJsonWithSpacedSeparators } from "./json-schema-validation.js";
9
+ /** {@link ModelOutputItem.provider} of every item {@link ScriptedModelClient} returns. */
10
+ export const scriptedModelProvider = "dex-scripted";
11
+ /** {@link ModelOutputItem.api} of every item {@link ScriptedModelClient} returns. */
12
+ export const scriptedModelApi = "scripted";
13
+ /** Default number of latest requests {@link ScriptedModelClient.requests} keeps. */
14
+ export const defaultMaxRecordedRequests = 100;
15
+ /**
16
+ * A Stepwise {@link ModelClient} that answers every model call from a script, for demos and tests without a
17
+ * model key. It mirrors the Python core's `ScriptedModelClient`.
18
+ *
19
+ * Use it as `AgentDefinition.model` to run a Stepwise agent with no provider account: a local demo
20
+ * mode of an application, a tutorial, or an integration test. It is a supported part of
21
+ * `@superdurable/dex-agents/stepwise` and needs no optional peer. `@superdurable/dex-agents/testing`
22
+ * exports the same class.
23
+ *
24
+ * The script is a function of the whole {@link ModelRequest}, so it can read the user text, with
25
+ * {@link ScriptedModelClient.userTexts}, and the tool results the runner replays, with
26
+ * {@link ScriptedModelClient.toolResults}, and it can call any offered tool, including built-in and tool
27
+ * source tools. Keep it deterministic: a Worker that crashes mid-call reruns it in a new process. Its output
28
+ * items use {@link scriptedModelProvider} and {@link scriptedModelApi}, so a session can switch to a real
29
+ * model later; that model sees the scripted replies as text.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const model = new ScriptedModelClient((request) =>
34
+ * ScriptedModelClient.toolResults(request).length > 0
35
+ * ? { text: "done" }
36
+ * : { toolCalls: [{ toolName: "lookup_order", arguments: { order_id: "7" } }] });
37
+ * const flow = createStepwiseAgentSessionFlow(
38
+ * { name: "demo", instructions: "Help.", model, tools: [lookupOrder] }, "DemoAgent");
39
+ * ```
40
+ */
41
+ export class ScriptedModelClient {
42
+ respond;
43
+ receivedRequests = [];
44
+ maxRecordedRequests;
45
+ /**
46
+ * Creates a client around a script.
47
+ * @param respond - Function that returns the reply for a request.
48
+ * @param options - `maxRecordedRequests`: how many of the latest requests {@link requests} keeps, so a
49
+ * long-running demo Worker does not keep every transcript. `0` records none. Defaults to
50
+ * {@link defaultMaxRecordedRequests}.
51
+ * @throws {RangeError} When `maxRecordedRequests` is not a non-negative integer.
52
+ */
53
+ constructor(respond, options = {}) {
54
+ this.respond = respond;
55
+ this.maxRecordedRequests = options.maxRecordedRequests ?? defaultMaxRecordedRequests;
56
+ if (!Number.isSafeInteger(this.maxRecordedRequests) || this.maxRecordedRequests < 0) {
57
+ throw new RangeError("maxRecordedRequests must be a non-negative integer");
58
+ }
59
+ }
60
+ /** The latest requests this client received in this process, up to `maxRecordedRequests`, oldest first. */
61
+ get requests() {
62
+ return [...this.receivedRequests];
63
+ }
64
+ /**
65
+ * Runs the script for one request and streams its reply.
66
+ * @param request - The request.
67
+ * @param output - Writer for text and reasoning deltas.
68
+ * @returns One reasoning item, one message item, and one item per tool call, for the parts the reply has.
69
+ */
70
+ async callModel(request, output) {
71
+ this.receivedRequests.push(request);
72
+ if (this.receivedRequests.length > this.maxRecordedRequests) {
73
+ this.receivedRequests.splice(0, this.receivedRequests.length - this.maxRecordedRequests);
74
+ }
75
+ const reply = await this.respond(request);
76
+ const text = reply.text ?? "";
77
+ const items = [];
78
+ if (reply.reasoning !== undefined && reply.reasoning !== null) {
79
+ output.writeReasoningDelta(reply.reasoning);
80
+ items.push(createScriptedItem({ type: "reasoning", summary: reply.reasoning }, null, []));
81
+ }
82
+ if (text !== "") {
83
+ output.writeTextDelta(text);
84
+ items.push(createScriptedItem({ type: "message", text }, text, []));
85
+ }
86
+ const toolCalls = [];
87
+ for (const [index, scripted] of (reply.toolCalls ?? []).entries()) {
88
+ const toolCall = {
89
+ toolCallId: scripted.toolCallId ?? `${request.metadata.stepExecutionId}-${index}`,
90
+ toolName: scripted.toolName,
91
+ arguments: typeof scripted.arguments === "string"
92
+ ? scripted.arguments
93
+ : serializeJsonWithSpacedSeparators(scripted.arguments ?? {}),
94
+ };
95
+ toolCalls.push(toolCall);
96
+ items.push(createScriptedItem({ type: "function_call", call_id: toolCall.toolCallId, name: toolCall.toolName, arguments: toolCall.arguments }, null, [toolCall]));
97
+ }
98
+ return {
99
+ outputItems: items,
100
+ text,
101
+ toolCalls,
102
+ usage: reply.usage ?? { modelCalls: 1, inputTokens: 10, outputTokens: 5, cachedInputTokens: 0, reasoningTokens: 0 },
103
+ responseModel: "scripted",
104
+ finishReason: toolCalls.length > 0 ? "tool_calls" : "stop",
105
+ };
106
+ }
107
+ /**
108
+ * Estimates four characters per token over the request text.
109
+ * @param request - The request.
110
+ * @returns The estimate.
111
+ */
112
+ estimateInputTokens(request) {
113
+ let characters = request.instructions.length;
114
+ for (const item of request.inputItems) {
115
+ characters += (item.type === "model_output" ? item.item : item.type === "user_text" ? item.text : item.output)
116
+ .length;
117
+ }
118
+ return Math.floor(characters / 4);
119
+ }
120
+ /**
121
+ * Returns the text of every user item in a request, oldest first.
122
+ * @param request - The request.
123
+ * @returns User texts, including Dex notes stored as user text.
124
+ */
125
+ static userTexts(request) {
126
+ return request.inputItems.flatMap((item) => (item.type === "user_text" ? [item.text] : []));
127
+ }
128
+ /**
129
+ * Returns the tool results after the last user item of a request.
130
+ * @param request - The request.
131
+ * @returns The current turn's tool results, oldest first.
132
+ */
133
+ static toolResults(request) {
134
+ let results = [];
135
+ for (const item of request.inputItems) {
136
+ if (item.type === "user_text") {
137
+ results = [];
138
+ }
139
+ else if (item.type === "tool_result") {
140
+ results.push(item);
141
+ }
142
+ }
143
+ return results;
144
+ }
145
+ }
146
+ function createScriptedItem(item, text, toolCalls) {
147
+ return {
148
+ type: "model_output",
149
+ provider: scriptedModelProvider,
150
+ api: scriptedModelApi,
151
+ item: JSON.stringify(item),
152
+ text,
153
+ toolCalls,
154
+ };
155
+ }
156
+ //# sourceMappingURL=scripted-model-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scripted-model-client.js","sourceRoot":"","sources":["../../../src/stepwise/scripted-model-client.ts"],"names":[],"mappings":"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"}