zeitlich 0.2.21 → 0.2.22

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 (117) hide show
  1. package/README.md +70 -55
  2. package/dist/adapters/sandbox/daytona/index.cjs +3 -0
  3. package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
  4. package/dist/adapters/sandbox/daytona/index.d.cts +2 -1
  5. package/dist/adapters/sandbox/daytona/index.d.ts +2 -1
  6. package/dist/adapters/sandbox/daytona/index.js +3 -0
  7. package/dist/adapters/sandbox/daytona/index.js.map +1 -1
  8. package/dist/adapters/sandbox/daytona/workflow.cjs +32 -0
  9. package/dist/adapters/sandbox/daytona/workflow.cjs.map +1 -0
  10. package/dist/adapters/sandbox/daytona/workflow.d.cts +27 -0
  11. package/dist/adapters/sandbox/daytona/workflow.d.ts +27 -0
  12. package/dist/adapters/sandbox/daytona/workflow.js +30 -0
  13. package/dist/adapters/sandbox/daytona/workflow.js.map +1 -0
  14. package/dist/adapters/sandbox/inmemory/index.cjs +4 -1
  15. package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
  16. package/dist/adapters/sandbox/inmemory/index.d.cts +3 -2
  17. package/dist/adapters/sandbox/inmemory/index.d.ts +3 -2
  18. package/dist/adapters/sandbox/inmemory/index.js +4 -1
  19. package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
  20. package/dist/adapters/sandbox/inmemory/workflow.cjs +32 -0
  21. package/dist/adapters/sandbox/inmemory/workflow.cjs.map +1 -0
  22. package/dist/adapters/sandbox/inmemory/workflow.d.cts +25 -0
  23. package/dist/adapters/sandbox/inmemory/workflow.d.ts +25 -0
  24. package/dist/adapters/sandbox/inmemory/workflow.js +30 -0
  25. package/dist/adapters/sandbox/inmemory/workflow.js.map +1 -0
  26. package/dist/adapters/sandbox/virtual/index.cjs +3 -0
  27. package/dist/adapters/sandbox/virtual/index.cjs.map +1 -1
  28. package/dist/adapters/sandbox/virtual/index.d.cts +6 -4
  29. package/dist/adapters/sandbox/virtual/index.d.ts +6 -4
  30. package/dist/adapters/sandbox/virtual/index.js +3 -0
  31. package/dist/adapters/sandbox/virtual/index.js.map +1 -1
  32. package/dist/adapters/sandbox/virtual/workflow.cjs +32 -0
  33. package/dist/adapters/sandbox/virtual/workflow.cjs.map +1 -0
  34. package/dist/adapters/sandbox/virtual/workflow.d.cts +27 -0
  35. package/dist/adapters/sandbox/virtual/workflow.d.ts +27 -0
  36. package/dist/adapters/sandbox/virtual/workflow.js +30 -0
  37. package/dist/adapters/sandbox/virtual/workflow.js.map +1 -0
  38. package/dist/adapters/thread/google-genai/index.cjs +9 -1
  39. package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
  40. package/dist/adapters/thread/google-genai/index.d.cts +30 -18
  41. package/dist/adapters/thread/google-genai/index.d.ts +30 -18
  42. package/dist/adapters/thread/google-genai/index.js +9 -1
  43. package/dist/adapters/thread/google-genai/index.js.map +1 -1
  44. package/dist/adapters/thread/google-genai/workflow.cjs +33 -0
  45. package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -0
  46. package/dist/adapters/thread/google-genai/workflow.d.cts +32 -0
  47. package/dist/adapters/thread/google-genai/workflow.d.ts +32 -0
  48. package/dist/adapters/thread/google-genai/workflow.js +31 -0
  49. package/dist/adapters/thread/google-genai/workflow.js.map +1 -0
  50. package/dist/adapters/thread/langchain/index.cjs +9 -1
  51. package/dist/adapters/thread/langchain/index.cjs.map +1 -1
  52. package/dist/adapters/thread/langchain/index.d.cts +26 -15
  53. package/dist/adapters/thread/langchain/index.d.ts +26 -15
  54. package/dist/adapters/thread/langchain/index.js +9 -1
  55. package/dist/adapters/thread/langchain/index.js.map +1 -1
  56. package/dist/adapters/thread/langchain/workflow.cjs +33 -0
  57. package/dist/adapters/thread/langchain/workflow.cjs.map +1 -0
  58. package/dist/adapters/thread/langchain/workflow.d.cts +32 -0
  59. package/dist/adapters/thread/langchain/workflow.d.ts +32 -0
  60. package/dist/adapters/thread/langchain/workflow.js +31 -0
  61. package/dist/adapters/thread/langchain/workflow.js.map +1 -0
  62. package/dist/index.cjs +36 -34
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +35 -14
  65. package/dist/index.d.ts +35 -14
  66. package/dist/index.js +38 -34
  67. package/dist/index.js.map +1 -1
  68. package/dist/queries-Bw6WEPMw.d.cts +44 -0
  69. package/dist/queries-C27raDaB.d.ts +44 -0
  70. package/dist/{queries-CHa2iv_I.d.cts → types-BJ8itUAl.d.cts} +2 -43
  71. package/dist/{types-BkAYmc96.d.ts → types-C5bkx6kQ.d.ts} +33 -5
  72. package/dist/{types-CES_30qx.d.cts → types-ClsHhtwL.d.cts} +33 -5
  73. package/dist/{queries-6Avfh74U.d.ts → types-ENYCKFBk.d.ts} +2 -43
  74. package/dist/{types-BMRzfELQ.d.cts → types-HBosetv3.d.cts} +15 -1
  75. package/dist/{types-BMRzfELQ.d.ts → types-HBosetv3.d.ts} +15 -1
  76. package/dist/workflow.cjs +4 -30
  77. package/dist/workflow.cjs.map +1 -1
  78. package/dist/workflow.d.cts +13 -41
  79. package/dist/workflow.d.ts +13 -41
  80. package/dist/workflow.js +6 -30
  81. package/dist/workflow.js.map +1 -1
  82. package/package.json +53 -1
  83. package/src/adapters/sandbox/daytona/index.ts +4 -0
  84. package/src/adapters/sandbox/daytona/proxy.ts +55 -0
  85. package/src/adapters/sandbox/e2b/filesystem.ts +147 -0
  86. package/src/adapters/sandbox/e2b/index.ts +159 -0
  87. package/src/adapters/sandbox/e2b/types.ts +23 -0
  88. package/src/adapters/sandbox/inmemory/index.ts +5 -1
  89. package/src/adapters/sandbox/inmemory/proxy.ts +53 -0
  90. package/src/adapters/sandbox/virtual/provider.ts +5 -1
  91. package/src/adapters/sandbox/virtual/proxy.ts +52 -0
  92. package/src/adapters/thread/google-genai/activities.ts +51 -17
  93. package/src/adapters/thread/google-genai/index.ts +1 -0
  94. package/src/adapters/thread/google-genai/proxy.ts +61 -0
  95. package/src/adapters/thread/langchain/activities.ts +47 -14
  96. package/src/adapters/thread/langchain/index.ts +1 -0
  97. package/src/adapters/thread/langchain/proxy.ts +61 -0
  98. package/src/lib/sandbox/manager.ts +40 -6
  99. package/src/lib/sandbox/sandbox.test.ts +12 -11
  100. package/src/lib/sandbox/types.ts +18 -0
  101. package/src/lib/session/index.ts +3 -5
  102. package/src/lib/session/session-edge-cases.integration.test.ts +45 -34
  103. package/src/lib/session/session.integration.test.ts +40 -48
  104. package/src/lib/session/session.ts +4 -66
  105. package/src/lib/session/types.ts +32 -1
  106. package/src/lib/subagent/define.ts +1 -1
  107. package/src/lib/subagent/handler.ts +9 -2
  108. package/src/lib/subagent/index.ts +1 -0
  109. package/src/lib/subagent/subagent.integration.test.ts +62 -0
  110. package/src/lib/subagent/types.ts +7 -2
  111. package/src/lib/tool-router/router-edge-cases.integration.test.ts +4 -1
  112. package/src/lib/tool-router/router.integration.test.ts +4 -1
  113. package/src/lib/workflow.test.ts +19 -10
  114. package/src/lib/workflow.ts +4 -1
  115. package/src/tools/bash/bash.test.ts +16 -7
  116. package/src/workflow.ts +6 -14
  117. package/tsup.config.ts +6 -0
@@ -56,12 +56,11 @@ type TurnScript = {
56
56
  * Wraps every method on a ThreadOps object so it also has `.executeWithOptions()`,
57
57
  * matching Temporal's `ActivityInterfaceFor<ThreadOps>` shape.
58
58
  */
59
- function toActivityInterface(
60
- raw: ThreadOps,
61
- ): ActivityInterfaceFor<ThreadOps> {
59
+ function toActivityInterface(raw: ThreadOps): ActivityInterfaceFor<ThreadOps> {
62
60
  const result = {} as Record<string, unknown>;
63
61
  for (const [key, fn] of Object.entries(raw)) {
64
- const wrapped = (...args: unknown[]) => (fn as (...a: unknown[]) => unknown)(...args);
62
+ const wrapped = (...args: unknown[]) =>
63
+ (fn as (...a: unknown[]) => unknown)(...args);
65
64
  wrapped.executeWithOptions = (_opts: unknown, args: unknown[]) =>
66
65
  (fn as (...a: unknown[]) => unknown)(...args);
67
66
  result[key] = wrapped;
@@ -75,14 +74,14 @@ function createMockThreadOps() {
75
74
  initializeThread: async (threadId) => {
76
75
  log.push({ op: "initializeThread", args: [threadId] });
77
76
  },
78
- appendHumanMessage: async (threadId, content) => {
79
- log.push({ op: "appendHumanMessage", args: [threadId, content] });
77
+ appendHumanMessage: async (threadId, id, content) => {
78
+ log.push({ op: "appendHumanMessage", args: [threadId, id, content] });
80
79
  },
81
- appendToolResult: async (config) => {
82
- log.push({ op: "appendToolResult", args: [config] });
80
+ appendToolResult: async (id, config) => {
81
+ log.push({ op: "appendToolResult", args: [id, config] });
83
82
  },
84
- appendSystemMessage: async (threadId, content) => {
85
- log.push({ op: "appendSystemMessage", args: [threadId, content] });
83
+ appendSystemMessage: async (threadId, id, content) => {
84
+ log.push({ op: "appendSystemMessage", args: [threadId, id, content] });
86
85
  },
87
86
  forkThread: async (source, target) => {
88
87
  log.push({ op: "forkThread", args: [source, target] });
@@ -91,7 +90,9 @@ function createMockThreadOps() {
91
90
  return { ops, log };
92
91
  }
93
92
 
94
- function createScriptedRunAgent(turns: TurnScript[]): RunAgentActivity<unknown> {
93
+ function createScriptedRunAgent(
94
+ turns: TurnScript[]
95
+ ): RunAgentActivity<unknown> {
95
96
  let call = 0;
96
97
  return async () => {
97
98
  const turn = turns[call++];
@@ -113,7 +114,7 @@ function createEchoTool() {
113
114
  schema: z.object({ text: z.string() }),
114
115
  handler: async (
115
116
  args: { text: string },
116
- _ctx: RouterContext,
117
+ _ctx: RouterContext
117
118
  ): Promise<ToolHandlerResponse<{ echoed: string }>> => ({
118
119
  toolResponse: `Echo: ${args.text}`,
119
120
  data: { echoed: args.text },
@@ -216,8 +217,11 @@ describe("createSession edge cases", () => {
216
217
 
217
218
  const errorResults = log.filter((l) => {
218
219
  if (l.op !== "appendToolResult") return false;
219
- const config = l.args[0] as ToolResultConfig;
220
- return typeof config.content === "string" && config.content.includes("Invalid tool call");
220
+ const config = l.args[1] as ToolResultConfig;
221
+ return (
222
+ typeof config.content === "string" &&
223
+ config.content.includes("Invalid tool call")
224
+ );
221
225
  });
222
226
  expect(errorResults).toHaveLength(2);
223
227
  });
@@ -365,7 +369,7 @@ describe("createSession edge cases", () => {
365
369
  });
366
370
 
367
371
  await expect(session.runSession({ stateManager })).rejects.toThrow(
368
- "unrecoverable tool",
372
+ "unrecoverable tool"
369
373
  );
370
374
  expect(endReason).toBe("failed");
371
375
  });
@@ -381,9 +385,7 @@ describe("createSession edge cases", () => {
381
385
  agentName: "TestAgent",
382
386
  threadId: "thread-1",
383
387
  metadata: { env: "test", version: 42 },
384
- runAgent: createScriptedRunAgent([
385
- { message: "done", toolCalls: [] },
386
- ]),
388
+ runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
387
389
  threadOps: ops,
388
390
  buildContextMessage: () => "go",
389
391
  hooks: {
@@ -422,6 +424,7 @@ describe("createSession edge cases", () => {
422
424
  data: null,
423
425
  createdAt: new Date().toISOString(),
424
426
  }),
427
+ forkSandbox: async () => "forked-sandbox-id",
425
428
  };
426
429
 
427
430
  const session = await createSession({
@@ -438,7 +441,7 @@ describe("createSession edge cases", () => {
438
441
  });
439
442
 
440
443
  await expect(session.runSession({ stateManager })).rejects.toThrow(
441
- "sandbox creation failed",
444
+ "sandbox creation failed"
442
445
  );
443
446
  });
444
447
 
@@ -462,6 +465,7 @@ describe("createSession edge cases", () => {
462
465
  data: null,
463
466
  createdAt: new Date().toISOString(),
464
467
  }),
468
+ forkSandbox: async () => "forked-sandbox-id",
465
469
  };
466
470
 
467
471
  const session = await createSession({
@@ -480,7 +484,7 @@ describe("createSession edge cases", () => {
480
484
  });
481
485
 
482
486
  await expect(session.runSession({ stateManager })).rejects.toThrow(
483
- "LLM crash",
487
+ "LLM crash"
484
488
  );
485
489
 
486
490
  expect(sandboxLog).toContain("create");
@@ -505,7 +509,7 @@ describe("createSession edge cases", () => {
505
509
  });
506
510
 
507
511
  await expect(session.runSession({ stateManager })).rejects.toThrow(
508
- "No system prompt in state",
512
+ "No system prompt in state"
509
513
  );
510
514
  });
511
515
 
@@ -700,24 +704,27 @@ describe("createSession edge cases", () => {
700
704
 
701
705
  const toolResults = log.filter((l) => l.op === "appendToolResult");
702
706
  const echoResult = toolResults.find((l) => {
703
- const config = l.args[0] as ToolResultConfig;
707
+ const config = l.args[1] as ToolResultConfig;
704
708
  return config.toolName === "Echo";
705
709
  });
706
710
  expect(echoResult).toBeDefined();
707
711
  if (echoResult) {
708
- expect((echoResult.args[0] as ToolResultConfig).content).toBe("Echo: valid");
712
+ expect((echoResult.args[1] as ToolResultConfig).content).toBe(
713
+ "Echo: valid"
714
+ );
709
715
  }
710
716
 
711
717
  const unknownResult = toolResults.find((l) => {
712
- const config = l.args[0] as ToolResultConfig;
718
+ const config = l.args[1] as ToolResultConfig;
713
719
  return config.toolName === "Unknown";
714
720
  });
715
721
  expect(unknownResult).toBeDefined();
716
722
  const unknownContent = unknownResult
717
- ? (unknownResult.args[0] as ToolResultConfig).content
723
+ ? (unknownResult.args[1] as ToolResultConfig).content
718
724
  : undefined;
719
725
  expect(
720
- typeof unknownContent === "string" && unknownContent.includes("Invalid tool call"),
726
+ typeof unknownContent === "string" &&
727
+ unknownContent.includes("Invalid tool call")
721
728
  ).toBe(true);
722
729
  });
723
730
 
@@ -729,9 +736,7 @@ describe("createSession edge cases", () => {
729
736
  const session = await createSession({
730
737
  agentName: "TestAgent",
731
738
  threadId: "thread-1",
732
- runAgent: createScriptedRunAgent([
733
- { message: "done", toolCalls: [] },
734
- ]),
739
+ runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
735
740
  threadOps: ops,
736
741
  buildContextMessage: () => [
737
742
  { type: "text", text: "Hello" },
@@ -749,7 +754,7 @@ describe("createSession edge cases", () => {
749
754
  expect(humanOps).toHaveLength(1);
750
755
  const humanOp = humanOps[0];
751
756
  if (!humanOp) throw new Error("expected human op");
752
- const content = humanOp.args[1];
757
+ const content = humanOp.args[2];
753
758
  expect(Array.isArray(content)).toBe(true);
754
759
  const firstContent = (content as { type: string }[])[0];
755
760
  if (!firstContent) throw new Error("expected content item");
@@ -834,7 +839,7 @@ describe("createSession edge cases", () => {
834
839
 
835
840
  const toolResults = log.filter((l) => {
836
841
  if (l.op !== "appendToolResult") return false;
837
- const config = l.args[0] as ToolResultConfig;
842
+ const config = l.args[1] as ToolResultConfig;
838
843
  return config.toolName === "SelfAppend";
839
844
  });
840
845
  expect(toolResults).toHaveLength(0);
@@ -860,7 +865,10 @@ describe("createSession edge cases", () => {
860
865
  buildContextMessage: () => "go",
861
866
  hooks: {
862
867
  onPreToolUse: async ({ toolCall }) => {
863
- if (toolCall.args && (toolCall.args as { text: string }).text === "skip-me") {
868
+ if (
869
+ toolCall.args &&
870
+ (toolCall.args as { text: string }).text === "skip-me"
871
+ ) {
864
872
  return { skip: true };
865
873
  }
866
874
  return {};
@@ -878,8 +886,10 @@ describe("createSession edge cases", () => {
878
886
  expect(toolResults).toHaveLength(1);
879
887
  const toolResult = toolResults[0];
880
888
  if (!toolResult) throw new Error("expected tool result");
881
- const content = (toolResult.args[0] as ToolResultConfig).content;
882
- expect(typeof content === "string" && content.includes("Skipped")).toBe(true);
889
+ const content = (toolResult.args[1] as ToolResultConfig).content;
890
+ expect(typeof content === "string" && content.includes("Skipped")).toBe(
891
+ true
892
+ );
883
893
  });
884
894
 
885
895
  // --- Sandbox snapshot is not called on normal flow ---
@@ -897,6 +907,7 @@ describe("createSession edge cases", () => {
897
907
  createSandbox: async () => ({ sandboxId: "sb-test" }),
898
908
  destroySandbox: async () => {},
899
909
  snapshotSandbox: snapshotSpy,
910
+ forkSandbox: async () => "forked-sandbox-id",
900
911
  };
901
912
 
902
913
  const session = await createSession({
@@ -39,7 +39,8 @@ vi.mock("@temporalio/workflow", () => {
39
39
  defineUpdate: (name: string) => ({ __type: "update", name }),
40
40
  defineQuery: (name: string) => ({ __type: "query", name }),
41
41
  setHandler: (_def: unknown, _handler: unknown) => {},
42
- uuid4: () => `00000000-0000-0000-0000-${String(++idCounter).padStart(12, "0")}`,
42
+ uuid4: () =>
43
+ `00000000-0000-0000-0000-${String(++idCounter).padStart(12, "0")}`,
43
44
  ApplicationFailure: MockApplicationFailure,
44
45
  };
45
46
  });
@@ -59,12 +60,11 @@ function at<T>(arr: T[], index: number): T {
59
60
  return val;
60
61
  }
61
62
 
62
- function toActivityInterface(
63
- raw: ThreadOps,
64
- ): ActivityInterfaceFor<ThreadOps> {
63
+ function toActivityInterface(raw: ThreadOps): ActivityInterfaceFor<ThreadOps> {
65
64
  const result = {} as Record<string, unknown>;
66
65
  for (const [key, fn] of Object.entries(raw)) {
67
- const wrapped = (...args: unknown[]) => (fn as (...a: unknown[]) => unknown)(...args);
66
+ const wrapped = (...args: unknown[]) =>
67
+ (fn as (...a: unknown[]) => unknown)(...args);
68
68
  wrapped.executeWithOptions = (_opts: unknown, args: unknown[]) =>
69
69
  (fn as (...a: unknown[]) => unknown)(...args);
70
70
  result[key] = wrapped;
@@ -79,14 +79,14 @@ function createMockThreadOps() {
79
79
  initializeThread: async (threadId) => {
80
80
  log.push({ op: "initializeThread", args: [threadId] });
81
81
  },
82
- appendHumanMessage: async (threadId, content) => {
83
- log.push({ op: "appendHumanMessage", args: [threadId, content] });
82
+ appendHumanMessage: async (threadId, id, content) => {
83
+ log.push({ op: "appendHumanMessage", args: [threadId, id, content] });
84
84
  },
85
- appendToolResult: async (config) => {
86
- log.push({ op: "appendToolResult", args: [config] });
85
+ appendToolResult: async (id, config) => {
86
+ log.push({ op: "appendToolResult", args: [id, config] });
87
87
  },
88
- appendSystemMessage: async (threadId, content) => {
89
- log.push({ op: "appendSystemMessage", args: [threadId, content] });
88
+ appendSystemMessage: async (threadId, id, content) => {
89
+ log.push({ op: "appendSystemMessage", args: [threadId, id, content] });
90
90
  },
91
91
  forkThread: async (source, target) => {
92
92
  log.push({ op: "forkThread", args: [source, target] });
@@ -102,7 +102,9 @@ type TurnScript = {
102
102
  usage?: TokenUsage;
103
103
  };
104
104
 
105
- function createScriptedRunAgent(turns: TurnScript[]): RunAgentActivity<unknown> {
105
+ function createScriptedRunAgent(
106
+ turns: TurnScript[]
107
+ ): RunAgentActivity<unknown> {
106
108
  let call = 0;
107
109
  return async () => {
108
110
  const turn = turns[call++];
@@ -124,7 +126,7 @@ function createEchoTool() {
124
126
  schema: z.object({ text: z.string() }),
125
127
  handler: async (
126
128
  args: { text: string },
127
- _ctx: RouterContext,
129
+ _ctx: RouterContext
128
130
  ): Promise<ToolHandlerResponse<{ echoed: string }>> => ({
129
131
  toolResponse: `Echo: ${args.text}`,
130
132
  data: { echoed: args.text },
@@ -149,9 +151,7 @@ describe("createSession integration", () => {
149
151
  const session = await createSession({
150
152
  agentName: "TestAgent",
151
153
  threadId: "thread-1",
152
- runAgent: createScriptedRunAgent([
153
- { message: "Hello!", toolCalls: [] },
154
- ]),
154
+ runAgent: createScriptedRunAgent([{ message: "Hello!", toolCalls: [] }]),
155
155
  threadOps: ops,
156
156
  buildContextMessage: () => "What is 2+2?",
157
157
  });
@@ -168,11 +168,11 @@ describe("createSession integration", () => {
168
168
 
169
169
  const systemOps = log.filter((l) => l.op === "appendSystemMessage");
170
170
  expect(systemOps).toHaveLength(1);
171
- expect(at(systemOps, 0).args[1]).toBe("You are a test assistant.");
171
+ expect(at(systemOps, 0).args[2]).toBe("You are a test assistant.");
172
172
 
173
173
  const humanOps = log.filter((l) => l.op === "appendHumanMessage");
174
174
  expect(humanOps).toHaveLength(1);
175
- expect(at(humanOps, 0).args[1]).toBe("What is 2+2?");
175
+ expect(at(humanOps, 0).args[2]).toBe("What is 2+2?");
176
176
  });
177
177
 
178
178
  // --- Tool execution ---
@@ -209,7 +209,7 @@ describe("createSession integration", () => {
209
209
 
210
210
  const toolResults = log.filter((l) => l.op === "appendToolResult");
211
211
  expect(toolResults).toHaveLength(1);
212
- const resultConfig = at(toolResults, 0).args[0] as ToolResultConfig;
212
+ const resultConfig = at(toolResults, 0).args[1] as ToolResultConfig;
213
213
  expect(resultConfig.toolName).toBe("Echo");
214
214
  expect(resultConfig.content).toBe("Echo: hello");
215
215
  });
@@ -265,7 +265,7 @@ describe("createSession integration", () => {
265
265
  Array.from({ length: 10 }, (_, i) => ({
266
266
  message: `turn ${i + 1}`,
267
267
  toolCalls: [{ id: `tc-${i}`, name: "Echo", args: { text: `${i}` } }],
268
- })),
268
+ }))
269
269
  );
270
270
 
271
271
  const session = await createSession({
@@ -298,9 +298,7 @@ describe("createSession integration", () => {
298
298
  const session = await createSession({
299
299
  agentName: "TestAgent",
300
300
  threadId: "thread-1",
301
- runAgent: createScriptedRunAgent([
302
- { message: "done", toolCalls: [] },
303
- ]),
301
+ runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
304
302
  threadOps: ops,
305
303
  buildContextMessage: () => "hi",
306
304
  hooks: {
@@ -343,7 +341,7 @@ describe("createSession integration", () => {
343
341
  });
344
342
 
345
343
  await expect(session.runSession({ stateManager })).rejects.toThrow(
346
- "No system prompt in state",
344
+ "No system prompt in state"
347
345
  );
348
346
  });
349
347
 
@@ -354,9 +352,7 @@ describe("createSession integration", () => {
354
352
  agentName: "TestAgent",
355
353
  threadId: "thread-1",
356
354
  appendSystemPrompt: false,
357
- runAgent: createScriptedRunAgent([
358
- { message: "ok", toolCalls: [] },
359
- ]),
355
+ runAgent: createScriptedRunAgent([{ message: "ok", toolCalls: [] }]),
360
356
  threadOps: ops,
361
357
  buildContextMessage: () => "hi",
362
358
  });
@@ -447,11 +443,11 @@ describe("createSession integration", () => {
447
443
  // One error result for bad call + one success result for good call
448
444
  expect(toolResults.length).toBeGreaterThanOrEqual(2);
449
445
  const errorResult = toolResults.find((l) => {
450
- const config = l.args[0] as ToolResultConfig;
446
+ const config = l.args[1] as ToolResultConfig;
451
447
  return config.toolCallId === "tc-bad";
452
448
  });
453
449
  expect(errorResult).toBeDefined();
454
- const errorConfig = errorResult?.args[0] as ToolResultConfig | undefined;
450
+ const errorConfig = errorResult?.args[1] as ToolResultConfig | undefined;
455
451
  expect(errorConfig?.content).toContain("Invalid tool call");
456
452
  });
457
453
 
@@ -507,14 +503,13 @@ describe("createSession integration", () => {
507
503
  data: null,
508
504
  createdAt: new Date().toISOString(),
509
505
  }),
506
+ forkSandbox: async () => "forked-sandbox-id",
510
507
  };
511
508
 
512
509
  const session = await createSession({
513
510
  agentName: "TestAgent",
514
511
  threadId: "thread-1",
515
- runAgent: createScriptedRunAgent([
516
- { message: "done", toolCalls: [] },
517
- ]),
512
+ runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
518
513
  threadOps: ops,
519
514
  buildContextMessage: () => "go",
520
515
  sandbox: sandboxOps,
@@ -548,14 +543,13 @@ describe("createSession integration", () => {
548
543
  data: null,
549
544
  createdAt: new Date().toISOString(),
550
545
  }),
546
+ forkSandbox: async () => "forked-sandbox-id",
551
547
  };
552
548
 
553
549
  const session = await createSession({
554
550
  agentName: "TestAgent",
555
551
  threadId: "thread-1",
556
- runAgent: createScriptedRunAgent([
557
- { message: "done", toolCalls: [] },
558
- ]),
552
+ runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
559
553
  threadOps: ops,
560
554
  buildContextMessage: () => "go",
561
555
  sandbox: sandboxOps,
@@ -638,7 +632,7 @@ describe("createSession integration", () => {
638
632
  });
639
633
 
640
634
  await expect(session.runSession({ stateManager })).rejects.toThrow(
641
- "LLM went down",
635
+ "LLM went down"
642
636
  );
643
637
 
644
638
  expect(endReason).toBe("failed");
@@ -690,9 +684,7 @@ describe("createSession integration", () => {
690
684
 
691
685
  const session = await createSession({
692
686
  agentName: "TestAgent",
693
- runAgent: createScriptedRunAgent([
694
- { message: "done", toolCalls: [] },
695
- ]),
687
+ runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
696
688
  threadOps: ops,
697
689
  buildContextMessage: () => "go",
698
690
  });
@@ -761,9 +753,7 @@ describe("createSession integration", () => {
761
753
  const session = await createSession({
762
754
  agentName: "TestAgent",
763
755
  threadId: "thread-1",
764
- runAgent: createScriptedRunAgent([
765
- { message: "done", toolCalls: [] },
766
- ]),
756
+ runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
767
757
  threadOps: ops,
768
758
  buildContextMessage: async () => {
769
759
  await new Promise((r) => setTimeout(r, 5));
@@ -778,7 +768,7 @@ describe("createSession integration", () => {
778
768
  await session.runSession({ stateManager });
779
769
 
780
770
  const humanOps = log.filter((l) => l.op === "appendHumanMessage");
781
- expect(at(humanOps, 0).args[1]).toBe("async context");
771
+ expect(at(humanOps, 0).args[2]).toBe("async context");
782
772
  });
783
773
 
784
774
  // --- Sandbox stateUpdate merge ---
@@ -798,14 +788,13 @@ describe("createSession integration", () => {
798
788
  data: null,
799
789
  createdAt: new Date().toISOString(),
800
790
  }),
791
+ forkSandbox: async () => "forked-sandbox-id",
801
792
  };
802
793
 
803
794
  const session = await createSession({
804
795
  agentName: "TestAgent",
805
796
  threadId: "thread-1",
806
- runAgent: createScriptedRunAgent([
807
- { message: "done", toolCalls: [] },
808
- ]),
797
+ runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
809
798
  threadOps: ops,
810
799
  buildContextMessage: () => "go",
811
800
  sandbox: sandboxOps,
@@ -845,7 +834,11 @@ describe("createSession integration", () => {
845
834
  toolCalls: [{ id: "tc-1", name: "UsageTool", args: {} }],
846
835
  usage: { inputTokens: 100, outputTokens: 50 },
847
836
  },
848
- { message: "done", toolCalls: [], usage: { inputTokens: 80, outputTokens: 40 } },
837
+ {
838
+ message: "done",
839
+ toolCalls: [],
840
+ usage: { inputTokens: 80, outputTokens: 40 },
841
+ },
849
842
  ]),
850
843
  threadOps: ops,
851
844
  tools: { UsageTool: usageTool },
@@ -864,4 +857,3 @@ describe("createSession integration", () => {
864
857
  expect(result.usage.totalOutputTokens).toBe(90);
865
858
  });
866
859
  });
867
-
@@ -1,14 +1,11 @@
1
1
  import {
2
- proxyActivities,
3
2
  condition,
4
3
  defineUpdate,
5
4
  setHandler,
6
5
  ApplicationFailure,
7
- type ActivityInterfaceFor,
8
6
  } from "@temporalio/workflow";
9
7
  import type { SessionExitReason, MessageContent } from "../types";
10
- import type { ThreadOps, SessionConfig, ZeitlichSession } from "./types";
11
- import type { SandboxOps } from "../sandbox/types";
8
+ import type { SessionConfig, ZeitlichSession } from "./types";
12
9
  import { type AgentStateManager, type JsonSerializable } from "../state/types";
13
10
  import { createToolRouter } from "../tool-router/router";
14
11
  import type { ParsedToolCallUnion, ToolMap } from "../tool-router/types";
@@ -27,16 +24,13 @@ import { uuid4 } from "@temporalio/workflow";
27
24
  * @example
28
25
  * ```typescript
29
26
  * import { createSession, createAgentStateManager, defineTool, bashTool } from 'zeitlich/workflow';
30
- *
31
- * const stateManager = createAgentStateManager({
32
- * initialState: { systemPrompt: "You are a helpful assistant." },
33
- * agentName: "my-agent",
34
- * });
27
+ * import { proxyGoogleGenAIThreadOps } from 'zeitlich/adapters/thread/google-genai/workflow';
35
28
  *
36
29
  * const session = await createSession({
37
30
  * agentName: "my-agent",
38
31
  * maxTurns: 20,
39
32
  * threadId: runId,
33
+ * threadOps: proxyGoogleGenAIThreadOps(), // auto-scoped to current workflow
40
34
  * runAgent: runAgentActivity,
41
35
  * buildContextMessage: () => [{ type: "text", text: prompt }],
42
36
  * subagents: [researcherSubagent],
@@ -79,7 +73,7 @@ export const createSession = async <T extends ToolMap, M = unknown>({
79
73
  initializeThread,
80
74
  appendSystemMessage,
81
75
  forkThread,
82
- } = threadOps ?? proxyDefaultThreadOps();
76
+ } = threadOps;
83
77
 
84
78
  const plugins: ToolMap[string][] = [];
85
79
  if (subagents) {
@@ -286,59 +280,3 @@ export const createSession = async <T extends ToolMap, M = unknown>({
286
280
  };
287
281
  };
288
282
 
289
- /**
290
- * Proxy the adapter's thread operations as Temporal activities.
291
- * Call this in workflow code to delegate thread operations to the
292
- * adapter-provided activities registered on the worker.
293
- *
294
- * @example
295
- * ```typescript
296
- * const session = await createSession({
297
- * threadOps: proxyDefaultThreadOps(),
298
- * // ...
299
- * });
300
- * ```
301
- */
302
- export function proxyDefaultThreadOps(
303
- options?: Parameters<typeof proxyActivities>[0]
304
- ): ActivityInterfaceFor<ThreadOps> {
305
- return proxyActivities<ThreadOps>(
306
- options ?? {
307
- startToCloseTimeout: "10s",
308
- retry: {
309
- maximumAttempts: 6,
310
- initialInterval: "5s",
311
- maximumInterval: "15m",
312
- backoffCoefficient: 4,
313
- },
314
- }
315
- );
316
- }
317
-
318
- /**
319
- * Proxy sandbox lifecycle operations as Temporal activities.
320
- * Call this in workflow code when the agent needs a sandbox.
321
- *
322
- * @example
323
- * ```typescript
324
- * const session = await createSession({
325
- * sandbox: proxySandboxOps(),
326
- * // ...
327
- * });
328
- * ```
329
- */
330
- export function proxySandboxOps(
331
- options?: Parameters<typeof proxyActivities>[0]
332
- ): SandboxOps {
333
- return proxyActivities<SandboxOps>(
334
- options ?? {
335
- startToCloseTimeout: "30s",
336
- retry: {
337
- maximumAttempts: 3,
338
- initialInterval: "2s",
339
- maximumInterval: "30s",
340
- backoffCoefficient: 2,
341
- },
342
- }
343
- );
344
- }
@@ -42,6 +42,37 @@ export interface ThreadOps {
42
42
  forkThread(sourceThreadId: string, targetThreadId: string): Promise<void>;
43
43
  }
44
44
 
45
+ /**
46
+ * Composes an adapter prefix + workflow scope for activity naming.
47
+ *
48
+ * The adapter prefix stays first (camelCase); the workflow scope is
49
+ * capitalised and appended. When `TScope` is empty the adapter prefix
50
+ * is used as-is.
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * ScopedPrefix<"codingAgent", "googleGenAI"> // "googleGenAICodingAgent"
55
+ * ScopedPrefix<"", "googleGenAI"> // "googleGenAI"
56
+ * ```
57
+ */
58
+ export type ScopedPrefix<
59
+ TScope extends string,
60
+ TAdapter extends string,
61
+ > = TScope extends "" ? TAdapter : `${TAdapter}${Capitalize<TScope>}`;
62
+
63
+ /**
64
+ * Maps generic {@link ThreadOps} method names to adapter-prefixed names.
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * type GoogleOps = PrefixedThreadOps<"googleGenAI">;
69
+ * // → { googleGenAIInitializeThread, googleGenAIAppendHumanMessage, … }
70
+ * ```
71
+ */
72
+ export type PrefixedThreadOps<TPrefix extends string> = {
73
+ [K in keyof ThreadOps as `${TPrefix}${Capitalize<K & string>}`]: ThreadOps[K];
74
+ };
75
+
45
76
  /**
46
77
  * Configuration for a Zeitlich agent session
47
78
  */
@@ -59,7 +90,7 @@ export interface SessionConfig<T extends ToolMap, M = unknown> {
59
90
  /** Workflow-specific runAgent activity (with tools pre-bound) */
60
91
  runAgent: RunAgentActivity<M>;
61
92
  /** Thread operations (initialize, append messages, parse tool calls) */
62
- threadOps?: ActivityInterfaceFor<ThreadOps>;
93
+ threadOps: ActivityInterfaceFor<ThreadOps>;
63
94
  /** Tool router for processing tool calls (optional if agent has no tools) */
64
95
  tools?: T;
65
96
  /** Subagent configurations */
@@ -38,7 +38,7 @@ export function defineSubagent<
38
38
  >(
39
39
  definition: SubagentDefinition<TResult, TContext>,
40
40
  overrides?: {
41
- context?: TContext;
41
+ context?: TContext | (() => TContext);
42
42
  hooks?: SubagentHooks<SubagentArgs, z.infer<TResult>>;
43
43
  enabled?: boolean | (() => boolean);
44
44
  taskQueue?: string;
@@ -47,12 +47,19 @@ export function createSubagentHandler<
47
47
  ...(inheritSandbox && { sandboxId: parentSandboxId }),
48
48
  };
49
49
 
50
+ const resolvedContext =
51
+ config.context === undefined
52
+ ? undefined
53
+ : typeof config.context === "function"
54
+ ? config.context()
55
+ : config.context;
56
+
50
57
  const childOpts = {
51
58
  workflowId: childWorkflowId,
52
59
  args:
53
- config.context === undefined
60
+ resolvedContext === undefined
54
61
  ? ([args.prompt, workflowInput] as const)
55
- : ([args.prompt, workflowInput, config.context] as const),
62
+ : ([args.prompt, workflowInput, resolvedContext] as const),
56
63
  taskQueue: config.taskQueue ?? parentTaskQueue,
57
64
  };
58
65
 
@@ -1,5 +1,6 @@
1
1
  export type {
2
2
  SubagentConfig,
3
+ SubagentContext,
3
4
  SubagentDefinition,
4
5
  SubagentHooks,
5
6
  SubagentHandlerResponse,