zeitlich 0.2.36 → 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/README.md +146 -92
- package/dist/{activities-BVI2lTwr.d.ts → activities-BKhMtKDd.d.ts} +4 -2
- package/dist/{activities-hd4aNnZE.d.cts → activities-CDcwkRZs.d.cts} +4 -2
- package/dist/adapters/sandbox/bedrock/index.cjs +17 -14
- package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
- package/dist/adapters/sandbox/bedrock/index.d.cts +7 -6
- package/dist/adapters/sandbox/bedrock/index.d.ts +7 -6
- package/dist/adapters/sandbox/bedrock/index.js +17 -14
- package/dist/adapters/sandbox/bedrock/index.js.map +1 -1
- package/dist/adapters/sandbox/bedrock/workflow.cjs +2 -0
- package/dist/adapters/sandbox/bedrock/workflow.cjs.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/bedrock/workflow.js +2 -0
- package/dist/adapters/sandbox/bedrock/workflow.js.map +1 -1
- package/dist/adapters/sandbox/daytona/index.cjs +11 -3
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/index.d.cts +5 -4
- package/dist/adapters/sandbox/daytona/index.d.ts +5 -4
- package/dist/adapters/sandbox/daytona/index.js +11 -3
- package/dist/adapters/sandbox/daytona/index.js.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.cjs +2 -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 +2 -0
- package/dist/adapters/sandbox/daytona/workflow.js.map +1 -1
- package/dist/adapters/sandbox/e2b/index.cjs +73 -12
- package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/index.d.cts +26 -4
- package/dist/adapters/sandbox/e2b/index.d.ts +26 -4
- package/dist/adapters/sandbox/e2b/index.js +73 -12
- package/dist/adapters/sandbox/e2b/index.js.map +1 -1
- package/dist/adapters/sandbox/e2b/workflow.cjs +2 -0
- package/dist/adapters/sandbox/e2b/workflow.cjs.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/e2b/workflow.js +2 -0
- package/dist/adapters/sandbox/e2b/workflow.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.cjs +8 -3
- package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
- package/dist/adapters/sandbox/inmemory/index.d.cts +5 -4
- package/dist/adapters/sandbox/inmemory/index.d.ts +5 -4
- package/dist/adapters/sandbox/inmemory/index.js +8 -3
- package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
- package/dist/adapters/sandbox/inmemory/workflow.cjs +2 -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 +2 -0
- package/dist/adapters/sandbox/inmemory/workflow.js.map +1 -1
- package/dist/adapters/thread/anthropic/index.cjs +94 -39
- 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 +94 -39
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +7 -2
- 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 +7 -2
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.cjs +77 -28
- 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 +77 -28
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.cjs +7 -2
- 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 +7 -2
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/langchain/index.cjs +57 -10
- 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 +57 -10
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +7 -2
- 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 +7 -2
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/index.cjs +322 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -14
- package/dist/index.d.ts +20 -14
- package/dist/index.js +323 -147
- package/dist/index.js.map +1 -1
- package/dist/{proxy-BjdFGPTm.d.ts → proxy-CUlKSvZS.d.ts} +1 -1
- package/dist/{proxy-7RnVaPdJ.d.cts → proxy-D_3x7RN4.d.cts} +1 -1
- package/dist/{thread-manager-CbpiGq1L.d.ts → thread-manager-CVu7o2cs.d.ts} +4 -2
- package/dist/{thread-manager-DzXm9eeI.d.cts → thread-manager-HSwyh28L.d.cts} +4 -2
- package/dist/{thread-manager-BBzNgQWH.d.cts → thread-manager-c1gPopAG.d.ts} +4 -2
- package/dist/{thread-manager-DjN5JYul.d.ts → thread-manager-wGi-LqIP.d.cts} +4 -2
- package/dist/{types-Mc_4BCfT.d.cts → types-BH_IRryz.d.ts} +10 -1
- package/dist/{types-yiXmqedU.d.ts → types-BaOw4hKI.d.cts} +10 -1
- package/dist/{types-DQ1l_gXL.d.cts → types-C06FwR96.d.cts} +121 -17
- package/dist/{types-wiGLvxWf.d.ts → types-DAsQ21Rt.d.ts} +1 -1
- package/dist/{types-CADc5V_P.d.ts → types-DNr31FzL.d.ts} +121 -17
- package/dist/{types-CBH54cwr.d.cts → types-lm8tMNJQ.d.cts} +1 -1
- package/dist/{types-DxCpFNv_.d.cts → types-yx0LzPGn.d.cts} +44 -5
- package/dist/{types-DxCpFNv_.d.ts → types-yx0LzPGn.d.ts} +44 -5
- package/dist/{workflow-DhtWRovz.d.cts → workflow-CSCkpwAL.d.ts} +2 -2
- package/dist/{workflow-P2pTSfKu.d.ts → workflow-DuvMZ8Vm.d.cts} +2 -2
- package/dist/workflow.cjs +274 -130
- 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 +275 -131
- package/dist/workflow.js.map +1 -1
- package/package.json +2 -2
- package/src/adapters/sandbox/bedrock/filesystem.ts +6 -12
- package/src/adapters/sandbox/bedrock/index.ts +22 -11
- package/src/adapters/sandbox/bedrock/proxy.ts +2 -0
- package/src/adapters/sandbox/daytona/index.ts +18 -3
- package/src/adapters/sandbox/daytona/proxy.ts +2 -0
- package/src/adapters/sandbox/e2b/filesystem.ts +5 -4
- package/src/adapters/sandbox/e2b/index.ts +87 -14
- package/src/adapters/sandbox/e2b/proxy.ts +2 -0
- package/src/adapters/sandbox/e2b/types.ts +16 -0
- package/src/adapters/sandbox/inmemory/index.ts +17 -3
- package/src/adapters/sandbox/inmemory/proxy.ts +2 -0
- package/src/adapters/thread/anthropic/activities.ts +58 -26
- package/src/adapters/thread/anthropic/model-invoker.ts +18 -7
- package/src/adapters/thread/anthropic/proxy.ts +6 -2
- package/src/adapters/thread/anthropic/thread-manager.test.ts +26 -7
- package/src/adapters/thread/anthropic/thread-manager.ts +63 -46
- package/src/adapters/thread/google-genai/activities.ts +20 -2
- package/src/adapters/thread/google-genai/model-invoker.ts +27 -7
- package/src/adapters/thread/google-genai/proxy.ts +6 -2
- package/src/adapters/thread/google-genai/thread-manager.test.ts +13 -3
- package/src/adapters/thread/google-genai/thread-manager.ts +57 -33
- package/src/adapters/thread/langchain/activities.ts +55 -24
- package/src/adapters/thread/langchain/hooks.test.ts +36 -49
- package/src/adapters/thread/langchain/hooks.ts +18 -5
- package/src/adapters/thread/langchain/model-invoker.ts +5 -4
- package/src/adapters/thread/langchain/proxy.ts +6 -2
- package/src/adapters/thread/langchain/thread-manager.test.ts +5 -1
- package/src/adapters/thread/langchain/thread-manager.ts +23 -9
- package/src/index.ts +4 -1
- package/src/lib/activity.ts +16 -6
- package/src/lib/hooks/types.ts +6 -6
- package/src/lib/lifecycle.ts +18 -3
- package/src/lib/model/proxy.ts +2 -2
- package/src/lib/model/types.ts +10 -0
- package/src/lib/observability/hooks.ts +4 -5
- package/src/lib/observability/index.ts +1 -4
- package/src/lib/sandbox/manager.ts +45 -20
- package/src/lib/sandbox/node-fs.ts +3 -6
- package/src/lib/sandbox/sandbox.test.ts +36 -3
- package/src/lib/sandbox/tree.integration.test.ts +10 -3
- package/src/lib/sandbox/types.ts +60 -6
- package/src/lib/session/session-edge-cases.integration.test.ts +316 -14
- package/src/lib/session/session.integration.test.ts +161 -1
- package/src/lib/session/session.ts +106 -21
- package/src/lib/session/types.ts +25 -5
- package/src/lib/skills/fs-provider.ts +12 -8
- package/src/lib/skills/handler.ts +1 -1
- package/src/lib/skills/parse.ts +3 -1
- package/src/lib/skills/register.ts +1 -3
- package/src/lib/skills/skills.integration.test.ts +25 -15
- package/src/lib/state/manager.integration.test.ts +12 -2
- package/src/lib/subagent/define.ts +1 -1
- package/src/lib/subagent/handler.ts +186 -71
- package/src/lib/subagent/index.ts +1 -5
- package/src/lib/subagent/register.ts +3 -2
- package/src/lib/subagent/signals.ts +1 -10
- package/src/lib/subagent/subagent.integration.test.ts +526 -248
- package/src/lib/subagent/tool.ts +4 -3
- package/src/lib/subagent/types.ts +50 -20
- package/src/lib/subagent/workflow.ts +9 -49
- package/src/lib/thread/id.test.ts +1 -1
- package/src/lib/thread/id.ts +1 -2
- package/src/lib/thread/manager.ts +18 -0
- package/src/lib/thread/proxy.ts +4 -4
- package/src/lib/thread/types.ts +20 -3
- package/src/lib/tool-router/index.ts +3 -5
- package/src/lib/tool-router/router-edge-cases.integration.test.ts +93 -1
- package/src/lib/tool-router/router.integration.test.ts +12 -0
- package/src/lib/tool-router/router.ts +90 -16
- package/src/lib/tool-router/types.ts +45 -4
- package/src/lib/tool-router/with-sandbox.ts +19 -5
- package/src/lib/virtual-fs/filesystem.ts +1 -1
- package/src/lib/virtual-fs/index.ts +5 -1
- package/src/lib/virtual-fs/mutations.ts +2 -4
- package/src/lib/virtual-fs/queries.ts +9 -5
- package/src/lib/virtual-fs/types.ts +4 -1
- package/src/lib/virtual-fs/virtual-fs.test.ts +9 -11
- package/src/lib/workflow.test.ts +7 -4
- package/src/lib/workflow.ts +1 -5
- package/src/tools/ask-user-question/tool.ts +1 -3
- package/src/tools/glob/handler.ts +1 -4
- package/src/tools/task-get/handler.ts +4 -5
- package/src/tools/task-list/handler.ts +1 -4
- package/src/tools/task-update/handler.ts +4 -5
- package/src/workflow.ts +22 -7
- package/tsup.config.ts +9 -6
- package/src/lib/.env +0 -1
- package/src/tools/bash/.env +0 -1
|
@@ -29,6 +29,16 @@ vi.mock("@temporalio/workflow", () => {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
class MockCancellationScope {
|
|
33
|
+
cancellable: boolean;
|
|
34
|
+
constructor(opts?: { cancellable?: boolean }) {
|
|
35
|
+
this.cancellable = opts?.cancellable ?? true;
|
|
36
|
+
}
|
|
37
|
+
async run<T>(fn: () => Promise<T>): Promise<T> {
|
|
38
|
+
return fn();
|
|
39
|
+
}
|
|
40
|
+
cancel(): void {}
|
|
41
|
+
}
|
|
32
42
|
return {
|
|
33
43
|
proxyActivities: <T>() => ({}) as T,
|
|
34
44
|
condition: async (fn: () => boolean) => fn(),
|
|
@@ -42,7 +52,15 @@ vi.mock("@temporalio/workflow", () => {
|
|
|
42
52
|
uuid4: () =>
|
|
43
53
|
`00000000-0000-0000-0000-${String(++idCounter).padStart(12, "0")}`,
|
|
44
54
|
ApplicationFailure: MockApplicationFailure,
|
|
45
|
-
|
|
55
|
+
CancellationScope: MockCancellationScope,
|
|
56
|
+
isCancellation: (_err: unknown) => false,
|
|
57
|
+
log: {
|
|
58
|
+
trace: () => {},
|
|
59
|
+
debug: () => {},
|
|
60
|
+
info: () => {},
|
|
61
|
+
warn: () => {},
|
|
62
|
+
error: () => {},
|
|
63
|
+
},
|
|
46
64
|
};
|
|
47
65
|
});
|
|
48
66
|
|
|
@@ -55,13 +73,16 @@ type TurnScript = {
|
|
|
55
73
|
message: unknown;
|
|
56
74
|
toolCalls: RawToolCall[];
|
|
57
75
|
usage?: TokenUsage;
|
|
76
|
+
threadLengthAtCall?: number;
|
|
58
77
|
};
|
|
59
78
|
|
|
60
79
|
/**
|
|
61
80
|
* Wraps every method on a ThreadOps object so it also has `.executeWithOptions()`,
|
|
62
81
|
* matching Temporal's `ActivityInterfaceFor<ThreadOps>` shape.
|
|
63
82
|
*/
|
|
64
|
-
function toActivityInterface<TContent = string>(
|
|
83
|
+
function toActivityInterface<TContent = string>(
|
|
84
|
+
raw: ThreadOps<TContent>
|
|
85
|
+
): ActivityInterfaceFor<ThreadOps<TContent>> {
|
|
65
86
|
const result = {} as Record<string, unknown>;
|
|
66
87
|
for (const [key, fn] of Object.entries(raw)) {
|
|
67
88
|
const wrapped = (...args: unknown[]) =>
|
|
@@ -94,6 +115,9 @@ function createMockThreadOps() {
|
|
|
94
115
|
forkThread: async (source, target) => {
|
|
95
116
|
log.push({ op: "forkThread", args: [source, target] });
|
|
96
117
|
},
|
|
118
|
+
truncateThread: async (threadId, length) => {
|
|
119
|
+
log.push({ op: "truncateThread", args: [threadId, length] });
|
|
120
|
+
},
|
|
97
121
|
});
|
|
98
122
|
return { ops, log };
|
|
99
123
|
}
|
|
@@ -105,12 +129,18 @@ function createScriptedRunAgent(
|
|
|
105
129
|
return async () => {
|
|
106
130
|
const turn = turns[call++];
|
|
107
131
|
if (!turn) {
|
|
108
|
-
return {
|
|
132
|
+
return {
|
|
133
|
+
message: "done",
|
|
134
|
+
rawToolCalls: [],
|
|
135
|
+
usage: undefined,
|
|
136
|
+
threadLengthAtCall: 0,
|
|
137
|
+
};
|
|
109
138
|
}
|
|
110
139
|
return {
|
|
111
140
|
message: turn.message,
|
|
112
141
|
rawToolCalls: turn.toolCalls,
|
|
113
142
|
usage: turn.usage,
|
|
143
|
+
threadLengthAtCall: turn.threadLengthAtCall ?? 0,
|
|
114
144
|
};
|
|
115
145
|
};
|
|
116
146
|
}
|
|
@@ -433,6 +463,8 @@ describe("createSession edge cases", () => {
|
|
|
433
463
|
createdAt: new Date().toISOString(),
|
|
434
464
|
}),
|
|
435
465
|
forkSandbox: async () => "forked-sandbox-id",
|
|
466
|
+
restoreSandbox: async () => "restored-sandbox-id",
|
|
467
|
+
deleteSandboxSnapshot: async () => {},
|
|
436
468
|
pauseSandbox: async () => {},
|
|
437
469
|
resumeSandbox: async () => {},
|
|
438
470
|
};
|
|
@@ -476,6 +508,8 @@ describe("createSession edge cases", () => {
|
|
|
476
508
|
createdAt: new Date().toISOString(),
|
|
477
509
|
}),
|
|
478
510
|
forkSandbox: async () => "forked-sandbox-id",
|
|
511
|
+
restoreSandbox: async () => "restored-sandbox-id",
|
|
512
|
+
deleteSandboxSnapshot: async () => {},
|
|
479
513
|
pauseSandbox: async () => {},
|
|
480
514
|
resumeSandbox: async () => {},
|
|
481
515
|
};
|
|
@@ -763,9 +797,16 @@ describe("createSession edge cases", () => {
|
|
|
763
797
|
forkThread: async (source, target) => {
|
|
764
798
|
log.push({ op: "forkThread", args: [source, target] });
|
|
765
799
|
},
|
|
800
|
+
truncateThread: async (threadId, length) => {
|
|
801
|
+
log.push({ op: "truncateThread", args: [threadId, length] });
|
|
802
|
+
},
|
|
766
803
|
});
|
|
767
804
|
|
|
768
|
-
const session = await createSession<
|
|
805
|
+
const session = await createSession<
|
|
806
|
+
Record<string, never>,
|
|
807
|
+
unknown,
|
|
808
|
+
TestContent
|
|
809
|
+
>({
|
|
769
810
|
agentName: "TestAgent",
|
|
770
811
|
thread: { mode: "new", threadId: "thread-1" },
|
|
771
812
|
runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
|
|
@@ -940,6 +981,8 @@ describe("createSession edge cases", () => {
|
|
|
940
981
|
destroySandbox: async () => {},
|
|
941
982
|
snapshotSandbox: snapshotSpy,
|
|
942
983
|
forkSandbox: async () => "forked-sandbox-id",
|
|
984
|
+
restoreSandbox: async () => "restored-sandbox-id",
|
|
985
|
+
deleteSandboxSnapshot: async () => {},
|
|
943
986
|
pauseSandbox: async () => {},
|
|
944
987
|
resumeSandbox: async () => {},
|
|
945
988
|
};
|
|
@@ -1040,6 +1083,8 @@ describe("createSession edge cases", () => {
|
|
|
1040
1083
|
createdAt: new Date().toISOString(),
|
|
1041
1084
|
}),
|
|
1042
1085
|
forkSandbox: async () => "forked-sb",
|
|
1086
|
+
restoreSandbox: async () => "restored-sb",
|
|
1087
|
+
deleteSandboxSnapshot: async () => {},
|
|
1043
1088
|
};
|
|
1044
1089
|
|
|
1045
1090
|
const session = await createSession({
|
|
@@ -1074,6 +1119,8 @@ describe("createSession edge cases", () => {
|
|
|
1074
1119
|
createdAt: new Date().toISOString(),
|
|
1075
1120
|
}),
|
|
1076
1121
|
forkSandbox: async () => "forked-sb",
|
|
1122
|
+
restoreSandbox: async () => "restored-sb",
|
|
1123
|
+
deleteSandboxSnapshot: async () => {},
|
|
1077
1124
|
};
|
|
1078
1125
|
|
|
1079
1126
|
const session = await createSession({
|
|
@@ -1119,6 +1166,8 @@ describe("createSession edge cases", () => {
|
|
|
1119
1166
|
createdAt: new Date().toISOString(),
|
|
1120
1167
|
}),
|
|
1121
1168
|
forkSandbox: async () => "forked-sb",
|
|
1169
|
+
restoreSandbox: async () => "restored-sb",
|
|
1170
|
+
deleteSandboxSnapshot: async () => {},
|
|
1122
1171
|
};
|
|
1123
1172
|
|
|
1124
1173
|
const session = await createSession({
|
|
@@ -1166,6 +1215,8 @@ describe("createSession edge cases", () => {
|
|
|
1166
1215
|
sandboxLog.push(`fork:${id}`);
|
|
1167
1216
|
return `forked-from-${id}`;
|
|
1168
1217
|
},
|
|
1218
|
+
restoreSandbox: async () => "restored-sb",
|
|
1219
|
+
deleteSandboxSnapshot: async () => {},
|
|
1169
1220
|
};
|
|
1170
1221
|
|
|
1171
1222
|
const session = await createSession({
|
|
@@ -1186,7 +1237,9 @@ describe("createSession edge cases", () => {
|
|
|
1186
1237
|
|
|
1187
1238
|
expect(sandboxLog).toContain("fork:paused-sb-1");
|
|
1188
1239
|
expect(sandboxLog).not.toContain("create");
|
|
1189
|
-
expect((result as { sandboxId?: string }).sandboxId).toBe(
|
|
1240
|
+
expect((result as { sandboxId?: string }).sandboxId).toBe(
|
|
1241
|
+
"forked-from-paused-sb-1"
|
|
1242
|
+
);
|
|
1190
1243
|
expect(sandboxLog).toContain("destroy:forked-from-paused-sb-1");
|
|
1191
1244
|
});
|
|
1192
1245
|
|
|
@@ -1210,6 +1263,8 @@ describe("createSession edge cases", () => {
|
|
|
1210
1263
|
createdAt: new Date().toISOString(),
|
|
1211
1264
|
}),
|
|
1212
1265
|
forkSandbox: async () => "forked-sb",
|
|
1266
|
+
restoreSandbox: async () => "restored-sb",
|
|
1267
|
+
deleteSandboxSnapshot: async () => {},
|
|
1213
1268
|
};
|
|
1214
1269
|
|
|
1215
1270
|
const session = await createSession({
|
|
@@ -1253,6 +1308,8 @@ describe("createSession edge cases", () => {
|
|
|
1253
1308
|
createdAt: new Date().toISOString(),
|
|
1254
1309
|
}),
|
|
1255
1310
|
forkSandbox: async () => "forked-sb",
|
|
1311
|
+
restoreSandbox: async () => "restored-sb",
|
|
1312
|
+
deleteSandboxSnapshot: async () => {},
|
|
1256
1313
|
};
|
|
1257
1314
|
|
|
1258
1315
|
const session = await createSession({
|
|
@@ -1297,6 +1354,8 @@ describe("createSession edge cases", () => {
|
|
|
1297
1354
|
createdAt: new Date().toISOString(),
|
|
1298
1355
|
}),
|
|
1299
1356
|
forkSandbox: async () => "forked-sb",
|
|
1357
|
+
restoreSandbox: async () => "restored-sb",
|
|
1358
|
+
deleteSandboxSnapshot: async () => {},
|
|
1300
1359
|
};
|
|
1301
1360
|
|
|
1302
1361
|
const session = await createSession({
|
|
@@ -1370,9 +1429,7 @@ describe("createSession edge cases", () => {
|
|
|
1370
1429
|
|
|
1371
1430
|
const session = await createSession({
|
|
1372
1431
|
agentName: "TestAgent",
|
|
1373
|
-
runAgent: createScriptedRunAgent([
|
|
1374
|
-
{ message: "done", toolCalls: [] },
|
|
1375
|
-
]),
|
|
1432
|
+
runAgent: createScriptedRunAgent([{ message: "done", toolCalls: [] }]),
|
|
1376
1433
|
threadOps: ops,
|
|
1377
1434
|
buildContextMessage: () => "go",
|
|
1378
1435
|
});
|
|
@@ -1413,6 +1470,8 @@ describe("createSession edge cases", () => {
|
|
|
1413
1470
|
createdAt: new Date().toISOString(),
|
|
1414
1471
|
}),
|
|
1415
1472
|
forkSandbox: async () => "forked-sb",
|
|
1473
|
+
restoreSandbox: async () => "restored-sb",
|
|
1474
|
+
deleteSandboxSnapshot: async () => {},
|
|
1416
1475
|
};
|
|
1417
1476
|
|
|
1418
1477
|
const session = await createSession({
|
|
@@ -1431,9 +1490,7 @@ describe("createSession edge cases", () => {
|
|
|
1431
1490
|
initialState: { systemPrompt: "test" },
|
|
1432
1491
|
});
|
|
1433
1492
|
|
|
1434
|
-
await expect(session.runSession({ stateManager })).rejects.toThrow(
|
|
1435
|
-
"crash"
|
|
1436
|
-
);
|
|
1493
|
+
await expect(session.runSession({ stateManager })).rejects.toThrow("crash");
|
|
1437
1494
|
|
|
1438
1495
|
expect(sandboxLog).toContain("pause:sb-err");
|
|
1439
1496
|
expect(sandboxLog).not.toContain("destroy:sb-err");
|
|
@@ -1461,6 +1518,8 @@ describe("createSession edge cases", () => {
|
|
|
1461
1518
|
createdAt: new Date().toISOString(),
|
|
1462
1519
|
}),
|
|
1463
1520
|
forkSandbox: async () => "forked-sb",
|
|
1521
|
+
restoreSandbox: async () => "restored-sb",
|
|
1522
|
+
deleteSandboxSnapshot: async () => {},
|
|
1464
1523
|
};
|
|
1465
1524
|
|
|
1466
1525
|
const session = await createSession({
|
|
@@ -1503,6 +1562,8 @@ describe("createSession edge cases", () => {
|
|
|
1503
1562
|
createdAt: new Date().toISOString(),
|
|
1504
1563
|
}),
|
|
1505
1564
|
forkSandbox: async () => "forked-sb",
|
|
1565
|
+
restoreSandbox: async () => "restored-sb",
|
|
1566
|
+
deleteSandboxSnapshot: async () => {},
|
|
1506
1567
|
};
|
|
1507
1568
|
|
|
1508
1569
|
const session = await createSession({
|
|
@@ -1521,9 +1582,7 @@ describe("createSession edge cases", () => {
|
|
|
1521
1582
|
initialState: { systemPrompt: "test" },
|
|
1522
1583
|
});
|
|
1523
1584
|
|
|
1524
|
-
await expect(session.runSession({ stateManager })).rejects.toThrow(
|
|
1525
|
-
"crash"
|
|
1526
|
-
);
|
|
1585
|
+
await expect(session.runSession({ stateManager })).rejects.toThrow("crash");
|
|
1527
1586
|
|
|
1528
1587
|
expect(sandboxLog).not.toContain("pause:sb-keep-err");
|
|
1529
1588
|
expect(sandboxLog).not.toContain("destroy:sb-keep-err");
|
|
@@ -1553,6 +1612,8 @@ describe("createSession edge cases", () => {
|
|
|
1553
1612
|
createdAt: new Date().toISOString(),
|
|
1554
1613
|
}),
|
|
1555
1614
|
forkSandbox: async () => "forked-sb",
|
|
1615
|
+
restoreSandbox: async () => "restored-sb",
|
|
1616
|
+
deleteSandboxSnapshot: async () => {},
|
|
1556
1617
|
};
|
|
1557
1618
|
|
|
1558
1619
|
const session = await createSession({
|
|
@@ -1598,6 +1659,8 @@ describe("createSession edge cases", () => {
|
|
|
1598
1659
|
createdAt: new Date().toISOString(),
|
|
1599
1660
|
}),
|
|
1600
1661
|
forkSandbox: async () => "forked-sb",
|
|
1662
|
+
restoreSandbox: async () => "restored-sb",
|
|
1663
|
+
deleteSandboxSnapshot: async () => {},
|
|
1601
1664
|
};
|
|
1602
1665
|
|
|
1603
1666
|
const session = await createSession({
|
|
@@ -1621,4 +1684,243 @@ describe("createSession edge cases", () => {
|
|
|
1621
1684
|
expect(sandboxLog).not.toContain("pause:kept-sb");
|
|
1622
1685
|
expect(sandboxLog).not.toContain("destroy:kept-sb");
|
|
1623
1686
|
});
|
|
1687
|
+
|
|
1688
|
+
// --- Rewind flow: tool requests rewind and turn is retried -------------
|
|
1689
|
+
|
|
1690
|
+
it("rewinds the turn when a tool handler returns rewind:true", async () => {
|
|
1691
|
+
const { ops, log } = createMockThreadOps();
|
|
1692
|
+
|
|
1693
|
+
let rewindAttempts = 0;
|
|
1694
|
+
const rewindTool = defineTool({
|
|
1695
|
+
name: "Rewind" as const,
|
|
1696
|
+
description: "rewinds once then succeeds",
|
|
1697
|
+
schema: z.object({}),
|
|
1698
|
+
handler: async () => {
|
|
1699
|
+
rewindAttempts += 1;
|
|
1700
|
+
if (rewindAttempts === 1) {
|
|
1701
|
+
return {
|
|
1702
|
+
toolResponse: "ignored",
|
|
1703
|
+
data: null,
|
|
1704
|
+
rewind: true,
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
return { toolResponse: "ok", data: null };
|
|
1708
|
+
},
|
|
1709
|
+
});
|
|
1710
|
+
|
|
1711
|
+
const session = await createSession({
|
|
1712
|
+
agentName: "TestAgent",
|
|
1713
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
1714
|
+
runAgent: createScriptedRunAgent([
|
|
1715
|
+
{
|
|
1716
|
+
message: "attempt-1",
|
|
1717
|
+
toolCalls: [{ id: "tc-1", name: "Rewind", args: {} }],
|
|
1718
|
+
},
|
|
1719
|
+
{
|
|
1720
|
+
message: "attempt-2",
|
|
1721
|
+
toolCalls: [{ id: "tc-2", name: "Rewind", args: {} }],
|
|
1722
|
+
},
|
|
1723
|
+
{ message: "done", toolCalls: [] },
|
|
1724
|
+
]),
|
|
1725
|
+
threadOps: ops,
|
|
1726
|
+
tools: { Rewind: rewindTool },
|
|
1727
|
+
buildContextMessage: () => "go",
|
|
1728
|
+
});
|
|
1729
|
+
|
|
1730
|
+
const stateManager = createAgentStateManager({
|
|
1731
|
+
initialState: { systemPrompt: "test" },
|
|
1732
|
+
});
|
|
1733
|
+
|
|
1734
|
+
const result = await session.runSession({ stateManager });
|
|
1735
|
+
|
|
1736
|
+
expect(result.exitReason).toBe("completed");
|
|
1737
|
+
expect(result.finalMessage).toBe("done");
|
|
1738
|
+
expect(rewindAttempts).toBe(2);
|
|
1739
|
+
|
|
1740
|
+
const truncateOps = log.filter((l) => l.op === "truncateThread");
|
|
1741
|
+
expect(truncateOps).toHaveLength(1);
|
|
1742
|
+
|
|
1743
|
+
const noRewindToolResult = log.filter((l) => {
|
|
1744
|
+
if (l.op !== "appendToolResult") return false;
|
|
1745
|
+
const config = l.args[1] as ToolResultConfig;
|
|
1746
|
+
return config.toolCallId === "tc-1";
|
|
1747
|
+
});
|
|
1748
|
+
expect(noRewindToolResult).toHaveLength(0);
|
|
1749
|
+
|
|
1750
|
+
const agentAppends = log.filter((l) => l.op === "appendAgentMessage");
|
|
1751
|
+
expect(agentAppends).toHaveLength(3);
|
|
1752
|
+
});
|
|
1753
|
+
|
|
1754
|
+
it("truncates the thread back to the pre-assistant state so sibling tool results are dropped on rewind", async () => {
|
|
1755
|
+
const { ops, log } = createMockThreadOps();
|
|
1756
|
+
|
|
1757
|
+
let rewindFired = false;
|
|
1758
|
+
|
|
1759
|
+
const siblingTool = defineTool({
|
|
1760
|
+
name: "Sibling" as const,
|
|
1761
|
+
description: "sibling",
|
|
1762
|
+
schema: z.object({}),
|
|
1763
|
+
handler: async () => ({ toolResponse: "sibling-ok", data: null }),
|
|
1764
|
+
});
|
|
1765
|
+
|
|
1766
|
+
const rewindTool = defineTool({
|
|
1767
|
+
name: "Rewind" as const,
|
|
1768
|
+
description: "rewinds",
|
|
1769
|
+
schema: z.object({}),
|
|
1770
|
+
handler: async () => {
|
|
1771
|
+
if (!rewindFired) {
|
|
1772
|
+
rewindFired = true;
|
|
1773
|
+
return { toolResponse: "ignored", data: null, rewind: true };
|
|
1774
|
+
}
|
|
1775
|
+
return { toolResponse: "ok", data: null };
|
|
1776
|
+
},
|
|
1777
|
+
});
|
|
1778
|
+
|
|
1779
|
+
const session = await createSession({
|
|
1780
|
+
agentName: "TestAgent",
|
|
1781
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
1782
|
+
runAgent: createScriptedRunAgent([
|
|
1783
|
+
{
|
|
1784
|
+
message: "parallel",
|
|
1785
|
+
toolCalls: [
|
|
1786
|
+
{ id: "tc-sibling", name: "Sibling", args: {} },
|
|
1787
|
+
{ id: "tc-rewind", name: "Rewind", args: {} },
|
|
1788
|
+
],
|
|
1789
|
+
// Invoker reports 2 stored messages (system + human) at the
|
|
1790
|
+
// moment the LLM was called.
|
|
1791
|
+
threadLengthAtCall: 2,
|
|
1792
|
+
},
|
|
1793
|
+
{ message: "done", toolCalls: [], threadLengthAtCall: 2 },
|
|
1794
|
+
]),
|
|
1795
|
+
threadOps: ops,
|
|
1796
|
+
tools: { Rewind: rewindTool, Sibling: siblingTool },
|
|
1797
|
+
buildContextMessage: () => "go",
|
|
1798
|
+
});
|
|
1799
|
+
|
|
1800
|
+
const stateManager = createAgentStateManager({
|
|
1801
|
+
initialState: { systemPrompt: "test" },
|
|
1802
|
+
});
|
|
1803
|
+
|
|
1804
|
+
const result = await session.runSession({ stateManager });
|
|
1805
|
+
|
|
1806
|
+
expect(result.exitReason).toBe("completed");
|
|
1807
|
+
|
|
1808
|
+
// Exactly one truncate fired — back to the pre-assistant-message
|
|
1809
|
+
// length that runAgent reported.
|
|
1810
|
+
const truncateOps = log.filter((l) => l.op === "truncateThread");
|
|
1811
|
+
expect(truncateOps).toHaveLength(1);
|
|
1812
|
+
const truncateOp = truncateOps[0];
|
|
1813
|
+
if (!truncateOp) throw new Error("expected truncate op");
|
|
1814
|
+
expect(truncateOp.args[1]).toBe(2);
|
|
1815
|
+
|
|
1816
|
+
// Rewinding tool never appends its own result.
|
|
1817
|
+
const rewindResultAppends = log.filter((l) => {
|
|
1818
|
+
if (l.op !== "appendToolResult") return false;
|
|
1819
|
+
const config = l.args[1] as ToolResultConfig;
|
|
1820
|
+
return config.toolCallId === "tc-rewind";
|
|
1821
|
+
});
|
|
1822
|
+
expect(rewindResultAppends).toHaveLength(0);
|
|
1823
|
+
|
|
1824
|
+
// Two assistant messages expected: one from the rewound turn, one from
|
|
1825
|
+
// the successful retry.
|
|
1826
|
+
const agentAppends = log.filter((l) => l.op === "appendAgentMessage");
|
|
1827
|
+
expect(agentAppends).toHaveLength(2);
|
|
1828
|
+
});
|
|
1829
|
+
|
|
1830
|
+
it("does not rewind when the rewinding tool is no longer present after retry", async () => {
|
|
1831
|
+
const { ops, log } = createMockThreadOps();
|
|
1832
|
+
|
|
1833
|
+
let attempts = 0;
|
|
1834
|
+
const rewindOnce = defineTool({
|
|
1835
|
+
name: "RewindOnce" as const,
|
|
1836
|
+
description: "rewinds once",
|
|
1837
|
+
schema: z.object({}),
|
|
1838
|
+
handler: async () => {
|
|
1839
|
+
attempts += 1;
|
|
1840
|
+
if (attempts === 1) {
|
|
1841
|
+
return { toolResponse: "ignored", data: null, rewind: true };
|
|
1842
|
+
}
|
|
1843
|
+
return { toolResponse: "ok", data: null };
|
|
1844
|
+
},
|
|
1845
|
+
});
|
|
1846
|
+
|
|
1847
|
+
const session = await createSession({
|
|
1848
|
+
agentName: "TestAgent",
|
|
1849
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
1850
|
+
maxTurns: 5,
|
|
1851
|
+
runAgent: createScriptedRunAgent([
|
|
1852
|
+
{
|
|
1853
|
+
message: "call-1",
|
|
1854
|
+
toolCalls: [{ id: "tc-1", name: "RewindOnce", args: {} }],
|
|
1855
|
+
},
|
|
1856
|
+
{
|
|
1857
|
+
message: "call-2",
|
|
1858
|
+
toolCalls: [{ id: "tc-2", name: "RewindOnce", args: {} }],
|
|
1859
|
+
},
|
|
1860
|
+
{ message: "done", toolCalls: [] },
|
|
1861
|
+
]),
|
|
1862
|
+
threadOps: ops,
|
|
1863
|
+
tools: { RewindOnce: rewindOnce },
|
|
1864
|
+
buildContextMessage: () => "go",
|
|
1865
|
+
});
|
|
1866
|
+
|
|
1867
|
+
const stateManager = createAgentStateManager({
|
|
1868
|
+
initialState: { systemPrompt: "test" },
|
|
1869
|
+
});
|
|
1870
|
+
|
|
1871
|
+
const result = await session.runSession({ stateManager });
|
|
1872
|
+
|
|
1873
|
+
expect(result.exitReason).toBe("completed");
|
|
1874
|
+
expect(result.finalMessage).toBe("done");
|
|
1875
|
+
// Each rewind still consumes a turn from the `maxTurns` budget:
|
|
1876
|
+
// turn 1 (rewound) + turn 2 (successful tool call) + turn 3 (done) = 3.
|
|
1877
|
+
expect(result.usage.turns).toBe(3);
|
|
1878
|
+
expect(attempts).toBe(2);
|
|
1879
|
+
|
|
1880
|
+
const truncateOps = log.filter((l) => l.op === "truncateThread");
|
|
1881
|
+
expect(truncateOps).toHaveLength(1);
|
|
1882
|
+
});
|
|
1883
|
+
|
|
1884
|
+
it("bails out with max_turns when a tool keeps requesting rewind", async () => {
|
|
1885
|
+
const { ops, log } = createMockThreadOps();
|
|
1886
|
+
|
|
1887
|
+
let attempts = 0;
|
|
1888
|
+
const alwaysRewind = defineTool({
|
|
1889
|
+
name: "AlwaysRewind" as const,
|
|
1890
|
+
description: "always rewinds",
|
|
1891
|
+
schema: z.object({}),
|
|
1892
|
+
handler: async () => {
|
|
1893
|
+
attempts += 1;
|
|
1894
|
+
return { toolResponse: "ignored", data: null, rewind: true };
|
|
1895
|
+
},
|
|
1896
|
+
});
|
|
1897
|
+
|
|
1898
|
+
const session = await createSession({
|
|
1899
|
+
agentName: "TestAgent",
|
|
1900
|
+
thread: { mode: "new", threadId: "thread-1" },
|
|
1901
|
+
maxTurns: 3,
|
|
1902
|
+
runAgent: createScriptedRunAgent([
|
|
1903
|
+
{ message: "t1", toolCalls: [{ id: "tc-1", name: "AlwaysRewind", args: {} }] },
|
|
1904
|
+
{ message: "t2", toolCalls: [{ id: "tc-2", name: "AlwaysRewind", args: {} }] },
|
|
1905
|
+
{ message: "t3", toolCalls: [{ id: "tc-3", name: "AlwaysRewind", args: {} }] },
|
|
1906
|
+
{ message: "t4", toolCalls: [{ id: "tc-4", name: "AlwaysRewind", args: {} }] },
|
|
1907
|
+
]),
|
|
1908
|
+
threadOps: ops,
|
|
1909
|
+
tools: { AlwaysRewind: alwaysRewind },
|
|
1910
|
+
buildContextMessage: () => "go",
|
|
1911
|
+
});
|
|
1912
|
+
|
|
1913
|
+
const stateManager = createAgentStateManager({
|
|
1914
|
+
initialState: { systemPrompt: "test" },
|
|
1915
|
+
});
|
|
1916
|
+
|
|
1917
|
+
const result = await session.runSession({ stateManager });
|
|
1918
|
+
|
|
1919
|
+
expect(result.exitReason).toBe("max_turns");
|
|
1920
|
+
expect(result.usage.turns).toBe(3);
|
|
1921
|
+
expect(attempts).toBe(3);
|
|
1922
|
+
|
|
1923
|
+
const truncateOps = log.filter((l) => l.op === "truncateThread");
|
|
1924
|
+
expect(truncateOps).toHaveLength(3);
|
|
1925
|
+
});
|
|
1624
1926
|
});
|