zeitlich 0.2.18 → 0.2.20

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 (59) hide show
  1. package/dist/adapters/sandbox/daytona/index.cjs +25 -10
  2. package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
  3. package/dist/adapters/sandbox/daytona/index.d.cts +4 -1
  4. package/dist/adapters/sandbox/daytona/index.d.ts +4 -1
  5. package/dist/adapters/sandbox/daytona/index.js +25 -10
  6. package/dist/adapters/sandbox/daytona/index.js.map +1 -1
  7. package/dist/adapters/sandbox/virtual/index.d.cts +4 -3
  8. package/dist/adapters/sandbox/virtual/index.d.ts +4 -3
  9. package/dist/adapters/thread/google-genai/index.cjs +0 -2
  10. package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
  11. package/dist/adapters/thread/google-genai/index.d.cts +2 -2
  12. package/dist/adapters/thread/google-genai/index.d.ts +2 -2
  13. package/dist/adapters/thread/google-genai/index.js +0 -2
  14. package/dist/adapters/thread/google-genai/index.js.map +1 -1
  15. package/dist/adapters/thread/langchain/index.cjs +3 -1
  16. package/dist/adapters/thread/langchain/index.cjs.map +1 -1
  17. package/dist/adapters/thread/langchain/index.d.cts +3 -3
  18. package/dist/adapters/thread/langchain/index.d.ts +3 -3
  19. package/dist/adapters/thread/langchain/index.js +3 -1
  20. package/dist/adapters/thread/langchain/index.js.map +1 -1
  21. package/dist/index.cjs +153 -123
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +13 -13
  24. package/dist/index.d.ts +13 -13
  25. package/dist/index.js +153 -123
  26. package/dist/index.js.map +1 -1
  27. package/dist/{queries-TwukRZ8b.d.ts → queries-KHj5Otv7.d.ts} +1 -1
  28. package/dist/{queries-DnX72m_Y.d.cts → queries-nIdzTCDS.d.cts} +1 -1
  29. package/dist/{types-CdB2D5Sq.d.ts → types-By80IE1x.d.ts} +3 -3
  30. package/dist/{types-CmOSypVk.d.ts → types-Ct2igz9y.d.cts} +6 -4
  31. package/dist/{types-CmOSypVk.d.cts → types-Ct2igz9y.d.ts} +6 -4
  32. package/dist/{types-DRvq2miV.d.cts → types-DZ7BkA3-.d.cts} +3 -3
  33. package/dist/workflow.cjs +70 -40
  34. package/dist/workflow.cjs.map +1 -1
  35. package/dist/workflow.d.cts +16 -12
  36. package/dist/workflow.d.ts +16 -12
  37. package/dist/workflow.js +70 -40
  38. package/dist/workflow.js.map +1 -1
  39. package/package.json +1 -1
  40. package/src/adapters/sandbox/daytona/filesystem.ts +21 -12
  41. package/src/adapters/sandbox/daytona/index.ts +24 -23
  42. package/src/adapters/thread/langchain/thread-manager.ts +11 -7
  43. package/src/lib/session/session-edge-cases.integration.test.ts +20 -2
  44. package/src/lib/session/session.integration.test.ts +16 -2
  45. package/src/lib/session/session.ts +2 -1
  46. package/src/lib/session/types.ts +2 -1
  47. package/src/lib/subagent/handler.ts +1 -1
  48. package/src/lib/subagent/register.ts +3 -9
  49. package/src/lib/subagent/subagent.integration.test.ts +10 -9
  50. package/src/lib/subagent/tool.ts +1 -1
  51. package/src/lib/thread/index.ts +0 -1
  52. package/src/lib/tool-router/router-edge-cases.integration.test.ts +8 -3
  53. package/src/lib/tool-router/router.integration.test.ts +8 -3
  54. package/src/lib/tool-router/router.ts +61 -31
  55. package/src/lib/tool-router/types.ts +14 -9
  56. package/src/lib/workflow.test.ts +18 -6
  57. package/src/lib/workflow.ts +13 -3
  58. package/src/tools/task-create/handler.ts +3 -6
  59. package/src/workflow.ts +2 -2
@@ -63,9 +63,11 @@ export function createToolRouter<T extends ToolMap>(
63
63
  toolMap.set(tool.name, tool as T[keyof T]);
64
64
  }
65
65
 
66
- /** Check if a tool is enabled (defaults to true when not specified) */
66
+ const resolve = <T>(v: T | (() => T)): T =>
67
+ typeof v === "function" ? (v as () => T)() : v;
68
+
67
69
  const isEnabled = (tool: ToolMap[string]): boolean =>
68
- typeof tool.enabled === "function" ? tool.enabled() : (tool.enabled ?? true);
70
+ resolve(tool.enabled) ?? true;
69
71
 
70
72
  if (options.plugins) {
71
73
  for (const plugin of options.plugins) {
@@ -128,7 +130,10 @@ export function createToolRouter<T extends ToolMap>(
128
130
  turn,
129
131
  });
130
132
  if (r?.fallbackContent !== undefined)
131
- return { content: r.fallbackContent, result: { error: errorStr, recovered: true } };
133
+ return {
134
+ content: r.fallbackContent,
135
+ result: { error: errorStr, recovered: true },
136
+ };
132
137
  if (r?.suppress)
133
138
  return {
134
139
  content: JSON.stringify({ error: errorStr, suppressed: true }),
@@ -144,7 +149,10 @@ export function createToolRouter<T extends ToolMap>(
144
149
  turn,
145
150
  });
146
151
  if (r?.fallbackContent !== undefined)
147
- return { content: r.fallbackContent, result: { error: errorStr, recovered: true } };
152
+ return {
153
+ content: r.fallbackContent,
154
+ result: { error: errorStr, recovered: true },
155
+ };
148
156
  if (r?.suppress)
149
157
  return {
150
158
  content: JSON.stringify({ error: errorStr, suppressed: true }),
@@ -199,7 +207,10 @@ export function createToolRouter<T extends ToolMap>(
199
207
  threadId: options.threadId,
200
208
  toolCallId: toolCall.id,
201
209
  toolName: toolCall.name,
202
- content: JSON.stringify({ skipped: true, reason: "Skipped by PreToolUse hook" }),
210
+ content: JSON.stringify({
211
+ skipped: true,
212
+ reason: "Skipped by PreToolUse hook",
213
+ }),
203
214
  });
204
215
  return null;
205
216
  }
@@ -230,19 +241,31 @@ export function createToolRouter<T extends ToolMap>(
230
241
  content = JSON.stringify(result, null, 2);
231
242
  }
232
243
  } catch (error) {
233
- const recovery = await runFailureHooks(toolCall, tool, error, effectiveArgs, turn);
244
+ const recovery = await runFailureHooks(
245
+ toolCall,
246
+ tool,
247
+ error,
248
+ effectiveArgs,
249
+ turn
250
+ );
234
251
  result = recovery.result;
235
252
  content = recovery.content;
236
253
  }
237
254
 
238
255
  // --- Append result to thread (unless handler already did) ---
239
256
  if (!resultAppended) {
240
- await appendToolResult({
257
+ const config = {
241
258
  threadId: options.threadId,
242
259
  toolCallId: toolCall.id,
243
260
  toolName: toolCall.name,
244
261
  content,
245
- });
262
+ };
263
+ await appendToolResult.executeWithOptions(
264
+ {
265
+ summary: `Append ${toolCall.name} result`,
266
+ },
267
+ [config]
268
+ );
246
269
  }
247
270
 
248
271
  const toolResult = {
@@ -252,7 +275,14 @@ export function createToolRouter<T extends ToolMap>(
252
275
  } as ToolCallResultUnion<TResults>;
253
276
 
254
277
  // --- Post-hooks ---
255
- await runPostHooks(toolCall, tool, toolResult, effectiveArgs, turn, Date.now() - startTime);
278
+ await runPostHooks(
279
+ toolCall,
280
+ tool,
281
+ toolResult,
282
+ effectiveArgs,
283
+ turn,
284
+ Date.now() - startTime
285
+ );
256
286
 
257
287
  return toolResult;
258
288
  }
@@ -269,7 +299,7 @@ export function createToolRouter<T extends ToolMap>(
269
299
  throw new Error(`Tool ${toolCall.name} not found`);
270
300
  }
271
301
 
272
- const parsedArgs = tool.schema.parse(toolCall.args);
302
+ const parsedArgs = resolve(tool.schema).parse(toolCall.args);
273
303
 
274
304
  return {
275
305
  id: toolCall.id ?? "",
@@ -294,8 +324,8 @@ export function createToolRouter<T extends ToolMap>(
294
324
  .filter(([, tool]) => isEnabled(tool))
295
325
  .map(([name, tool]) => ({
296
326
  name,
297
- description: tool.description,
298
- schema: tool.schema,
327
+ description: resolve(tool.description),
328
+ schema: resolve(tool.schema),
299
329
  strict: tool.strict,
300
330
  max_uses: tool.max_uses,
301
331
  }));
@@ -314,9 +344,7 @@ export function createToolRouter<T extends ToolMap>(
314
344
 
315
345
  if (options.parallel) {
316
346
  const results = await Promise.all(
317
- toolCalls.map((tc) =>
318
- processToolCall(tc, turn, sandboxId)
319
- )
347
+ toolCalls.map((tc) => processToolCall(tc, turn, sandboxId))
320
348
  );
321
349
  return results.filter(
322
350
  (r): r is NonNullable<typeof r> => r !== null
@@ -325,11 +353,7 @@ export function createToolRouter<T extends ToolMap>(
325
353
 
326
354
  const results: ToolCallResultUnion<TResults>[] = [];
327
355
  for (const toolCall of toolCalls) {
328
- const result = await processToolCall(
329
- toolCall,
330
- turn,
331
- sandboxId
332
- );
356
+ const result = await processToolCall(toolCall, turn, sandboxId);
333
357
  if (result !== null) {
334
358
  results.push(result);
335
359
  }
@@ -337,10 +361,7 @@ export function createToolRouter<T extends ToolMap>(
337
361
  return results;
338
362
  },
339
363
 
340
- async processToolCallsByName<
341
- TName extends ToolNames<T>,
342
- TResult,
343
- >(
364
+ async processToolCallsByName<TName extends ToolNames<T>, TResult>(
344
365
  toolCalls: ParsedToolCallUnion<T>[],
345
366
  toolName: TName,
346
367
  handler: ToolHandler<ToolArgs<T, TName>, TResult>,
@@ -359,7 +380,9 @@ export function createToolRouter<T extends ToolMap>(
359
380
  threadId: options.threadId,
360
381
  toolCallId: toolCall.id,
361
382
  toolName: toolCall.name as TName,
362
- ...(context?.sandboxId !== undefined && { sandboxId: context.sandboxId }),
383
+ ...(context?.sandboxId !== undefined && {
384
+ sandboxId: context.sandboxId,
385
+ }),
363
386
  };
364
387
  const response = await handler(
365
388
  toolCall.args as ToolArgs<T, TName>,
@@ -367,12 +390,19 @@ export function createToolRouter<T extends ToolMap>(
367
390
  );
368
391
 
369
392
  if (!response.resultAppended) {
370
- await appendToolResult({
371
- threadId: options.threadId,
372
- toolCallId: toolCall.id,
373
- toolName: toolCall.name,
374
- content: response.toolResponse,
375
- });
393
+ await appendToolResult.executeWithOptions(
394
+ {
395
+ summary: `Append ${toolCall.name} result`,
396
+ },
397
+ [
398
+ {
399
+ threadId: options.threadId,
400
+ toolCallId: toolCall.id,
401
+ toolName: toolCall.name,
402
+ content: response.toolResponse,
403
+ },
404
+ ]
405
+ );
376
406
  }
377
407
 
378
408
  return {
@@ -4,6 +4,7 @@ import type {
4
4
  ToolResultConfig,
5
5
  } from "../types";
6
6
  import type { z } from "zod";
7
+ import type { ActivityFunctionWithOptions } from "@temporalio/workflow";
7
8
 
8
9
  // ============================================================================
9
10
  // Tool Definition Types
@@ -58,8 +59,8 @@ export type ToolMap = Record<
58
59
  string,
59
60
  {
60
61
  name: string;
61
- description: string;
62
- schema: z.ZodType;
62
+ description: string | (() => string);
63
+ schema: z.ZodType | (() => z.ZodType);
63
64
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
64
65
  handler: ToolHandler<any, any, any>;
65
66
  strict?: boolean;
@@ -114,7 +115,9 @@ export type ParsedToolCallUnion<T extends ToolMap> = {
114
115
  /**
115
116
  * Function signature for appending tool results to a thread.
116
117
  */
117
- export type AppendToolResultFn = (config: ToolResultConfig) => Promise<void>;
118
+ export type AppendToolResultFn = ActivityFunctionWithOptions<
119
+ (config: ToolResultConfig) => Promise<void>
120
+ >;
118
121
 
119
122
  /**
120
123
  * The response from a tool handler.
@@ -157,7 +160,11 @@ export interface RouterContext {
157
160
  * Receives the parsed args and a context that always includes {@link RouterContext}
158
161
  * fields, plus any additional properties when TContext extends RouterContext.
159
162
  */
160
- export type ToolHandler<TArgs, TResult, TContext extends RouterContext = RouterContext> = (
163
+ export type ToolHandler<
164
+ TArgs,
165
+ TResult,
166
+ TContext extends RouterContext = RouterContext,
167
+ > = (
161
168
  args: TArgs,
162
169
  context: TContext
163
170
  ) => ToolHandlerResponse<TResult> | Promise<ToolHandlerResponse<TResult>>;
@@ -392,7 +399,8 @@ export interface ToolRouterOptions<T extends ToolMap> {
392
399
  tools: T;
393
400
  /** Thread ID for appending tool results */
394
401
  threadId: string;
395
- /** Function to append tool results to the thread (called automatically after each handler) */
402
+ /** Function to append tool results to the thread (called automatically after each handler).
403
+ * Accepts a Temporal activity proxy with {@link ActivityFunctionWithOptions}. */
396
404
  appendToolResult: AppendToolResultFn;
397
405
  /** Whether to process tools in parallel (default: true) */
398
406
  parallel?: boolean;
@@ -445,10 +453,7 @@ export interface ToolRouter<T extends ToolMap> {
445
453
  * Process tool calls matching a specific name with a custom handler.
446
454
  * Useful for overriding the default handler for specific cases.
447
455
  */
448
- processToolCallsByName<
449
- TName extends ToolNames<T>,
450
- TResult,
451
- >(
456
+ processToolCallsByName<TName extends ToolNames<T>, TResult>(
452
457
  toolCalls: ParsedToolCallUnion<T>[],
453
458
  toolName: TName,
454
459
  handler: ToolHandler<ToolArgs<T, TName>, TResult>,
@@ -5,11 +5,13 @@ import {
5
5
  type WorkflowSessionInput,
6
6
  } from "./workflow";
7
7
 
8
+ const cfg = { name: "test-workflow" };
9
+
8
10
  describe("defineWorkflow", () => {
9
11
  it("maps previousThreadId to threadId + continueThread", async () => {
10
12
  let capturedSession: WorkflowSessionInput | undefined;
11
13
 
12
- const workflow = defineWorkflow(async (_input, sessionInput) => {
14
+ const workflow = defineWorkflow(cfg, async (_input, sessionInput) => {
13
15
  capturedSession = sessionInput;
14
16
  return { ok: true };
15
17
  });
@@ -25,7 +27,7 @@ describe("defineWorkflow", () => {
25
27
  it("maps sandboxId", async () => {
26
28
  let capturedSession: WorkflowSessionInput | undefined;
27
29
 
28
- const workflow = defineWorkflow(async (_input, sessionInput) => {
30
+ const workflow = defineWorkflow(cfg, async (_input, sessionInput) => {
29
31
  capturedSession = sessionInput;
30
32
  return { ok: true };
31
33
  });
@@ -38,7 +40,7 @@ describe("defineWorkflow", () => {
38
40
  it("maps both previousThreadId and sandboxId together", async () => {
39
41
  let capturedSession: WorkflowSessionInput | undefined;
40
42
 
41
- const workflow = defineWorkflow(async (_input, sessionInput) => {
43
+ const workflow = defineWorkflow(cfg, async (_input, sessionInput) => {
42
44
  capturedSession = sessionInput;
43
45
  return { ok: true };
44
46
  });
@@ -55,7 +57,7 @@ describe("defineWorkflow", () => {
55
57
  it("returns empty sessionInput when no previousThreadId or sandboxId", async () => {
56
58
  let capturedSession: WorkflowSessionInput | undefined;
57
59
 
58
- const workflow = defineWorkflow(async (_input, sessionInput) => {
60
+ const workflow = defineWorkflow(cfg, async (_input, sessionInput) => {
59
61
  capturedSession = sessionInput;
60
62
  return { ok: true };
61
63
  });
@@ -73,7 +75,7 @@ describe("defineWorkflow", () => {
73
75
  metadata: { key: string };
74
76
  previousThreadId?: string;
75
77
  sandboxId?: string;
76
- }, { ok: boolean }>(async (input, _sessionInput) => {
78
+ }, { ok: boolean }>(cfg, async (input, _sessionInput) => {
77
79
  capturedInput = input;
78
80
  return { ok: true };
79
81
  });
@@ -94,6 +96,7 @@ describe("defineWorkflow", () => {
94
96
  let capturedSession: WorkflowSessionInput | undefined;
95
97
 
96
98
  const workflow = defineWorkflow<{ prompt: string }, { ok: boolean }>(
99
+ cfg,
97
100
  async (input, sessionInput) => {
98
101
  capturedInput = input;
99
102
  capturedSession = sessionInput;
@@ -116,7 +119,7 @@ describe("defineWorkflow", () => {
116
119
  });
117
120
 
118
121
  it("returns the handler response unchanged", async () => {
119
- const workflow = defineWorkflow(async () => ({
122
+ const workflow = defineWorkflow(cfg, async () => ({
120
123
  finalMessage: "result text",
121
124
  threadId: "thread-123",
122
125
  }));
@@ -128,4 +131,13 @@ describe("defineWorkflow", () => {
128
131
  threadId: "thread-123",
129
132
  });
130
133
  });
134
+
135
+ it("sets the function name from config", () => {
136
+ const workflow = defineWorkflow(
137
+ { name: "my-main-workflow" },
138
+ async () => ({}),
139
+ );
140
+
141
+ expect(workflow.name).toBe("my-main-workflow");
142
+ });
131
143
  });
@@ -19,20 +19,26 @@ export interface WorkflowInput {
19
19
  sandboxId?: string;
20
20
  }
21
21
 
22
+ export interface WorkflowConfig {
23
+ /** Workflow name — used as the Temporal workflow function name */
24
+ name: string;
25
+ }
26
+
22
27
  /**
23
28
  * Wraps a main workflow function, translating workflow input fields into
24
29
  * session-compatible fields that can be spread directly into `createSession`.
25
30
  *
26
31
  * The wrapper:
27
- * - Accepts a generic typed `input` as first argument
28
- * - Accepts optional `workflowInput` ({ previousThreadId, sandboxId }) as second argument
32
+ * - Accepts a `config` with at least a `name` (used for Temporal workflow naming)
33
+ * - Accepts a handler `fn` receiving `(input, sessionInput)`
29
34
  * - Derives `threadId` + `continueThread` from `workflowInput.previousThreadId`
30
35
  * - Derives `sandboxId` from `workflowInput.sandboxId`
31
36
  */
32
37
  export function defineWorkflow<TInput, TResult>(
38
+ config: WorkflowConfig,
33
39
  fn: (input: TInput, sessionInput: WorkflowSessionInput) => Promise<TResult>,
34
40
  ): (input: TInput, workflowInput?: WorkflowInput) => Promise<TResult> {
35
- return async (input, workflowInput = {}) => {
41
+ const workflow = async (input: TInput, workflowInput: WorkflowInput = {}) => {
36
42
  const sessionInput: WorkflowSessionInput = {
37
43
  ...(workflowInput.previousThreadId && {
38
44
  threadId: workflowInput.previousThreadId,
@@ -42,4 +48,8 @@ export function defineWorkflow<TInput, TResult>(
42
48
  };
43
49
  return fn(input, sessionInput);
44
50
  };
51
+
52
+ Object.defineProperty(workflow, "name", { value: config.name });
53
+
54
+ return workflow;
45
55
  }
@@ -1,11 +1,8 @@
1
- import type {
2
- AgentStateManager,
3
- JsonSerializable,
4
- } from "../../lib/state";
1
+ import type { AgentStateManager, JsonSerializable } from "../../lib/state";
5
2
  import type { ToolHandler } from "../../lib/tool-router";
6
3
  import type { WorkflowTask } from "../../lib/types";
4
+ import { getShortId } from "../../workflow";
7
5
  import type { TaskCreateArgs } from "./tool";
8
- import { uuid4 } from "@temporalio/workflow";
9
6
 
10
7
  /**
11
8
  * Creates a TaskCreate handler that adds tasks to the workflow state.
@@ -20,7 +17,7 @@ export function createTaskCreateHandler<
20
17
  ): ToolHandler<TaskCreateArgs, WorkflowTask> {
21
18
  return (args) => {
22
19
  const task: WorkflowTask = {
23
- id: uuid4(),
20
+ id: getShortId(),
24
21
  subject: args.subject,
25
22
  description: args.description,
26
23
  activeForm: args.activeForm,
package/src/workflow.ts CHANGED
@@ -26,10 +26,10 @@ export {
26
26
  } from "./lib/session";
27
27
  export type { ZeitlichSession, ThreadOps, SessionConfig } from "./lib/session";
28
28
  export { defineWorkflow } from "./lib/workflow";
29
- export type { WorkflowInput, WorkflowSessionInput } from "./lib/workflow";
29
+ export type { WorkflowConfig, WorkflowInput, WorkflowSessionInput } from "./lib/workflow";
30
30
 
31
31
  // Thread utilities
32
- export { getShortId } from "./lib/thread";
32
+ export { getShortId } from "./lib/thread/id";
33
33
 
34
34
  // State management
35
35
  export { createAgentStateManager } from "./lib/state";