@superdurable/dex-agents 0.0.0-stage → 0.1.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 (57) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +475 -2
  3. package/dist/src/agent-event-writer.d.ts +26 -0
  4. package/dist/src/agent-event-writer.js +110 -0
  5. package/dist/src/agent-event-writer.js.map +1 -0
  6. package/dist/src/agent-framework-runner.d.ts +368 -0
  7. package/dist/src/agent-framework-runner.js +81 -0
  8. package/dist/src/agent-framework-runner.js.map +1 -0
  9. package/dist/src/agent-session-codecs.d.ts +44 -0
  10. package/dist/src/agent-session-codecs.js +355 -0
  11. package/dist/src/agent-session-codecs.js.map +1 -0
  12. package/dist/src/agent-session-flow.d.ts +148 -0
  13. package/dist/src/agent-session-flow.js +276 -0
  14. package/dist/src/agent-session-flow.js.map +1 -0
  15. package/dist/src/agent-session-persistence.d.ts +56 -0
  16. package/dist/src/agent-session-persistence.js +43 -0
  17. package/dist/src/agent-session-persistence.js.map +1 -0
  18. package/dist/src/agent-session-steps.d.ts +86 -0
  19. package/dist/src/agent-session-steps.js +533 -0
  20. package/dist/src/agent-session-steps.js.map +1 -0
  21. package/dist/src/agent-session-transitions.d.ts +61 -0
  22. package/dist/src/agent-session-transitions.js +202 -0
  23. package/dist/src/agent-session-transitions.js.map +1 -0
  24. package/dist/src/agent-session-values.d.ts +337 -0
  25. package/dist/src/agent-session-values.js +127 -0
  26. package/dist/src/agent-session-values.js.map +1 -0
  27. package/dist/src/index.d.ts +4 -0
  28. package/dist/src/index.js +12 -0
  29. package/dist/src/index.js.map +1 -0
  30. package/dist/src/testing/agent-session-test-client.d.ts +148 -0
  31. package/dist/src/testing/agent-session-test-client.js +217 -0
  32. package/dist/src/testing/agent-session-test-client.js.map +1 -0
  33. package/dist/src/testing/agent-test-environment.d.ts +52 -0
  34. package/dist/src/testing/agent-test-environment.js +86 -0
  35. package/dist/src/testing/agent-test-environment.js.map +1 -0
  36. package/dist/src/testing/agent-worker-process.d.ts +91 -0
  37. package/dist/src/testing/agent-worker-process.js +150 -0
  38. package/dist/src/testing/agent-worker-process.js.map +1 -0
  39. package/dist/src/testing/child-process-group.d.ts +33 -0
  40. package/dist/src/testing/child-process-group.js +164 -0
  41. package/dist/src/testing/child-process-group.js.map +1 -0
  42. package/dist/src/testing/coordination.d.ts +99 -0
  43. package/dist/src/testing/coordination.js +155 -0
  44. package/dist/src/testing/coordination.js.map +1 -0
  45. package/dist/src/testing/index.d.ts +7 -0
  46. package/dist/src/testing/index.js +15 -0
  47. package/dist/src/testing/index.js.map +1 -0
  48. package/dist/src/testing/polling.d.ts +31 -0
  49. package/dist/src/testing/polling.js +51 -0
  50. package/dist/src/testing/polling.js.map +1 -0
  51. package/dist/src/testing/private-dex-engine.d.ts +92 -0
  52. package/dist/src/testing/private-dex-engine.js +215 -0
  53. package/dist/src/testing/private-dex-engine.js.map +1 -0
  54. package/dist/src/testing/step-history.d.ts +40 -0
  55. package/dist/src/testing/step-history.js +59 -0
  56. package/dist/src/testing/step-history.js.map +1 -0
  57. package/package.json +50 -4
@@ -0,0 +1,127 @@
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
+ * Returns usage with every counter at zero.
10
+ *
11
+ * @returns A new {@link AgentUsage} whose counters are all `0`.
12
+ */
13
+ export function emptyAgentUsage() {
14
+ return {
15
+ modelCalls: 0,
16
+ inputTokens: 0,
17
+ outputTokens: 0,
18
+ cachedInputTokens: 0,
19
+ reasoningTokens: 0,
20
+ };
21
+ }
22
+ /**
23
+ * Adds two usage values counter by counter.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * let usage = emptyAgentUsage();
28
+ * usage = addAgentUsage(usage, { ...emptyAgentUsage(), modelCalls: 1, inputTokens: 120, outputTokens: 30 });
29
+ * ```
30
+ * @param left - First usage value.
31
+ * @param right - Second usage value.
32
+ * @returns A new {@link AgentUsage} holding the sums; neither input is changed.
33
+ */
34
+ export function addAgentUsage(left, right) {
35
+ return {
36
+ modelCalls: left.modelCalls + right.modelCalls,
37
+ inputTokens: left.inputTokens + right.inputTokens,
38
+ outputTokens: left.outputTokens + right.outputTokens,
39
+ cachedInputTokens: left.cachedInputTokens + right.cachedInputTokens,
40
+ reasoningTokens: left.reasoningTokens + right.reasoningTokens,
41
+ };
42
+ }
43
+ /**
44
+ * Reports whether a tool call status is final.
45
+ *
46
+ * @param status - Status to classify.
47
+ * @returns `true` for `rejected`, `succeeded`, `failed`, and `outcome_unknown`; `false` for
48
+ * `awaiting_approval` and `approved`.
49
+ */
50
+ export function isFinalToolCallStatus(status) {
51
+ return status !== "awaiting_approval" && status !== "approved";
52
+ }
53
+ /** Tool result text the model sees for an `outcome_unknown` call; the same text as the Python core. */
54
+ export const outcomeUnknownToolResult = "The tool call's outcome is unknown: it stopped without returning a result, so it may " +
55
+ "or may not have taken effect. It will not be retried automatically.";
56
+ /** First line of the note `RecordTurnFailure` stores after a failed turn ran tools. */
57
+ export const turnFailureNoteHeader = "[Dex] The previous turn failed after these tool calls ran:";
58
+ /** Last line of that note. */
59
+ export const turnFailureNoteFooter = "Do not repeat these tool calls unless the user asks again.";
60
+ /** Tool result text the model sees for a rejection without a message; the same text as the Python core. */
61
+ export const defaultRejectionToolResult = "The user rejected this tool call.";
62
+ /** Rejection message recorded when an approval deadline passes. */
63
+ export const approvalDeadlinePassed = "approval deadline passed";
64
+ /**
65
+ * Returns the note text that tells the model what a failed turn already did.
66
+ *
67
+ * `RecordTurnFailure` stores this note through {@link AgentFrameworkRunner.buildUserMessage} when a
68
+ * failed turn has final tool call records, as the failed turn's last message, so the next turn's model
69
+ * does not repeat a write. The text matches the Python core's `build_turn_failure_note`:
70
+ *
71
+ * ```text
72
+ * [Dex] The previous turn failed after these tool calls ran:
73
+ * - charge {"amount": 5} -> succeeded: charged 5
74
+ * Do not repeat these tool calls unless the user asks again.
75
+ * ```
76
+ *
77
+ * @param toolCalls - Final records of the failed turn; they are listed in `deferralOrder`.
78
+ * @returns {@link turnFailureNoteHeader}, one `- <toolName> <arguments> -> <status>: <outcome>` line
79
+ * per record, with the outcome from {@link describeToolCallOutcome}, and {@link turnFailureNoteFooter},
80
+ * joined with newlines.
81
+ * @throws {TypeError} When a record is not final.
82
+ */
83
+ export function buildTurnFailureNote(toolCalls) {
84
+ const lines = [turnFailureNoteHeader];
85
+ for (const toolCall of [...toolCalls].sort((left, right) => left.deferralOrder - right.deferralOrder)) {
86
+ const outcome = describeToolCallOutcome(toolCall);
87
+ lines.push(`- ${toolCall.toolName} ${toolCall.arguments} -> ${toolCall.status}: ${outcome}`);
88
+ }
89
+ lines.push(turnFailureNoteFooter);
90
+ return lines.join("\n");
91
+ }
92
+ /**
93
+ * Returns the tool result text a runner shows the model for a final tool call record.
94
+ *
95
+ * Use it when resuming a framework whose tool result must be text. A runner whose framework has a
96
+ * native rejection, such as a rejection message argument, may pass `rejectionMessage` there instead.
97
+ * The texts match the Python core's `describe_tool_call_outcome`.
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * const record = turn.recordedToolCall(pendingCallId);
102
+ * if (record !== undefined && isFinalToolCallStatus(record.status)) {
103
+ * frameworkToolResult = describeToolCallOutcome(record);
104
+ * }
105
+ * ```
106
+ * @param toolCall - Record whose status is final.
107
+ * @returns The output for `succeeded`; `The tool call failed: <error>` for `failed`; the rejection
108
+ * message, or {@link defaultRejectionToolResult}, for `rejected`; {@link outcomeUnknownToolResult}
109
+ * for `outcome_unknown`.
110
+ * @throws {TypeError} When the record status is `awaiting_approval` or `approved`.
111
+ */
112
+ export function describeToolCallOutcome(toolCall) {
113
+ switch (toolCall.status) {
114
+ case "succeeded":
115
+ return toolCall.output ?? "";
116
+ case "failed":
117
+ return `The tool call failed: ${toolCall.error ?? "unknown error"}`;
118
+ case "rejected":
119
+ return toolCall.rejectionMessage ?? defaultRejectionToolResult;
120
+ case "outcome_unknown":
121
+ return outcomeUnknownToolResult;
122
+ case "awaiting_approval":
123
+ case "approved":
124
+ throw new TypeError(`tool call ${toolCall.toolCallId} has no final outcome yet`);
125
+ }
126
+ }
127
+ //# sourceMappingURL=agent-session-values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-session-values.js","sourceRoot":"","sources":["../../src/agent-session-values.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,kDAAkD;AAClD,mEAAmE;AACnE,+CAA+C;AAC/C,EAAE;AACF,0DAA0D;AA0S1D;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,UAAU,EAAE,CAAC;QACb,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,CAAC;QACf,iBAAiB,EAAE,CAAC;QACpB,eAAe,EAAE,CAAC;KACnB,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,IAAgB,EAAE,KAAiB;IAC/D,OAAO;QACL,UAAU,EAAE,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU;QAC9C,WAAW,EAAE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW;QACjD,YAAY,EAAE,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY;QACpD,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC,iBAAiB;QACnE,eAAe,EAAE,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe;KAC9D,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAA2B;IAC/D,OAAO,MAAM,KAAK,mBAAmB,IAAI,MAAM,KAAK,UAAU,CAAC;AACjE,CAAC;AAED,uGAAuG;AACvG,MAAM,CAAC,MAAM,wBAAwB,GACnC,uFAAuF;IACvF,qEAAqE,CAAC;AAExE,uFAAuF;AACvF,MAAM,CAAC,MAAM,qBAAqB,GAAG,4DAA4D,CAAC;AAElG,8BAA8B;AAC9B,MAAM,CAAC,MAAM,qBAAqB,GAAG,4DAA4D,CAAC;AAElG,2GAA2G;AAC3G,MAAM,CAAC,MAAM,0BAA0B,GAAG,mCAAmC,CAAC;AAE9E,mEAAmE;AACnE,MAAM,CAAC,MAAM,sBAAsB,GAAG,0BAA0B,CAAC;AAEjE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAmC;IACtE,MAAM,KAAK,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACtC,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;QACtG,MAAM,OAAO,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,SAAS,OAAO,QAAQ,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC,CAAC;IAC/F,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAClC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAAuB;IAC7D,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxB,KAAK,WAAW;YACd,OAAO,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC;QAC/B,KAAK,QAAQ;YACX,OAAO,yBAAyB,QAAQ,CAAC,KAAK,IAAI,eAAe,EAAE,CAAC;QACtE,KAAK,UAAU;YACb,OAAO,QAAQ,CAAC,gBAAgB,IAAI,0BAA0B,CAAC;QACjE,KAAK,iBAAiB;YACpB,OAAO,wBAAwB,CAAC;QAClC,KAAK,mBAAmB,CAAC;QACzB,KAAK,UAAU;YACb,MAAM,IAAI,SAAS,CAAC,aAAa,QAAQ,CAAC,UAAU,2BAA2B,CAAC,CAAC;IACrF,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { ToolExecutionError, resolveToolPolicy, toolEffectFromMcpToolAnnotations, type AgentEventWriter, type AgentFrameworkRunner, type AgentTurnContext, type AgentTurnOutcome, type DeferredToolCall, type DeferredToolExecution, type McpToolAnnotations, type ResolvedToolPolicy, type ToolExecutionResult, type ToolPolicy, type TurnCompleted, type ToolCallsRequested, } from "./agent-framework-runner.js";
2
+ export { createAgentSessionFlow, type AgentSessionFlow, type AgentSessionOptions, type ResolvedAgentSessionOptions, } from "./agent-session-flow.js";
3
+ export { defaultAgentEventsCapacityBytes, messageSequenceKey, type AgentSessionPersistence, } from "./agent-session-persistence.js";
4
+ export { addAgentUsage, approvalDeadlinePassed, buildTurnFailureNote, defaultRejectionToolResult, describeToolCallOutcome, emptyAgentUsage, isFinalToolCallStatus, outcomeUnknownToolResult, turnFailureNoteFooter, turnFailureNoteHeader, type AgentEvent, type AgentEventType, type AgentInterrupt, type AgentInterruptResolution, type AgentMessage, type AgentMessageRole, type AgentMessagesPage, type AgentSessionStartInput, type AgentSessionStatus, type AgentSnapshot, type AgentState, type AgentToolCall, type AgentToolCallStatus, type AgentUsage, type AgentUserMessage, type FrameworkMessage, type ListAgentMessagesInput, type ResolveInterruptInput, type ToolCallCompleted, type ToolEffect, } from "./agent-session-values.js";
@@ -0,0 +1,12 @@
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 { ToolExecutionError, resolveToolPolicy, toolEffectFromMcpToolAnnotations, } from "./agent-framework-runner.js";
9
+ export { createAgentSessionFlow, } from "./agent-session-flow.js";
10
+ export { defaultAgentEventsCapacityBytes, messageSequenceKey, } from "./agent-session-persistence.js";
11
+ export { addAgentUsage, approvalDeadlinePassed, buildTurnFailureNote, defaultRejectionToolResult, describeToolCallOutcome, emptyAgentUsage, isFinalToolCallStatus, outcomeUnknownToolResult, turnFailureNoteFooter, turnFailureNoteHeader, } from "./agent-session-values.js";
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,kDAAkD;AAClD,mEAAmE;AACnE,+CAA+C;AAC/C,EAAE;AACF,0DAA0D;AAE1D,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,gCAAgC,GAajC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,sBAAsB,GAIvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,+BAA+B,EAC/B,kBAAkB,GAEnB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,oBAAoB,EACpB,0BAA0B,EAC1B,uBAAuB,EACvB,eAAe,EACf,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,GAqBtB,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,148 @@
1
+ import { type Client, type StartFlowOptions } from "@superdurable/dex";
2
+ import type { AgentSessionFlow } from "../agent-session-flow.js";
3
+ import type { AgentEvent, AgentInterrupt, AgentMessagesPage, AgentSnapshot, AgentState, AgentToolCall } from "../agent-session-values.js";
4
+ /** Options of the `waitFor*` methods of {@link AgentSessionTestClient}. */
5
+ export interface AgentSessionWaitOptions {
6
+ /** Total milliseconds to wait. Defaults to 60,000. */
7
+ readonly timeoutMs?: number;
8
+ }
9
+ /**
10
+ * Typed Client calls for one agent session Flow, with waits suited to integration tests.
11
+ *
12
+ * RPC methods need a running Worker. The `read*` and `waitFor*` methods use `Client.getAttributes`,
13
+ * which reads committed Attributes without a Worker, so they also work while a killed Worker is down.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const sessions = new AgentSessionTestClient(environment.client, flow);
18
+ * await sessions.startSession(sessionId, "send the report");
19
+ * const interrupt = await sessions.waitForPendingInterrupt(sessionId, "send_email");
20
+ * assert.equal(await sessions.resolveInterrupt(sessionId, interrupt.interruptId, true), true);
21
+ * const state = await sessions.waitForCompletedTurns(sessionId, 1);
22
+ * const snapshot = await sessions.getAgentSnapshot(sessionId);
23
+ * ```
24
+ */
25
+ export declare class AgentSessionTestClient {
26
+ /** Client used for every call. */
27
+ readonly client: Client;
28
+ /** Flow whose sessions this helper drives. */
29
+ readonly flow: AgentSessionFlow;
30
+ /**
31
+ * Creates the helper.
32
+ * @param client - Client whose Registry contains `flow`.
33
+ * @param flow - The agent session Flow, the same object registered in the Client's Registry.
34
+ */
35
+ constructor(
36
+ /** Client used for every call. */
37
+ client: Client,
38
+ /** Flow whose sessions this helper drives. */
39
+ flow: AgentSessionFlow);
40
+ /**
41
+ * Starts a session.
42
+ * @param sessionId - Flow ID of the new session.
43
+ * @param initialMessage - First user message, or `null` to start idle. Defaults to `null`.
44
+ * @param startFlowOptions - Start options, such as a `configOverride` with `stepDurability`.
45
+ * @returns A Promise that resolves after Dex accepted the start.
46
+ */
47
+ startSession(sessionId: string, initialMessage?: string | null, startFlowOptions?: StartFlowOptions): Promise<void>;
48
+ /**
49
+ * Calls `send_user_message`.
50
+ * @param sessionId - Session Flow ID.
51
+ * @param text - Message text.
52
+ * @returns The RPC result: `false` for blank text.
53
+ */
54
+ sendUserMessage(sessionId: string, text: string): Promise<boolean>;
55
+ /**
56
+ * Calls `resolve_interrupt`, retrying an `RpcLockConflictError` for up to 30 seconds.
57
+ * @param sessionId - Session Flow ID.
58
+ * @param interruptId - Interrupt to resolve.
59
+ * @param approved - Whether the tool call may run.
60
+ * @param rejectionMessage - Text shown to the model on rejection. Defaults to `null`.
61
+ * @returns The RPC result: `false` when the interrupt was not pending.
62
+ */
63
+ resolveInterrupt(sessionId: string, interruptId: string, approved: boolean, rejectionMessage?: string | null): Promise<boolean>;
64
+ /**
65
+ * Calls `get_agent_snapshot`.
66
+ * @param sessionId - Session Flow ID.
67
+ * @returns The snapshot.
68
+ */
69
+ getAgentSnapshot(sessionId: string): Promise<AgentSnapshot>;
70
+ /**
71
+ * Calls `list_agent_messages`.
72
+ * @param sessionId - Session Flow ID.
73
+ * @param beforeSequence - Exclusive upper bound, or `null` for the newest page.
74
+ * @param limit - Page size, clamped by the session to 1..200.
75
+ * @returns The page.
76
+ */
77
+ listAgentMessages(sessionId: string, beforeSequence: number | null, limit: number): Promise<AgentMessagesPage>;
78
+ /**
79
+ * Reads the committed `AgentState` without a Worker.
80
+ * @param sessionId - Session Flow ID.
81
+ * @returns The state, or `undefined` before `StartAgentSession` committed.
82
+ */
83
+ readAgentState(sessionId: string): Promise<AgentState | undefined>;
84
+ /**
85
+ * Reads one committed tool call record without a Worker.
86
+ * @param sessionId - Session Flow ID.
87
+ * @param toolCallId - Tool call ID.
88
+ * @returns The record, or `undefined` when it does not exist or its turn completed.
89
+ */
90
+ readToolCall(sessionId: string, toolCallId: string): Promise<AgentToolCall | undefined>;
91
+ /**
92
+ * Reads the committed `PendingInterrupts` without a Worker.
93
+ * @param sessionId - Session Flow ID.
94
+ * @returns The pending interrupts, or an empty array.
95
+ */
96
+ readPendingInterrupts(sessionId: string): Promise<readonly AgentInterrupt[]>;
97
+ /**
98
+ * Polls `get_agent_snapshot` until a predicate holds; RPC failures while no Worker runs count as not ready.
99
+ * @param sessionId - Session Flow ID.
100
+ * @param predicate - Returns `true` for the awaited snapshot.
101
+ * @param description - What is awaited, for the timeout error.
102
+ * @param options - Timeout.
103
+ * @returns The first matching snapshot.
104
+ * @throws {Error} When the timeout passes.
105
+ */
106
+ waitForAgentSnapshot(sessionId: string, predicate: (snapshot: AgentSnapshot) => boolean, description: string, options?: AgentSessionWaitOptions): Promise<AgentSnapshot>;
107
+ /**
108
+ * Polls the committed `AgentState` until a predicate holds.
109
+ * @param sessionId - Session Flow ID.
110
+ * @param predicate - Returns `true` for the awaited state.
111
+ * @param description - What is awaited, for the timeout error.
112
+ * @param options - Timeout.
113
+ * @returns The first matching state.
114
+ * @throws {Error} When the timeout passes.
115
+ */
116
+ waitForAgentState(sessionId: string, predicate: (state: AgentState) => boolean, description: string, options?: AgentSessionWaitOptions): Promise<AgentState>;
117
+ /**
118
+ * Waits until the session is idle after at least `turnCount` completed or failed turns.
119
+ * @param sessionId - Session Flow ID.
120
+ * @param turnCount - Minimum `turnCount`.
121
+ * @param options - Timeout.
122
+ * @returns The idle state.
123
+ */
124
+ waitForCompletedTurns(sessionId: string, turnCount: number, options?: AgentSessionWaitOptions): Promise<AgentState>;
125
+ /**
126
+ * Polls `PendingInterrupts` until an interrupt appears.
127
+ * @param sessionId - Session Flow ID.
128
+ * @param toolName - Tool whose interrupt is awaited, or `undefined` for any tool.
129
+ * @param options - Timeout.
130
+ * @returns The first matching pending interrupt.
131
+ */
132
+ waitForPendingInterrupt(sessionId: string, toolName?: string, options?: AgentSessionWaitOptions): Promise<AgentInterrupt>;
133
+ /**
134
+ * Polls one tool call record until a predicate holds.
135
+ * @param sessionId - Session Flow ID.
136
+ * @param toolCallId - Tool call ID.
137
+ * @param predicate - Returns `true` for the awaited record.
138
+ * @param options - Timeout.
139
+ * @returns The first matching record.
140
+ */
141
+ waitForToolCall(sessionId: string, toolCallId: string, predicate: (toolCall: AgentToolCall) => boolean, options?: AgentSessionWaitOptions): Promise<AgentToolCall>;
142
+ /**
143
+ * Reads every retained `AgentEvents` message, oldest first.
144
+ * @param sessionId - Session Flow ID.
145
+ * @returns The retained events; trimming may have removed the oldest.
146
+ */
147
+ listAgentEvents(sessionId: string): Promise<AgentEvent[]>;
148
+ }
@@ -0,0 +1,217 @@
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 { setTimeout as delay } from "node:timers/promises";
9
+ import { RpcLockConflictError } from "@superdurable/dex";
10
+ import { pollUntil } from "./polling.js";
11
+ const lockConflictRetryTimeoutMs = 30_000;
12
+ const lockConflictRetryIntervalMs = 50;
13
+ const streamPageSize = 500;
14
+ /**
15
+ * Typed Client calls for one agent session Flow, with waits suited to integration tests.
16
+ *
17
+ * RPC methods need a running Worker. The `read*` and `waitFor*` methods use `Client.getAttributes`,
18
+ * which reads committed Attributes without a Worker, so they also work while a killed Worker is down.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const sessions = new AgentSessionTestClient(environment.client, flow);
23
+ * await sessions.startSession(sessionId, "send the report");
24
+ * const interrupt = await sessions.waitForPendingInterrupt(sessionId, "send_email");
25
+ * assert.equal(await sessions.resolveInterrupt(sessionId, interrupt.interruptId, true), true);
26
+ * const state = await sessions.waitForCompletedTurns(sessionId, 1);
27
+ * const snapshot = await sessions.getAgentSnapshot(sessionId);
28
+ * ```
29
+ */
30
+ export class AgentSessionTestClient {
31
+ client;
32
+ flow;
33
+ /**
34
+ * Creates the helper.
35
+ * @param client - Client whose Registry contains `flow`.
36
+ * @param flow - The agent session Flow, the same object registered in the Client's Registry.
37
+ */
38
+ constructor(
39
+ /** Client used for every call. */
40
+ client,
41
+ /** Flow whose sessions this helper drives. */
42
+ flow) {
43
+ this.client = client;
44
+ this.flow = flow;
45
+ }
46
+ /**
47
+ * Starts a session.
48
+ * @param sessionId - Flow ID of the new session.
49
+ * @param initialMessage - First user message, or `null` to start idle. Defaults to `null`.
50
+ * @param startFlowOptions - Start options, such as a `configOverride` with `stepDurability`.
51
+ * @returns A Promise that resolves after Dex accepted the start.
52
+ */
53
+ async startSession(sessionId, initialMessage = null, startFlowOptions = {}) {
54
+ await this.client.startFlow(this.flow, sessionId, { initialMessage }, startFlowOptions);
55
+ }
56
+ /**
57
+ * Calls `send_user_message`.
58
+ * @param sessionId - Session Flow ID.
59
+ * @param text - Message text.
60
+ * @returns The RPC result: `false` for blank text.
61
+ */
62
+ sendUserMessage(sessionId, text) {
63
+ return this.client.invokeRPC(this.flow.sendUserMessage, sessionId, { text });
64
+ }
65
+ /**
66
+ * Calls `resolve_interrupt`, retrying an `RpcLockConflictError` for up to 30 seconds.
67
+ * @param sessionId - Session Flow ID.
68
+ * @param interruptId - Interrupt to resolve.
69
+ * @param approved - Whether the tool call may run.
70
+ * @param rejectionMessage - Text shown to the model on rejection. Defaults to `null`.
71
+ * @returns The RPC result: `false` when the interrupt was not pending.
72
+ */
73
+ async resolveInterrupt(sessionId, interruptId, approved, rejectionMessage = null) {
74
+ const deadline = Date.now() + lockConflictRetryTimeoutMs;
75
+ for (;;) {
76
+ try {
77
+ return await this.client.invokeRPC(this.flow.resolveInterrupt, sessionId, {
78
+ interruptId,
79
+ approved,
80
+ rejectionMessage,
81
+ });
82
+ }
83
+ catch (error) {
84
+ if (!(error instanceof RpcLockConflictError) || Date.now() >= deadline) {
85
+ throw error;
86
+ }
87
+ }
88
+ await delay(lockConflictRetryIntervalMs);
89
+ }
90
+ }
91
+ /**
92
+ * Calls `get_agent_snapshot`.
93
+ * @param sessionId - Session Flow ID.
94
+ * @returns The snapshot.
95
+ */
96
+ getAgentSnapshot(sessionId) {
97
+ return this.client.invokeRPC(this.flow.getAgentSnapshot, sessionId);
98
+ }
99
+ /**
100
+ * Calls `list_agent_messages`.
101
+ * @param sessionId - Session Flow ID.
102
+ * @param beforeSequence - Exclusive upper bound, or `null` for the newest page.
103
+ * @param limit - Page size, clamped by the session to 1..200.
104
+ * @returns The page.
105
+ */
106
+ listAgentMessages(sessionId, beforeSequence, limit) {
107
+ return this.client.invokeRPC(this.flow.listAgentMessages, sessionId, { beforeSequence, limit });
108
+ }
109
+ /**
110
+ * Reads the committed `AgentState` without a Worker.
111
+ * @param sessionId - Session Flow ID.
112
+ * @returns The state, or `undefined` before `StartAgentSession` committed.
113
+ */
114
+ async readAgentState(sessionId) {
115
+ const [state] = await this.client.getAttributes(sessionId, this.flow.agentState);
116
+ return state;
117
+ }
118
+ /**
119
+ * Reads one committed tool call record without a Worker.
120
+ * @param sessionId - Session Flow ID.
121
+ * @param toolCallId - Tool call ID.
122
+ * @returns The record, or `undefined` when it does not exist or its turn completed.
123
+ */
124
+ async readToolCall(sessionId, toolCallId) {
125
+ const [toolCall] = await this.client.getAttributes(sessionId, this.flow.agentToolCalls.instance(toolCallId));
126
+ return toolCall;
127
+ }
128
+ /**
129
+ * Reads the committed `PendingInterrupts` without a Worker.
130
+ * @param sessionId - Session Flow ID.
131
+ * @returns The pending interrupts, or an empty array.
132
+ */
133
+ async readPendingInterrupts(sessionId) {
134
+ const [interrupts] = await this.client.getAttributes(sessionId, this.flow.pendingInterrupts);
135
+ return interrupts ?? [];
136
+ }
137
+ /**
138
+ * Polls `get_agent_snapshot` until a predicate holds; RPC failures while no Worker runs count as not ready.
139
+ * @param sessionId - Session Flow ID.
140
+ * @param predicate - Returns `true` for the awaited snapshot.
141
+ * @param description - What is awaited, for the timeout error.
142
+ * @param options - Timeout.
143
+ * @returns The first matching snapshot.
144
+ * @throws {Error} When the timeout passes.
145
+ */
146
+ waitForAgentSnapshot(sessionId, predicate, description, options = {}) {
147
+ return pollUntil(async () => {
148
+ const snapshot = await this.getAgentSnapshot(sessionId);
149
+ return predicate(snapshot) ? snapshot : undefined;
150
+ }, { description: `${description} in session ${sessionId}`, ...options });
151
+ }
152
+ /**
153
+ * Polls the committed `AgentState` until a predicate holds.
154
+ * @param sessionId - Session Flow ID.
155
+ * @param predicate - Returns `true` for the awaited state.
156
+ * @param description - What is awaited, for the timeout error.
157
+ * @param options - Timeout.
158
+ * @returns The first matching state.
159
+ * @throws {Error} When the timeout passes.
160
+ */
161
+ waitForAgentState(sessionId, predicate, description, options = {}) {
162
+ return pollUntil(async () => {
163
+ const state = await this.readAgentState(sessionId);
164
+ return state !== undefined && predicate(state) ? state : undefined;
165
+ }, { description: `${description} in session ${sessionId}`, ...options });
166
+ }
167
+ /**
168
+ * Waits until the session is idle after at least `turnCount` completed or failed turns.
169
+ * @param sessionId - Session Flow ID.
170
+ * @param turnCount - Minimum `turnCount`.
171
+ * @param options - Timeout.
172
+ * @returns The idle state.
173
+ */
174
+ waitForCompletedTurns(sessionId, turnCount, options = {}) {
175
+ return this.waitForAgentState(sessionId, (state) => state.status === "waiting_for_user_message" && state.turnCount >= turnCount, `${turnCount} finished turns`, options);
176
+ }
177
+ /**
178
+ * Polls `PendingInterrupts` until an interrupt appears.
179
+ * @param sessionId - Session Flow ID.
180
+ * @param toolName - Tool whose interrupt is awaited, or `undefined` for any tool.
181
+ * @param options - Timeout.
182
+ * @returns The first matching pending interrupt.
183
+ */
184
+ waitForPendingInterrupt(sessionId, toolName, options = {}) {
185
+ return pollUntil(async () => (await this.readPendingInterrupts(sessionId)).find((interrupt) => toolName === undefined || interrupt.toolName === toolName), { description: `pending interrupt for ${toolName ?? "any tool"} in session ${sessionId}`, ...options });
186
+ }
187
+ /**
188
+ * Polls one tool call record until a predicate holds.
189
+ * @param sessionId - Session Flow ID.
190
+ * @param toolCallId - Tool call ID.
191
+ * @param predicate - Returns `true` for the awaited record.
192
+ * @param options - Timeout.
193
+ * @returns The first matching record.
194
+ */
195
+ waitForToolCall(sessionId, toolCallId, predicate, options = {}) {
196
+ return pollUntil(async () => {
197
+ const toolCall = await this.readToolCall(sessionId, toolCallId);
198
+ return toolCall !== undefined && predicate(toolCall) ? toolCall : undefined;
199
+ }, { description: `tool call ${toolCallId} in session ${sessionId}`, ...options });
200
+ }
201
+ /**
202
+ * Reads every retained `AgentEvents` message, oldest first.
203
+ * @param sessionId - Session Flow ID.
204
+ * @returns The retained events; trimming may have removed the oldest.
205
+ */
206
+ async listAgentEvents(sessionId) {
207
+ const newestFirst = [];
208
+ let pageToken = "";
209
+ do {
210
+ const page = await this.client.listStreamMessages(sessionId, this.flow.agentEvents, streamPageSize, pageToken);
211
+ newestFirst.push(...page.messages.map((message) => message.value));
212
+ pageToken = page.nextPageToken;
213
+ } while (pageToken !== "");
214
+ return newestFirst.reverse();
215
+ }
216
+ }
217
+ //# sourceMappingURL=agent-session-test-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-session-test-client.js","sourceRoot":"","sources":["../../../src/testing/agent-session-test-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { Client, Registry, Worker, type Flow } from "@superdurable/dex";
2
+ /** Options of {@link AgentTestEnvironment.start}. */
3
+ export interface AgentTestEnvironmentOptions {
4
+ /** Dex Server address, usually {@link PrivateDexEngine.serverAddress}. */
5
+ readonly serverAddress: string;
6
+ /** Flows registered in the environment's Registry. */
7
+ readonly flows: readonly Flow<any>[];
8
+ /**
9
+ * Whether to run a pull Worker in this process. Pass `false` when the Worker runs in a
10
+ * {@link KillableWorkerProcess}; the Client still needs the same Flows in its Registry.
11
+ */
12
+ readonly isWorkerInProcess: boolean;
13
+ }
14
+ /**
15
+ * A Registry, BlobCache, Client, and optional in-process Worker for one test file.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const environment = await AgentTestEnvironment.start({
20
+ * serverAddress: engine.serverAddress, flows: [flow], isWorkerInProcess: true });
21
+ * try {
22
+ * const sessions = new AgentSessionTestClient(environment.client, flow);
23
+ * // ...
24
+ * } finally {
25
+ * await environment.close();
26
+ * }
27
+ * ```
28
+ */
29
+ export declare class AgentTestEnvironment {
30
+ /** Registry shared by the Client and the in-process Worker. */
31
+ readonly registry: Registry;
32
+ /** Client connected to the server. */
33
+ readonly client: Client;
34
+ /** In-process Worker, or `undefined` when the Worker runs elsewhere. */
35
+ readonly worker: Worker | undefined;
36
+ private readonly blobCache;
37
+ private readonly cacheDirectory;
38
+ private constructor();
39
+ /**
40
+ * Creates the environment and, when requested, starts the Worker and waits for its registration.
41
+ * @param options - Server address, Flows, and Worker placement.
42
+ * @returns The ready environment.
43
+ * @throws {FlowDefinitionError} When the Flows are invalid.
44
+ * @throws {Error} When the Worker cannot register within 30 seconds.
45
+ */
46
+ static start(options: AgentTestEnvironmentOptions): Promise<AgentTestEnvironment>;
47
+ /**
48
+ * Closes the Client, the in-process Worker, and the BlobCache, then deletes the cache directory.
49
+ * @returns A Promise that resolves after everything closed.
50
+ */
51
+ close(): Promise<void>;
52
+ }