zeitlich 0.2.37 → 0.2.39

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 (172) hide show
  1. package/README.md +18 -0
  2. package/dist/{activities-Bb-nAjwQ.d.ts → activities-Bmu7XnaG.d.ts} +4 -4
  3. package/dist/{activities-vkI4_3CC.d.cts → activities-ByBFLvm2.d.cts} +4 -4
  4. package/dist/adapter-id-BB-mmrts.d.cts +17 -0
  5. package/dist/adapter-id-BB-mmrts.d.ts +17 -0
  6. package/dist/adapter-id-CMwVrVqv.d.cts +17 -0
  7. package/dist/adapter-id-CMwVrVqv.d.ts +17 -0
  8. package/dist/adapter-id-CbY2zeSt.d.cts +17 -0
  9. package/dist/adapter-id-CbY2zeSt.d.ts +17 -0
  10. package/dist/adapters/sandbox/bedrock/index.cjs +3 -3
  11. package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
  12. package/dist/adapters/sandbox/bedrock/index.d.cts +6 -6
  13. package/dist/adapters/sandbox/bedrock/index.d.ts +6 -6
  14. package/dist/adapters/sandbox/bedrock/index.js +3 -3
  15. package/dist/adapters/sandbox/bedrock/index.js.map +1 -1
  16. package/dist/adapters/sandbox/bedrock/workflow.d.cts +2 -2
  17. package/dist/adapters/sandbox/bedrock/workflow.d.ts +2 -2
  18. package/dist/adapters/sandbox/daytona/index.cjs +3 -3
  19. package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
  20. package/dist/adapters/sandbox/daytona/index.d.cts +4 -4
  21. package/dist/adapters/sandbox/daytona/index.d.ts +4 -4
  22. package/dist/adapters/sandbox/daytona/index.js +3 -3
  23. package/dist/adapters/sandbox/daytona/index.js.map +1 -1
  24. package/dist/adapters/sandbox/daytona/workflow.d.cts +1 -1
  25. package/dist/adapters/sandbox/daytona/workflow.d.ts +1 -1
  26. package/dist/adapters/sandbox/e2b/index.cjs +26 -14
  27. package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
  28. package/dist/adapters/sandbox/e2b/index.d.cts +24 -4
  29. package/dist/adapters/sandbox/e2b/index.d.ts +24 -4
  30. package/dist/adapters/sandbox/e2b/index.js +26 -14
  31. package/dist/adapters/sandbox/e2b/index.js.map +1 -1
  32. package/dist/adapters/sandbox/e2b/workflow.d.cts +1 -1
  33. package/dist/adapters/sandbox/e2b/workflow.d.ts +1 -1
  34. package/dist/adapters/sandbox/inmemory/index.cjs +3 -3
  35. package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
  36. package/dist/adapters/sandbox/inmemory/index.d.cts +4 -4
  37. package/dist/adapters/sandbox/inmemory/index.d.ts +4 -4
  38. package/dist/adapters/sandbox/inmemory/index.js +3 -3
  39. package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
  40. package/dist/adapters/sandbox/inmemory/workflow.d.cts +1 -1
  41. package/dist/adapters/sandbox/inmemory/workflow.d.ts +1 -1
  42. package/dist/adapters/thread/anthropic/index.cjs +150 -13
  43. package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
  44. package/dist/adapters/thread/anthropic/index.d.cts +9 -8
  45. package/dist/adapters/thread/anthropic/index.d.ts +9 -8
  46. package/dist/adapters/thread/anthropic/index.js +150 -14
  47. package/dist/adapters/thread/anthropic/index.js.map +1 -1
  48. package/dist/adapters/thread/anthropic/workflow.cjs +9 -3
  49. package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
  50. package/dist/adapters/thread/anthropic/workflow.d.cts +6 -5
  51. package/dist/adapters/thread/anthropic/workflow.d.ts +6 -5
  52. package/dist/adapters/thread/anthropic/workflow.js +9 -4
  53. package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
  54. package/dist/adapters/thread/google-genai/index.cjs +154 -13
  55. package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
  56. package/dist/adapters/thread/google-genai/index.d.cts +6 -5
  57. package/dist/adapters/thread/google-genai/index.d.ts +6 -5
  58. package/dist/adapters/thread/google-genai/index.js +154 -14
  59. package/dist/adapters/thread/google-genai/index.js.map +1 -1
  60. package/dist/adapters/thread/google-genai/workflow.cjs +9 -3
  61. package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
  62. package/dist/adapters/thread/google-genai/workflow.d.cts +6 -5
  63. package/dist/adapters/thread/google-genai/workflow.d.ts +6 -5
  64. package/dist/adapters/thread/google-genai/workflow.js +9 -4
  65. package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
  66. package/dist/adapters/thread/index.cjs +16 -0
  67. package/dist/adapters/thread/index.cjs.map +1 -0
  68. package/dist/adapters/thread/index.d.cts +34 -0
  69. package/dist/adapters/thread/index.d.ts +34 -0
  70. package/dist/adapters/thread/index.js +12 -0
  71. package/dist/adapters/thread/index.js.map +1 -0
  72. package/dist/adapters/thread/langchain/index.cjs +149 -14
  73. package/dist/adapters/thread/langchain/index.cjs.map +1 -1
  74. package/dist/adapters/thread/langchain/index.d.cts +9 -8
  75. package/dist/adapters/thread/langchain/index.d.ts +9 -8
  76. package/dist/adapters/thread/langchain/index.js +149 -15
  77. package/dist/adapters/thread/langchain/index.js.map +1 -1
  78. package/dist/adapters/thread/langchain/workflow.cjs +9 -3
  79. package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
  80. package/dist/adapters/thread/langchain/workflow.d.cts +6 -5
  81. package/dist/adapters/thread/langchain/workflow.d.ts +6 -5
  82. package/dist/adapters/thread/langchain/workflow.js +9 -4
  83. package/dist/adapters/thread/langchain/workflow.js.map +1 -1
  84. package/dist/index.cjs +367 -59
  85. package/dist/index.cjs.map +1 -1
  86. package/dist/index.d.cts +11 -11
  87. package/dist/index.d.ts +11 -11
  88. package/dist/index.js +365 -61
  89. package/dist/index.js.map +1 -1
  90. package/dist/{proxy-DEtowJyd.d.cts → proxy-BAKzNGRq.d.cts} +1 -1
  91. package/dist/{proxy-0smGKvx8.d.ts → proxy-DO_MXbY4.d.ts} +1 -1
  92. package/dist/{thread-manager-C-C4pI2z.d.ts → thread-manager-CcRXasqs.d.ts} +2 -2
  93. package/dist/{thread-manager-D4vgzYrh.d.cts → thread-manager-ClwSaUnj.d.cts} +2 -2
  94. package/dist/{thread-manager-3fszQih4.d.ts → thread-manager-D-7lp1JK.d.ts} +2 -2
  95. package/dist/{thread-manager-CzYln2OC.d.cts → thread-manager-Y8Ucf0Tf.d.cts} +2 -2
  96. package/dist/{types-CPKDl-y_.d.ts → types-Bcbiq8iv.d.cts} +195 -22
  97. package/dist/{types-CNuWnvy9.d.ts → types-DAsQ21Rt.d.ts} +1 -1
  98. package/dist/{types-B37hKoWA.d.ts → types-DpHTX-iO.d.ts} +58 -1
  99. package/dist/{types-BO7Yju20.d.cts → types-Dt8-HBBT.d.ts} +195 -22
  100. package/dist/{types-D08CXPh8.d.cts → types-hFFi-Zd9.d.cts} +58 -1
  101. package/dist/{types-DWEUmYAJ.d.cts → types-lm8tMNJQ.d.cts} +1 -1
  102. package/dist/{types-tQL9njTu.d.cts → types-yx0LzPGn.d.cts} +21 -7
  103. package/dist/{types-tQL9njTu.d.ts → types-yx0LzPGn.d.ts} +21 -7
  104. package/dist/{workflow-CjXHbZZc.d.ts → workflow-Bmf9EtDW.d.ts} +83 -3
  105. package/dist/{workflow-Do_lzJpT.d.cts → workflow-Bx9utBwb.d.cts} +83 -3
  106. package/dist/workflow.cjs +266 -39
  107. package/dist/workflow.cjs.map +1 -1
  108. package/dist/workflow.d.cts +3 -3
  109. package/dist/workflow.d.ts +3 -3
  110. package/dist/workflow.js +264 -41
  111. package/dist/workflow.js.map +1 -1
  112. package/package.json +12 -2
  113. package/src/adapters/sandbox/bedrock/index.ts +12 -3
  114. package/src/adapters/sandbox/daytona/index.ts +12 -3
  115. package/src/adapters/sandbox/e2b/index.ts +36 -14
  116. package/src/adapters/sandbox/e2b/types.ts +16 -0
  117. package/src/adapters/sandbox/inmemory/index.ts +12 -3
  118. package/src/adapters/thread/adapter-id.test.ts +42 -0
  119. package/src/adapters/thread/anthropic/activities.ts +40 -5
  120. package/src/adapters/thread/anthropic/adapter-id.ts +16 -0
  121. package/src/adapters/thread/anthropic/fork-transform.test.ts +291 -0
  122. package/src/adapters/thread/anthropic/index.ts +3 -0
  123. package/src/adapters/thread/anthropic/model-invoker.ts +7 -1
  124. package/src/adapters/thread/anthropic/proxy.ts +3 -2
  125. package/src/adapters/thread/anthropic/thread-manager.ts +27 -1
  126. package/src/adapters/thread/google-genai/activities.ts +44 -5
  127. package/src/adapters/thread/google-genai/adapter-id.ts +16 -0
  128. package/src/adapters/thread/google-genai/fork-transform.test.ts +149 -0
  129. package/src/adapters/thread/google-genai/index.ts +3 -0
  130. package/src/adapters/thread/google-genai/model-invoker.ts +8 -2
  131. package/src/adapters/thread/google-genai/proxy.ts +3 -2
  132. package/src/adapters/thread/google-genai/thread-manager.ts +27 -1
  133. package/src/adapters/thread/index.ts +39 -0
  134. package/src/adapters/thread/langchain/activities.ts +40 -5
  135. package/src/adapters/thread/langchain/adapter-id.ts +16 -0
  136. package/src/adapters/thread/langchain/fork-transform.test.ts +142 -0
  137. package/src/adapters/thread/langchain/index.ts +3 -0
  138. package/src/adapters/thread/langchain/model-invoker.ts +7 -1
  139. package/src/adapters/thread/langchain/proxy.ts +3 -2
  140. package/src/adapters/thread/langchain/thread-manager.ts +27 -1
  141. package/src/lib/lifecycle.ts +14 -5
  142. package/src/lib/model/types.ts +7 -0
  143. package/src/lib/sandbox/manager.ts +26 -18
  144. package/src/lib/sandbox/types.ts +27 -7
  145. package/src/lib/session/session-edge-cases.integration.test.ts +336 -4
  146. package/src/lib/session/session.integration.test.ts +192 -2
  147. package/src/lib/session/session.ts +102 -8
  148. package/src/lib/session/types.ts +66 -3
  149. package/src/lib/state/index.ts +1 -0
  150. package/src/lib/state/manager.integration.test.ts +109 -0
  151. package/src/lib/state/manager.ts +38 -8
  152. package/src/lib/state/types.ts +25 -0
  153. package/src/lib/subagent/handler.ts +124 -11
  154. package/src/lib/subagent/index.ts +5 -1
  155. package/src/lib/subagent/subagent.integration.test.ts +628 -104
  156. package/src/lib/subagent/types.ts +63 -14
  157. package/src/lib/subagent/workflow.ts +29 -2
  158. package/src/lib/thread/index.ts +5 -0
  159. package/src/lib/thread/keys.test.ts +101 -0
  160. package/src/lib/thread/keys.ts +94 -0
  161. package/src/lib/thread/manager.test.ts +139 -0
  162. package/src/lib/thread/manager.ts +105 -9
  163. package/src/lib/thread/proxy.ts +3 -0
  164. package/src/lib/thread/types.ts +64 -1
  165. package/src/lib/tool-router/index.ts +2 -0
  166. package/src/lib/tool-router/router-edge-cases.integration.test.ts +92 -0
  167. package/src/lib/tool-router/router.integration.test.ts +12 -0
  168. package/src/lib/tool-router/router.ts +89 -16
  169. package/src/lib/tool-router/types.ts +42 -1
  170. package/src/lib/types.ts +12 -0
  171. package/src/workflow.ts +14 -1
  172. package/tsup.config.ts +1 -0
@@ -0,0 +1,142 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import {
3
+ HumanMessage,
4
+ AIMessage,
5
+ type StoredMessage,
6
+ } from "@langchain/core/messages";
7
+ import { createLangChainThreadManager } from "./thread-manager";
8
+
9
+ function createStatefulRedis() {
10
+ const lists = new Map<string, string[]>();
11
+ const strings = new Map<string, string>();
12
+
13
+ return {
14
+ exists: vi.fn(async (...keys: string[]) =>
15
+ keys.reduce(
16
+ (acc, k) => acc + (lists.has(k) || strings.has(k) ? 1 : 0),
17
+ 0
18
+ )
19
+ ),
20
+ lrange: vi.fn(async (key: string, start: number, stop: number) => {
21
+ const list = lists.get(key) ?? [];
22
+ const end = stop === -1 ? list.length : stop + 1;
23
+ return list.slice(start, end);
24
+ }),
25
+ rpush: vi.fn(async (key: string, ...values: string[]) => {
26
+ const list = lists.get(key) ?? [];
27
+ list.push(...values);
28
+ lists.set(key, list);
29
+ return list.length;
30
+ }),
31
+ ltrim: vi.fn(async () => "OK"),
32
+ del: vi.fn(async (...keys: string[]) => {
33
+ let removed = 0;
34
+ for (const k of keys) {
35
+ if (lists.delete(k)) removed++;
36
+ if (strings.delete(k)) removed++;
37
+ }
38
+ return removed;
39
+ }),
40
+ set: vi.fn(async (key: string, value: string) => {
41
+ strings.set(key, value);
42
+ return "OK";
43
+ }),
44
+ get: vi.fn(async (key: string) => strings.get(key) ?? null),
45
+ expire: vi.fn(async () => 1),
46
+ llen: vi.fn(async (key: string) => (lists.get(key) ?? []).length),
47
+ eval: vi.fn(
48
+ async (_script: string, _numKeys: number, ...args: string[]) => {
49
+ const [dedupKey, listKey, , ...serialised] = args;
50
+ if (!dedupKey || !listKey) return 0;
51
+ if (strings.has(dedupKey)) return 0;
52
+ const list = lists.get(listKey) ?? [];
53
+ list.push(...serialised);
54
+ lists.set(listKey, list);
55
+ strings.set(dedupKey, "1");
56
+ return 1;
57
+ }
58
+ ),
59
+ };
60
+ }
61
+
62
+ const humanMsg = new HumanMessage({ id: "msg-1", content: "Hello" }).toDict();
63
+ const aiMsg = new AIMessage({ id: "msg-2", content: "Hi there!" }).toDict();
64
+ const humanMsg2 = new HumanMessage({
65
+ id: "msg-3",
66
+ content: "Again please",
67
+ }).toDict();
68
+
69
+ async function seed(
70
+ redis: ReturnType<typeof createStatefulRedis>,
71
+ threadId: string,
72
+ messages: StoredMessage[]
73
+ ): Promise<void> {
74
+ const tm = createLangChainThreadManager({
75
+ redis: redis as never,
76
+ threadId,
77
+ });
78
+ await tm.initialize();
79
+ await tm.append(messages);
80
+ }
81
+
82
+ describe("LangChain fork + transform hooks", () => {
83
+ it("falls back to plain fork when no hooks are set", async () => {
84
+ const redis = createStatefulRedis();
85
+ await seed(redis, "src", [humanMsg, aiMsg]);
86
+
87
+ const tm = createLangChainThreadManager({
88
+ redis: redis as never,
89
+ threadId: "src",
90
+ });
91
+ const forked = await tm.fork("dst");
92
+ expect(await forked.load()).toEqual([humanMsg, aiMsg]);
93
+ });
94
+
95
+ it("applies onForkPrepareThread then onForkTransform in order", async () => {
96
+ const redis = createStatefulRedis();
97
+ await seed(redis, "src", [humanMsg, aiMsg, humanMsg2]);
98
+
99
+ const order: string[] = [];
100
+ const tm = createLangChainThreadManager({
101
+ redis: redis as never,
102
+ threadId: "src",
103
+ hooks: {
104
+ onForkPrepareThread: async (messages) => {
105
+ order.push("prepare");
106
+ return messages.slice(0, -1);
107
+ },
108
+ onForkTransform: (msg, i) => {
109
+ order.push("transform");
110
+ return { ...msg, data: { ...msg.data, content: `[x${i}]` } };
111
+ },
112
+ },
113
+ });
114
+
115
+ const forked = await tm.fork("dst");
116
+ const loaded = await forked.load();
117
+
118
+ expect(order).toEqual(["prepare", "transform", "transform"]);
119
+ expect(loaded).toHaveLength(2);
120
+ expect(loaded[0]?.data.content).toBe("[x0]");
121
+ expect(loaded[1]?.data.content).toBe("[x1]");
122
+ });
123
+
124
+ it("keeps the source thread untouched", async () => {
125
+ const redis = createStatefulRedis();
126
+ await seed(redis, "src", [humanMsg, aiMsg]);
127
+
128
+ const tm = createLangChainThreadManager({
129
+ redis: redis as never,
130
+ threadId: "src",
131
+ hooks: {
132
+ onForkTransform: (msg) => ({
133
+ ...msg,
134
+ data: { ...msg.data, content: "mutated" },
135
+ }),
136
+ },
137
+ });
138
+
139
+ await tm.fork("dst");
140
+ expect(await tm.load()).toEqual([humanMsg, aiMsg]);
141
+ });
142
+ });
@@ -15,6 +15,9 @@
15
15
  * ```
16
16
  */
17
17
 
18
+ // Adapter identity (wire format — matches Temporal activity-name prefix)
19
+ export { ADAPTER_ID, type AdapterId } from "./adapter-id";
20
+
18
21
  // Adapter (primary API)
19
22
  export {
20
23
  createLangChainAdapter,
@@ -47,7 +47,8 @@ export function createLangChainModelInvoker<
47
47
  return async function invokeLangChainModel(
48
48
  config: ModelInvokerConfig
49
49
  ): Promise<AgentResponse<StoredMessage>> {
50
- const { threadId, threadKey, agentName, state, metadata } = config;
50
+ const { threadId, threadKey, agentName, state, metadata, assistantMessageId } =
51
+ config;
51
52
  const { heartbeat, signal } = getActivityContext();
52
53
 
53
54
  const thread = createLangChainThreadManager({
@@ -58,6 +59,11 @@ export function createLangChainModelInvoker<
58
59
  });
59
60
  const runId = uuidv4();
60
61
 
62
+ // Truncate the thread starting at the id the assistant message
63
+ // will be stored under. No-op on the first attempt; on rewind
64
+ // retry / Temporal reset it wipes the prior attempt's assistant
65
+ // + tool results so the LLM sees the original pre-call state.
66
+ await thread.truncateFromId(assistantMessageId);
61
67
  const { messages } = await thread.prepareForInvocation();
62
68
 
63
69
  const heartbeatInterval = heartbeat
@@ -22,15 +22,16 @@ import { type ActivityInterfaceFor } from "@temporalio/workflow";
22
22
  import type { ThreadOps } from "../../../lib/session/types";
23
23
  import type { LangChainContent } from "./thread-manager";
24
24
  import { createThreadOpsProxy } from "../../../lib/thread/proxy";
25
+ import { ADAPTER_ID } from "./adapter-id";
25
26
 
26
- const ADAPTER_PREFIX = "langChain";
27
+ export { ADAPTER_ID, type AdapterId } from "./adapter-id";
27
28
 
28
29
  export function proxyLangChainThreadOps(
29
30
  scope?: string,
30
31
  options?: Parameters<typeof createThreadOpsProxy>[2]
31
32
  ): ActivityInterfaceFor<ThreadOps<LangChainContent>> {
32
33
  return createThreadOpsProxy(
33
- ADAPTER_PREFIX,
34
+ ADAPTER_ID,
34
35
  scope,
35
36
  options
36
37
  ) as ActivityInterfaceFor<ThreadOps<LangChainContent>>;
@@ -143,5 +143,31 @@ export function createLangChainThreadManager(
143
143
  },
144
144
  };
145
145
 
146
- return Object.assign(base, helpers);
146
+ const manager = Object.assign(base, helpers);
147
+
148
+ const originalFork = manager.fork.bind(manager);
149
+ manager.fork = async (
150
+ newThreadId: string
151
+ ): Promise<LangChainThreadManager> => {
152
+ await originalFork(newThreadId);
153
+ const forked = createLangChainThreadManager({
154
+ ...config,
155
+ threadId: newThreadId,
156
+ });
157
+ const { onForkPrepareThread, onForkTransform } = config.hooks ?? {};
158
+ if (!onForkPrepareThread && !onForkTransform) {
159
+ return forked;
160
+ }
161
+ let next = await forked.load();
162
+ if (onForkPrepareThread) {
163
+ next = await onForkPrepareThread(next);
164
+ }
165
+ if (onForkTransform) {
166
+ next = next.map((msg, i) => onForkTransform(msg, i, next));
167
+ }
168
+ await forked.replaceAll(next);
169
+ return forked;
170
+ };
171
+
172
+ return manager;
147
173
  }
@@ -8,7 +8,9 @@
8
8
  * - `"new"` — start a fresh thread (optionally specify its ID).
9
9
  * - `"continue"` — append directly to an existing thread in-place.
10
10
  * - `"fork"` — copy all messages from an existing thread into a new one and
11
- * continue there.
11
+ * continue there. When the adapter has `onForkPrepareThread` and/or
12
+ * `onForkTransform` hooks configured, they are applied once to the forked
13
+ * thread before the session starts.
12
14
  */
13
15
  export type ThreadInit =
14
16
  | { mode: "new"; threadId?: string }
@@ -19,7 +21,7 @@ export type ThreadInit =
19
21
  // Sandbox lifecycle
20
22
  // ============================================================================
21
23
 
22
- import type { SandboxSnapshot } from "./sandbox/types";
24
+ import type { SandboxCreateOptions, SandboxSnapshot } from "./sandbox/types";
23
25
 
24
26
  /**
25
27
  * Sandbox initialization strategy.
@@ -31,17 +33,24 @@ import type { SandboxSnapshot } from "./sandbox/types";
31
33
  * Paused sandboxes are automatically resumed. The shutdown policy applies
32
34
  * on exit.
33
35
  * - `"fork"` — fork from an existing (or paused) sandbox; a new sandbox is
34
- * created and owned by this session.
36
+ * created and owned by this session. `options` is an optional per-call
37
+ * override merged on top of the provider's static defaults.
35
38
  * - `"from-snapshot"` — restore a fresh sandbox from a previously captured
36
39
  * {@link SandboxSnapshot}. The new sandbox is owned by this session.
40
+ * `options` is an optional per-call override merged on top of the
41
+ * provider's static defaults.
37
42
  * - `"inherit"` — use a sandbox owned by someone else (e.g. a parent agent).
38
43
  * The session will **not** manage its lifecycle on exit.
39
44
  */
40
45
  export type SandboxInit =
41
46
  | { mode: "new"; ctx?: unknown }
42
47
  | { mode: "continue"; sandboxId: string }
43
- | { mode: "fork"; sandboxId: string }
44
- | { mode: "from-snapshot"; snapshot: SandboxSnapshot }
48
+ | { mode: "fork"; sandboxId: string; options?: SandboxCreateOptions }
49
+ | {
50
+ mode: "from-snapshot";
51
+ snapshot: SandboxSnapshot;
52
+ options?: SandboxCreateOptions;
53
+ }
45
54
  | {
46
55
  mode: "inherit";
47
56
  sandboxId: string;
@@ -29,6 +29,13 @@ export interface ModelInvokerConfig {
29
29
  agentName: string;
30
30
  state: BaseAgentState;
31
31
  metadata?: Record<string, unknown>;
32
+ /**
33
+ * The id the assistant message produced by this call will be stored
34
+ * under. Invokers truncate the thread from this id on entry so that
35
+ * rewind retries and Temporal workflow resets restore the pre-call
36
+ * state before re-invoking the LLM. See {@link RunAgentConfig}.
37
+ */
38
+ assistantMessageId: string;
32
39
  }
33
40
 
34
41
  /**
@@ -120,9 +120,7 @@ export class SandboxManager<
120
120
  async create(
121
121
  options?: TOptions,
122
122
  ctx?: TCtx
123
- ): Promise<{
124
- sandboxId: string;
125
- } | null> {
123
+ ): Promise<{ sandboxId: string } | null> {
126
124
  let providerOptions = options;
127
125
 
128
126
  if (this.hooks.onPreCreate) {
@@ -175,12 +173,15 @@ export class SandboxManager<
175
173
  await this.provider.resume(id);
176
174
  }
177
175
 
178
- async snapshot(id: string): Promise<SandboxSnapshot> {
179
- return this.provider.snapshot(id);
176
+ async snapshot(id: string, options?: TOptions): Promise<SandboxSnapshot> {
177
+ return this.provider.snapshot(id, options);
180
178
  }
181
179
 
182
- async restore(snapshot: SandboxSnapshot): Promise<string> {
183
- const sandbox = await this.provider.restore(snapshot);
180
+ async restore(
181
+ snapshot: SandboxSnapshot,
182
+ options?: TOptions
183
+ ): Promise<string> {
184
+ const sandbox = await this.provider.restore(snapshot, options);
184
185
  return sandbox.id;
185
186
  }
186
187
 
@@ -188,8 +189,8 @@ export class SandboxManager<
188
189
  await this.provider.deleteSnapshot(snapshot);
189
190
  }
190
191
 
191
- async fork(sandboxId: string): Promise<string> {
192
- const sandbox = await this.provider.fork(sandboxId);
192
+ async fork(sandboxId: string, options?: TOptions): Promise<string> {
193
+ const sandbox = await this.provider.fork(sandboxId, options);
193
194
  return sandbox.id;
194
195
  }
195
196
 
@@ -221,9 +222,7 @@ export class SandboxManager<
221
222
  createSandbox: async (
222
223
  options?: TOptions,
223
224
  ctx?: TCtx
224
- ): Promise<{
225
- sandboxId: string;
226
- } | null> => {
225
+ ): Promise<{ sandboxId: string } | null> => {
227
226
  return this.create(options, ctx);
228
227
  },
229
228
  destroySandbox: async (sandboxId: string): Promise<void> => {
@@ -238,19 +237,28 @@ export class SandboxManager<
238
237
  resumeSandbox: async (sandboxId: string): Promise<void> => {
239
238
  await this.resume(sandboxId);
240
239
  },
241
- snapshotSandbox: async (sandboxId: string): Promise<SandboxSnapshot> => {
242
- return this.snapshot(sandboxId);
240
+ snapshotSandbox: async (
241
+ sandboxId: string,
242
+ options?: TOptions
243
+ ): Promise<SandboxSnapshot> => {
244
+ return this.snapshot(sandboxId, options);
243
245
  },
244
- restoreSandbox: async (snapshot: SandboxSnapshot): Promise<string> => {
245
- return this.restore(snapshot);
246
+ restoreSandbox: async (
247
+ snapshot: SandboxSnapshot,
248
+ options?: TOptions
249
+ ): Promise<string> => {
250
+ return this.restore(snapshot, options);
246
251
  },
247
252
  deleteSandboxSnapshot: async (
248
253
  snapshot: SandboxSnapshot
249
254
  ): Promise<void> => {
250
255
  await this.deleteSnapshot(snapshot);
251
256
  },
252
- forkSandbox: async (sandboxId: string): Promise<string> => {
253
- return this.fork(sandboxId);
257
+ forkSandbox: async (
258
+ sandboxId: string,
259
+ options?: TOptions
260
+ ): Promise<string> => {
261
+ return this.fork(sandboxId, options);
254
262
  },
255
263
  };
256
264
  const cap = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1);
@@ -158,11 +158,23 @@ export interface SandboxProvider<
158
158
  pause(sandboxId: string, ttlSeconds?: number): Promise<void>;
159
159
  /** Resume a paused sandbox. No-op if already running. */
160
160
  resume(sandboxId: string): Promise<void>;
161
- snapshot(sandboxId: string): Promise<SandboxSnapshot>;
162
- restore(snapshot: SandboxSnapshot): Promise<Sandbox>;
161
+ /**
162
+ * Capture a snapshot of a running sandbox. `options` is a per-call override
163
+ * merged on top of the provider's static defaults.
164
+ */
165
+ snapshot(sandboxId: string, options?: TOptions): Promise<SandboxSnapshot>;
166
+ /**
167
+ * Restore a sandbox from a snapshot. `options` is a per-call override
168
+ * merged on top of the provider's static defaults.
169
+ */
170
+ restore(snapshot: SandboxSnapshot, options?: TOptions): Promise<Sandbox>;
163
171
  /** Delete a previously captured snapshot. No-op if already deleted. */
164
172
  deleteSnapshot(snapshot: SandboxSnapshot): Promise<void>;
165
- fork(sandboxId: string): Promise<Sandbox>;
173
+ /**
174
+ * Fork a running sandbox into a new one. `options` is a per-call override
175
+ * merged on top of the provider's static defaults.
176
+ */
177
+ fork(sandboxId: string, options?: TOptions): Promise<Sandbox>;
166
178
  }
167
179
 
168
180
  // ============================================================================
@@ -181,12 +193,20 @@ export interface SandboxOps<
181
193
  pauseSandbox(sandboxId: string): Promise<void>;
182
194
  /** Resume a paused sandbox. No-op if already running. */
183
195
  resumeSandbox(sandboxId: string): Promise<void>;
184
- snapshotSandbox(sandboxId: string): Promise<SandboxSnapshot>;
185
- /** Create a fresh sandbox from a previously captured snapshot. */
186
- restoreSandbox(snapshot: SandboxSnapshot): Promise<string>;
196
+ /** Capture a snapshot. `options` is a per-call override merged on top of provider defaults. */
197
+ snapshotSandbox(
198
+ sandboxId: string,
199
+ options?: TOptions
200
+ ): Promise<SandboxSnapshot>;
201
+ /** Create a fresh sandbox from a snapshot. `options` is a per-call override merged on top of provider defaults. */
202
+ restoreSandbox(
203
+ snapshot: SandboxSnapshot,
204
+ options?: TOptions
205
+ ): Promise<string>;
187
206
  /** Delete a previously captured snapshot. No-op if already deleted. */
188
207
  deleteSandboxSnapshot(snapshot: SandboxSnapshot): Promise<void>;
189
- forkSandbox(sandboxId: string): Promise<string>;
208
+ /** Fork a running sandbox. `options` is a per-call override merged on top of provider defaults. */
209
+ forkSandbox(sandboxId: string, options?: TOptions): Promise<string>;
190
210
  }
191
211
 
192
212
  /**