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