zeitlich 0.2.19 → 0.2.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/sandbox/daytona/index.cjs +25 -10
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/index.d.cts +4 -1
- package/dist/adapters/sandbox/daytona/index.d.ts +4 -1
- package/dist/adapters/sandbox/daytona/index.js +25 -10
- package/dist/adapters/sandbox/daytona/index.js.map +1 -1
- package/dist/adapters/sandbox/virtual/index.d.cts +4 -3
- package/dist/adapters/sandbox/virtual/index.d.ts +4 -3
- package/dist/adapters/thread/google-genai/index.cjs +69 -24
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +10 -10
- package/dist/adapters/thread/google-genai/index.d.ts +10 -10
- package/dist/adapters/thread/google-genai/index.js +69 -24
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/langchain/index.cjs +76 -69
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +11 -11
- package/dist/adapters/thread/langchain/index.d.ts +11 -11
- package/dist/adapters/thread/langchain/index.js +76 -69
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/index.cjs +198 -118
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +198 -118
- package/dist/index.js.map +1 -1
- package/dist/{queries-D8T4pEeu.d.ts → queries-6Avfh74U.d.ts} +1 -1
- package/dist/{queries-D22uWTOb.d.cts → queries-CHa2iv_I.d.cts} +1 -1
- package/dist/{types-CxWLeJTB.d.ts → types-BkAYmc96.d.ts} +6 -6
- package/dist/{types-CCfJb5Jl.d.cts → types-CES_30qx.d.cts} +6 -6
- package/dist/{types-DjT78Sdp.d.cts → types-YbL7JpEA.d.cts} +4 -2
- package/dist/{types-DjT78Sdp.d.ts → types-YbL7JpEA.d.ts} +4 -2
- package/dist/workflow.cjs +68 -34
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +16 -12
- package/dist/workflow.d.ts +16 -12
- package/dist/workflow.js +68 -34
- package/dist/workflow.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/sandbox/daytona/filesystem.ts +21 -12
- package/src/adapters/sandbox/daytona/index.ts +24 -23
- package/src/adapters/thread/google-genai/activities.ts +11 -9
- package/src/adapters/thread/google-genai/model-invoker.ts +6 -11
- package/src/adapters/thread/google-genai/thread-manager.ts +44 -29
- package/src/adapters/thread/langchain/activities.ts +6 -4
- package/src/adapters/thread/langchain/thread-manager.ts +55 -27
- package/src/lib/session/session-edge-cases.integration.test.ts +20 -2
- package/src/lib/session/session.integration.test.ts +16 -2
- package/src/lib/session/session.ts +7 -5
- package/src/lib/session/types.ts +9 -3
- package/src/lib/subagent/handler.ts +1 -1
- package/src/lib/subagent/subagent.integration.test.ts +5 -4
- package/src/lib/subagent/tool.ts +1 -1
- package/src/lib/thread/index.ts +0 -1
- package/src/lib/tool-router/auto-append-sandbox.integration.test.ts +20 -21
- package/src/lib/tool-router/auto-append.ts +3 -2
- package/src/lib/tool-router/router-edge-cases.integration.test.ts +64 -23
- package/src/lib/tool-router/router.integration.test.ts +60 -23
- package/src/lib/tool-router/router.ts +58 -29
- package/src/lib/tool-router/types.ts +12 -7
- package/src/lib/workflow.test.ts +18 -6
- package/src/lib/workflow.ts +13 -3
- package/src/tools/task-create/handler.ts +3 -6
- package/src/workflow.ts +2 -2
|
@@ -15,10 +15,7 @@ vi.mock("@temporalio/workflow", () => {
|
|
|
15
15
|
err.nonRetryable = nonRetryable;
|
|
16
16
|
return err;
|
|
17
17
|
}
|
|
18
|
-
static fromError(
|
|
19
|
-
error: unknown,
|
|
20
|
-
options?: { nonRetryable?: boolean },
|
|
21
|
-
) {
|
|
18
|
+
static fromError(error: unknown, options?: { nonRetryable?: boolean }) {
|
|
22
19
|
const src = error instanceof Error ? error : new Error(String(error));
|
|
23
20
|
const err = new MockApplicationFailure(src.message);
|
|
24
21
|
err.nonRetryable = options?.nonRetryable;
|
|
@@ -45,7 +42,9 @@ const echoTool = defineTool({
|
|
|
45
42
|
name: "Echo" as const,
|
|
46
43
|
description: "Echoes back the input",
|
|
47
44
|
schema: z.object({ text: z.string() }),
|
|
48
|
-
handler: async (args: {
|
|
45
|
+
handler: async (args: {
|
|
46
|
+
text: string;
|
|
47
|
+
}): Promise<ToolHandlerResponse<{ echoed: string }>> => ({
|
|
49
48
|
toolResponse: `Echo: ${args.text}`,
|
|
50
49
|
data: { echoed: args.text },
|
|
51
50
|
}),
|
|
@@ -55,7 +54,10 @@ const mathTool = defineTool({
|
|
|
55
54
|
name: "Add" as const,
|
|
56
55
|
description: "Adds two numbers",
|
|
57
56
|
schema: z.object({ a: z.number(), b: z.number() }),
|
|
58
|
-
handler: async (args: {
|
|
57
|
+
handler: async (args: {
|
|
58
|
+
a: number;
|
|
59
|
+
b: number;
|
|
60
|
+
}): Promise<ToolHandlerResponse<{ sum: number }>> => ({
|
|
59
61
|
toolResponse: `Sum: ${args.a + args.b}`,
|
|
60
62
|
data: { sum: args.a + args.b },
|
|
61
63
|
}),
|
|
@@ -65,7 +67,9 @@ const failingTool = defineTool({
|
|
|
65
67
|
name: "Fail" as const,
|
|
66
68
|
description: "Always fails",
|
|
67
69
|
schema: z.object({ reason: z.string() }),
|
|
68
|
-
handler: async (args: {
|
|
70
|
+
handler: async (args: {
|
|
71
|
+
reason: string;
|
|
72
|
+
}): Promise<ToolHandlerResponse<null>> => {
|
|
69
73
|
throw new Error(args.reason);
|
|
70
74
|
},
|
|
71
75
|
});
|
|
@@ -86,9 +90,20 @@ function createTools() {
|
|
|
86
90
|
|
|
87
91
|
function createAppendSpy() {
|
|
88
92
|
const calls: ToolResultConfig[] = [];
|
|
89
|
-
const fn
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
const fn = Object.assign(
|
|
94
|
+
async (_id: string, config: ToolResultConfig) => {
|
|
95
|
+
calls.push(config);
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
executeWithOptions: (
|
|
99
|
+
_opts: unknown,
|
|
100
|
+
[, config]: [string, ToolResultConfig]
|
|
101
|
+
) => {
|
|
102
|
+
calls.push(config);
|
|
103
|
+
return Promise.resolve();
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
) as AppendToolResultFn;
|
|
92
107
|
return { fn, calls };
|
|
93
108
|
}
|
|
94
109
|
|
|
@@ -163,7 +178,7 @@ describe("createToolRouter integration", () => {
|
|
|
163
178
|
});
|
|
164
179
|
|
|
165
180
|
expect(() =>
|
|
166
|
-
router.parseToolCall({ id: "tc-1", name: "Unknown", args: {} })
|
|
181
|
+
router.parseToolCall({ id: "tc-1", name: "Unknown", args: {} })
|
|
167
182
|
).toThrow("Tool Unknown not found");
|
|
168
183
|
});
|
|
169
184
|
|
|
@@ -175,7 +190,7 @@ describe("createToolRouter integration", () => {
|
|
|
175
190
|
});
|
|
176
191
|
|
|
177
192
|
expect(() =>
|
|
178
|
-
router.parseToolCall({ id: "tc-1", name: "Echo", args: { text: 123 } })
|
|
193
|
+
router.parseToolCall({ id: "tc-1", name: "Echo", args: { text: 123 } })
|
|
179
194
|
).toThrow();
|
|
180
195
|
});
|
|
181
196
|
|
|
@@ -324,7 +339,7 @@ describe("createToolRouter integration", () => {
|
|
|
324
339
|
toolCallId: "tc-99",
|
|
325
340
|
toolName: "Spy",
|
|
326
341
|
sandboxId: "sandbox-1",
|
|
327
|
-
})
|
|
342
|
+
})
|
|
328
343
|
);
|
|
329
344
|
});
|
|
330
345
|
|
|
@@ -352,12 +367,18 @@ describe("createToolRouter integration", () => {
|
|
|
352
367
|
},
|
|
353
368
|
});
|
|
354
369
|
|
|
355
|
-
const parsed = router.parseToolCall({
|
|
370
|
+
const parsed = router.parseToolCall({
|
|
371
|
+
id: "tc-1",
|
|
372
|
+
name: "Skippable",
|
|
373
|
+
args: {},
|
|
374
|
+
});
|
|
356
375
|
const results = await router.processToolCalls([parsed], { turn: 1 });
|
|
357
376
|
|
|
358
377
|
expect(handlerSpy).not.toHaveBeenCalled();
|
|
359
378
|
expect(results).toHaveLength(0);
|
|
360
|
-
expect(at(appendSpy.calls, 0).content).toContain(
|
|
379
|
+
expect(at(appendSpy.calls, 0).content).toContain(
|
|
380
|
+
"Skipped by PreToolUse hook"
|
|
381
|
+
);
|
|
361
382
|
});
|
|
362
383
|
|
|
363
384
|
it("pre-hook can modify arguments", async () => {
|
|
@@ -416,7 +437,11 @@ describe("createToolRouter integration", () => {
|
|
|
416
437
|
appendToolResult: appendSpy.fn,
|
|
417
438
|
});
|
|
418
439
|
|
|
419
|
-
const parsed = router.parseToolCall({
|
|
440
|
+
const parsed = router.parseToolCall({
|
|
441
|
+
id: "tc-1",
|
|
442
|
+
name: "Hooked",
|
|
443
|
+
args: {},
|
|
444
|
+
});
|
|
420
445
|
const results = await router.processToolCalls([parsed], { turn: 1 });
|
|
421
446
|
|
|
422
447
|
expect(handlerSpy).not.toHaveBeenCalled();
|
|
@@ -445,7 +470,10 @@ describe("createToolRouter integration", () => {
|
|
|
445
470
|
await router.processToolCalls([parsed], { turn: 1 });
|
|
446
471
|
|
|
447
472
|
expect(hookData).not.toBeNull();
|
|
448
|
-
const data = hookData as unknown as {
|
|
473
|
+
const data = hookData as unknown as {
|
|
474
|
+
result: { data: unknown };
|
|
475
|
+
durationMs: number;
|
|
476
|
+
};
|
|
449
477
|
expect(data.result.data).toEqual({ sum: 7 });
|
|
450
478
|
expect(data.durationMs).toBeGreaterThanOrEqual(0);
|
|
451
479
|
});
|
|
@@ -506,7 +534,10 @@ describe("createToolRouter integration", () => {
|
|
|
506
534
|
const results = await router.processToolCalls([parsed], { turn: 1 });
|
|
507
535
|
|
|
508
536
|
expect(results).toHaveLength(1);
|
|
509
|
-
expect(at(results, 0).data).toEqual({
|
|
537
|
+
expect(at(results, 0).data).toEqual({
|
|
538
|
+
error: "Error: boom",
|
|
539
|
+
recovered: true,
|
|
540
|
+
});
|
|
510
541
|
expect(at(appendSpy.calls, 0).content).toBe("recovered gracefully");
|
|
511
542
|
});
|
|
512
543
|
|
|
@@ -515,7 +546,9 @@ describe("createToolRouter integration", () => {
|
|
|
515
546
|
name: "Fail" as const,
|
|
516
547
|
description: "fails but suppresses",
|
|
517
548
|
schema: z.object({ reason: z.string() }),
|
|
518
|
-
handler: async (args: {
|
|
549
|
+
handler: async (args: {
|
|
550
|
+
reason: string;
|
|
551
|
+
}): Promise<ToolHandlerResponse<null>> => {
|
|
519
552
|
throw new Error(args.reason);
|
|
520
553
|
},
|
|
521
554
|
hooks: {
|
|
@@ -557,7 +590,7 @@ describe("createToolRouter integration", () => {
|
|
|
557
590
|
});
|
|
558
591
|
|
|
559
592
|
await expect(
|
|
560
|
-
router.processToolCalls([parsed], { turn: 1 })
|
|
593
|
+
router.processToolCalls([parsed], { turn: 1 })
|
|
561
594
|
).rejects.toThrow("unrecoverable");
|
|
562
595
|
});
|
|
563
596
|
|
|
@@ -581,7 +614,7 @@ describe("createToolRouter integration", () => {
|
|
|
581
614
|
expect(router.hasTool("Disabled")).toBe(false);
|
|
582
615
|
expect(router.getToolNames()).not.toContain("Disabled");
|
|
583
616
|
expect(() =>
|
|
584
|
-
router.parseToolCall({ id: "tc-1", name: "Disabled", args: {} })
|
|
617
|
+
router.parseToolCall({ id: "tc-1", name: "Disabled", args: {} })
|
|
585
618
|
).toThrow("Tool Disabled not found");
|
|
586
619
|
});
|
|
587
620
|
|
|
@@ -638,7 +671,7 @@ describe("createToolRouter integration", () => {
|
|
|
638
671
|
async (args: { text: string }) => ({
|
|
639
672
|
toolResponse: `custom: ${args.text}`,
|
|
640
673
|
data: { custom: args.text },
|
|
641
|
-
})
|
|
674
|
+
})
|
|
642
675
|
);
|
|
643
676
|
|
|
644
677
|
expect(results).toHaveLength(2);
|
|
@@ -691,7 +724,11 @@ describe("createToolRouter integration", () => {
|
|
|
691
724
|
appendToolResult: appendSpy.fn,
|
|
692
725
|
});
|
|
693
726
|
|
|
694
|
-
const parsed = router.parseToolCall({
|
|
727
|
+
const parsed = router.parseToolCall({
|
|
728
|
+
id: "tc-1",
|
|
729
|
+
name: "SelfAppend",
|
|
730
|
+
args: {},
|
|
731
|
+
});
|
|
695
732
|
await router.processToolCalls([parsed]);
|
|
696
733
|
|
|
697
734
|
expect(appendSpy.calls).toHaveLength(0);
|
|
@@ -20,7 +20,7 @@ import type {
|
|
|
20
20
|
} from "./types";
|
|
21
21
|
|
|
22
22
|
import type { z } from "zod";
|
|
23
|
-
import { ApplicationFailure } from "@temporalio/workflow";
|
|
23
|
+
import { ApplicationFailure, uuid4 } from "@temporalio/workflow";
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Creates a tool router for declarative tool call processing.
|
|
@@ -63,7 +63,7 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
63
63
|
toolMap.set(tool.name, tool as T[keyof T]);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const resolve = <T
|
|
66
|
+
const resolve = <T>(v: T | (() => T)): T =>
|
|
67
67
|
typeof v === "function" ? (v as () => T)() : v;
|
|
68
68
|
|
|
69
69
|
const isEnabled = (tool: ToolMap[string]): boolean =>
|
|
@@ -130,7 +130,10 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
130
130
|
turn,
|
|
131
131
|
});
|
|
132
132
|
if (r?.fallbackContent !== undefined)
|
|
133
|
-
return {
|
|
133
|
+
return {
|
|
134
|
+
content: r.fallbackContent,
|
|
135
|
+
result: { error: errorStr, recovered: true },
|
|
136
|
+
};
|
|
134
137
|
if (r?.suppress)
|
|
135
138
|
return {
|
|
136
139
|
content: JSON.stringify({ error: errorStr, suppressed: true }),
|
|
@@ -146,7 +149,10 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
146
149
|
turn,
|
|
147
150
|
});
|
|
148
151
|
if (r?.fallbackContent !== undefined)
|
|
149
|
-
return {
|
|
152
|
+
return {
|
|
153
|
+
content: r.fallbackContent,
|
|
154
|
+
result: { error: errorStr, recovered: true },
|
|
155
|
+
};
|
|
150
156
|
if (r?.suppress)
|
|
151
157
|
return {
|
|
152
158
|
content: JSON.stringify({ error: errorStr, suppressed: true }),
|
|
@@ -197,11 +203,14 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
197
203
|
// --- Pre-hooks: may skip or modify args ---
|
|
198
204
|
const preResult = await runPreHooks(toolCall, tool, turn);
|
|
199
205
|
if (preResult.skip) {
|
|
200
|
-
await appendToolResult({
|
|
206
|
+
await appendToolResult(uuid4(), {
|
|
201
207
|
threadId: options.threadId,
|
|
202
208
|
toolCallId: toolCall.id,
|
|
203
209
|
toolName: toolCall.name,
|
|
204
|
-
content: JSON.stringify({
|
|
210
|
+
content: JSON.stringify({
|
|
211
|
+
skipped: true,
|
|
212
|
+
reason: "Skipped by PreToolUse hook",
|
|
213
|
+
}),
|
|
205
214
|
});
|
|
206
215
|
return null;
|
|
207
216
|
}
|
|
@@ -232,19 +241,31 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
232
241
|
content = JSON.stringify(result, null, 2);
|
|
233
242
|
}
|
|
234
243
|
} catch (error) {
|
|
235
|
-
const recovery = await runFailureHooks(
|
|
244
|
+
const recovery = await runFailureHooks(
|
|
245
|
+
toolCall,
|
|
246
|
+
tool,
|
|
247
|
+
error,
|
|
248
|
+
effectiveArgs,
|
|
249
|
+
turn
|
|
250
|
+
);
|
|
236
251
|
result = recovery.result;
|
|
237
252
|
content = recovery.content;
|
|
238
253
|
}
|
|
239
254
|
|
|
240
255
|
// --- Append result to thread (unless handler already did) ---
|
|
241
256
|
if (!resultAppended) {
|
|
242
|
-
|
|
257
|
+
const config = {
|
|
243
258
|
threadId: options.threadId,
|
|
244
259
|
toolCallId: toolCall.id,
|
|
245
260
|
toolName: toolCall.name,
|
|
246
261
|
content,
|
|
247
|
-
}
|
|
262
|
+
};
|
|
263
|
+
await appendToolResult.executeWithOptions(
|
|
264
|
+
{
|
|
265
|
+
summary: `Append ${toolCall.name} result`,
|
|
266
|
+
},
|
|
267
|
+
[uuid4(), config]
|
|
268
|
+
);
|
|
248
269
|
}
|
|
249
270
|
|
|
250
271
|
const toolResult = {
|
|
@@ -254,7 +275,14 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
254
275
|
} as ToolCallResultUnion<TResults>;
|
|
255
276
|
|
|
256
277
|
// --- Post-hooks ---
|
|
257
|
-
await runPostHooks(
|
|
278
|
+
await runPostHooks(
|
|
279
|
+
toolCall,
|
|
280
|
+
tool,
|
|
281
|
+
toolResult,
|
|
282
|
+
effectiveArgs,
|
|
283
|
+
turn,
|
|
284
|
+
Date.now() - startTime
|
|
285
|
+
);
|
|
258
286
|
|
|
259
287
|
return toolResult;
|
|
260
288
|
}
|
|
@@ -316,9 +344,7 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
316
344
|
|
|
317
345
|
if (options.parallel) {
|
|
318
346
|
const results = await Promise.all(
|
|
319
|
-
toolCalls.map((tc) =>
|
|
320
|
-
processToolCall(tc, turn, sandboxId)
|
|
321
|
-
)
|
|
347
|
+
toolCalls.map((tc) => processToolCall(tc, turn, sandboxId))
|
|
322
348
|
);
|
|
323
349
|
return results.filter(
|
|
324
350
|
(r): r is NonNullable<typeof r> => r !== null
|
|
@@ -327,11 +353,7 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
327
353
|
|
|
328
354
|
const results: ToolCallResultUnion<TResults>[] = [];
|
|
329
355
|
for (const toolCall of toolCalls) {
|
|
330
|
-
const result = await processToolCall(
|
|
331
|
-
toolCall,
|
|
332
|
-
turn,
|
|
333
|
-
sandboxId
|
|
334
|
-
);
|
|
356
|
+
const result = await processToolCall(toolCall, turn, sandboxId);
|
|
335
357
|
if (result !== null) {
|
|
336
358
|
results.push(result);
|
|
337
359
|
}
|
|
@@ -339,10 +361,7 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
339
361
|
return results;
|
|
340
362
|
},
|
|
341
363
|
|
|
342
|
-
async processToolCallsByName<
|
|
343
|
-
TName extends ToolNames<T>,
|
|
344
|
-
TResult,
|
|
345
|
-
>(
|
|
364
|
+
async processToolCallsByName<TName extends ToolNames<T>, TResult>(
|
|
346
365
|
toolCalls: ParsedToolCallUnion<T>[],
|
|
347
366
|
toolName: TName,
|
|
348
367
|
handler: ToolHandler<ToolArgs<T, TName>, TResult>,
|
|
@@ -361,7 +380,9 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
361
380
|
threadId: options.threadId,
|
|
362
381
|
toolCallId: toolCall.id,
|
|
363
382
|
toolName: toolCall.name as TName,
|
|
364
|
-
...(context?.sandboxId !== undefined && {
|
|
383
|
+
...(context?.sandboxId !== undefined && {
|
|
384
|
+
sandboxId: context.sandboxId,
|
|
385
|
+
}),
|
|
365
386
|
};
|
|
366
387
|
const response = await handler(
|
|
367
388
|
toolCall.args as ToolArgs<T, TName>,
|
|
@@ -369,12 +390,20 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
369
390
|
);
|
|
370
391
|
|
|
371
392
|
if (!response.resultAppended) {
|
|
372
|
-
await appendToolResult(
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
393
|
+
await appendToolResult.executeWithOptions(
|
|
394
|
+
{
|
|
395
|
+
summary: `Append ${toolCall.name} result`,
|
|
396
|
+
},
|
|
397
|
+
[
|
|
398
|
+
uuid4(),
|
|
399
|
+
{
|
|
400
|
+
threadId: options.threadId,
|
|
401
|
+
toolCallId: toolCall.id,
|
|
402
|
+
toolName: toolCall.name,
|
|
403
|
+
content: response.toolResponse,
|
|
404
|
+
},
|
|
405
|
+
]
|
|
406
|
+
);
|
|
378
407
|
}
|
|
379
408
|
|
|
380
409
|
return {
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
ToolResultConfig,
|
|
5
5
|
} from "../types";
|
|
6
6
|
import type { z } from "zod";
|
|
7
|
+
import type { ActivityFunctionWithOptions } from "@temporalio/workflow";
|
|
7
8
|
|
|
8
9
|
// ============================================================================
|
|
9
10
|
// Tool Definition Types
|
|
@@ -114,7 +115,9 @@ export type ParsedToolCallUnion<T extends ToolMap> = {
|
|
|
114
115
|
/**
|
|
115
116
|
* Function signature for appending tool results to a thread.
|
|
116
117
|
*/
|
|
117
|
-
export type AppendToolResultFn =
|
|
118
|
+
export type AppendToolResultFn = ActivityFunctionWithOptions<
|
|
119
|
+
(id: string, config: ToolResultConfig) => Promise<void>
|
|
120
|
+
>;
|
|
118
121
|
|
|
119
122
|
/**
|
|
120
123
|
* The response from a tool handler.
|
|
@@ -157,7 +160,11 @@ export interface RouterContext {
|
|
|
157
160
|
* Receives the parsed args and a context that always includes {@link RouterContext}
|
|
158
161
|
* fields, plus any additional properties when TContext extends RouterContext.
|
|
159
162
|
*/
|
|
160
|
-
export type ToolHandler<
|
|
163
|
+
export type ToolHandler<
|
|
164
|
+
TArgs,
|
|
165
|
+
TResult,
|
|
166
|
+
TContext extends RouterContext = RouterContext,
|
|
167
|
+
> = (
|
|
161
168
|
args: TArgs,
|
|
162
169
|
context: TContext
|
|
163
170
|
) => ToolHandlerResponse<TResult> | Promise<ToolHandlerResponse<TResult>>;
|
|
@@ -392,7 +399,8 @@ export interface ToolRouterOptions<T extends ToolMap> {
|
|
|
392
399
|
tools: T;
|
|
393
400
|
/** Thread ID for appending tool results */
|
|
394
401
|
threadId: string;
|
|
395
|
-
/** Function to append tool results to the thread (called automatically after each handler)
|
|
402
|
+
/** Function to append tool results to the thread (called automatically after each handler).
|
|
403
|
+
* Accepts a Temporal activity proxy with {@link ActivityFunctionWithOptions}. */
|
|
396
404
|
appendToolResult: AppendToolResultFn;
|
|
397
405
|
/** Whether to process tools in parallel (default: true) */
|
|
398
406
|
parallel?: boolean;
|
|
@@ -445,10 +453,7 @@ export interface ToolRouter<T extends ToolMap> {
|
|
|
445
453
|
* Process tool calls matching a specific name with a custom handler.
|
|
446
454
|
* Useful for overriding the default handler for specific cases.
|
|
447
455
|
*/
|
|
448
|
-
processToolCallsByName<
|
|
449
|
-
TName extends ToolNames<T>,
|
|
450
|
-
TResult,
|
|
451
|
-
>(
|
|
456
|
+
processToolCallsByName<TName extends ToolNames<T>, TResult>(
|
|
452
457
|
toolCalls: ParsedToolCallUnion<T>[],
|
|
453
458
|
toolName: TName,
|
|
454
459
|
handler: ToolHandler<ToolArgs<T, TName>, TResult>,
|
package/src/lib/workflow.test.ts
CHANGED
|
@@ -5,11 +5,13 @@ import {
|
|
|
5
5
|
type WorkflowSessionInput,
|
|
6
6
|
} from "./workflow";
|
|
7
7
|
|
|
8
|
+
const cfg = { name: "test-workflow" };
|
|
9
|
+
|
|
8
10
|
describe("defineWorkflow", () => {
|
|
9
11
|
it("maps previousThreadId to threadId + continueThread", async () => {
|
|
10
12
|
let capturedSession: WorkflowSessionInput | undefined;
|
|
11
13
|
|
|
12
|
-
const workflow = defineWorkflow(async (_input, sessionInput) => {
|
|
14
|
+
const workflow = defineWorkflow(cfg, async (_input, sessionInput) => {
|
|
13
15
|
capturedSession = sessionInput;
|
|
14
16
|
return { ok: true };
|
|
15
17
|
});
|
|
@@ -25,7 +27,7 @@ describe("defineWorkflow", () => {
|
|
|
25
27
|
it("maps sandboxId", async () => {
|
|
26
28
|
let capturedSession: WorkflowSessionInput | undefined;
|
|
27
29
|
|
|
28
|
-
const workflow = defineWorkflow(async (_input, sessionInput) => {
|
|
30
|
+
const workflow = defineWorkflow(cfg, async (_input, sessionInput) => {
|
|
29
31
|
capturedSession = sessionInput;
|
|
30
32
|
return { ok: true };
|
|
31
33
|
});
|
|
@@ -38,7 +40,7 @@ describe("defineWorkflow", () => {
|
|
|
38
40
|
it("maps both previousThreadId and sandboxId together", async () => {
|
|
39
41
|
let capturedSession: WorkflowSessionInput | undefined;
|
|
40
42
|
|
|
41
|
-
const workflow = defineWorkflow(async (_input, sessionInput) => {
|
|
43
|
+
const workflow = defineWorkflow(cfg, async (_input, sessionInput) => {
|
|
42
44
|
capturedSession = sessionInput;
|
|
43
45
|
return { ok: true };
|
|
44
46
|
});
|
|
@@ -55,7 +57,7 @@ describe("defineWorkflow", () => {
|
|
|
55
57
|
it("returns empty sessionInput when no previousThreadId or sandboxId", async () => {
|
|
56
58
|
let capturedSession: WorkflowSessionInput | undefined;
|
|
57
59
|
|
|
58
|
-
const workflow = defineWorkflow(async (_input, sessionInput) => {
|
|
60
|
+
const workflow = defineWorkflow(cfg, async (_input, sessionInput) => {
|
|
59
61
|
capturedSession = sessionInput;
|
|
60
62
|
return { ok: true };
|
|
61
63
|
});
|
|
@@ -73,7 +75,7 @@ describe("defineWorkflow", () => {
|
|
|
73
75
|
metadata: { key: string };
|
|
74
76
|
previousThreadId?: string;
|
|
75
77
|
sandboxId?: string;
|
|
76
|
-
}, { ok: boolean }>(async (input, _sessionInput) => {
|
|
78
|
+
}, { ok: boolean }>(cfg, async (input, _sessionInput) => {
|
|
77
79
|
capturedInput = input;
|
|
78
80
|
return { ok: true };
|
|
79
81
|
});
|
|
@@ -94,6 +96,7 @@ describe("defineWorkflow", () => {
|
|
|
94
96
|
let capturedSession: WorkflowSessionInput | undefined;
|
|
95
97
|
|
|
96
98
|
const workflow = defineWorkflow<{ prompt: string }, { ok: boolean }>(
|
|
99
|
+
cfg,
|
|
97
100
|
async (input, sessionInput) => {
|
|
98
101
|
capturedInput = input;
|
|
99
102
|
capturedSession = sessionInput;
|
|
@@ -116,7 +119,7 @@ describe("defineWorkflow", () => {
|
|
|
116
119
|
});
|
|
117
120
|
|
|
118
121
|
it("returns the handler response unchanged", async () => {
|
|
119
|
-
const workflow = defineWorkflow(async () => ({
|
|
122
|
+
const workflow = defineWorkflow(cfg, async () => ({
|
|
120
123
|
finalMessage: "result text",
|
|
121
124
|
threadId: "thread-123",
|
|
122
125
|
}));
|
|
@@ -128,4 +131,13 @@ describe("defineWorkflow", () => {
|
|
|
128
131
|
threadId: "thread-123",
|
|
129
132
|
});
|
|
130
133
|
});
|
|
134
|
+
|
|
135
|
+
it("sets the function name from config", () => {
|
|
136
|
+
const workflow = defineWorkflow(
|
|
137
|
+
{ name: "my-main-workflow" },
|
|
138
|
+
async () => ({}),
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
expect(workflow.name).toBe("my-main-workflow");
|
|
142
|
+
});
|
|
131
143
|
});
|
package/src/lib/workflow.ts
CHANGED
|
@@ -19,20 +19,26 @@ export interface WorkflowInput {
|
|
|
19
19
|
sandboxId?: string;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
export interface WorkflowConfig {
|
|
23
|
+
/** Workflow name — used as the Temporal workflow function name */
|
|
24
|
+
name: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
22
27
|
/**
|
|
23
28
|
* Wraps a main workflow function, translating workflow input fields into
|
|
24
29
|
* session-compatible fields that can be spread directly into `createSession`.
|
|
25
30
|
*
|
|
26
31
|
* The wrapper:
|
|
27
|
-
* - Accepts a
|
|
28
|
-
* - Accepts
|
|
32
|
+
* - Accepts a `config` with at least a `name` (used for Temporal workflow naming)
|
|
33
|
+
* - Accepts a handler `fn` receiving `(input, sessionInput)`
|
|
29
34
|
* - Derives `threadId` + `continueThread` from `workflowInput.previousThreadId`
|
|
30
35
|
* - Derives `sandboxId` from `workflowInput.sandboxId`
|
|
31
36
|
*/
|
|
32
37
|
export function defineWorkflow<TInput, TResult>(
|
|
38
|
+
config: WorkflowConfig,
|
|
33
39
|
fn: (input: TInput, sessionInput: WorkflowSessionInput) => Promise<TResult>,
|
|
34
40
|
): (input: TInput, workflowInput?: WorkflowInput) => Promise<TResult> {
|
|
35
|
-
|
|
41
|
+
const workflow = async (input: TInput, workflowInput: WorkflowInput = {}) => {
|
|
36
42
|
const sessionInput: WorkflowSessionInput = {
|
|
37
43
|
...(workflowInput.previousThreadId && {
|
|
38
44
|
threadId: workflowInput.previousThreadId,
|
|
@@ -42,4 +48,8 @@ export function defineWorkflow<TInput, TResult>(
|
|
|
42
48
|
};
|
|
43
49
|
return fn(input, sessionInput);
|
|
44
50
|
};
|
|
51
|
+
|
|
52
|
+
Object.defineProperty(workflow, "name", { value: config.name });
|
|
53
|
+
|
|
54
|
+
return workflow;
|
|
45
55
|
}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AgentStateManager,
|
|
3
|
-
JsonSerializable,
|
|
4
|
-
} from "../../lib/state";
|
|
1
|
+
import type { AgentStateManager, JsonSerializable } from "../../lib/state";
|
|
5
2
|
import type { ToolHandler } from "../../lib/tool-router";
|
|
6
3
|
import type { WorkflowTask } from "../../lib/types";
|
|
4
|
+
import { getShortId } from "../../workflow";
|
|
7
5
|
import type { TaskCreateArgs } from "./tool";
|
|
8
|
-
import { uuid4 } from "@temporalio/workflow";
|
|
9
6
|
|
|
10
7
|
/**
|
|
11
8
|
* Creates a TaskCreate handler that adds tasks to the workflow state.
|
|
@@ -20,7 +17,7 @@ export function createTaskCreateHandler<
|
|
|
20
17
|
): ToolHandler<TaskCreateArgs, WorkflowTask> {
|
|
21
18
|
return (args) => {
|
|
22
19
|
const task: WorkflowTask = {
|
|
23
|
-
id:
|
|
20
|
+
id: getShortId(),
|
|
24
21
|
subject: args.subject,
|
|
25
22
|
description: args.description,
|
|
26
23
|
activeForm: args.activeForm,
|
package/src/workflow.ts
CHANGED
|
@@ -26,10 +26,10 @@ export {
|
|
|
26
26
|
} from "./lib/session";
|
|
27
27
|
export type { ZeitlichSession, ThreadOps, SessionConfig } from "./lib/session";
|
|
28
28
|
export { defineWorkflow } from "./lib/workflow";
|
|
29
|
-
export type { WorkflowInput, WorkflowSessionInput } from "./lib/workflow";
|
|
29
|
+
export type { WorkflowConfig, WorkflowInput, WorkflowSessionInput } from "./lib/workflow";
|
|
30
30
|
|
|
31
31
|
// Thread utilities
|
|
32
|
-
export { getShortId } from "./lib/thread";
|
|
32
|
+
export { getShortId } from "./lib/thread/id";
|
|
33
33
|
|
|
34
34
|
// State management
|
|
35
35
|
export { createAgentStateManager } from "./lib/state";
|