zeitlich 0.2.35 → 0.2.37

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 (199) hide show
  1. package/README.md +146 -92
  2. package/dist/{activities-BVI2lTwr.d.ts → activities-Bb-nAjwQ.d.ts} +2 -2
  3. package/dist/{activities-hd4aNnZE.d.cts → activities-vkI4_3CC.d.cts} +2 -2
  4. package/dist/adapters/sandbox/bedrock/index.cjs +14 -11
  5. package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
  6. package/dist/adapters/sandbox/bedrock/index.d.cts +4 -3
  7. package/dist/adapters/sandbox/bedrock/index.d.ts +4 -3
  8. package/dist/adapters/sandbox/bedrock/index.js +14 -11
  9. package/dist/adapters/sandbox/bedrock/index.js.map +1 -1
  10. package/dist/adapters/sandbox/bedrock/workflow.cjs +2 -0
  11. package/dist/adapters/sandbox/bedrock/workflow.cjs.map +1 -1
  12. package/dist/adapters/sandbox/bedrock/workflow.d.cts +2 -2
  13. package/dist/adapters/sandbox/bedrock/workflow.d.ts +2 -2
  14. package/dist/adapters/sandbox/bedrock/workflow.js +2 -0
  15. package/dist/adapters/sandbox/bedrock/workflow.js.map +1 -1
  16. package/dist/adapters/sandbox/daytona/index.cjs +35 -6
  17. package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
  18. package/dist/adapters/sandbox/daytona/index.d.cts +3 -1
  19. package/dist/adapters/sandbox/daytona/index.d.ts +3 -1
  20. package/dist/adapters/sandbox/daytona/index.js +35 -6
  21. package/dist/adapters/sandbox/daytona/index.js.map +1 -1
  22. package/dist/adapters/sandbox/daytona/workflow.cjs +2 -0
  23. package/dist/adapters/sandbox/daytona/workflow.cjs.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/daytona/workflow.js +2 -0
  27. package/dist/adapters/sandbox/daytona/workflow.js.map +1 -1
  28. package/dist/adapters/sandbox/e2b/index.cjs +59 -10
  29. package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
  30. package/dist/adapters/sandbox/e2b/index.d.cts +5 -3
  31. package/dist/adapters/sandbox/e2b/index.d.ts +5 -3
  32. package/dist/adapters/sandbox/e2b/index.js +59 -10
  33. package/dist/adapters/sandbox/e2b/index.js.map +1 -1
  34. package/dist/adapters/sandbox/e2b/workflow.cjs +2 -0
  35. package/dist/adapters/sandbox/e2b/workflow.cjs.map +1 -1
  36. package/dist/adapters/sandbox/e2b/workflow.d.cts +1 -1
  37. package/dist/adapters/sandbox/e2b/workflow.d.ts +1 -1
  38. package/dist/adapters/sandbox/e2b/workflow.js +2 -0
  39. package/dist/adapters/sandbox/e2b/workflow.js.map +1 -1
  40. package/dist/adapters/sandbox/inmemory/index.cjs +5 -0
  41. package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
  42. package/dist/adapters/sandbox/inmemory/index.d.cts +2 -1
  43. package/dist/adapters/sandbox/inmemory/index.d.ts +2 -1
  44. package/dist/adapters/sandbox/inmemory/index.js +5 -0
  45. package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
  46. package/dist/adapters/sandbox/inmemory/workflow.cjs +2 -0
  47. package/dist/adapters/sandbox/inmemory/workflow.cjs.map +1 -1
  48. package/dist/adapters/sandbox/inmemory/workflow.d.cts +1 -1
  49. package/dist/adapters/sandbox/inmemory/workflow.d.ts +1 -1
  50. package/dist/adapters/sandbox/inmemory/workflow.js +2 -0
  51. package/dist/adapters/sandbox/inmemory/workflow.js.map +1 -1
  52. package/dist/adapters/thread/anthropic/index.cjs +71 -36
  53. package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
  54. package/dist/adapters/thread/anthropic/index.d.cts +5 -5
  55. package/dist/adapters/thread/anthropic/index.d.ts +5 -5
  56. package/dist/adapters/thread/anthropic/index.js +71 -36
  57. package/dist/adapters/thread/anthropic/index.js.map +1 -1
  58. package/dist/adapters/thread/anthropic/workflow.cjs +5 -1
  59. package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
  60. package/dist/adapters/thread/anthropic/workflow.d.cts +5 -5
  61. package/dist/adapters/thread/anthropic/workflow.d.ts +5 -5
  62. package/dist/adapters/thread/anthropic/workflow.js +5 -1
  63. package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
  64. package/dist/adapters/thread/google-genai/index.cjs +50 -25
  65. package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
  66. package/dist/adapters/thread/google-genai/index.d.cts +5 -5
  67. package/dist/adapters/thread/google-genai/index.d.ts +5 -5
  68. package/dist/adapters/thread/google-genai/index.js +50 -25
  69. package/dist/adapters/thread/google-genai/index.js.map +1 -1
  70. package/dist/adapters/thread/google-genai/workflow.cjs +5 -1
  71. package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
  72. package/dist/adapters/thread/google-genai/workflow.d.cts +5 -5
  73. package/dist/adapters/thread/google-genai/workflow.d.ts +5 -5
  74. package/dist/adapters/thread/google-genai/workflow.js +5 -1
  75. package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
  76. package/dist/adapters/thread/langchain/index.cjs +34 -7
  77. package/dist/adapters/thread/langchain/index.cjs.map +1 -1
  78. package/dist/adapters/thread/langchain/index.d.cts +5 -5
  79. package/dist/adapters/thread/langchain/index.d.ts +5 -5
  80. package/dist/adapters/thread/langchain/index.js +34 -7
  81. package/dist/adapters/thread/langchain/index.js.map +1 -1
  82. package/dist/adapters/thread/langchain/workflow.cjs +5 -1
  83. package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
  84. package/dist/adapters/thread/langchain/workflow.d.cts +5 -5
  85. package/dist/adapters/thread/langchain/workflow.d.ts +5 -5
  86. package/dist/adapters/thread/langchain/workflow.js +5 -1
  87. package/dist/adapters/thread/langchain/workflow.js.map +1 -1
  88. package/dist/index.cjs +206 -120
  89. package/dist/index.cjs.map +1 -1
  90. package/dist/index.d.cts +17 -11
  91. package/dist/index.d.ts +17 -11
  92. package/dist/index.js +207 -121
  93. package/dist/index.js.map +1 -1
  94. package/dist/{proxy-BjdFGPTm.d.ts → proxy-0smGKvx8.d.ts} +1 -1
  95. package/dist/{proxy-7RnVaPdJ.d.cts → proxy-DEtowJyd.d.cts} +1 -1
  96. package/dist/{thread-manager-DjN5JYul.d.ts → thread-manager-3fszQih4.d.ts} +2 -2
  97. package/dist/{thread-manager-CbpiGq1L.d.ts → thread-manager-C-C4pI2z.d.ts} +2 -2
  98. package/dist/{thread-manager-BBzNgQWH.d.cts → thread-manager-CzYln2OC.d.cts} +2 -2
  99. package/dist/{thread-manager-DzXm9eeI.d.cts → thread-manager-D4vgzYrh.d.cts} +2 -2
  100. package/dist/{types-yiXmqedU.d.ts → types-B37hKoWA.d.ts} +1 -1
  101. package/dist/{types-DQ1l_gXL.d.cts → types-BO7Yju20.d.cts} +63 -14
  102. package/dist/{types-wiGLvxWf.d.ts → types-CNuWnvy9.d.ts} +1 -1
  103. package/dist/{types-CADc5V_P.d.ts → types-CPKDl-y_.d.ts} +63 -14
  104. package/dist/{types-Mc_4BCfT.d.cts → types-D08CXPh8.d.cts} +1 -1
  105. package/dist/{types-CBH54cwr.d.cts → types-DWEUmYAJ.d.cts} +1 -1
  106. package/dist/{types-DxCpFNv_.d.cts → types-tQL9njTu.d.cts} +25 -0
  107. package/dist/{types-DxCpFNv_.d.ts → types-tQL9njTu.d.ts} +25 -0
  108. package/dist/{workflow-P2pTSfKu.d.ts → workflow-CjXHbZZc.d.ts} +2 -2
  109. package/dist/{workflow-DhtWRovz.d.cts → workflow-Do_lzJpT.d.cts} +2 -2
  110. package/dist/workflow.cjs +182 -114
  111. package/dist/workflow.cjs.map +1 -1
  112. package/dist/workflow.d.cts +3 -3
  113. package/dist/workflow.d.ts +3 -3
  114. package/dist/workflow.js +183 -115
  115. package/dist/workflow.js.map +1 -1
  116. package/package.json +1 -1
  117. package/src/adapters/sandbox/bedrock/filesystem.ts +6 -12
  118. package/src/adapters/sandbox/bedrock/index.ts +10 -8
  119. package/src/adapters/sandbox/bedrock/proxy.ts +2 -0
  120. package/src/adapters/sandbox/daytona/filesystem.ts +29 -6
  121. package/src/adapters/sandbox/daytona/index.ts +6 -0
  122. package/src/adapters/sandbox/daytona/proxy.ts +2 -0
  123. package/src/adapters/sandbox/e2b/filesystem.ts +5 -4
  124. package/src/adapters/sandbox/e2b/index.ts +63 -12
  125. package/src/adapters/sandbox/e2b/proxy.ts +2 -0
  126. package/src/adapters/sandbox/inmemory/index.ts +5 -0
  127. package/src/adapters/sandbox/inmemory/proxy.ts +2 -0
  128. package/src/adapters/thread/anthropic/activities.ts +49 -26
  129. package/src/adapters/thread/anthropic/model-invoker.ts +15 -6
  130. package/src/adapters/thread/anthropic/proxy.ts +6 -2
  131. package/src/adapters/thread/anthropic/thread-manager.test.ts +26 -7
  132. package/src/adapters/thread/anthropic/thread-manager.ts +60 -46
  133. package/src/adapters/thread/google-genai/activities.ts +7 -2
  134. package/src/adapters/thread/google-genai/model-invoker.ts +26 -8
  135. package/src/adapters/thread/google-genai/proxy.ts +6 -2
  136. package/src/adapters/thread/google-genai/thread-manager.test.ts +13 -3
  137. package/src/adapters/thread/google-genai/thread-manager.ts +54 -33
  138. package/src/adapters/thread/langchain/activities.ts +46 -24
  139. package/src/adapters/thread/langchain/hooks.test.ts +36 -49
  140. package/src/adapters/thread/langchain/hooks.ts +18 -5
  141. package/src/adapters/thread/langchain/model-invoker.ts +3 -3
  142. package/src/adapters/thread/langchain/proxy.ts +6 -2
  143. package/src/adapters/thread/langchain/thread-manager.test.ts +5 -1
  144. package/src/adapters/thread/langchain/thread-manager.ts +20 -9
  145. package/src/index.ts +4 -1
  146. package/src/lib/activity.ts +16 -6
  147. package/src/lib/hooks/types.ts +6 -6
  148. package/src/lib/lifecycle.ts +9 -1
  149. package/src/lib/model/proxy.ts +2 -2
  150. package/src/lib/observability/hooks.ts +4 -5
  151. package/src/lib/observability/index.ts +1 -4
  152. package/src/lib/sandbox/manager.ts +21 -4
  153. package/src/lib/sandbox/node-fs.ts +3 -6
  154. package/src/lib/sandbox/sandbox.test.ts +36 -3
  155. package/src/lib/sandbox/tree.integration.test.ts +10 -3
  156. package/src/lib/sandbox/types.ts +35 -1
  157. package/src/lib/session/session-edge-cases.integration.test.ts +51 -13
  158. package/src/lib/session/session.integration.test.ts +139 -0
  159. package/src/lib/session/session.ts +50 -19
  160. package/src/lib/session/types.ts +13 -5
  161. package/src/lib/skills/fs-provider.ts +12 -8
  162. package/src/lib/skills/handler.ts +1 -1
  163. package/src/lib/skills/parse.ts +3 -1
  164. package/src/lib/skills/register.ts +1 -3
  165. package/src/lib/skills/skills.integration.test.ts +25 -15
  166. package/src/lib/state/manager.integration.test.ts +12 -2
  167. package/src/lib/subagent/define.ts +1 -1
  168. package/src/lib/subagent/handler.ts +186 -71
  169. package/src/lib/subagent/index.ts +1 -5
  170. package/src/lib/subagent/register.ts +3 -2
  171. package/src/lib/subagent/signals.ts +1 -10
  172. package/src/lib/subagent/subagent.integration.test.ts +438 -156
  173. package/src/lib/subagent/tool.ts +4 -3
  174. package/src/lib/subagent/types.ts +50 -20
  175. package/src/lib/subagent/workflow.ts +9 -49
  176. package/src/lib/thread/id.test.ts +1 -1
  177. package/src/lib/thread/id.ts +1 -2
  178. package/src/lib/thread/proxy.ts +3 -4
  179. package/src/lib/thread/types.ts +11 -3
  180. package/src/lib/tool-router/index.ts +1 -5
  181. package/src/lib/tool-router/router-edge-cases.integration.test.ts +1 -1
  182. package/src/lib/tool-router/router.ts +3 -2
  183. package/src/lib/tool-router/types.ts +11 -3
  184. package/src/lib/tool-router/with-sandbox.ts +19 -5
  185. package/src/lib/virtual-fs/filesystem.ts +1 -1
  186. package/src/lib/virtual-fs/index.ts +5 -1
  187. package/src/lib/virtual-fs/mutations.ts +2 -4
  188. package/src/lib/virtual-fs/queries.ts +9 -5
  189. package/src/lib/virtual-fs/types.ts +4 -1
  190. package/src/lib/virtual-fs/virtual-fs.test.ts +9 -11
  191. package/src/lib/workflow.test.ts +7 -4
  192. package/src/lib/workflow.ts +1 -5
  193. package/src/tools/ask-user-question/tool.ts +1 -3
  194. package/src/tools/glob/handler.ts +1 -4
  195. package/src/tools/task-get/handler.ts +4 -5
  196. package/src/tools/task-list/handler.ts +1 -4
  197. package/src/tools/task-update/handler.ts +4 -5
  198. package/src/workflow.ts +20 -7
  199. package/tsup.config.ts +9 -6
@@ -24,8 +24,10 @@ import { createLangChainModelInvoker } from "./model-invoker";
24
24
 
25
25
  const ADAPTER_PREFIX = "langChain" as const;
26
26
 
27
- export type LangChainThreadOps<TScope extends string = ""> =
28
- PrefixedThreadOps<ScopedPrefix<TScope, typeof ADAPTER_PREFIX>, LangChainContent>;
27
+ export type LangChainThreadOps<TScope extends string = ""> = PrefixedThreadOps<
28
+ ScopedPrefix<TScope, typeof ADAPTER_PREFIX>,
29
+ LangChainContent
30
+ >;
29
31
 
30
32
  export interface LangChainAdapterConfig {
31
33
  redis: Redis;
@@ -61,9 +63,7 @@ export interface LangChainAdapter {
61
63
  * // → { langChainCodingAgentInitializeThread, langChainCodingAgentAppendHumanMessage, … }
62
64
  * ```
63
65
  */
64
- createActivities<S extends string = "">(
65
- scope?: S,
66
- ): LangChainThreadOps<S>;
66
+ createActivities<S extends string = "">(scope?: S): LangChainThreadOps<S>;
67
67
 
68
68
  /**
69
69
  * Identity wrapper that types a tool handler for this adapter.
@@ -72,8 +72,8 @@ export interface LangChainAdapter {
72
72
  wrapHandler<TArgs, TResult, TContext extends RouterContext = RouterContext>(
73
73
  handler: (
74
74
  args: TArgs,
75
- context: TContext,
76
- ) => Promise<ToolHandlerResponse<TResult, LangChainToolResponse>>,
75
+ context: TContext
76
+ ) => Promise<ToolHandlerResponse<TResult, LangChainToolResponse>>
77
77
  ): ActivityToolHandler<TArgs, TResult, TContext, LangChainToolResponse>;
78
78
  }
79
79
 
@@ -113,13 +113,20 @@ export interface LangChainAdapter {
113
113
  * ```
114
114
  */
115
115
  export function createLangChainAdapter(
116
- config: LangChainAdapterConfig,
116
+ config: LangChainAdapterConfig
117
117
  ): LangChainAdapter {
118
118
  const { redis } = config;
119
119
 
120
120
  const threadOps: ThreadOps<LangChainContent> = {
121
- async initializeThread(threadId: string, threadKey?: string): Promise<void> {
122
- const thread = createLangChainThreadManager({ redis, threadId, key: threadKey });
121
+ async initializeThread(
122
+ threadId: string,
123
+ threadKey?: string
124
+ ): Promise<void> {
125
+ const thread = createLangChainThreadManager({
126
+ redis,
127
+ threadId,
128
+ key: threadKey,
129
+ });
123
130
  await thread.initialize();
124
131
  },
125
132
 
@@ -127,9 +134,13 @@ export function createLangChainAdapter(
127
134
  threadId: string,
128
135
  id: string,
129
136
  content: LangChainContent,
130
- threadKey?: string,
137
+ threadKey?: string
131
138
  ): Promise<void> {
132
- const thread = createLangChainThreadManager({ redis, threadId, key: threadKey });
139
+ const thread = createLangChainThreadManager({
140
+ redis,
141
+ threadId,
142
+ key: threadKey,
143
+ });
133
144
  await thread.appendUserMessage(id, content);
134
145
  },
135
146
 
@@ -137,15 +148,23 @@ export function createLangChainAdapter(
137
148
  threadId: string,
138
149
  id: string,
139
150
  content: LangChainSystemContent,
140
- threadKey?: string,
151
+ threadKey?: string
141
152
  ): Promise<void> {
142
- const thread = createLangChainThreadManager({ redis, threadId, key: threadKey });
153
+ const thread = createLangChainThreadManager({
154
+ redis,
155
+ threadId,
156
+ key: threadKey,
157
+ });
143
158
  await thread.appendSystemMessage(id, content);
144
159
  },
145
160
 
146
161
  async appendToolResult(id: string, cfg: ToolResultConfig): Promise<void> {
147
162
  const { threadId, threadKey, toolCallId, content } = cfg;
148
- const thread = createLangChainThreadManager({ redis, threadId, key: threadKey });
163
+ const thread = createLangChainThreadManager({
164
+ redis,
165
+ threadId,
166
+ key: threadKey,
167
+ });
149
168
  await thread.appendToolResult(id, toolCallId, "", content);
150
169
  },
151
170
 
@@ -153,9 +172,13 @@ export function createLangChainAdapter(
153
172
  threadId: string,
154
173
  id: string,
155
174
  message: StoredMessage,
156
- threadKey?: string,
175
+ threadKey?: string
157
176
  ): Promise<void> {
158
- const thread = createLangChainThreadManager({ redis, threadId, key: threadKey });
177
+ const thread = createLangChainThreadManager({
178
+ redis,
179
+ threadId,
180
+ key: threadKey,
181
+ });
159
182
  const patched = { ...message, data: { ...message.data, id } };
160
183
  await thread.append([patched]);
161
184
  },
@@ -163,7 +186,7 @@ export function createLangChainAdapter(
163
186
  async forkThread(
164
187
  sourceThreadId: string,
165
188
  targetThreadId: string,
166
- threadKey?: string,
189
+ threadKey?: string
167
190
  ): Promise<void> {
168
191
  const thread = createLangChainThreadManager({
169
192
  redis,
@@ -175,21 +198,20 @@ export function createLangChainAdapter(
175
198
  };
176
199
 
177
200
  function createActivities<S extends string = "">(
178
- scope?: S,
201
+ scope?: S
179
202
  ): LangChainThreadOps<S> {
180
203
  const prefix = scope
181
204
  ? `${ADAPTER_PREFIX}${scope.charAt(0).toUpperCase()}${scope.slice(1)}`
182
205
  : ADAPTER_PREFIX;
183
- const cap = (s: string): string =>
184
- s.charAt(0).toUpperCase() + s.slice(1);
206
+ const cap = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1);
185
207
  return Object.fromEntries(
186
- Object.entries(threadOps).map(([k, v]) => [`${prefix}${cap(k)}`, v]),
208
+ Object.entries(threadOps).map(([k, v]) => [`${prefix}${cap(k)}`, v])
187
209
  ) as LangChainThreadOps<S>;
188
210
  }
189
211
 
190
212
  const makeInvoker = (
191
213
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
192
- model: BaseChatModel<any>,
214
+ model: BaseChatModel<any>
193
215
  ): ModelInvoker<StoredMessage> =>
194
216
  createLangChainModelInvoker({ redis, model, hooks: config.hooks });
195
217
 
@@ -198,7 +220,7 @@ export function createLangChainAdapter(
198
220
  : () => {
199
221
  throw new Error(
200
222
  "No default model provided to createLangChainAdapter. " +
201
- "Either pass `model` in the config or use `createModelInvoker(model)` instead.",
223
+ "Either pass `model` in the config or use `createModelInvoker(model)` instead."
202
224
  );
203
225
  };
204
226
 
@@ -3,11 +3,14 @@ import { HumanMessage, AIMessage } from "@langchain/core/messages";
3
3
  import type { BaseMessage } from "@langchain/core/messages";
4
4
  import { appendCachePoint } from "./hooks";
5
5
 
6
- const cacheBlock = { type: "cache_control" as const, cache_control: { type: "ephemeral" as const } };
6
+ const cacheBlock = {
7
+ type: "cache_control" as const,
8
+ cache_control: { type: "ephemeral" as const },
9
+ };
7
10
 
8
11
  function applyHook(
9
12
  messages: BaseMessage[],
10
- hook: ReturnType<typeof appendCachePoint>,
13
+ hook: ReturnType<typeof appendCachePoint>
11
14
  ): BaseMessage[] {
12
15
  return messages.map((m, i, arr) => hook(m, i, arr));
13
16
  }
@@ -47,29 +50,25 @@ describe("appendCachePoint", () => {
47
50
  it("deduplicates within the last message", () => {
48
51
  const messages: BaseMessage[] = [
49
52
  new HumanMessage({
50
- content: [
51
- { type: "text", text: "hello" },
52
- cacheBlock,
53
- ],
53
+ content: [{ type: "text", text: "hello" }, cacheBlock],
54
54
  }),
55
55
  ];
56
56
  const hook = appendCachePoint(cacheBlock);
57
57
  const result = applyHook(messages, hook);
58
58
 
59
- const blocks = (messageAt(result, 0).content as Array<{ type: string }>).filter(
60
- (b) => b.type === cacheBlock.type,
61
- );
59
+ const blocks = (
60
+ messageAt(result, 0).content as Array<{ type: string }>
61
+ ).filter((b) => b.type === cacheBlock.type);
62
62
  expect(blocks).toHaveLength(1);
63
63
  });
64
64
 
65
65
  it("strips old cache blocks when total would exceed maxBlocks", () => {
66
- const messages: BaseMessage[] = Array.from({ length: 6 }, (_, i) =>
67
- new HumanMessage({
68
- content: [
69
- { type: "text", text: `msg ${i}` },
70
- cacheBlock,
71
- ],
72
- }),
66
+ const messages: BaseMessage[] = Array.from(
67
+ { length: 6 },
68
+ (_, i) =>
69
+ new HumanMessage({
70
+ content: [{ type: "text", text: `msg ${i}` }, cacheBlock],
71
+ })
73
72
  );
74
73
  const hook = appendCachePoint(cacheBlock, { maxBlocks: 4 });
75
74
  const result = applyHook(messages, hook);
@@ -78,13 +77,12 @@ describe("appendCachePoint", () => {
78
77
  });
79
78
 
80
79
  it("keeps the most recent cache blocks", () => {
81
- const messages: BaseMessage[] = Array.from({ length: 6 }, (_, i) =>
82
- new HumanMessage({
83
- content: [
84
- { type: "text", text: `msg ${i}` },
85
- cacheBlock,
86
- ],
87
- }),
80
+ const messages: BaseMessage[] = Array.from(
81
+ { length: 6 },
82
+ (_, i) =>
83
+ new HumanMessage({
84
+ content: [{ type: "text", text: `msg ${i}` }, cacheBlock],
85
+ })
88
86
  );
89
87
  const hook = appendCachePoint(cacheBlock, { maxBlocks: 4 });
90
88
  const result = applyHook(messages, hook);
@@ -101,13 +99,12 @@ describe("appendCachePoint", () => {
101
99
  });
102
100
 
103
101
  it("respects a custom maxBlocks value", () => {
104
- const messages: BaseMessage[] = Array.from({ length: 5 }, (_, i) =>
105
- new HumanMessage({
106
- content: [
107
- { type: "text", text: `msg ${i}` },
108
- cacheBlock,
109
- ],
110
- }),
102
+ const messages: BaseMessage[] = Array.from(
103
+ { length: 5 },
104
+ (_, i) =>
105
+ new HumanMessage({
106
+ content: [{ type: "text", text: `msg ${i}` }, cacheBlock],
107
+ })
111
108
  );
112
109
  const hook = appendCachePoint(cacheBlock, { maxBlocks: 2 });
113
110
  const result = applyHook(messages, hook);
@@ -141,13 +138,12 @@ describe("appendCachePoint", () => {
141
138
  });
142
139
 
143
140
  it("defaults maxBlocks to 4", () => {
144
- const messages: BaseMessage[] = Array.from({ length: 8 }, (_, i) =>
145
- new HumanMessage({
146
- content: [
147
- { type: "text", text: `msg ${i}` },
148
- cacheBlock,
149
- ],
150
- }),
141
+ const messages: BaseMessage[] = Array.from(
142
+ { length: 8 },
143
+ (_, i) =>
144
+ new HumanMessage({
145
+ content: [{ type: "text", text: `msg ${i}` }, cacheBlock],
146
+ })
151
147
  );
152
148
  const hook = appendCachePoint(cacheBlock);
153
149
  const result = applyHook(messages, hook);
@@ -165,22 +161,13 @@ describe("appendCachePoint", () => {
165
161
  ],
166
162
  }),
167
163
  new HumanMessage({
168
- content: [
169
- { type: "text", text: "msg 1" },
170
- cacheBlock,
171
- ],
164
+ content: [{ type: "text", text: "msg 1" }, cacheBlock],
172
165
  }),
173
166
  new HumanMessage({
174
- content: [
175
- { type: "text", text: "msg 2" },
176
- cacheBlock,
177
- ],
167
+ content: [{ type: "text", text: "msg 2" }, cacheBlock],
178
168
  }),
179
169
  new HumanMessage({
180
- content: [
181
- { type: "text", text: "msg 3" },
182
- cacheBlock,
183
- ],
170
+ content: [{ type: "text", text: "msg 3" }, cacheBlock],
184
171
  }),
185
172
  new HumanMessage("last"),
186
173
  ];
@@ -12,8 +12,12 @@ type ContentBlock = MessageContent extends (infer U)[] | string ? U : never;
12
12
  */
13
13
  export function appendCachePoint(
14
14
  block: ContentBlock,
15
- { maxBlocks = 4 }: { maxBlocks?: number } = {},
16
- ): (message: BaseMessage, index: number, messages: readonly BaseMessage[]) => BaseMessage {
15
+ { maxBlocks = 4 }: { maxBlocks?: number } = {}
16
+ ): (
17
+ message: BaseMessage,
18
+ index: number,
19
+ messages: readonly BaseMessage[]
20
+ ) => BaseMessage {
17
21
  return (message, index, messages) => {
18
22
  const isLast = index === messages.length - 1;
19
23
 
@@ -23,13 +27,19 @@ export function appendCachePoint(
23
27
  if (content.some((b) => b.type === block.type)) return message;
24
28
  message.content = [...content, block];
25
29
  } else if (typeof content === "string") {
26
- message.content = [{ type: "text", text: content }, block] satisfies MessageContent;
30
+ message.content = [
31
+ { type: "text", text: content },
32
+ block,
33
+ ] satisfies MessageContent;
27
34
  }
28
35
  return message;
29
36
  }
30
37
 
31
38
  const { content } = message;
32
- if (!Array.isArray(content) || !content.some((b) => b.type === block.type)) {
39
+ if (
40
+ !Array.isArray(content) ||
41
+ !content.some((b) => b.type === block.type)
42
+ ) {
33
43
  return message;
34
44
  }
35
45
 
@@ -40,7 +50,10 @@ export function appendCachePoint(
40
50
  const msg = messages[i];
41
51
  if (!msg) continue;
42
52
  const c = msg.content;
43
- if (Array.isArray(c) && c.some((b: ContentBlock) => b.type === block.type)) {
53
+ if (
54
+ Array.isArray(c) &&
55
+ c.some((b: ContentBlock) => b.type === block.type)
56
+ ) {
44
57
  cacheBlocksAfter++;
45
58
  }
46
59
  }
@@ -9,7 +9,7 @@ import {
9
9
  } from "./thread-manager";
10
10
  import { getActivityContext } from "../../../lib/activity";
11
11
 
12
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+
13
13
  export interface LangChainModelInvokerConfig<
14
14
  TModel extends BaseChatModel<any> = BaseChatModel<any>,
15
15
  > {
@@ -40,7 +40,7 @@ export interface LangChainModelInvokerConfig<
40
40
  * return { ...createRunAgentActivity(client, invoker, "myAgent") };
41
41
  * ```
42
42
  */
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
43
+
44
44
  export function createLangChainModelInvoker<
45
45
  TModel extends BaseChatModel<any> = BaseChatModel<any>,
46
46
  >({ redis, model, hooks }: LangChainModelInvokerConfig<TModel>) {
@@ -109,7 +109,7 @@ export function createLangChainModelInvoker<
109
109
  * Convenience wrapper around createLangChainModelInvoker for cases where
110
110
  * you don't need to reuse the invoker.
111
111
  */
112
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
112
+
113
113
  export async function invokeLangChainModel<
114
114
  TModel extends BaseChatModel<any> = BaseChatModel<any>,
115
115
  >({
@@ -27,7 +27,11 @@ const ADAPTER_PREFIX = "langChain";
27
27
 
28
28
  export function proxyLangChainThreadOps(
29
29
  scope?: string,
30
- options?: Parameters<typeof createThreadOpsProxy>[2],
30
+ options?: Parameters<typeof createThreadOpsProxy>[2]
31
31
  ): ActivityInterfaceFor<ThreadOps<LangChainContent>> {
32
- return createThreadOpsProxy(ADAPTER_PREFIX, scope, options) as ActivityInterfaceFor<ThreadOps<LangChainContent>>;
32
+ return createThreadOpsProxy(
33
+ ADAPTER_PREFIX,
34
+ scope,
35
+ options
36
+ ) as ActivityInterfaceFor<ThreadOps<LangChainContent>>;
33
37
  }
@@ -91,7 +91,11 @@ describe("LangChain thread manager hooks", () => {
91
91
 
92
92
  await tm.prepareForInvocation();
93
93
 
94
- const args = hook.mock.calls[0] as unknown as [unknown, number, unknown[]];
94
+ const args = hook.mock.calls[0] as unknown as [
95
+ unknown,
96
+ number,
97
+ unknown[],
98
+ ];
95
99
  expect(args[2]).toHaveLength(2);
96
100
  });
97
101
  });
@@ -23,7 +23,10 @@ export type LangChainContent = string | MessageContent;
23
23
  /** SDK-native content type for LangChain system messages */
24
24
  export type LangChainSystemContent = string | MessageContent;
25
25
 
26
- export type LangChainThreadManagerHooks = ThreadManagerHooks<StoredMessage, BaseMessage>;
26
+ export type LangChainThreadManagerHooks = ThreadManagerHooks<
27
+ StoredMessage,
28
+ BaseMessage
29
+ >;
27
30
 
28
31
  export interface LangChainThreadManagerConfig {
29
32
  redis: Redis;
@@ -39,8 +42,12 @@ export interface LangChainInvocationPayload {
39
42
  }
40
43
 
41
44
  /** Thread manager with LangChain StoredMessage convenience helpers */
42
- export interface LangChainThreadManager
43
- extends ProviderThreadManager<StoredMessage, LangChainContent, JsonValue, LangChainSystemContent> {
45
+ export interface LangChainThreadManager extends ProviderThreadManager<
46
+ StoredMessage,
47
+ LangChainContent,
48
+ JsonValue,
49
+ LangChainSystemContent
50
+ > {
44
51
  appendAIMessage(id: string, content: string | MessageContent): Promise<void>;
45
52
  prepareForInvocation(): Promise<LangChainInvocationPayload>;
46
53
  }
@@ -63,7 +70,7 @@ function storedMessageId(msg: StoredMessage): string {
63
70
  * appending typed LangChain messages.
64
71
  */
65
72
  export function createLangChainThreadManager(
66
- config: LangChainThreadManagerConfig,
73
+ config: LangChainThreadManagerConfig
67
74
  ): LangChainThreadManager {
68
75
  const baseConfig: ThreadManagerConfig<StoredMessage> = {
69
76
  redis: config.redis,
@@ -77,7 +84,7 @@ export function createLangChainThreadManager(
77
84
  const helpers: Omit<LangChainThreadManager, keyof typeof base> = {
78
85
  async appendUserMessage(
79
86
  id: string,
80
- content: LangChainContent,
87
+ content: LangChainContent
81
88
  ): Promise<void> {
82
89
  await base.append([
83
90
  new HumanMessage({ id, content: content as MessageContent }).toDict(),
@@ -86,7 +93,7 @@ export function createLangChainThreadManager(
86
93
 
87
94
  async appendSystemMessage(
88
95
  id: string,
89
- content: LangChainSystemContent,
96
+ content: LangChainSystemContent
90
97
  ): Promise<void> {
91
98
  await base.initialize();
92
99
  await base.append([
@@ -99,7 +106,7 @@ export function createLangChainThreadManager(
99
106
 
100
107
  async appendAIMessage(
101
108
  id: string,
102
- content: string | MessageContent,
109
+ content: string | MessageContent
103
110
  ): Promise<void> {
104
111
  await base.append([
105
112
  new AIMessage({ id, content: content as MessageContent }).toDict(),
@@ -110,10 +117,14 @@ export function createLangChainThreadManager(
110
117
  id: string,
111
118
  _toolCallId: string,
112
119
  _toolName: string,
113
- content: JsonValue,
120
+ content: JsonValue
114
121
  ): Promise<void> {
115
122
  await base.append([
116
- new ToolMessage({ id, content: content as MessageContent, tool_call_id: _toolCallId }).toDict(),
123
+ new ToolMessage({
124
+ id,
125
+ content: content as MessageContent,
126
+ tool_call_id: _toolCallId,
127
+ }).toDict(),
117
128
  ]);
118
129
  },
119
130
 
package/src/index.ts CHANGED
@@ -58,7 +58,10 @@ export type { AgentStateContext } from "./lib/activity";
58
58
 
59
59
  // Sandbox (activity-side: manager + Node.js filesystem adapter)
60
60
  export { SandboxManager } from "./lib/sandbox/manager";
61
- export type { SandboxManagerHooks, PreCreateHookResult } from "./lib/sandbox/manager";
61
+ export type {
62
+ SandboxManagerHooks,
63
+ PreCreateHookResult,
64
+ } from "./lib/sandbox/manager";
62
65
  export { NodeFsSandboxFileSystem } from "./lib/sandbox/node-fs";
63
66
 
64
67
  // Virtual filesystem (activity-side)
@@ -59,10 +59,13 @@ export async function queryParentWorkflowState<T>(
59
59
  * };
60
60
  * ```
61
61
  */
62
- export function createRunAgentActivity<R, S extends BaseAgentState = BaseAgentState>(
62
+ export function createRunAgentActivity<
63
+ R,
64
+ S extends BaseAgentState = BaseAgentState,
65
+ >(
63
66
  client: WorkflowClient,
64
67
  handler: (config: RunAgentConfig & { state: S }) => Promise<R>,
65
- scope: string,
68
+ scope: string
66
69
  ): Record<string, (config: RunAgentConfig) => Promise<R>> {
67
70
  const name = `run${scope.charAt(0).toUpperCase()}${scope.slice(1)}`;
68
71
  return {
@@ -76,7 +79,9 @@ export function createRunAgentActivity<R, S extends BaseAgentState = BaseAgentSt
76
79
  /**
77
80
  * Context injected into tool handlers created via {@link withParentWorkflowState}.
78
81
  */
79
- export interface AgentStateContext<S extends BaseAgentState = BaseAgentState> extends RouterContext {
82
+ export interface AgentStateContext<
83
+ S extends BaseAgentState = BaseAgentState,
84
+ > extends RouterContext {
80
85
  state: S;
81
86
  }
82
87
 
@@ -101,12 +106,17 @@ export interface AgentStateContext<S extends BaseAgentState = BaseAgentState> ex
101
106
  * );
102
107
  * ```
103
108
  */
104
- export function withParentWorkflowState<TArgs, TResult, S extends BaseAgentState = BaseAgentState, TToolResponse = JsonValue>(
109
+ export function withParentWorkflowState<
110
+ TArgs,
111
+ TResult,
112
+ S extends BaseAgentState = BaseAgentState,
113
+ TToolResponse = JsonValue,
114
+ >(
105
115
  client: WorkflowClient,
106
116
  handler: (
107
117
  args: TArgs,
108
- context: AgentStateContext<S>,
109
- ) => Promise<ToolHandlerResponse<TResult, TToolResponse>>,
118
+ context: AgentStateContext<S>
119
+ ) => Promise<ToolHandlerResponse<TResult, TToolResponse>>
110
120
  ): ActivityToolHandler<TArgs, TResult, RouterContext, TToolResponse> {
111
121
  return async (args, context) => {
112
122
  const state = await queryParentWorkflowState<S>(client);
@@ -1,8 +1,5 @@
1
1
  import type { SessionExitReason } from "../types";
2
- import type {
3
- ToolMap,
4
- ToolRouterHooks,
5
- } from "../tool-router/types";
2
+ import type { ToolMap, ToolRouterHooks } from "../tool-router/types";
6
3
 
7
4
  // ============================================================================
8
5
  // Session Lifecycle Hooks
@@ -85,8 +82,11 @@ export type PostHumanMessageAppendHook<TContent = unknown> = (
85
82
  * (consumed by the router) with session/message lifecycle hooks
86
83
  * (consumed directly by the session).
87
84
  */
88
- export interface Hooks<T extends ToolMap, TResult = unknown, TContent = unknown>
89
- extends ToolRouterHooks<T, TResult> {
85
+ export interface Hooks<
86
+ T extends ToolMap,
87
+ TResult = unknown,
88
+ TContent = unknown,
89
+ > extends ToolRouterHooks<T, TResult> {
90
90
  /** Called before each human message is appended to the thread */
91
91
  onPreHumanMessageAppend?: PreHumanMessageAppendHook<TContent>;
92
92
  /** Called after each human message is appended to the thread */
@@ -19,6 +19,8 @@ export type ThreadInit =
19
19
  // Sandbox lifecycle
20
20
  // ============================================================================
21
21
 
22
+ import type { SandboxSnapshot } from "./sandbox/types";
23
+
22
24
  /**
23
25
  * Sandbox initialization strategy.
24
26
  *
@@ -30,6 +32,8 @@ export type ThreadInit =
30
32
  * on exit.
31
33
  * - `"fork"` — fork from an existing (or paused) sandbox; a new sandbox is
32
34
  * created and owned by this session.
35
+ * - `"from-snapshot"` — restore a fresh sandbox from a previously captured
36
+ * {@link SandboxSnapshot}. The new sandbox is owned by this session.
33
37
  * - `"inherit"` — use a sandbox owned by someone else (e.g. a parent agent).
34
38
  * The session will **not** manage its lifecycle on exit.
35
39
  */
@@ -37,6 +41,7 @@ export type SandboxInit =
37
41
  | { mode: "new"; ctx?: unknown }
38
42
  | { mode: "continue"; sandboxId: string }
39
43
  | { mode: "fork"; sandboxId: string }
44
+ | { mode: "from-snapshot"; snapshot: SandboxSnapshot }
40
45
  | {
41
46
  mode: "inherit";
42
47
  sandboxId: string;
@@ -48,8 +53,11 @@ export type SandboxInit =
48
53
  * - `"destroy"` — tear down the sandbox entirely.
49
54
  * - `"pause"` — pause the sandbox so it can be resumed later.
50
55
  * - `"keep"` — leave the sandbox running (no-op on exit).
56
+ * - `"snapshot"` — capture a snapshot then destroy the sandbox. The snapshot
57
+ * is surfaced on the session result so the caller can reuse it to spawn
58
+ * future sandboxes.
51
59
  */
52
- export type SandboxShutdown = "destroy" | "pause" | "keep";
60
+ export type SandboxShutdown = "destroy" | "pause" | "keep" | "snapshot";
53
61
 
54
62
  /**
55
63
  * Extended shutdown options available to subagent workflows.
@@ -29,7 +29,7 @@ import type { RunAgentConfig } from "../types";
29
29
 
30
30
  export function proxyRunAgent<M = unknown>(
31
31
  scope?: string,
32
- options?: Parameters<typeof proxyActivities>[0],
32
+ options?: Parameters<typeof proxyActivities>[0]
33
33
  ): (config: RunAgentConfig) => Promise<AgentResponse<M>> {
34
34
  const resolvedScope = scope ?? workflowInfo().workflowType;
35
35
  const name = `run${resolvedScope.charAt(0).toUpperCase()}${resolvedScope.slice(1)}`;
@@ -44,7 +44,7 @@ export function proxyRunAgent<M = unknown>(
44
44
  maximumInterval: "2m",
45
45
  backoffCoefficient: 3,
46
46
  },
47
- },
47
+ }
48
48
  );
49
49
  return acts[name] as (config: RunAgentConfig) => Promise<AgentResponse<M>>;
50
50
  }
@@ -1,9 +1,6 @@
1
1
  import { proxySinks } from "@temporalio/workflow";
2
2
  import type { ZeitlichObservabilitySinks } from "./sinks";
3
- import type {
4
- SessionStartHook,
5
- SessionEndHook,
6
- } from "../hooks/types";
3
+ import type { SessionStartHook, SessionEndHook } from "../hooks/types";
7
4
  import type {
8
5
  PostToolUseHook,
9
6
  PostToolUseFailureHook,
@@ -39,7 +36,9 @@ export interface ObservabilityHooks {
39
36
  *
40
37
  * @param agentName - Agent name attached to every emitted event
41
38
  */
42
- export function createObservabilityHooks(agentName: string): ObservabilityHooks {
39
+ export function createObservabilityHooks(
40
+ agentName: string
41
+ ): ObservabilityHooks {
43
42
  const { zeitlichMetrics } = proxySinks<ZeitlichObservabilitySinks>();
44
43
  let sessionStartMs = Date.now();
45
44
 
@@ -1,7 +1,4 @@
1
- export {
2
- createObservabilityHooks,
3
- composeHooks,
4
- } from "./hooks";
1
+ export { createObservabilityHooks, composeHooks } from "./hooks";
5
2
  export type { ObservabilityHooks } from "./hooks";
6
3
 
7
4
  export type {