zeitlich 0.2.22 → 0.2.23
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/README.md +242 -59
- package/dist/adapters/sandbox/daytona/index.cjs +4 -1
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/index.d.cts +2 -1
- package/dist/adapters/sandbox/daytona/index.d.ts +2 -1
- package/dist/adapters/sandbox/daytona/index.js +4 -1
- package/dist/adapters/sandbox/daytona/index.js.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.cjs +1 -0
- package/dist/adapters/sandbox/daytona/workflow.cjs.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/daytona/workflow.js +1 -0
- package/dist/adapters/sandbox/daytona/workflow.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.cjs +16 -2
- package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.d.cts +3 -2
- package/dist/adapters/sandbox/inmemory/index.d.ts +3 -2
- package/dist/adapters/sandbox/inmemory/index.js +16 -2
- package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.cjs +1 -0
- package/dist/adapters/sandbox/inmemory/workflow.cjs.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/sandbox/inmemory/workflow.js +1 -0
- package/dist/adapters/sandbox/inmemory/workflow.js.map +1 -1
- package/dist/adapters/sandbox/virtual/index.cjs +33 -9
- package/dist/adapters/sandbox/virtual/index.cjs.map +1 -1
- package/dist/adapters/sandbox/virtual/index.d.cts +6 -5
- package/dist/adapters/sandbox/virtual/index.d.ts +6 -5
- package/dist/adapters/sandbox/virtual/index.js +33 -9
- package/dist/adapters/sandbox/virtual/index.js.map +1 -1
- package/dist/adapters/sandbox/virtual/workflow.cjs +1 -0
- package/dist/adapters/sandbox/virtual/workflow.cjs.map +1 -1
- package/dist/adapters/sandbox/virtual/workflow.d.cts +3 -3
- package/dist/adapters/sandbox/virtual/workflow.d.ts +3 -3
- package/dist/adapters/sandbox/virtual/workflow.js +1 -0
- package/dist/adapters/sandbox/virtual/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +3 -3
- package/dist/adapters/thread/google-genai/index.d.ts +3 -3
- package/dist/adapters/thread/google-genai/workflow.d.cts +3 -3
- package/dist/adapters/thread/google-genai/workflow.d.ts +3 -3
- package/dist/adapters/thread/langchain/index.d.cts +3 -3
- package/dist/adapters/thread/langchain/index.d.ts +3 -3
- package/dist/adapters/thread/langchain/workflow.d.cts +3 -3
- package/dist/adapters/thread/langchain/workflow.d.ts +3 -3
- package/dist/index.cjs +247 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -8
- package/dist/index.d.ts +9 -8
- package/dist/index.js +245 -55
- package/dist/index.js.map +1 -1
- package/dist/{queries-Bw6WEPMw.d.cts → queries-DModcWRy.d.cts} +1 -1
- package/dist/{queries-C27raDaB.d.ts → queries-byD0jr1Y.d.ts} +1 -1
- package/dist/{types-ClsHhtwL.d.cts → types-B50pBPEV.d.ts} +159 -35
- package/dist/{types-YbL7JpEA.d.cts → types-Bll19FZJ.d.cts} +7 -0
- package/dist/{types-YbL7JpEA.d.ts → types-Bll19FZJ.d.ts} +7 -0
- package/dist/{types-BJ8itUAl.d.cts → types-BuXdFhaZ.d.cts} +6 -6
- package/dist/{types-HBosetv3.d.cts → types-ChAMwU3q.d.cts} +2 -0
- package/dist/{types-HBosetv3.d.ts → types-ChAMwU3q.d.ts} +2 -0
- package/dist/{types-C5bkx6kQ.d.ts → types-DQW8l7pY.d.cts} +159 -35
- package/dist/{types-ENYCKFBk.d.ts → types-GZ76HZSj.d.ts} +6 -6
- package/dist/workflow.cjs +241 -57
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +49 -32
- package/dist/workflow.d.ts +49 -32
- package/dist/workflow.js +239 -55
- package/dist/workflow.js.map +1 -1
- package/package.json +2 -2
- package/src/adapters/sandbox/daytona/filesystem.ts +1 -1
- package/src/adapters/sandbox/daytona/index.ts +4 -0
- package/src/adapters/sandbox/daytona/proxy.ts +4 -3
- package/src/adapters/sandbox/e2b/index.ts +5 -0
- package/src/adapters/sandbox/inmemory/index.ts +24 -4
- package/src/adapters/sandbox/inmemory/proxy.ts +2 -2
- package/src/adapters/sandbox/virtual/filesystem.ts +41 -17
- package/src/adapters/sandbox/virtual/provider.ts +4 -0
- package/src/adapters/sandbox/virtual/proxy.ts +1 -0
- package/src/adapters/sandbox/virtual/types.ts +9 -4
- package/src/lib/lifecycle.ts +57 -0
- package/src/lib/sandbox/manager.ts +13 -1
- package/src/lib/sandbox/types.ts +13 -4
- package/src/lib/session/index.ts +1 -0
- package/src/lib/session/session-edge-cases.integration.test.ts +447 -33
- package/src/lib/session/session.integration.test.ts +52 -32
- package/src/lib/session/session.ts +107 -33
- package/src/lib/session/types.ts +55 -16
- package/src/lib/subagent/define.ts +5 -4
- package/src/lib/subagent/handler.ts +139 -14
- package/src/lib/subagent/index.ts +3 -0
- package/src/lib/subagent/register.ts +10 -3
- package/src/lib/subagent/signals.ts +8 -0
- package/src/lib/subagent/subagent.integration.test.ts +853 -150
- package/src/lib/subagent/tool.ts +2 -2
- package/src/lib/subagent/types.ts +77 -19
- package/src/lib/subagent/workflow.ts +83 -12
- package/src/lib/tool-router/router.integration.test.ts +137 -4
- package/src/lib/tool-router/router.ts +13 -3
- package/src/lib/tool-router/types.ts +7 -0
- package/src/lib/workflow.test.ts +89 -21
- package/src/lib/workflow.ts +33 -18
- package/src/workflow.ts +6 -1
|
@@ -38,7 +38,11 @@ vi.mock("@temporalio/workflow", () => {
|
|
|
38
38
|
condition: async (fn: () => boolean) => fn(),
|
|
39
39
|
defineUpdate: (name: string) => ({ __type: "update", name }),
|
|
40
40
|
defineQuery: (name: string) => ({ __type: "query", name }),
|
|
41
|
+
defineSignal: (name: string) => ({ __type: "signal", name }),
|
|
41
42
|
setHandler: (_def: unknown, _handler: unknown) => {},
|
|
43
|
+
startChild: async () => ({ result: () => Promise.resolve(null) }),
|
|
44
|
+
workflowInfo: () => ({ taskQueue: "default-queue" }),
|
|
45
|
+
getExternalWorkflowHandle: () => ({ signal: async () => {} }),
|
|
42
46
|
uuid4: () =>
|
|
43
47
|
`00000000-0000-0000-0000-${String(++idCounter).padStart(12, "0")}`,
|
|
44
48
|
ApplicationFailure: MockApplicationFailure,
|
|
@@ -150,7 +154,7 @@ describe("createSession integration", () => {
|
|
|
150
154
|
|
|
151
155
|
const session = await createSession({
|
|
152
156
|
agentName: "TestAgent",
|
|
153
|
-
threadId: "thread-1",
|
|
157
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
154
158
|
runAgent: createScriptedRunAgent([{ message: "Hello!", toolCalls: [] }]),
|
|
155
159
|
threadOps: ops,
|
|
156
160
|
buildContextMessage: () => "What is 2+2?",
|
|
@@ -182,7 +186,7 @@ describe("createSession integration", () => {
|
|
|
182
186
|
|
|
183
187
|
const session = await createSession({
|
|
184
188
|
agentName: "TestAgent",
|
|
185
|
-
threadId: "thread-1",
|
|
189
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
186
190
|
runAgent: createScriptedRunAgent([
|
|
187
191
|
{
|
|
188
192
|
message: "Let me echo that.",
|
|
@@ -221,7 +225,7 @@ describe("createSession integration", () => {
|
|
|
221
225
|
|
|
222
226
|
const session = await createSession({
|
|
223
227
|
agentName: "TestAgent",
|
|
224
|
-
threadId: "thread-1",
|
|
228
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
225
229
|
runAgent: createScriptedRunAgent([
|
|
226
230
|
{
|
|
227
231
|
message: "turn 1",
|
|
@@ -270,7 +274,7 @@ describe("createSession integration", () => {
|
|
|
270
274
|
|
|
271
275
|
const session = await createSession({
|
|
272
276
|
agentName: "TestAgent",
|
|
273
|
-
threadId: "thread-1",
|
|
277
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
274
278
|
maxTurns: 3,
|
|
275
279
|
runAgent: infiniteAgent,
|
|
276
280
|
threadOps: ops,
|
|
@@ -297,7 +301,7 @@ describe("createSession integration", () => {
|
|
|
297
301
|
|
|
298
302
|
const session = await createSession({
|
|
299
303
|
agentName: "TestAgent",
|
|
300
|
-
threadId: "thread-1",
|
|
304
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
301
305
|
runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
|
|
302
306
|
threadOps: ops,
|
|
303
307
|
buildContextMessage: () => "hi",
|
|
@@ -330,7 +334,7 @@ describe("createSession integration", () => {
|
|
|
330
334
|
|
|
331
335
|
const session = await createSession({
|
|
332
336
|
agentName: "TestAgent",
|
|
333
|
-
threadId: "thread-1",
|
|
337
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
334
338
|
runAgent: createScriptedRunAgent([]),
|
|
335
339
|
threadOps: ops,
|
|
336
340
|
buildContextMessage: () => "hi",
|
|
@@ -350,7 +354,7 @@ describe("createSession integration", () => {
|
|
|
350
354
|
|
|
351
355
|
const session = await createSession({
|
|
352
356
|
agentName: "TestAgent",
|
|
353
|
-
threadId: "thread-1",
|
|
357
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
354
358
|
appendSystemPrompt: false,
|
|
355
359
|
runAgent: createScriptedRunAgent([{ message: "ok", toolCalls: [] }]),
|
|
356
360
|
threadOps: ops,
|
|
@@ -377,7 +381,7 @@ describe("createSession integration", () => {
|
|
|
377
381
|
|
|
378
382
|
const session = await createSession({
|
|
379
383
|
agentName: "TestAgent",
|
|
380
|
-
threadId: "thread-1",
|
|
384
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
381
385
|
runAgent: createScriptedRunAgent([
|
|
382
386
|
{
|
|
383
387
|
message: "turn 1",
|
|
@@ -413,7 +417,7 @@ describe("createSession integration", () => {
|
|
|
413
417
|
|
|
414
418
|
const session = await createSession({
|
|
415
419
|
agentName: "TestAgent",
|
|
416
|
-
threadId: "thread-1",
|
|
420
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
417
421
|
runAgent: createScriptedRunAgent([
|
|
418
422
|
{
|
|
419
423
|
message: "bad call",
|
|
@@ -451,15 +455,14 @@ describe("createSession integration", () => {
|
|
|
451
455
|
expect(errorConfig?.content).toContain("Invalid tool call");
|
|
452
456
|
});
|
|
453
457
|
|
|
454
|
-
// ---
|
|
458
|
+
// --- Thread fork mode ---
|
|
455
459
|
|
|
456
|
-
it("forks thread when
|
|
460
|
+
it("forks thread when thread mode is fork", async () => {
|
|
457
461
|
const { ops, log } = createMockThreadOps();
|
|
458
462
|
|
|
459
463
|
const session = await createSession({
|
|
460
464
|
agentName: "TestAgent",
|
|
461
|
-
threadId: "source-thread",
|
|
462
|
-
continueThread: true,
|
|
465
|
+
thread: { mode: "fork", threadId: "source-thread" },
|
|
463
466
|
runAgent: createScriptedRunAgent([
|
|
464
467
|
{ message: "continued", toolCalls: [] },
|
|
465
468
|
]),
|
|
@@ -490,9 +493,9 @@ describe("createSession integration", () => {
|
|
|
490
493
|
const sandboxLog: string[] = [];
|
|
491
494
|
|
|
492
495
|
const sandboxOps: SandboxOps = {
|
|
493
|
-
createSandbox: async (
|
|
494
|
-
sandboxLog.push(
|
|
495
|
-
return { sandboxId:
|
|
496
|
+
createSandbox: async () => {
|
|
497
|
+
sandboxLog.push("create");
|
|
498
|
+
return { sandboxId: "sb-1" };
|
|
496
499
|
},
|
|
497
500
|
destroySandbox: async (sandboxId: string) => {
|
|
498
501
|
sandboxLog.push(`destroy:${sandboxId}`);
|
|
@@ -504,15 +507,16 @@ describe("createSession integration", () => {
|
|
|
504
507
|
createdAt: new Date().toISOString(),
|
|
505
508
|
}),
|
|
506
509
|
forkSandbox: async () => "forked-sandbox-id",
|
|
510
|
+
pauseSandbox: async () => {},
|
|
507
511
|
};
|
|
508
512
|
|
|
509
513
|
const session = await createSession({
|
|
510
514
|
agentName: "TestAgent",
|
|
511
|
-
threadId: "thread-1",
|
|
515
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
512
516
|
runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
|
|
513
517
|
threadOps: ops,
|
|
514
518
|
buildContextMessage: () => "go",
|
|
515
|
-
|
|
519
|
+
sandboxOps,
|
|
516
520
|
});
|
|
517
521
|
|
|
518
522
|
const stateManager = createAgentStateManager({
|
|
@@ -521,8 +525,8 @@ describe("createSession integration", () => {
|
|
|
521
525
|
|
|
522
526
|
await session.runSession({ stateManager });
|
|
523
527
|
|
|
524
|
-
expect(sandboxLog).toContain("create
|
|
525
|
-
expect(sandboxLog).toContain("destroy:sb-
|
|
528
|
+
expect(sandboxLog).toContain("create");
|
|
529
|
+
expect(sandboxLog).toContain("destroy:sb-1");
|
|
526
530
|
});
|
|
527
531
|
|
|
528
532
|
it("does not create or destroy sandbox when sandboxId is inherited", async () => {
|
|
@@ -544,16 +548,17 @@ describe("createSession integration", () => {
|
|
|
544
548
|
createdAt: new Date().toISOString(),
|
|
545
549
|
}),
|
|
546
550
|
forkSandbox: async () => "forked-sandbox-id",
|
|
551
|
+
pauseSandbox: async () => {},
|
|
547
552
|
};
|
|
548
553
|
|
|
549
554
|
const session = await createSession({
|
|
550
555
|
agentName: "TestAgent",
|
|
551
|
-
threadId: "thread-1",
|
|
556
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
552
557
|
runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
|
|
553
558
|
threadOps: ops,
|
|
554
559
|
buildContextMessage: () => "go",
|
|
555
|
-
|
|
556
|
-
sandboxId: "inherited-sb",
|
|
560
|
+
sandboxOps,
|
|
561
|
+
sandbox: { mode: "inherit", sandboxId: "inherited-sb" },
|
|
557
562
|
});
|
|
558
563
|
|
|
559
564
|
const stateManager = createAgentStateManager({
|
|
@@ -581,9 +586,22 @@ describe("createSession integration", () => {
|
|
|
581
586
|
},
|
|
582
587
|
});
|
|
583
588
|
|
|
589
|
+
const sandboxOps: SandboxOps = {
|
|
590
|
+
createSandbox: async () => ({ sandboxId: "sb" }),
|
|
591
|
+
destroySandbox: async () => {},
|
|
592
|
+
pauseSandbox: async () => {},
|
|
593
|
+
snapshotSandbox: async () => ({
|
|
594
|
+
sandboxId: "sb",
|
|
595
|
+
providerId: "test",
|
|
596
|
+
data: null,
|
|
597
|
+
createdAt: new Date().toISOString(),
|
|
598
|
+
}),
|
|
599
|
+
forkSandbox: async () => "forked-sb",
|
|
600
|
+
};
|
|
601
|
+
|
|
584
602
|
const session = await createSession({
|
|
585
603
|
agentName: "TestAgent",
|
|
586
|
-
threadId: "thread-1",
|
|
604
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
587
605
|
runAgent: createScriptedRunAgent([
|
|
588
606
|
{
|
|
589
607
|
message: "spy",
|
|
@@ -594,7 +612,8 @@ describe("createSession integration", () => {
|
|
|
594
612
|
threadOps: ops,
|
|
595
613
|
tools: { Spy: spyTool },
|
|
596
614
|
buildContextMessage: () => "go",
|
|
597
|
-
sandboxId: "my-sandbox",
|
|
615
|
+
sandbox: { mode: "inherit", sandboxId: "my-sandbox" },
|
|
616
|
+
sandboxOps,
|
|
598
617
|
});
|
|
599
618
|
|
|
600
619
|
const stateManager = createAgentStateManager({
|
|
@@ -614,7 +633,7 @@ describe("createSession integration", () => {
|
|
|
614
633
|
|
|
615
634
|
const session = await createSession({
|
|
616
635
|
agentName: "TestAgent",
|
|
617
|
-
threadId: "thread-1",
|
|
636
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
618
637
|
runAgent: async () => {
|
|
619
638
|
throw new Error("LLM went down");
|
|
620
639
|
},
|
|
@@ -646,7 +665,7 @@ describe("createSession integration", () => {
|
|
|
646
665
|
|
|
647
666
|
const session = await createSession({
|
|
648
667
|
agentName: "TestAgent",
|
|
649
|
-
threadId: "thread-1",
|
|
668
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
650
669
|
runAgent: createScriptedRunAgent([
|
|
651
670
|
{
|
|
652
671
|
message: "call echo",
|
|
@@ -716,7 +735,7 @@ describe("createSession integration", () => {
|
|
|
716
735
|
|
|
717
736
|
const session = await createSession({
|
|
718
737
|
agentName: "TestAgent",
|
|
719
|
-
threadId: "thread-1",
|
|
738
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
720
739
|
runAgent: createScriptedRunAgent([
|
|
721
740
|
{
|
|
722
741
|
message: "computing",
|
|
@@ -752,7 +771,7 @@ describe("createSession integration", () => {
|
|
|
752
771
|
|
|
753
772
|
const session = await createSession({
|
|
754
773
|
agentName: "TestAgent",
|
|
755
|
-
threadId: "thread-1",
|
|
774
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
756
775
|
runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
|
|
757
776
|
threadOps: ops,
|
|
758
777
|
buildContextMessage: async () => {
|
|
@@ -789,15 +808,16 @@ describe("createSession integration", () => {
|
|
|
789
808
|
createdAt: new Date().toISOString(),
|
|
790
809
|
}),
|
|
791
810
|
forkSandbox: async () => "forked-sandbox-id",
|
|
811
|
+
pauseSandbox: async () => {},
|
|
792
812
|
};
|
|
793
813
|
|
|
794
814
|
const session = await createSession({
|
|
795
815
|
agentName: "TestAgent",
|
|
796
|
-
threadId: "thread-1",
|
|
816
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
797
817
|
runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
|
|
798
818
|
threadOps: ops,
|
|
799
819
|
buildContextMessage: () => "go",
|
|
800
|
-
|
|
820
|
+
sandboxOps,
|
|
801
821
|
});
|
|
802
822
|
|
|
803
823
|
const stateManager = createAgentStateManager<{ customField: string }>({
|
|
@@ -827,7 +847,7 @@ describe("createSession integration", () => {
|
|
|
827
847
|
|
|
828
848
|
const session = await createSession({
|
|
829
849
|
agentName: "TestAgent",
|
|
830
|
-
threadId: "thread-1",
|
|
850
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
831
851
|
runAgent: createScriptedRunAgent([
|
|
832
852
|
{
|
|
833
853
|
message: "t1",
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "@temporalio/workflow";
|
|
7
7
|
import type { SessionExitReason, MessageContent } from "../types";
|
|
8
8
|
import type { SessionConfig, ZeitlichSession } from "./types";
|
|
9
|
+
import type { SandboxOps } from "../sandbox/types";
|
|
9
10
|
import { type AgentStateManager, type JsonSerializable } from "../state/types";
|
|
10
11
|
import { createToolRouter } from "../tool-router/router";
|
|
11
12
|
import type { ParsedToolCallUnion, ToolMap } from "../tool-router/types";
|
|
@@ -18,6 +19,9 @@ import { uuid4 } from "@temporalio/workflow";
|
|
|
18
19
|
* Creates an agent session that manages the agent loop: LLM invocation,
|
|
19
20
|
* tool routing, subagent coordination, and lifecycle hooks.
|
|
20
21
|
*
|
|
22
|
+
* When `sandboxOps` is provided the returned session result is guaranteed to
|
|
23
|
+
* include `sandboxId: string`. Without it, `sandboxId` is `undefined`.
|
|
24
|
+
*
|
|
21
25
|
* @param config - Session and agent configuration (merged `SessionConfig` and `AgentConfig`)
|
|
22
26
|
* @returns A session object with `runSession()` to start the agent loop
|
|
23
27
|
*
|
|
@@ -29,8 +33,8 @@ import { uuid4 } from "@temporalio/workflow";
|
|
|
29
33
|
* const session = await createSession({
|
|
30
34
|
* agentName: "my-agent",
|
|
31
35
|
* maxTurns: 20,
|
|
32
|
-
*
|
|
33
|
-
* threadOps: proxyGoogleGenAIThreadOps(),
|
|
36
|
+
* thread: { mode: "new" },
|
|
37
|
+
* threadOps: proxyGoogleGenAIThreadOps(),
|
|
34
38
|
* runAgent: runAgentActivity,
|
|
35
39
|
* buildContextMessage: () => [{ type: "text", text: prompt }],
|
|
36
40
|
* subagents: [researcherSubagent],
|
|
@@ -42,8 +46,13 @@ import { uuid4 } from "@temporalio/workflow";
|
|
|
42
46
|
* const { finalMessage, exitReason } = await session.runSession({ stateManager });
|
|
43
47
|
* ```
|
|
44
48
|
*/
|
|
45
|
-
export
|
|
46
|
-
|
|
49
|
+
export async function createSession<T extends ToolMap, M = unknown>(
|
|
50
|
+
config: SessionConfig<T, M> & { sandboxOps: SandboxOps }
|
|
51
|
+
): Promise<ZeitlichSession<M, true>>;
|
|
52
|
+
export async function createSession<T extends ToolMap, M = unknown>(
|
|
53
|
+
config: SessionConfig<T, M>
|
|
54
|
+
): Promise<ZeitlichSession<M, false>>;
|
|
55
|
+
export async function createSession<T extends ToolMap, M = unknown>({
|
|
47
56
|
agentName,
|
|
48
57
|
maxTurns = 50,
|
|
49
58
|
metadata = {},
|
|
@@ -56,16 +65,33 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
56
65
|
processToolsInParallel = true,
|
|
57
66
|
hooks = {},
|
|
58
67
|
appendSystemPrompt = true,
|
|
59
|
-
continueThread = false,
|
|
60
68
|
waitForInputTimeout = "48h",
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
sandboxOps,
|
|
70
|
+
thread: threadInit,
|
|
71
|
+
sandbox: sandboxInit,
|
|
72
|
+
sandboxShutdown = "destroy",
|
|
73
|
+
}: SessionConfig<T, M>): Promise<ZeitlichSession<M, boolean>> {
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Thread resolution
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
const threadMode = threadInit?.mode ?? "new";
|
|
78
|
+
let threadId: string;
|
|
79
|
+
let sourceThreadId: string | undefined;
|
|
80
|
+
|
|
81
|
+
switch (threadMode) {
|
|
82
|
+
case "new":
|
|
83
|
+
threadId = threadInit?.mode === "new" && threadInit.threadId
|
|
84
|
+
? threadInit.threadId
|
|
85
|
+
: getShortId();
|
|
86
|
+
break;
|
|
87
|
+
case "continue":
|
|
88
|
+
threadId = (threadInit as { mode: "continue"; threadId: string }).threadId;
|
|
89
|
+
break;
|
|
90
|
+
case "fork":
|
|
91
|
+
sourceThreadId = (threadInit as { mode: "fork"; threadId: string }).threadId;
|
|
92
|
+
threadId = getShortId();
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
69
95
|
|
|
70
96
|
const {
|
|
71
97
|
appendToolResult,
|
|
@@ -76,9 +102,13 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
76
102
|
} = threadOps;
|
|
77
103
|
|
|
78
104
|
const plugins: ToolMap[string][] = [];
|
|
105
|
+
let destroySubagentSandboxes: (() => Promise<void>) | undefined;
|
|
79
106
|
if (subagents) {
|
|
80
|
-
const
|
|
81
|
-
if (
|
|
107
|
+
const result = buildSubagentRegistration(subagents);
|
|
108
|
+
if (result) {
|
|
109
|
+
plugins.push(result.registration);
|
|
110
|
+
destroySubagentSandboxes = result.destroySubagentSandboxes;
|
|
111
|
+
}
|
|
82
112
|
}
|
|
83
113
|
if (skills) {
|
|
84
114
|
const reg = buildSkillRegistration(skills);
|
|
@@ -114,12 +144,7 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
114
144
|
stateManager,
|
|
115
145
|
}: {
|
|
116
146
|
stateManager: AgentStateManager<TState>;
|
|
117
|
-
})
|
|
118
|
-
threadId: string;
|
|
119
|
-
finalMessage: M | null;
|
|
120
|
-
exitReason: SessionExitReason;
|
|
121
|
-
usage: ReturnType<AgentStateManager<TState>["getTotalUsage"]>;
|
|
122
|
-
}> => {
|
|
147
|
+
}) => {
|
|
123
148
|
setHandler(
|
|
124
149
|
defineUpdate<unknown, [MessageContent]>(`add${agentName}Message`),
|
|
125
150
|
async (message: MessageContent) => {
|
|
@@ -140,12 +165,43 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
140
165
|
}
|
|
141
166
|
);
|
|
142
167
|
|
|
143
|
-
// --- Sandbox lifecycle: create or inherit
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
168
|
+
// --- Sandbox lifecycle: create, continue, fork, or inherit ----------
|
|
169
|
+
const sandboxMode = sandboxInit?.mode;
|
|
170
|
+
let sandboxId: string | undefined;
|
|
171
|
+
let sandboxOwned = false;
|
|
172
|
+
|
|
173
|
+
if (sandboxMode === "inherit") {
|
|
174
|
+
sandboxId = (sandboxInit as { mode: "inherit"; sandboxId: string }).sandboxId;
|
|
175
|
+
if (!sandboxOps) {
|
|
176
|
+
throw ApplicationFailure.create({
|
|
177
|
+
message: "sandboxId provided but no sandboxOps — cannot manage sandbox lifecycle",
|
|
178
|
+
nonRetryable: true,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
} else if (sandboxMode === "continue") {
|
|
182
|
+
if (!sandboxOps) {
|
|
183
|
+
throw ApplicationFailure.create({
|
|
184
|
+
message: "No sandboxOps provided — cannot continue sandbox",
|
|
185
|
+
nonRetryable: true,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
sandboxId = (sandboxInit as { mode: "continue"; sandboxId: string }).sandboxId;
|
|
189
|
+
sandboxOwned = true;
|
|
190
|
+
} else if (sandboxMode === "fork") {
|
|
191
|
+
if (!sandboxOps) {
|
|
192
|
+
throw ApplicationFailure.create({
|
|
193
|
+
message: "No sandboxOps provided — cannot fork sandbox",
|
|
194
|
+
nonRetryable: true,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
sandboxId = await sandboxOps.forkSandbox(
|
|
198
|
+
(sandboxInit as { mode: "fork"; sandboxId: string }).sandboxId
|
|
199
|
+
);
|
|
200
|
+
sandboxOwned = true;
|
|
201
|
+
} else if (sandboxOps) {
|
|
202
|
+
const result = await sandboxOps.createSandbox();
|
|
148
203
|
sandboxId = result.sandboxId;
|
|
204
|
+
sandboxOwned = true;
|
|
149
205
|
if (result.stateUpdate) {
|
|
150
206
|
stateManager.mergeUpdate(result.stateUpdate as Partial<TState>);
|
|
151
207
|
}
|
|
@@ -161,8 +217,11 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
161
217
|
|
|
162
218
|
const systemPrompt = stateManager.getSystemPrompt();
|
|
163
219
|
|
|
164
|
-
|
|
220
|
+
// --- Thread lifecycle: new, continue, or fork ----------------------
|
|
221
|
+
if (threadMode === "fork" && sourceThreadId) {
|
|
165
222
|
await forkThread(sourceThreadId, threadId);
|
|
223
|
+
} else if (threadMode === "continue") {
|
|
224
|
+
// "continue" — thread already exists, just append the new message
|
|
166
225
|
} else {
|
|
167
226
|
if (appendSystemPrompt) {
|
|
168
227
|
if (!systemPrompt || systemPrompt.trim() === "") {
|
|
@@ -209,7 +268,8 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
209
268
|
finalMessage: message,
|
|
210
269
|
exitReason,
|
|
211
270
|
usage: stateManager.getTotalUsage(),
|
|
212
|
-
|
|
271
|
+
sandboxId,
|
|
272
|
+
} as Awaited<ReturnType<ZeitlichSession<M, boolean>["runSession"]>>;
|
|
213
273
|
}
|
|
214
274
|
|
|
215
275
|
const parsedToolCalls: ParsedToolCallUnion<T>[] = [];
|
|
@@ -265,8 +325,22 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
265
325
|
} finally {
|
|
266
326
|
await callSessionEnd(exitReason, stateManager.getTurns());
|
|
267
327
|
|
|
268
|
-
if (
|
|
269
|
-
|
|
328
|
+
if (sandboxOwned && sandboxId && sandboxOps) {
|
|
329
|
+
switch (sandboxShutdown) {
|
|
330
|
+
case "destroy":
|
|
331
|
+
await sandboxOps.destroySandbox(sandboxId);
|
|
332
|
+
break;
|
|
333
|
+
case "pause":
|
|
334
|
+
case "pause-until-parent-close":
|
|
335
|
+
await sandboxOps.pauseSandbox(sandboxId);
|
|
336
|
+
break;
|
|
337
|
+
case "keep":
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (destroySubagentSandboxes) {
|
|
343
|
+
await destroySubagentSandboxes();
|
|
270
344
|
}
|
|
271
345
|
}
|
|
272
346
|
|
|
@@ -275,8 +349,8 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
275
349
|
finalMessage: null,
|
|
276
350
|
exitReason,
|
|
277
351
|
usage: stateManager.getTotalUsage(),
|
|
278
|
-
|
|
352
|
+
sandboxId,
|
|
353
|
+
} as Awaited<ReturnType<ZeitlichSession<M, boolean>["runSession"]>>;
|
|
279
354
|
},
|
|
280
355
|
};
|
|
281
|
-
}
|
|
282
|
-
|
|
356
|
+
}
|
package/src/lib/session/types.ts
CHANGED
|
@@ -16,6 +16,7 @@ import type { SandboxOps } from "../sandbox/types";
|
|
|
16
16
|
import type { RunAgentActivity } from "../model/types";
|
|
17
17
|
import type { AgentStateManager, JsonSerializable } from "../state/types";
|
|
18
18
|
import type { ActivityInterfaceFor } from "@temporalio/workflow";
|
|
19
|
+
import type { ThreadInit, SandboxInit, SubagentSandboxShutdown } from "../lifecycle";
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Thread operations required by a session.
|
|
@@ -79,8 +80,6 @@ export type PrefixedThreadOps<TPrefix extends string> = {
|
|
|
79
80
|
export interface SessionConfig<T extends ToolMap, M = unknown> {
|
|
80
81
|
/** The name of the agent, should be unique within the workflows */
|
|
81
82
|
agentName: string;
|
|
82
|
-
/** The thread ID to use for the session (defaults to a short generated ID) */
|
|
83
|
-
threadId?: string;
|
|
84
83
|
/** Metadata for the session */
|
|
85
84
|
metadata?: Record<string, unknown>;
|
|
86
85
|
/** Whether to append the system prompt as message to the thread */
|
|
@@ -106,27 +105,67 @@ export interface SessionConfig<T extends ToolMap, M = unknown> {
|
|
|
106
105
|
* Returns MessageContent array for the initial HumanMessage.
|
|
107
106
|
*/
|
|
108
107
|
buildContextMessage: () => MessageContent | Promise<MessageContent>;
|
|
109
|
-
/** When true, skip thread initialization and system prompt — append only the new human message to the existing thread. */
|
|
110
|
-
continueThread?: boolean;
|
|
111
108
|
/** How long to wait for input before cancelling the workflow */
|
|
112
109
|
waitForInputTimeout?: Duration;
|
|
110
|
+
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
// Thread lifecycle
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Thread initialization strategy (default: `{ mode: "new" }`).
|
|
117
|
+
*
|
|
118
|
+
* - `{ mode: "new" }` — start a fresh thread.
|
|
119
|
+
* - `{ mode: "new", threadId: "..." }` — start a fresh thread with a specific ID.
|
|
120
|
+
* - `{ mode: "continue", threadId: "..." }` — append to an existing thread in-place.
|
|
121
|
+
* - `{ mode: "fork", threadId: "..." }` — fork an existing thread and continue in the copy.
|
|
122
|
+
*/
|
|
123
|
+
thread?: ThreadInit;
|
|
124
|
+
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Sandbox lifecycle
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
|
|
113
129
|
/** Sandbox lifecycle operations (optional — omit for agents that don't need a sandbox) */
|
|
114
|
-
|
|
130
|
+
sandboxOps?: SandboxOps;
|
|
131
|
+
/**
|
|
132
|
+
* Sandbox initialization strategy.
|
|
133
|
+
*
|
|
134
|
+
* - `{ mode: "new" }` — create a fresh sandbox.
|
|
135
|
+
* - `{ mode: "continue", sandboxId: "..." }` — resume a paused sandbox (session owns it).
|
|
136
|
+
* - `{ mode: "fork", sandboxId: "..." }` — fork from an existing sandbox.
|
|
137
|
+
* - `{ mode: "inherit", sandboxId: "..." }` — use a parent's sandbox without ownership.
|
|
138
|
+
*
|
|
139
|
+
* When omitted and `sandboxOps` is provided, defaults to `{ mode: "new" }`.
|
|
140
|
+
*/
|
|
141
|
+
sandbox?: SandboxInit;
|
|
115
142
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
143
|
+
* What to do with the sandbox when this session exits.
|
|
144
|
+
*
|
|
145
|
+
* Defaults to `"destroy"` when omitted.
|
|
146
|
+
* Has no effect when the sandbox is inherited (`sandbox.mode === "inherit"`).
|
|
119
147
|
*/
|
|
120
|
-
|
|
148
|
+
sandboxShutdown?: SubagentSandboxShutdown;
|
|
121
149
|
}
|
|
122
150
|
|
|
123
|
-
export
|
|
151
|
+
export type SessionResult<
|
|
152
|
+
M,
|
|
153
|
+
TState extends JsonSerializable<TState>,
|
|
154
|
+
HasSandbox extends boolean = boolean,
|
|
155
|
+
> = {
|
|
156
|
+
threadId: string;
|
|
157
|
+
finalMessage: M | null;
|
|
158
|
+
exitReason: SessionExitReason;
|
|
159
|
+
usage: ReturnType<AgentStateManager<TState>["getTotalUsage"]>;
|
|
160
|
+
} & (HasSandbox extends true
|
|
161
|
+
? { sandboxId: string }
|
|
162
|
+
: { sandboxId?: undefined });
|
|
163
|
+
|
|
164
|
+
export interface ZeitlichSession<
|
|
165
|
+
M = unknown,
|
|
166
|
+
HasSandbox extends boolean = boolean,
|
|
167
|
+
> {
|
|
124
168
|
runSession<T extends JsonSerializable<T>>(args: {
|
|
125
169
|
stateManager: AgentStateManager<T>;
|
|
126
|
-
}): Promise<
|
|
127
|
-
threadId: string;
|
|
128
|
-
finalMessage: M | null;
|
|
129
|
-
exitReason: SessionExitReason;
|
|
130
|
-
usage: ReturnType<AgentStateManager<T>["getTotalUsage"]>;
|
|
131
|
-
}>;
|
|
170
|
+
}): Promise<SessionResult<M, T, HasSandbox>>;
|
|
132
171
|
}
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
SubagentConfig,
|
|
4
4
|
SubagentDefinition,
|
|
5
5
|
SubagentHooks,
|
|
6
|
+
SubagentSandboxConfig,
|
|
6
7
|
SubagentWorkflow,
|
|
7
8
|
} from "./types";
|
|
8
9
|
import type { SubagentArgs } from "./tool";
|
|
@@ -19,8 +20,8 @@ import type { SubagentArgs } from "./tool";
|
|
|
19
20
|
*
|
|
20
21
|
* // With parent-specific overrides
|
|
21
22
|
* export const researcher = defineSubagent(researcherWorkflow, {
|
|
22
|
-
*
|
|
23
|
-
* sandbox: "own",
|
|
23
|
+
* thread: "fork",
|
|
24
|
+
* sandbox: { source: "own", shutdown: "pause" },
|
|
24
25
|
* hooks: {
|
|
25
26
|
* onPostExecution: ({ result }) => console.log(result),
|
|
26
27
|
* },
|
|
@@ -42,8 +43,8 @@ export function defineSubagent<
|
|
|
42
43
|
hooks?: SubagentHooks<SubagentArgs, z.infer<TResult>>;
|
|
43
44
|
enabled?: boolean | (() => boolean);
|
|
44
45
|
taskQueue?: string;
|
|
45
|
-
|
|
46
|
-
sandbox?:
|
|
46
|
+
thread?: "new" | "fork" | "continue";
|
|
47
|
+
sandbox?: SubagentSandboxConfig;
|
|
47
48
|
},
|
|
48
49
|
): SubagentConfig<TResult> {
|
|
49
50
|
return {
|