zeitlich 0.2.19 → 0.2.21

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 (64) 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 +69 -24
  10. package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
  11. package/dist/adapters/thread/google-genai/index.d.cts +10 -10
  12. package/dist/adapters/thread/google-genai/index.d.ts +10 -10
  13. package/dist/adapters/thread/google-genai/index.js +69 -24
  14. package/dist/adapters/thread/google-genai/index.js.map +1 -1
  15. package/dist/adapters/thread/langchain/index.cjs +76 -69
  16. package/dist/adapters/thread/langchain/index.cjs.map +1 -1
  17. package/dist/adapters/thread/langchain/index.d.cts +11 -11
  18. package/dist/adapters/thread/langchain/index.d.ts +11 -11
  19. package/dist/adapters/thread/langchain/index.js +76 -69
  20. package/dist/adapters/thread/langchain/index.js.map +1 -1
  21. package/dist/index.cjs +198 -118
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +14 -14
  24. package/dist/index.d.ts +14 -14
  25. package/dist/index.js +198 -118
  26. package/dist/index.js.map +1 -1
  27. package/dist/{queries-D8T4pEeu.d.ts → queries-6Avfh74U.d.ts} +1 -1
  28. package/dist/{queries-D22uWTOb.d.cts → queries-CHa2iv_I.d.cts} +1 -1
  29. package/dist/{types-CxWLeJTB.d.ts → types-BkAYmc96.d.ts} +6 -6
  30. package/dist/{types-CCfJb5Jl.d.cts → types-CES_30qx.d.cts} +6 -6
  31. package/dist/{types-DjT78Sdp.d.cts → types-YbL7JpEA.d.cts} +4 -2
  32. package/dist/{types-DjT78Sdp.d.ts → types-YbL7JpEA.d.ts} +4 -2
  33. package/dist/workflow.cjs +68 -34
  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 +68 -34
  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/google-genai/activities.ts +11 -9
  43. package/src/adapters/thread/google-genai/model-invoker.ts +6 -11
  44. package/src/adapters/thread/google-genai/thread-manager.ts +44 -29
  45. package/src/adapters/thread/langchain/activities.ts +6 -4
  46. package/src/adapters/thread/langchain/thread-manager.ts +55 -27
  47. package/src/lib/session/session-edge-cases.integration.test.ts +20 -2
  48. package/src/lib/session/session.integration.test.ts +16 -2
  49. package/src/lib/session/session.ts +7 -5
  50. package/src/lib/session/types.ts +9 -3
  51. package/src/lib/subagent/handler.ts +1 -1
  52. package/src/lib/subagent/subagent.integration.test.ts +5 -4
  53. package/src/lib/subagent/tool.ts +1 -1
  54. package/src/lib/thread/index.ts +0 -1
  55. package/src/lib/tool-router/auto-append-sandbox.integration.test.ts +20 -21
  56. package/src/lib/tool-router/auto-append.ts +3 -2
  57. package/src/lib/tool-router/router-edge-cases.integration.test.ts +64 -23
  58. package/src/lib/tool-router/router.integration.test.ts +60 -23
  59. package/src/lib/tool-router/router.ts +58 -29
  60. package/src/lib/tool-router/types.ts +12 -7
  61. package/src/lib/workflow.test.ts +18 -6
  62. package/src/lib/workflow.ts +13 -3
  63. package/src/tools/task-create/handler.ts +3 -6
  64. package/src/workflow.ts +2 -2
@@ -15,10 +15,7 @@ vi.mock("@temporalio/workflow", () => {
15
15
  err.nonRetryable = nonRetryable;
16
16
  return err;
17
17
  }
18
- static fromError(
19
- error: unknown,
20
- options?: { nonRetryable?: boolean },
21
- ) {
18
+ static fromError(error: unknown, options?: { nonRetryable?: boolean }) {
22
19
  const src = error instanceof Error ? error : new Error(String(error));
23
20
  const err = new MockApplicationFailure(src.message);
24
21
  err.nonRetryable = options?.nonRetryable;
@@ -45,7 +42,9 @@ const echoTool = defineTool({
45
42
  name: "Echo" as const,
46
43
  description: "Echoes back the input",
47
44
  schema: z.object({ text: z.string() }),
48
- handler: async (args: { text: string }): Promise<ToolHandlerResponse<{ echoed: string }>> => ({
45
+ handler: async (args: {
46
+ text: string;
47
+ }): Promise<ToolHandlerResponse<{ echoed: string }>> => ({
49
48
  toolResponse: `Echo: ${args.text}`,
50
49
  data: { echoed: args.text },
51
50
  }),
@@ -55,7 +54,10 @@ const mathTool = defineTool({
55
54
  name: "Add" as const,
56
55
  description: "Adds two numbers",
57
56
  schema: z.object({ a: z.number(), b: z.number() }),
58
- handler: async (args: { a: number; b: number }): Promise<ToolHandlerResponse<{ sum: number }>> => ({
57
+ handler: async (args: {
58
+ a: number;
59
+ b: number;
60
+ }): Promise<ToolHandlerResponse<{ sum: number }>> => ({
59
61
  toolResponse: `Sum: ${args.a + args.b}`,
60
62
  data: { sum: args.a + args.b },
61
63
  }),
@@ -65,7 +67,9 @@ const failingTool = defineTool({
65
67
  name: "Fail" as const,
66
68
  description: "Always fails",
67
69
  schema: z.object({ reason: z.string() }),
68
- handler: async (args: { reason: string }): Promise<ToolHandlerResponse<null>> => {
70
+ handler: async (args: {
71
+ reason: string;
72
+ }): Promise<ToolHandlerResponse<null>> => {
69
73
  throw new Error(args.reason);
70
74
  },
71
75
  });
@@ -86,9 +90,20 @@ function createTools() {
86
90
 
87
91
  function createAppendSpy() {
88
92
  const calls: ToolResultConfig[] = [];
89
- const fn: AppendToolResultFn = async (config) => {
90
- calls.push(config);
91
- };
93
+ const fn = Object.assign(
94
+ async (_id: string, config: ToolResultConfig) => {
95
+ calls.push(config);
96
+ },
97
+ {
98
+ executeWithOptions: (
99
+ _opts: unknown,
100
+ [, config]: [string, ToolResultConfig]
101
+ ) => {
102
+ calls.push(config);
103
+ return Promise.resolve();
104
+ },
105
+ }
106
+ ) as AppendToolResultFn;
92
107
  return { fn, calls };
93
108
  }
94
109
 
@@ -163,7 +178,7 @@ describe("createToolRouter integration", () => {
163
178
  });
164
179
 
165
180
  expect(() =>
166
- router.parseToolCall({ id: "tc-1", name: "Unknown", args: {} }),
181
+ router.parseToolCall({ id: "tc-1", name: "Unknown", args: {} })
167
182
  ).toThrow("Tool Unknown not found");
168
183
  });
169
184
 
@@ -175,7 +190,7 @@ describe("createToolRouter integration", () => {
175
190
  });
176
191
 
177
192
  expect(() =>
178
- router.parseToolCall({ id: "tc-1", name: "Echo", args: { text: 123 } }),
193
+ router.parseToolCall({ id: "tc-1", name: "Echo", args: { text: 123 } })
179
194
  ).toThrow();
180
195
  });
181
196
 
@@ -324,7 +339,7 @@ describe("createToolRouter integration", () => {
324
339
  toolCallId: "tc-99",
325
340
  toolName: "Spy",
326
341
  sandboxId: "sandbox-1",
327
- }),
342
+ })
328
343
  );
329
344
  });
330
345
 
@@ -352,12 +367,18 @@ describe("createToolRouter integration", () => {
352
367
  },
353
368
  });
354
369
 
355
- const parsed = router.parseToolCall({ id: "tc-1", name: "Skippable", args: {} });
370
+ const parsed = router.parseToolCall({
371
+ id: "tc-1",
372
+ name: "Skippable",
373
+ args: {},
374
+ });
356
375
  const results = await router.processToolCalls([parsed], { turn: 1 });
357
376
 
358
377
  expect(handlerSpy).not.toHaveBeenCalled();
359
378
  expect(results).toHaveLength(0);
360
- expect(at(appendSpy.calls, 0).content).toContain("Skipped by PreToolUse hook");
379
+ expect(at(appendSpy.calls, 0).content).toContain(
380
+ "Skipped by PreToolUse hook"
381
+ );
361
382
  });
362
383
 
363
384
  it("pre-hook can modify arguments", async () => {
@@ -416,7 +437,11 @@ describe("createToolRouter integration", () => {
416
437
  appendToolResult: appendSpy.fn,
417
438
  });
418
439
 
419
- const parsed = router.parseToolCall({ id: "tc-1", name: "Hooked", args: {} });
440
+ const parsed = router.parseToolCall({
441
+ id: "tc-1",
442
+ name: "Hooked",
443
+ args: {},
444
+ });
420
445
  const results = await router.processToolCalls([parsed], { turn: 1 });
421
446
 
422
447
  expect(handlerSpy).not.toHaveBeenCalled();
@@ -445,7 +470,10 @@ describe("createToolRouter integration", () => {
445
470
  await router.processToolCalls([parsed], { turn: 1 });
446
471
 
447
472
  expect(hookData).not.toBeNull();
448
- const data = hookData as unknown as { result: { data: unknown }; durationMs: number };
473
+ const data = hookData as unknown as {
474
+ result: { data: unknown };
475
+ durationMs: number;
476
+ };
449
477
  expect(data.result.data).toEqual({ sum: 7 });
450
478
  expect(data.durationMs).toBeGreaterThanOrEqual(0);
451
479
  });
@@ -506,7 +534,10 @@ describe("createToolRouter integration", () => {
506
534
  const results = await router.processToolCalls([parsed], { turn: 1 });
507
535
 
508
536
  expect(results).toHaveLength(1);
509
- expect(at(results, 0).data).toEqual({ error: "Error: boom", recovered: true });
537
+ expect(at(results, 0).data).toEqual({
538
+ error: "Error: boom",
539
+ recovered: true,
540
+ });
510
541
  expect(at(appendSpy.calls, 0).content).toBe("recovered gracefully");
511
542
  });
512
543
 
@@ -515,7 +546,9 @@ describe("createToolRouter integration", () => {
515
546
  name: "Fail" as const,
516
547
  description: "fails but suppresses",
517
548
  schema: z.object({ reason: z.string() }),
518
- handler: async (args: { reason: string }): Promise<ToolHandlerResponse<null>> => {
549
+ handler: async (args: {
550
+ reason: string;
551
+ }): Promise<ToolHandlerResponse<null>> => {
519
552
  throw new Error(args.reason);
520
553
  },
521
554
  hooks: {
@@ -557,7 +590,7 @@ describe("createToolRouter integration", () => {
557
590
  });
558
591
 
559
592
  await expect(
560
- router.processToolCalls([parsed], { turn: 1 }),
593
+ router.processToolCalls([parsed], { turn: 1 })
561
594
  ).rejects.toThrow("unrecoverable");
562
595
  });
563
596
 
@@ -581,7 +614,7 @@ describe("createToolRouter integration", () => {
581
614
  expect(router.hasTool("Disabled")).toBe(false);
582
615
  expect(router.getToolNames()).not.toContain("Disabled");
583
616
  expect(() =>
584
- router.parseToolCall({ id: "tc-1", name: "Disabled", args: {} }),
617
+ router.parseToolCall({ id: "tc-1", name: "Disabled", args: {} })
585
618
  ).toThrow("Tool Disabled not found");
586
619
  });
587
620
 
@@ -638,7 +671,7 @@ describe("createToolRouter integration", () => {
638
671
  async (args: { text: string }) => ({
639
672
  toolResponse: `custom: ${args.text}`,
640
673
  data: { custom: args.text },
641
- }),
674
+ })
642
675
  );
643
676
 
644
677
  expect(results).toHaveLength(2);
@@ -691,7 +724,11 @@ describe("createToolRouter integration", () => {
691
724
  appendToolResult: appendSpy.fn,
692
725
  });
693
726
 
694
- const parsed = router.parseToolCall({ id: "tc-1", name: "SelfAppend", args: {} });
727
+ const parsed = router.parseToolCall({
728
+ id: "tc-1",
729
+ name: "SelfAppend",
730
+ args: {},
731
+ });
695
732
  await router.processToolCalls([parsed]);
696
733
 
697
734
  expect(appendSpy.calls).toHaveLength(0);
@@ -20,7 +20,7 @@ import type {
20
20
  } from "./types";
21
21
 
22
22
  import type { z } from "zod";
23
- import { ApplicationFailure } from "@temporalio/workflow";
23
+ import { ApplicationFailure, uuid4 } from "@temporalio/workflow";
24
24
 
25
25
  /**
26
26
  * Creates a tool router for declarative tool call processing.
@@ -63,7 +63,7 @@ export function createToolRouter<T extends ToolMap>(
63
63
  toolMap.set(tool.name, tool as T[keyof T]);
64
64
  }
65
65
 
66
- const resolve = <T,>(v: T | (() => T)): T =>
66
+ const resolve = <T>(v: T | (() => T)): T =>
67
67
  typeof v === "function" ? (v as () => T)() : v;
68
68
 
69
69
  const isEnabled = (tool: ToolMap[string]): boolean =>
@@ -130,7 +130,10 @@ export function createToolRouter<T extends ToolMap>(
130
130
  turn,
131
131
  });
132
132
  if (r?.fallbackContent !== undefined)
133
- return { content: r.fallbackContent, result: { error: errorStr, recovered: true } };
133
+ return {
134
+ content: r.fallbackContent,
135
+ result: { error: errorStr, recovered: true },
136
+ };
134
137
  if (r?.suppress)
135
138
  return {
136
139
  content: JSON.stringify({ error: errorStr, suppressed: true }),
@@ -146,7 +149,10 @@ export function createToolRouter<T extends ToolMap>(
146
149
  turn,
147
150
  });
148
151
  if (r?.fallbackContent !== undefined)
149
- return { content: r.fallbackContent, result: { error: errorStr, recovered: true } };
152
+ return {
153
+ content: r.fallbackContent,
154
+ result: { error: errorStr, recovered: true },
155
+ };
150
156
  if (r?.suppress)
151
157
  return {
152
158
  content: JSON.stringify({ error: errorStr, suppressed: true }),
@@ -197,11 +203,14 @@ export function createToolRouter<T extends ToolMap>(
197
203
  // --- Pre-hooks: may skip or modify args ---
198
204
  const preResult = await runPreHooks(toolCall, tool, turn);
199
205
  if (preResult.skip) {
200
- await appendToolResult({
206
+ await appendToolResult(uuid4(), {
201
207
  threadId: options.threadId,
202
208
  toolCallId: toolCall.id,
203
209
  toolName: toolCall.name,
204
- content: JSON.stringify({ skipped: true, reason: "Skipped by PreToolUse hook" }),
210
+ content: JSON.stringify({
211
+ skipped: true,
212
+ reason: "Skipped by PreToolUse hook",
213
+ }),
205
214
  });
206
215
  return null;
207
216
  }
@@ -232,19 +241,31 @@ export function createToolRouter<T extends ToolMap>(
232
241
  content = JSON.stringify(result, null, 2);
233
242
  }
234
243
  } catch (error) {
235
- 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
+ );
236
251
  result = recovery.result;
237
252
  content = recovery.content;
238
253
  }
239
254
 
240
255
  // --- Append result to thread (unless handler already did) ---
241
256
  if (!resultAppended) {
242
- await appendToolResult({
257
+ const config = {
243
258
  threadId: options.threadId,
244
259
  toolCallId: toolCall.id,
245
260
  toolName: toolCall.name,
246
261
  content,
247
- });
262
+ };
263
+ await appendToolResult.executeWithOptions(
264
+ {
265
+ summary: `Append ${toolCall.name} result`,
266
+ },
267
+ [uuid4(), config]
268
+ );
248
269
  }
249
270
 
250
271
  const toolResult = {
@@ -254,7 +275,14 @@ export function createToolRouter<T extends ToolMap>(
254
275
  } as ToolCallResultUnion<TResults>;
255
276
 
256
277
  // --- Post-hooks ---
257
- 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
+ );
258
286
 
259
287
  return toolResult;
260
288
  }
@@ -316,9 +344,7 @@ export function createToolRouter<T extends ToolMap>(
316
344
 
317
345
  if (options.parallel) {
318
346
  const results = await Promise.all(
319
- toolCalls.map((tc) =>
320
- processToolCall(tc, turn, sandboxId)
321
- )
347
+ toolCalls.map((tc) => processToolCall(tc, turn, sandboxId))
322
348
  );
323
349
  return results.filter(
324
350
  (r): r is NonNullable<typeof r> => r !== null
@@ -327,11 +353,7 @@ export function createToolRouter<T extends ToolMap>(
327
353
 
328
354
  const results: ToolCallResultUnion<TResults>[] = [];
329
355
  for (const toolCall of toolCalls) {
330
- const result = await processToolCall(
331
- toolCall,
332
- turn,
333
- sandboxId
334
- );
356
+ const result = await processToolCall(toolCall, turn, sandboxId);
335
357
  if (result !== null) {
336
358
  results.push(result);
337
359
  }
@@ -339,10 +361,7 @@ export function createToolRouter<T extends ToolMap>(
339
361
  return results;
340
362
  },
341
363
 
342
- async processToolCallsByName<
343
- TName extends ToolNames<T>,
344
- TResult,
345
- >(
364
+ async processToolCallsByName<TName extends ToolNames<T>, TResult>(
346
365
  toolCalls: ParsedToolCallUnion<T>[],
347
366
  toolName: TName,
348
367
  handler: ToolHandler<ToolArgs<T, TName>, TResult>,
@@ -361,7 +380,9 @@ export function createToolRouter<T extends ToolMap>(
361
380
  threadId: options.threadId,
362
381
  toolCallId: toolCall.id,
363
382
  toolName: toolCall.name as TName,
364
- ...(context?.sandboxId !== undefined && { sandboxId: context.sandboxId }),
383
+ ...(context?.sandboxId !== undefined && {
384
+ sandboxId: context.sandboxId,
385
+ }),
365
386
  };
366
387
  const response = await handler(
367
388
  toolCall.args as ToolArgs<T, TName>,
@@ -369,12 +390,20 @@ export function createToolRouter<T extends ToolMap>(
369
390
  );
370
391
 
371
392
  if (!response.resultAppended) {
372
- await appendToolResult({
373
- threadId: options.threadId,
374
- toolCallId: toolCall.id,
375
- toolName: toolCall.name,
376
- content: response.toolResponse,
377
- });
393
+ await appendToolResult.executeWithOptions(
394
+ {
395
+ summary: `Append ${toolCall.name} result`,
396
+ },
397
+ [
398
+ uuid4(),
399
+ {
400
+ threadId: options.threadId,
401
+ toolCallId: toolCall.id,
402
+ toolName: toolCall.name,
403
+ content: response.toolResponse,
404
+ },
405
+ ]
406
+ );
378
407
  }
379
408
 
380
409
  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
@@ -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
+ (id: string, 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";