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.
- package/dist/{activities-Bb-nAjwQ.d.ts → activities-BKhMtKDd.d.ts} +4 -2
- package/dist/{activities-vkI4_3CC.d.cts → activities-CDcwkRZs.d.cts} +4 -2
- package/dist/adapters/sandbox/bedrock/index.cjs +3 -3
- package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
- package/dist/adapters/sandbox/bedrock/index.d.cts +6 -6
- package/dist/adapters/sandbox/bedrock/index.d.ts +6 -6
- package/dist/adapters/sandbox/bedrock/index.js +3 -3
- package/dist/adapters/sandbox/bedrock/index.js.map +1 -1
- package/dist/adapters/sandbox/bedrock/workflow.d.cts +2 -2
- package/dist/adapters/sandbox/bedrock/workflow.d.ts +2 -2
- package/dist/adapters/sandbox/daytona/index.cjs +3 -3
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/index.d.cts +4 -4
- package/dist/adapters/sandbox/daytona/index.d.ts +4 -4
- package/dist/adapters/sandbox/daytona/index.js +3 -3
- package/dist/adapters/sandbox/daytona/index.js.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/daytona/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/e2b/index.cjs +26 -14
- package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/index.d.cts +24 -4
- package/dist/adapters/sandbox/e2b/index.d.ts +24 -4
- package/dist/adapters/sandbox/e2b/index.js +26 -14
- package/dist/adapters/sandbox/e2b/index.js.map +1 -1
- package/dist/adapters/sandbox/e2b/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/e2b/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/inmemory/index.cjs +3 -3
- package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.d.cts +4 -4
- package/dist/adapters/sandbox/inmemory/index.d.ts +4 -4
- package/dist/adapters/sandbox/inmemory/index.js +3 -3
- package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.d.ts +1 -1
- package/dist/adapters/thread/anthropic/index.cjs +23 -3
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +5 -5
- package/dist/adapters/thread/anthropic/index.d.ts +5 -5
- package/dist/adapters/thread/anthropic/index.js +23 -3
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +2 -1
- package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +5 -5
- package/dist/adapters/thread/anthropic/workflow.d.ts +5 -5
- package/dist/adapters/thread/anthropic/workflow.js +2 -1
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.cjs +27 -3
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +5 -5
- package/dist/adapters/thread/google-genai/index.d.ts +5 -5
- package/dist/adapters/thread/google-genai/index.js +27 -3
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.cjs +2 -1
- package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +5 -5
- package/dist/adapters/thread/google-genai/workflow.d.ts +5 -5
- package/dist/adapters/thread/google-genai/workflow.js +2 -1
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/langchain/index.cjs +23 -3
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +5 -5
- package/dist/adapters/thread/langchain/index.d.ts +5 -5
- package/dist/adapters/thread/langchain/index.js +23 -3
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +2 -1
- package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +5 -5
- package/dist/adapters/thread/langchain/workflow.d.ts +5 -5
- package/dist/adapters/thread/langchain/workflow.js +2 -1
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/index.cjs +120 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -11
- package/dist/index.d.ts +11 -11
- package/dist/index.js +121 -31
- package/dist/index.js.map +1 -1
- package/dist/{proxy-0smGKvx8.d.ts → proxy-CUlKSvZS.d.ts} +1 -1
- package/dist/{proxy-DEtowJyd.d.cts → proxy-D_3x7RN4.d.cts} +1 -1
- package/dist/{thread-manager-C-C4pI2z.d.ts → thread-manager-CVu7o2cs.d.ts} +4 -2
- package/dist/{thread-manager-D4vgzYrh.d.cts → thread-manager-HSwyh28L.d.cts} +4 -2
- package/dist/{thread-manager-3fszQih4.d.ts → thread-manager-c1gPopAG.d.ts} +4 -2
- package/dist/{thread-manager-CzYln2OC.d.cts → thread-manager-wGi-LqIP.d.cts} +4 -2
- package/dist/{types-B37hKoWA.d.ts → types-BH_IRryz.d.ts} +10 -1
- package/dist/{types-D08CXPh8.d.cts → types-BaOw4hKI.d.cts} +10 -1
- package/dist/{types-CPKDl-y_.d.ts → types-C06FwR96.d.cts} +59 -4
- package/dist/{types-CNuWnvy9.d.ts → types-DAsQ21Rt.d.ts} +1 -1
- package/dist/{types-BO7Yju20.d.cts → types-DNr31FzL.d.ts} +59 -4
- package/dist/{types-DWEUmYAJ.d.cts → types-lm8tMNJQ.d.cts} +1 -1
- package/dist/{types-tQL9njTu.d.cts → types-yx0LzPGn.d.cts} +21 -7
- package/dist/{types-tQL9njTu.d.ts → types-yx0LzPGn.d.ts} +21 -7
- package/dist/{workflow-CjXHbZZc.d.ts → workflow-CSCkpwAL.d.ts} +2 -2
- package/dist/{workflow-Do_lzJpT.d.cts → workflow-DuvMZ8Vm.d.cts} +2 -2
- package/dist/workflow.cjs +94 -18
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +3 -3
- package/dist/workflow.d.ts +3 -3
- package/dist/workflow.js +95 -19
- package/dist/workflow.js.map +1 -1
- package/package.json +2 -2
- package/src/adapters/sandbox/bedrock/index.ts +12 -3
- package/src/adapters/sandbox/daytona/index.ts +12 -3
- package/src/adapters/sandbox/e2b/index.ts +36 -14
- package/src/adapters/sandbox/e2b/types.ts +16 -0
- package/src/adapters/sandbox/inmemory/index.ts +12 -3
- package/src/adapters/thread/anthropic/activities.ts +9 -0
- package/src/adapters/thread/anthropic/model-invoker.ts +3 -1
- package/src/adapters/thread/anthropic/thread-manager.ts +3 -0
- package/src/adapters/thread/google-genai/activities.ts +13 -0
- package/src/adapters/thread/google-genai/model-invoker.ts +3 -1
- package/src/adapters/thread/google-genai/thread-manager.ts +3 -0
- package/src/adapters/thread/langchain/activities.ts +9 -0
- package/src/adapters/thread/langchain/model-invoker.ts +2 -1
- package/src/adapters/thread/langchain/thread-manager.ts +3 -0
- package/src/lib/lifecycle.ts +11 -4
- package/src/lib/model/types.ts +10 -0
- package/src/lib/sandbox/manager.ts +26 -18
- package/src/lib/sandbox/types.ts +27 -7
- package/src/lib/session/session-edge-cases.integration.test.ts +265 -1
- package/src/lib/session/session.integration.test.ts +22 -1
- package/src/lib/session/session.ts +61 -7
- package/src/lib/session/types.ts +12 -0
- package/src/lib/subagent/subagent.integration.test.ts +100 -104
- package/src/lib/thread/manager.ts +18 -0
- package/src/lib/thread/proxy.ts +1 -0
- package/src/lib/thread/types.ts +9 -0
- package/src/lib/tool-router/index.ts +2 -0
- package/src/lib/tool-router/router-edge-cases.integration.test.ts +92 -0
- package/src/lib/tool-router/router.integration.test.ts +12 -0
- package/src/lib/tool-router/router.ts +89 -16
- package/src/lib/tool-router/types.ts +34 -1
- 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
|
-
|
|
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 {
|
|
382
|
-
const
|
|
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 =
|
|
408
|
-
if (!lastCall) throw new Error("expected
|
|
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 {
|
|
440
|
-
const
|
|
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 =
|
|
462
|
-
if (!lastCall) throw new Error("expected
|
|
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 {
|
|
469
|
-
const
|
|
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 =
|
|
490
|
-
if (!lastCall) throw new Error("expected
|
|
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 {
|
|
497
|
-
const
|
|
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 =
|
|
514
|
-
if (!lastCall) throw new Error("expected
|
|
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 {
|
|
521
|
-
const
|
|
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 =
|
|
543
|
-
if (!lastCall) throw new Error("expected
|
|
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 {
|
|
552
|
-
const
|
|
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 =
|
|
574
|
-
if (!lastCall) throw new Error("expected
|
|
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 {
|
|
584
|
-
const
|
|
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 =
|
|
606
|
-
if (!lastCall) throw new Error("expected
|
|
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 {
|
|
616
|
-
const
|
|
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 =
|
|
637
|
-
if (!lastCall) throw new Error("expected
|
|
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 {
|
|
646
|
-
const
|
|
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 =
|
|
668
|
-
if (!lastCall) throw new Error("expected
|
|
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 {
|
|
675
|
-
const
|
|
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 =
|
|
717
|
-
if (!secondCall) throw new Error("expected second
|
|
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 {
|
|
731
|
-
const
|
|
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 =
|
|
768
|
-
if (!secondCall) throw new Error("expected
|
|
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 {
|
|
886
|
-
const
|
|
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 =
|
|
907
|
-
if (!lastCall) throw new Error("expected
|
|
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 {
|
|
914
|
-
const
|
|
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 =
|
|
936
|
-
if (!lastCall) throw new Error("expected
|
|
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 {
|
|
965
|
-
const
|
|
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 =
|
|
991
|
-
if (!lastCall) throw new Error("expected
|
|
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 {
|
|
1003
|
-
const
|
|
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 =
|
|
1049
|
-
if (!secondCall) throw new Error("expected
|
|
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 {
|
|
1062
|
-
const
|
|
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 =
|
|
1092
|
-
if (!firstCall) throw new Error("expected
|
|
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 =
|
|
1111
|
-
if (!secondCall) throw new Error("expected
|
|
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 {
|
|
1123
|
-
const
|
|
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 =
|
|
1164
|
-
if (!secondCall) throw new Error("expected
|
|
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 {
|
|
1402
|
-
const
|
|
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 =
|
|
1432
|
-
if (!firstCall) throw new Error("expected
|
|
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 {
|
|
1439
|
-
const
|
|
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 =
|
|
1469
|
-
if (!firstCall) throw new Error("expected
|
|
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 {
|
|
1476
|
-
const
|
|
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 =
|
|
1506
|
-
if (!firstCall) throw new Error("expected
|
|
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 {
|
|
1513
|
-
const
|
|
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 =
|
|
1543
|
-
if (!firstCall) throw new Error("expected
|
|
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 {
|
|
1552
|
-
const
|
|
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 =
|
|
1593
|
-
if (!firstCall) throw new Error("expected
|
|
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 {
|
|
1601
|
-
const
|
|
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 =
|
|
1664
|
-
if (!secondCall) throw new Error("expected
|
|
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 {
|
|
1675
|
-
const
|
|
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 =
|
|
1735
|
-
if (!secondCall) throw new Error("expected
|
|
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
|
}
|
package/src/lib/thread/proxy.ts
CHANGED
|
@@ -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
|
}
|
package/src/lib/thread/types.ts
CHANGED
|
@@ -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
|
/**
|