zeitlich 0.2.37 → 0.2.38

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 (131) hide show
  1. package/dist/{activities-Bb-nAjwQ.d.ts → activities-BKhMtKDd.d.ts} +4 -2
  2. package/dist/{activities-vkI4_3CC.d.cts → activities-CDcwkRZs.d.cts} +4 -2
  3. package/dist/adapters/sandbox/bedrock/index.cjs +3 -3
  4. package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
  5. package/dist/adapters/sandbox/bedrock/index.d.cts +6 -6
  6. package/dist/adapters/sandbox/bedrock/index.d.ts +6 -6
  7. package/dist/adapters/sandbox/bedrock/index.js +3 -3
  8. package/dist/adapters/sandbox/bedrock/index.js.map +1 -1
  9. package/dist/adapters/sandbox/bedrock/workflow.d.cts +2 -2
  10. package/dist/adapters/sandbox/bedrock/workflow.d.ts +2 -2
  11. package/dist/adapters/sandbox/daytona/index.cjs +3 -3
  12. package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
  13. package/dist/adapters/sandbox/daytona/index.d.cts +4 -4
  14. package/dist/adapters/sandbox/daytona/index.d.ts +4 -4
  15. package/dist/adapters/sandbox/daytona/index.js +3 -3
  16. package/dist/adapters/sandbox/daytona/index.js.map +1 -1
  17. package/dist/adapters/sandbox/daytona/workflow.d.cts +1 -1
  18. package/dist/adapters/sandbox/daytona/workflow.d.ts +1 -1
  19. package/dist/adapters/sandbox/e2b/index.cjs +26 -14
  20. package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
  21. package/dist/adapters/sandbox/e2b/index.d.cts +24 -4
  22. package/dist/adapters/sandbox/e2b/index.d.ts +24 -4
  23. package/dist/adapters/sandbox/e2b/index.js +26 -14
  24. package/dist/adapters/sandbox/e2b/index.js.map +1 -1
  25. package/dist/adapters/sandbox/e2b/workflow.d.cts +1 -1
  26. package/dist/adapters/sandbox/e2b/workflow.d.ts +1 -1
  27. package/dist/adapters/sandbox/inmemory/index.cjs +3 -3
  28. package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
  29. package/dist/adapters/sandbox/inmemory/index.d.cts +4 -4
  30. package/dist/adapters/sandbox/inmemory/index.d.ts +4 -4
  31. package/dist/adapters/sandbox/inmemory/index.js +3 -3
  32. package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
  33. package/dist/adapters/sandbox/inmemory/workflow.d.cts +1 -1
  34. package/dist/adapters/sandbox/inmemory/workflow.d.ts +1 -1
  35. package/dist/adapters/thread/anthropic/index.cjs +23 -3
  36. package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
  37. package/dist/adapters/thread/anthropic/index.d.cts +5 -5
  38. package/dist/adapters/thread/anthropic/index.d.ts +5 -5
  39. package/dist/adapters/thread/anthropic/index.js +23 -3
  40. package/dist/adapters/thread/anthropic/index.js.map +1 -1
  41. package/dist/adapters/thread/anthropic/workflow.cjs +2 -1
  42. package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
  43. package/dist/adapters/thread/anthropic/workflow.d.cts +5 -5
  44. package/dist/adapters/thread/anthropic/workflow.d.ts +5 -5
  45. package/dist/adapters/thread/anthropic/workflow.js +2 -1
  46. package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
  47. package/dist/adapters/thread/google-genai/index.cjs +27 -3
  48. package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
  49. package/dist/adapters/thread/google-genai/index.d.cts +5 -5
  50. package/dist/adapters/thread/google-genai/index.d.ts +5 -5
  51. package/dist/adapters/thread/google-genai/index.js +27 -3
  52. package/dist/adapters/thread/google-genai/index.js.map +1 -1
  53. package/dist/adapters/thread/google-genai/workflow.cjs +2 -1
  54. package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
  55. package/dist/adapters/thread/google-genai/workflow.d.cts +5 -5
  56. package/dist/adapters/thread/google-genai/workflow.d.ts +5 -5
  57. package/dist/adapters/thread/google-genai/workflow.js +2 -1
  58. package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
  59. package/dist/adapters/thread/langchain/index.cjs +23 -3
  60. package/dist/adapters/thread/langchain/index.cjs.map +1 -1
  61. package/dist/adapters/thread/langchain/index.d.cts +5 -5
  62. package/dist/adapters/thread/langchain/index.d.ts +5 -5
  63. package/dist/adapters/thread/langchain/index.js +23 -3
  64. package/dist/adapters/thread/langchain/index.js.map +1 -1
  65. package/dist/adapters/thread/langchain/workflow.cjs +2 -1
  66. package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
  67. package/dist/adapters/thread/langchain/workflow.d.cts +5 -5
  68. package/dist/adapters/thread/langchain/workflow.d.ts +5 -5
  69. package/dist/adapters/thread/langchain/workflow.js +2 -1
  70. package/dist/adapters/thread/langchain/workflow.js.map +1 -1
  71. package/dist/index.cjs +120 -30
  72. package/dist/index.cjs.map +1 -1
  73. package/dist/index.d.cts +11 -11
  74. package/dist/index.d.ts +11 -11
  75. package/dist/index.js +121 -31
  76. package/dist/index.js.map +1 -1
  77. package/dist/{proxy-0smGKvx8.d.ts → proxy-CUlKSvZS.d.ts} +1 -1
  78. package/dist/{proxy-DEtowJyd.d.cts → proxy-D_3x7RN4.d.cts} +1 -1
  79. package/dist/{thread-manager-C-C4pI2z.d.ts → thread-manager-CVu7o2cs.d.ts} +4 -2
  80. package/dist/{thread-manager-D4vgzYrh.d.cts → thread-manager-HSwyh28L.d.cts} +4 -2
  81. package/dist/{thread-manager-3fszQih4.d.ts → thread-manager-c1gPopAG.d.ts} +4 -2
  82. package/dist/{thread-manager-CzYln2OC.d.cts → thread-manager-wGi-LqIP.d.cts} +4 -2
  83. package/dist/{types-B37hKoWA.d.ts → types-BH_IRryz.d.ts} +10 -1
  84. package/dist/{types-D08CXPh8.d.cts → types-BaOw4hKI.d.cts} +10 -1
  85. package/dist/{types-CPKDl-y_.d.ts → types-C06FwR96.d.cts} +59 -4
  86. package/dist/{types-CNuWnvy9.d.ts → types-DAsQ21Rt.d.ts} +1 -1
  87. package/dist/{types-BO7Yju20.d.cts → types-DNr31FzL.d.ts} +59 -4
  88. package/dist/{types-DWEUmYAJ.d.cts → types-lm8tMNJQ.d.cts} +1 -1
  89. package/dist/{types-tQL9njTu.d.cts → types-yx0LzPGn.d.cts} +21 -7
  90. package/dist/{types-tQL9njTu.d.ts → types-yx0LzPGn.d.ts} +21 -7
  91. package/dist/{workflow-CjXHbZZc.d.ts → workflow-CSCkpwAL.d.ts} +2 -2
  92. package/dist/{workflow-Do_lzJpT.d.cts → workflow-DuvMZ8Vm.d.cts} +2 -2
  93. package/dist/workflow.cjs +94 -18
  94. package/dist/workflow.cjs.map +1 -1
  95. package/dist/workflow.d.cts +3 -3
  96. package/dist/workflow.d.ts +3 -3
  97. package/dist/workflow.js +95 -19
  98. package/dist/workflow.js.map +1 -1
  99. package/package.json +2 -2
  100. package/src/adapters/sandbox/bedrock/index.ts +12 -3
  101. package/src/adapters/sandbox/daytona/index.ts +12 -3
  102. package/src/adapters/sandbox/e2b/index.ts +36 -14
  103. package/src/adapters/sandbox/e2b/types.ts +16 -0
  104. package/src/adapters/sandbox/inmemory/index.ts +12 -3
  105. package/src/adapters/thread/anthropic/activities.ts +9 -0
  106. package/src/adapters/thread/anthropic/model-invoker.ts +3 -1
  107. package/src/adapters/thread/anthropic/thread-manager.ts +3 -0
  108. package/src/adapters/thread/google-genai/activities.ts +13 -0
  109. package/src/adapters/thread/google-genai/model-invoker.ts +3 -1
  110. package/src/adapters/thread/google-genai/thread-manager.ts +3 -0
  111. package/src/adapters/thread/langchain/activities.ts +9 -0
  112. package/src/adapters/thread/langchain/model-invoker.ts +2 -1
  113. package/src/adapters/thread/langchain/thread-manager.ts +3 -0
  114. package/src/lib/lifecycle.ts +11 -4
  115. package/src/lib/model/types.ts +10 -0
  116. package/src/lib/sandbox/manager.ts +26 -18
  117. package/src/lib/sandbox/types.ts +27 -7
  118. package/src/lib/session/session-edge-cases.integration.test.ts +265 -1
  119. package/src/lib/session/session.integration.test.ts +22 -1
  120. package/src/lib/session/session.ts +61 -7
  121. package/src/lib/session/types.ts +12 -0
  122. package/src/lib/subagent/subagent.integration.test.ts +100 -104
  123. package/src/lib/thread/manager.ts +18 -0
  124. package/src/lib/thread/proxy.ts +1 -0
  125. package/src/lib/thread/types.ts +9 -0
  126. package/src/lib/tool-router/index.ts +2 -0
  127. package/src/lib/tool-router/router-edge-cases.integration.test.ts +92 -0
  128. package/src/lib/tool-router/router.integration.test.ts +12 -0
  129. package/src/lib/tool-router/router.ts +89 -16
  130. package/src/lib/tool-router/types.ts +34 -1
  131. package/src/workflow.ts +2 -0
@@ -36,7 +36,7 @@ vi.mock("@temporalio/workflow", () => {
36
36
  condition: vi.fn(async (fn: () => boolean) => {
37
37
  if (!fn()) throw new Error("condition predicate was not satisfied");
38
38
  }),
39
- startChild: vi.fn(
39
+ executeChild: vi.fn(
40
40
  async (
41
41
  _workflow: unknown,
42
42
  opts: { workflowId: string; args: unknown[] }
@@ -51,11 +51,7 @@ vi.mock("@temporalio/workflow", () => {
51
51
  usage: { inputTokens: 100, outputTokens: 50 },
52
52
  };
53
53
 
54
- return {
55
- signal: vi.fn(),
56
- result: () => Promise.resolve(result),
57
- workflowId: opts.workflowId,
58
- };
54
+ return result;
59
55
  }
60
56
  ),
61
57
  getExternalWorkflowHandle: vi.fn((_id: string) => ({
@@ -378,8 +374,8 @@ describe("createSubagentHandler", () => {
378
374
  });
379
375
 
380
376
  it("passes sandbox inherit to child when sandbox is inherit", async () => {
381
- const { startChild } = await import("@temporalio/workflow");
382
- const startMock = startChild as ReturnType<typeof vi.fn>;
377
+ const { executeChild } = await import("@temporalio/workflow");
378
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
383
379
 
384
380
  const inheritSubagent: SubagentConfig = {
385
381
  agentName: "inherit-agent",
@@ -404,8 +400,8 @@ describe("createSubagentHandler", () => {
404
400
  }
405
401
  );
406
402
 
407
- const lastCall = startMock.mock.calls[startMock.mock.calls.length - 1];
408
- if (!lastCall) throw new Error("expected startChild call");
403
+ const lastCall = execMock.mock.calls[execMock.mock.calls.length - 1];
404
+ if (!lastCall) throw new Error("expected executeChild call");
409
405
  const workflowInput = lastCall[1].args[1] as SubagentWorkflowInput;
410
406
  expect(workflowInput.sandbox).toEqual({
411
407
  mode: "inherit",
@@ -436,8 +432,8 @@ describe("createSubagentHandler", () => {
436
432
  });
437
433
 
438
434
  it("does not pass sandboxId to child when sandbox is own (first call)", async () => {
439
- const { startChild } = await import("@temporalio/workflow");
440
- const startMock = startChild as ReturnType<typeof vi.fn>;
435
+ const { executeChild } = await import("@temporalio/workflow");
436
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
441
437
 
442
438
  const ownSubagent: SubagentConfig = {
443
439
  agentName: "own-agent",
@@ -458,15 +454,15 @@ describe("createSubagentHandler", () => {
458
454
  }
459
455
  );
460
456
 
461
- const lastCall = startMock.mock.calls[startMock.mock.calls.length - 1];
462
- if (!lastCall) throw new Error("expected startChild call");
457
+ const lastCall = execMock.mock.calls[execMock.mock.calls.length - 1];
458
+ if (!lastCall) throw new Error("expected executeChild call");
463
459
  const workflowInput = lastCall[1].args[1] as SubagentWorkflowInput;
464
460
  expect(workflowInput.sandbox).toBeUndefined();
465
461
  });
466
462
 
467
463
  it("resolves context function at invocation time", async () => {
468
- const { startChild } = await import("@temporalio/workflow");
469
- const startMock = startChild as ReturnType<typeof vi.fn>;
464
+ const { executeChild } = await import("@temporalio/workflow");
465
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
470
466
 
471
467
  let counter = 0;
472
468
  const dynamicSubagent: SubagentConfig = {
@@ -486,15 +482,15 @@ describe("createSubagentHandler", () => {
486
482
  { threadId: "t", toolCallId: "tc", toolName: "Subagent" }
487
483
  );
488
484
 
489
- const lastCall = startMock.mock.calls[startMock.mock.calls.length - 1];
490
- if (!lastCall) throw new Error("expected startChild call");
485
+ const lastCall = execMock.mock.calls[execMock.mock.calls.length - 1];
486
+ if (!lastCall) throw new Error("expected executeChild call");
491
487
  const context = lastCall[1].args[2] as Record<string, unknown>;
492
488
  expect(context).toEqual({ invocation: 1 });
493
489
  });
494
490
 
495
491
  it("passes static context unchanged", async () => {
496
- const { startChild } = await import("@temporalio/workflow");
497
- const startMock = startChild as ReturnType<typeof vi.fn>;
492
+ const { executeChild } = await import("@temporalio/workflow");
493
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
498
494
 
499
495
  const staticSubagent: SubagentConfig = {
500
496
  agentName: "static-ctx",
@@ -510,15 +506,15 @@ describe("createSubagentHandler", () => {
510
506
  { threadId: "t", toolCallId: "tc", toolName: "Subagent" }
511
507
  );
512
508
 
513
- const lastCall = startMock.mock.calls[startMock.mock.calls.length - 1];
514
- if (!lastCall) throw new Error("expected startChild call");
509
+ const lastCall = execMock.mock.calls[execMock.mock.calls.length - 1];
510
+ if (!lastCall) throw new Error("expected executeChild call");
515
511
  const context = lastCall[1].args[2] as Record<string, unknown>;
516
512
  expect(context).toEqual({ key: "value" });
517
513
  });
518
514
 
519
515
  it("does not pass sandbox init when sandbox is own without prior sandbox", async () => {
520
- const { startChild } = await import("@temporalio/workflow");
521
- const startMock = startChild as ReturnType<typeof vi.fn>;
516
+ const { executeChild } = await import("@temporalio/workflow");
517
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
522
518
 
523
519
  const ownSubagent: SubagentConfig = {
524
520
  agentName: "own-agent",
@@ -539,8 +535,8 @@ describe("createSubagentHandler", () => {
539
535
  }
540
536
  );
541
537
 
542
- const lastCall = startMock.mock.calls[startMock.mock.calls.length - 1];
543
- if (!lastCall) throw new Error("expected startChild call");
538
+ const lastCall = execMock.mock.calls[execMock.mock.calls.length - 1];
539
+ if (!lastCall) throw new Error("expected executeChild call");
544
540
  const workflowInput = lastCall[1].args[1] as SubagentWorkflowInput;
545
541
  expect(workflowInput.sandbox).toBeUndefined();
546
542
  });
@@ -548,8 +544,8 @@ describe("createSubagentHandler", () => {
548
544
  // --- Thread mode ---
549
545
 
550
546
  it("passes thread fork when thread is fork and threadId provided", async () => {
551
- const { startChild } = await import("@temporalio/workflow");
552
- const startMock = startChild as ReturnType<typeof vi.fn>;
547
+ const { executeChild } = await import("@temporalio/workflow");
548
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
553
549
 
554
550
  const contSubagent: SubagentConfig = {
555
551
  agentName: "cont",
@@ -570,8 +566,8 @@ describe("createSubagentHandler", () => {
570
566
  { threadId: "t", toolCallId: "tc", toolName: "Subagent" }
571
567
  );
572
568
 
573
- const lastCall = startMock.mock.calls[startMock.mock.calls.length - 1];
574
- if (!lastCall) throw new Error("expected startChild call");
569
+ const lastCall = execMock.mock.calls[execMock.mock.calls.length - 1];
570
+ if (!lastCall) throw new Error("expected executeChild call");
575
571
  const workflowInput = lastCall[1].args[1] as SubagentWorkflowInput;
576
572
  expect(workflowInput.thread).toEqual({
577
573
  mode: "fork",
@@ -580,8 +576,8 @@ describe("createSubagentHandler", () => {
580
576
  });
581
577
 
582
578
  it("passes thread continue when thread is continue", async () => {
583
- const { startChild } = await import("@temporalio/workflow");
584
- const startMock = startChild as ReturnType<typeof vi.fn>;
579
+ const { executeChild } = await import("@temporalio/workflow");
580
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
585
581
 
586
582
  const contSubagent: SubagentConfig = {
587
583
  agentName: "cont-mode",
@@ -602,8 +598,8 @@ describe("createSubagentHandler", () => {
602
598
  { threadId: "t", toolCallId: "tc", toolName: "Subagent" }
603
599
  );
604
600
 
605
- const lastCall = startMock.mock.calls[startMock.mock.calls.length - 1];
606
- if (!lastCall) throw new Error("expected startChild call");
601
+ const lastCall = execMock.mock.calls[execMock.mock.calls.length - 1];
602
+ if (!lastCall) throw new Error("expected executeChild call");
607
603
  const workflowInput = lastCall[1].args[1] as SubagentWorkflowInput;
608
604
  expect(workflowInput.thread).toEqual({
609
605
  mode: "continue",
@@ -612,8 +608,8 @@ describe("createSubagentHandler", () => {
612
608
  });
613
609
 
614
610
  it("does not pass thread when thread is new", async () => {
615
- const { startChild } = await import("@temporalio/workflow");
616
- const startMock = startChild as ReturnType<typeof vi.fn>;
611
+ const { executeChild } = await import("@temporalio/workflow");
612
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
617
613
 
618
614
  const noContSubagent: SubagentConfig = {
619
615
  agentName: "no-cont",
@@ -633,8 +629,8 @@ describe("createSubagentHandler", () => {
633
629
  { threadId: "t", toolCallId: "tc", toolName: "Subagent" }
634
630
  );
635
631
 
636
- const lastCall = startMock.mock.calls[startMock.mock.calls.length - 1];
637
- if (!lastCall) throw new Error("expected startChild call");
632
+ const lastCall = execMock.mock.calls[execMock.mock.calls.length - 1];
633
+ if (!lastCall) throw new Error("expected executeChild call");
638
634
  const workflowInput = lastCall[1].args[1] as SubagentWorkflowInput;
639
635
  expect(workflowInput.thread).toBeUndefined();
640
636
  });
@@ -642,8 +638,8 @@ describe("createSubagentHandler", () => {
642
638
  // --- Sandbox continuation ---
643
639
 
644
640
  it("does not pass sandbox when thread is fork (own sandbox)", async () => {
645
- const { startChild } = await import("@temporalio/workflow");
646
- const startMock = startChild as ReturnType<typeof vi.fn>;
641
+ const { executeChild } = await import("@temporalio/workflow");
642
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
647
643
 
648
644
  const contSandboxSubagent: SubagentConfig = {
649
645
  agentName: "sb-cont",
@@ -664,15 +660,15 @@ describe("createSubagentHandler", () => {
664
660
  }
665
661
  );
666
662
 
667
- const lastCall = startMock.mock.calls[startMock.mock.calls.length - 1];
668
- if (!lastCall) throw new Error("expected startChild call");
663
+ const lastCall = execMock.mock.calls[execMock.mock.calls.length - 1];
664
+ if (!lastCall) throw new Error("expected executeChild call");
669
665
  const workflowInput = lastCall[1].args[1] as SubagentWorkflowInput;
670
666
  expect(workflowInput.sandbox).toBeUndefined();
671
667
  });
672
668
 
673
669
  it("tracks sandbox ID and passes sandbox fork on continuation", async () => {
674
- const { startChild } = await import("@temporalio/workflow");
675
- const startMock = startChild as ReturnType<typeof vi.fn>;
670
+ const { executeChild } = await import("@temporalio/workflow");
671
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
676
672
 
677
673
  nextStartChildResult = () => ({
678
674
  toolResponse: "first run done",
@@ -713,8 +709,8 @@ describe("createSubagentHandler", () => {
713
709
  { threadId: "t", toolCallId: "tc-2", toolName: "Subagent" }
714
710
  );
715
711
 
716
- const secondCall = startMock.mock.calls[startMock.mock.calls.length - 1];
717
- if (!secondCall) throw new Error("expected second startChild call");
712
+ const secondCall = execMock.mock.calls[execMock.mock.calls.length - 1];
713
+ if (!secondCall) throw new Error("expected second executeChild call");
718
714
  const workflowInput = secondCall[1].args[1] as SubagentWorkflowInput;
719
715
  expect(workflowInput.thread).toEqual({
720
716
  mode: "fork",
@@ -727,8 +723,8 @@ describe("createSubagentHandler", () => {
727
723
  });
728
724
 
729
725
  it("does not pass sandbox fork without thread continuation", async () => {
730
- const { startChild } = await import("@temporalio/workflow");
731
- const startMock = startChild as ReturnType<typeof vi.fn>;
726
+ const { executeChild } = await import("@temporalio/workflow");
727
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
732
728
 
733
729
  nextStartChildResult = () => ({
734
730
  toolResponse: "done",
@@ -764,8 +760,8 @@ describe("createSubagentHandler", () => {
764
760
  { threadId: "t", toolCallId: "tc-2", toolName: "Subagent" }
765
761
  );
766
762
 
767
- const secondCall = startMock.mock.calls[startMock.mock.calls.length - 1];
768
- if (!secondCall) throw new Error("expected startChild call");
763
+ const secondCall = execMock.mock.calls[execMock.mock.calls.length - 1];
764
+ if (!secondCall) throw new Error("expected executeChild call");
769
765
  const workflowInput = secondCall[1].args[1] as SubagentWorkflowInput;
770
766
  expect(workflowInput.sandbox).toBeUndefined();
771
767
  expect(workflowInput.thread).toBeUndefined();
@@ -882,8 +878,8 @@ describe("createSubagentHandler", () => {
882
878
  });
883
879
 
884
880
  it("does not pass sandboxId when sandbox is none (default)", async () => {
885
- const { startChild } = await import("@temporalio/workflow");
886
- const startMock = startChild as ReturnType<typeof vi.fn>;
881
+ const { executeChild } = await import("@temporalio/workflow");
882
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
887
883
 
888
884
  const noneSubagent: SubagentConfig = {
889
885
  agentName: "none-agent",
@@ -903,15 +899,15 @@ describe("createSubagentHandler", () => {
903
899
  }
904
900
  );
905
901
 
906
- const lastCall = startMock.mock.calls[startMock.mock.calls.length - 1];
907
- if (!lastCall) throw new Error("expected startChild call");
902
+ const lastCall = execMock.mock.calls[execMock.mock.calls.length - 1];
903
+ if (!lastCall) throw new Error("expected executeChild call");
908
904
  const workflowInput = lastCall[1].args[1] as SubagentWorkflowInput;
909
905
  expect(workflowInput.sandbox).toBeUndefined();
910
906
  });
911
907
 
912
908
  it("does not pass sandboxId when sandbox is explicitly none", async () => {
913
- const { startChild } = await import("@temporalio/workflow");
914
- const startMock = startChild as ReturnType<typeof vi.fn>;
909
+ const { executeChild } = await import("@temporalio/workflow");
910
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
915
911
 
916
912
  const noneSubagent: SubagentConfig = {
917
913
  agentName: "none-agent",
@@ -932,8 +928,8 @@ describe("createSubagentHandler", () => {
932
928
  }
933
929
  );
934
930
 
935
- const lastCall = startMock.mock.calls[startMock.mock.calls.length - 1];
936
- if (!lastCall) throw new Error("expected startChild call");
931
+ const lastCall = execMock.mock.calls[execMock.mock.calls.length - 1];
932
+ if (!lastCall) throw new Error("expected executeChild call");
937
933
  const workflowInput = lastCall[1].args[1] as SubagentWorkflowInput;
938
934
  expect(workflowInput.sandbox).toBeUndefined();
939
935
  });
@@ -961,8 +957,8 @@ describe("createSubagentHandler", () => {
961
957
  // --- inherit + continuation: fork ---
962
958
 
963
959
  it("forks from parent sandbox when inherit + continuation=fork", async () => {
964
- const { startChild } = await import("@temporalio/workflow");
965
- const startMock = startChild as ReturnType<typeof vi.fn>;
960
+ const { executeChild } = await import("@temporalio/workflow");
961
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
966
962
 
967
963
  const config: SubagentConfig = {
968
964
  agentName: "inherit-fork",
@@ -987,8 +983,8 @@ describe("createSubagentHandler", () => {
987
983
  }
988
984
  );
989
985
 
990
- const lastCall = startMock.mock.calls.at(-1);
991
- if (!lastCall) throw new Error("expected startChild call");
986
+ const lastCall = execMock.mock.calls.at(-1);
987
+ if (!lastCall) throw new Error("expected executeChild call");
992
988
  const workflowInput = lastCall[1].args[1] as SubagentWorkflowInput;
993
989
  expect(workflowInput.sandbox).toEqual({
994
990
  mode: "fork",
@@ -999,8 +995,8 @@ describe("createSubagentHandler", () => {
999
995
  // --- own + continuation: continue ---
1000
996
 
1001
997
  it("passes sandbox continue on thread continuation with continuation=continue", async () => {
1002
- const { startChild } = await import("@temporalio/workflow");
1003
- const startMock = startChild as ReturnType<typeof vi.fn>;
998
+ const { executeChild } = await import("@temporalio/workflow");
999
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
1004
1000
 
1005
1001
  nextStartChildResult = () => ({
1006
1002
  toolResponse: "first",
@@ -1045,8 +1041,8 @@ describe("createSubagentHandler", () => {
1045
1041
  { threadId: "t", toolCallId: "tc-2", toolName: "Subagent" }
1046
1042
  );
1047
1043
 
1048
- const secondCall = startMock.mock.calls.at(-1);
1049
- if (!secondCall) throw new Error("expected startChild call");
1044
+ const secondCall = execMock.mock.calls.at(-1);
1045
+ if (!secondCall) throw new Error("expected executeChild call");
1050
1046
  const workflowInput = secondCall[1].args[1] as SubagentWorkflowInput;
1051
1047
  expect(workflowInput.sandbox).toEqual({
1052
1048
  mode: "continue",
@@ -1058,8 +1054,8 @@ describe("createSubagentHandler", () => {
1058
1054
  // --- own + init: once + continuation: fork ---
1059
1055
 
1060
1056
  it("stores sandbox on first call and forks from it on second call (init=once, continuation=fork)", async () => {
1061
- const { startChild } = await import("@temporalio/workflow");
1062
- const startMock = startChild as ReturnType<typeof vi.fn>;
1057
+ const { executeChild } = await import("@temporalio/workflow");
1058
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
1063
1059
 
1064
1060
  nextStartChildResult = () => ({
1065
1061
  toolResponse: "first",
@@ -1088,8 +1084,8 @@ describe("createSubagentHandler", () => {
1088
1084
  );
1089
1085
 
1090
1086
  // First call: no sandbox init (child creates fresh), forced pause-until-parent-close
1091
- const firstCall = startMock.mock.calls.at(-1);
1092
- if (!firstCall) throw new Error("expected startChild call");
1087
+ const firstCall = execMock.mock.calls.at(-1);
1088
+ if (!firstCall) throw new Error("expected executeChild call");
1093
1089
  const firstInput = firstCall[1].args[1] as SubagentWorkflowInput;
1094
1090
  expect(firstInput.sandbox).toBeUndefined();
1095
1091
  expect(firstInput.sandboxShutdown).toBe("pause-until-parent-close");
@@ -1107,8 +1103,8 @@ describe("createSubagentHandler", () => {
1107
1103
  { threadId: "t", toolCallId: "tc-2", toolName: "Subagent" }
1108
1104
  );
1109
1105
 
1110
- const secondCall = startMock.mock.calls.at(-1);
1111
- if (!secondCall) throw new Error("expected startChild call");
1106
+ const secondCall = execMock.mock.calls.at(-1);
1107
+ if (!secondCall) throw new Error("expected executeChild call");
1112
1108
  const secondInput = secondCall[1].args[1] as SubagentWorkflowInput;
1113
1109
  expect(secondInput.sandbox).toEqual({
1114
1110
  mode: "fork",
@@ -1119,8 +1115,8 @@ describe("createSubagentHandler", () => {
1119
1115
  // --- own + init: once + continuation: continue ---
1120
1116
 
1121
1117
  it("stores sandbox on first call and continues it on second call (init=once, continuation=continue)", async () => {
1122
- const { startChild } = await import("@temporalio/workflow");
1123
- const startMock = startChild as ReturnType<typeof vi.fn>;
1118
+ const { executeChild } = await import("@temporalio/workflow");
1119
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
1124
1120
 
1125
1121
  nextStartChildResult = () => ({
1126
1122
  toolResponse: "first",
@@ -1160,8 +1156,8 @@ describe("createSubagentHandler", () => {
1160
1156
  { threadId: "t", toolCallId: "tc-2", toolName: "Subagent" }
1161
1157
  );
1162
1158
 
1163
- const secondCall = startMock.mock.calls.at(-1);
1164
- if (!secondCall) throw new Error("expected startChild call");
1159
+ const secondCall = execMock.mock.calls.at(-1);
1160
+ if (!secondCall) throw new Error("expected executeChild call");
1165
1161
  const secondInput = secondCall[1].args[1] as SubagentWorkflowInput;
1166
1162
  expect(secondInput.sandbox).toEqual({
1167
1163
  mode: "continue",
@@ -1398,8 +1394,8 @@ describe("createSubagentHandler", () => {
1398
1394
  // --- mustSurvive does not override user shutdown ---
1399
1395
 
1400
1396
  it("does not override keep-until-parent-close with pause-until-parent-close for init=once", async () => {
1401
- const { startChild } = await import("@temporalio/workflow");
1402
- const startMock = startChild as ReturnType<typeof vi.fn>;
1397
+ const { executeChild } = await import("@temporalio/workflow");
1398
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
1403
1399
 
1404
1400
  nextStartChildResult = () => ({
1405
1401
  toolResponse: "first",
@@ -1428,15 +1424,15 @@ describe("createSubagentHandler", () => {
1428
1424
  { threadId: "t", toolCallId: "tc-1", toolName: "Subagent" }
1429
1425
  );
1430
1426
 
1431
- const firstCall = startMock.mock.calls.at(-1);
1432
- if (!firstCall) throw new Error("expected startChild call");
1427
+ const firstCall = execMock.mock.calls.at(-1);
1428
+ if (!firstCall) throw new Error("expected executeChild call");
1433
1429
  const firstInput = firstCall[1].args[1] as SubagentWorkflowInput;
1434
1430
  expect(firstInput.sandboxShutdown).toBe("keep-until-parent-close");
1435
1431
  });
1436
1432
 
1437
1433
  it("does not override pause with pause-until-parent-close for init=once", async () => {
1438
- const { startChild } = await import("@temporalio/workflow");
1439
- const startMock = startChild as ReturnType<typeof vi.fn>;
1434
+ const { executeChild } = await import("@temporalio/workflow");
1435
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
1440
1436
 
1441
1437
  nextStartChildResult = () => ({
1442
1438
  toolResponse: "first",
@@ -1465,15 +1461,15 @@ describe("createSubagentHandler", () => {
1465
1461
  { threadId: "t", toolCallId: "tc-1", toolName: "Subagent" }
1466
1462
  );
1467
1463
 
1468
- const firstCall = startMock.mock.calls.at(-1);
1469
- if (!firstCall) throw new Error("expected startChild call");
1464
+ const firstCall = execMock.mock.calls.at(-1);
1465
+ if (!firstCall) throw new Error("expected executeChild call");
1470
1466
  const firstInput = firstCall[1].args[1] as SubagentWorkflowInput;
1471
1467
  expect(firstInput.sandboxShutdown).toBe("pause");
1472
1468
  });
1473
1469
 
1474
1470
  it("does not override keep with pause for continuation=continue", async () => {
1475
- const { startChild } = await import("@temporalio/workflow");
1476
- const startMock = startChild as ReturnType<typeof vi.fn>;
1471
+ const { executeChild } = await import("@temporalio/workflow");
1472
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
1477
1473
 
1478
1474
  nextStartChildResult = () => ({
1479
1475
  toolResponse: "first",
@@ -1502,15 +1498,15 @@ describe("createSubagentHandler", () => {
1502
1498
  { threadId: "t", toolCallId: "tc-1", toolName: "Subagent" }
1503
1499
  );
1504
1500
 
1505
- const firstCall = startMock.mock.calls.at(-1);
1506
- if (!firstCall) throw new Error("expected startChild call");
1501
+ const firstCall = execMock.mock.calls.at(-1);
1502
+ if (!firstCall) throw new Error("expected executeChild call");
1507
1503
  const firstInput = firstCall[1].args[1] as SubagentWorkflowInput;
1508
1504
  expect(firstInput.sandboxShutdown).toBe("keep");
1509
1505
  });
1510
1506
 
1511
1507
  it("still overrides destroy with pause for continuation=continue", async () => {
1512
- const { startChild } = await import("@temporalio/workflow");
1513
- const startMock = startChild as ReturnType<typeof vi.fn>;
1508
+ const { executeChild } = await import("@temporalio/workflow");
1509
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
1514
1510
 
1515
1511
  nextStartChildResult = () => ({
1516
1512
  toolResponse: "first",
@@ -1539,8 +1535,8 @@ describe("createSubagentHandler", () => {
1539
1535
  { threadId: "t", toolCallId: "tc-1", toolName: "Subagent" }
1540
1536
  );
1541
1537
 
1542
- const firstCall = startMock.mock.calls.at(-1);
1543
- if (!firstCall) throw new Error("expected startChild call");
1538
+ const firstCall = execMock.mock.calls.at(-1);
1539
+ if (!firstCall) throw new Error("expected executeChild call");
1544
1540
  const firstInput = firstCall[1].args[1] as SubagentWorkflowInput;
1545
1541
  expect(firstInput.sandboxShutdown).toBe("pause");
1546
1542
  });
@@ -1548,8 +1544,8 @@ describe("createSubagentHandler", () => {
1548
1544
  // --- snapshot continuation ---
1549
1545
 
1550
1546
  it("forces sandboxShutdown=snapshot and passes no sandbox on first call (continuation=snapshot)", async () => {
1551
- const { startChild } = await import("@temporalio/workflow");
1552
- const startMock = startChild as ReturnType<typeof vi.fn>;
1547
+ const { executeChild } = await import("@temporalio/workflow");
1548
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
1553
1549
 
1554
1550
  nextStartChildResult = () => ({
1555
1551
  toolResponse: "first",
@@ -1589,16 +1585,16 @@ describe("createSubagentHandler", () => {
1589
1585
  { threadId: "t", toolCallId: "tc-1", toolName: "Subagent" }
1590
1586
  );
1591
1587
 
1592
- const firstCall = startMock.mock.calls.at(-1);
1593
- if (!firstCall) throw new Error("expected startChild call");
1588
+ const firstCall = execMock.mock.calls.at(-1);
1589
+ if (!firstCall) throw new Error("expected executeChild call");
1594
1590
  const firstInput = firstCall[1].args[1] as SubagentWorkflowInput;
1595
1591
  expect(firstInput.sandbox).toBeUndefined();
1596
1592
  expect(firstInput.sandboxShutdown).toBe("snapshot");
1597
1593
  });
1598
1594
 
1599
1595
  it("boots follow-up from stored thread snapshot on continuation=snapshot", async () => {
1600
- const { startChild } = await import("@temporalio/workflow");
1601
- const startMock = startChild as ReturnType<typeof vi.fn>;
1596
+ const { executeChild } = await import("@temporalio/workflow");
1597
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
1602
1598
 
1603
1599
  nextStartChildResult = () => ({
1604
1600
  toolResponse: "first",
@@ -1660,8 +1656,8 @@ describe("createSubagentHandler", () => {
1660
1656
  { threadId: "t", toolCallId: "tc-2", toolName: "Subagent" }
1661
1657
  );
1662
1658
 
1663
- const secondCall = startMock.mock.calls.at(-1);
1664
- if (!secondCall) throw new Error("expected startChild call");
1659
+ const secondCall = execMock.mock.calls.at(-1);
1660
+ if (!secondCall) throw new Error("expected executeChild call");
1665
1661
  const secondInput = secondCall[1].args[1] as SubagentWorkflowInput;
1666
1662
  expect(secondInput.sandbox).toEqual({
1667
1663
  mode: "from-snapshot",
@@ -1671,8 +1667,8 @@ describe("createSubagentHandler", () => {
1671
1667
  });
1672
1668
 
1673
1669
  it("uses per-agent base snapshot for a new thread when init=once + continuation=snapshot", async () => {
1674
- const { startChild } = await import("@temporalio/workflow");
1675
- const startMock = startChild as ReturnType<typeof vi.fn>;
1670
+ const { executeChild } = await import("@temporalio/workflow");
1671
+ const execMock = executeChild as ReturnType<typeof vi.fn>;
1676
1672
 
1677
1673
  // First call — establishes base snapshot.
1678
1674
  nextStartChildResult = () => ({
@@ -1731,8 +1727,8 @@ describe("createSubagentHandler", () => {
1731
1727
  { threadId: "t", toolCallId: "tc-2", toolName: "Subagent" }
1732
1728
  );
1733
1729
 
1734
- const secondCall = startMock.mock.calls.at(-1);
1735
- if (!secondCall) throw new Error("expected startChild call");
1730
+ const secondCall = execMock.mock.calls.at(-1);
1731
+ if (!secondCall) throw new Error("expected executeChild call");
1736
1732
  const secondInput = secondCall[1].args[1] as SubagentWorkflowInput;
1737
1733
  expect(secondInput.sandbox).toEqual({
1738
1734
  mode: "from-snapshot",
@@ -104,5 +104,23 @@ export function createThreadManager<T>(
104
104
  async delete(): Promise<void> {
105
105
  await redis.del(redisKey, metaKey);
106
106
  },
107
+
108
+ async length(): Promise<number> {
109
+ await assertThreadExists();
110
+ return redis.llen(redisKey);
111
+ },
112
+
113
+ async truncate(length: number): Promise<void> {
114
+ await assertThreadExists();
115
+ if (length <= 0) {
116
+ await redis.del(redisKey);
117
+ await redis.expire(metaKey, THREAD_TTL_SECONDS);
118
+ } else {
119
+ await redis.ltrim(redisKey, 0, length - 1);
120
+ await redis.expire(redisKey, THREAD_TTL_SECONDS);
121
+ }
122
+ // Dedup keys for removed messages are left to expire via their TTL.
123
+ // Post-truncate appends use fresh ids so collisions do not occur in practice.
124
+ },
107
125
  };
108
126
  }
@@ -53,5 +53,6 @@ export function createThreadOpsProxy(
53
53
  appendAgentMessage: acts[p("appendAgentMessage")],
54
54
  appendSystemMessage: acts[p("appendSystemMessage")],
55
55
  forkThread: acts[p("forkThread")],
56
+ truncateThread: acts[p("truncateThread")],
56
57
  } as ActivityInterfaceFor<ThreadOps>;
57
58
  }
@@ -36,6 +36,15 @@ export interface BaseThreadManager<T> {
36
36
  fork(newThreadId: string): Promise<BaseThreadManager<T>>;
37
37
  /** Delete the thread */
38
38
  delete(): Promise<void>;
39
+ /** Get the number of stored messages currently in the thread */
40
+ length(): Promise<number>;
41
+ /**
42
+ * Truncate the thread to the given length (inclusive). Any messages
43
+ * beyond `length` are removed. When `length` is 0 the thread ends up
44
+ * empty (but still exists). Also clears any dedup markers so that
45
+ * subsequent appends with the same ids replay correctly.
46
+ */
47
+ truncate(length: number): Promise<void>;
39
48
  }
40
49
 
41
50
  /**
@@ -22,6 +22,8 @@ export type {
22
22
  InferToolResults,
23
23
  ToolCallResultUnion,
24
24
  ProcessToolCallsContext,
25
+ ProcessToolCallsResult,
26
+ RewindSignal,
25
27
  PreToolUseHookResult,
26
28
  PostToolUseFailureHookResult,
27
29
  ToolHooks,