zeitlich 0.2.21 → 0.2.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.md +303 -105
  2. package/dist/adapters/sandbox/daytona/index.cjs +7 -1
  3. package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
  4. package/dist/adapters/sandbox/daytona/index.d.cts +3 -1
  5. package/dist/adapters/sandbox/daytona/index.d.ts +3 -1
  6. package/dist/adapters/sandbox/daytona/index.js +7 -1
  7. package/dist/adapters/sandbox/daytona/index.js.map +1 -1
  8. package/dist/adapters/sandbox/daytona/workflow.cjs +33 -0
  9. package/dist/adapters/sandbox/daytona/workflow.cjs.map +1 -0
  10. package/dist/adapters/sandbox/daytona/workflow.d.cts +27 -0
  11. package/dist/adapters/sandbox/daytona/workflow.d.ts +27 -0
  12. package/dist/adapters/sandbox/daytona/workflow.js +31 -0
  13. package/dist/adapters/sandbox/daytona/workflow.js.map +1 -0
  14. package/dist/adapters/sandbox/inmemory/index.cjs +18 -1
  15. package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
  16. package/dist/adapters/sandbox/inmemory/index.d.cts +4 -2
  17. package/dist/adapters/sandbox/inmemory/index.d.ts +4 -2
  18. package/dist/adapters/sandbox/inmemory/index.js +18 -1
  19. package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
  20. package/dist/adapters/sandbox/inmemory/workflow.cjs +33 -0
  21. package/dist/adapters/sandbox/inmemory/workflow.cjs.map +1 -0
  22. package/dist/adapters/sandbox/inmemory/workflow.d.cts +25 -0
  23. package/dist/adapters/sandbox/inmemory/workflow.d.ts +25 -0
  24. package/dist/adapters/sandbox/inmemory/workflow.js +31 -0
  25. package/dist/adapters/sandbox/inmemory/workflow.js.map +1 -0
  26. package/dist/adapters/sandbox/virtual/index.cjs +36 -9
  27. package/dist/adapters/sandbox/virtual/index.cjs.map +1 -1
  28. package/dist/adapters/sandbox/virtual/index.d.cts +8 -5
  29. package/dist/adapters/sandbox/virtual/index.d.ts +8 -5
  30. package/dist/adapters/sandbox/virtual/index.js +36 -9
  31. package/dist/adapters/sandbox/virtual/index.js.map +1 -1
  32. package/dist/adapters/sandbox/virtual/workflow.cjs +33 -0
  33. package/dist/adapters/sandbox/virtual/workflow.cjs.map +1 -0
  34. package/dist/adapters/sandbox/virtual/workflow.d.cts +27 -0
  35. package/dist/adapters/sandbox/virtual/workflow.d.ts +27 -0
  36. package/dist/adapters/sandbox/virtual/workflow.js +31 -0
  37. package/dist/adapters/sandbox/virtual/workflow.js.map +1 -0
  38. package/dist/adapters/thread/google-genai/index.cjs +9 -1
  39. package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
  40. package/dist/adapters/thread/google-genai/index.d.cts +31 -19
  41. package/dist/adapters/thread/google-genai/index.d.ts +31 -19
  42. package/dist/adapters/thread/google-genai/index.js +9 -1
  43. package/dist/adapters/thread/google-genai/index.js.map +1 -1
  44. package/dist/adapters/thread/google-genai/workflow.cjs +33 -0
  45. package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -0
  46. package/dist/adapters/thread/google-genai/workflow.d.cts +32 -0
  47. package/dist/adapters/thread/google-genai/workflow.d.ts +32 -0
  48. package/dist/adapters/thread/google-genai/workflow.js +31 -0
  49. package/dist/adapters/thread/google-genai/workflow.js.map +1 -0
  50. package/dist/adapters/thread/langchain/index.cjs +9 -1
  51. package/dist/adapters/thread/langchain/index.cjs.map +1 -1
  52. package/dist/adapters/thread/langchain/index.d.cts +27 -16
  53. package/dist/adapters/thread/langchain/index.d.ts +27 -16
  54. package/dist/adapters/thread/langchain/index.js +9 -1
  55. package/dist/adapters/thread/langchain/index.js.map +1 -1
  56. package/dist/adapters/thread/langchain/workflow.cjs +33 -0
  57. package/dist/adapters/thread/langchain/workflow.cjs.map +1 -0
  58. package/dist/adapters/thread/langchain/workflow.d.cts +32 -0
  59. package/dist/adapters/thread/langchain/workflow.d.ts +32 -0
  60. package/dist/adapters/thread/langchain/workflow.js +31 -0
  61. package/dist/adapters/thread/langchain/workflow.js.map +1 -0
  62. package/dist/index.cjs +282 -90
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +38 -16
  65. package/dist/index.d.ts +38 -16
  66. package/dist/index.js +281 -87
  67. package/dist/index.js.map +1 -1
  68. package/dist/queries-DModcWRy.d.cts +44 -0
  69. package/dist/queries-byD0jr1Y.d.ts +44 -0
  70. package/dist/{types-BkAYmc96.d.ts → types-B50pBPEV.d.ts} +190 -38
  71. package/dist/{types-YbL7JpEA.d.cts → types-Bll19FZJ.d.cts} +7 -0
  72. package/dist/{types-YbL7JpEA.d.ts → types-Bll19FZJ.d.ts} +7 -0
  73. package/dist/{queries-6Avfh74U.d.ts → types-BuXdFhaZ.d.cts} +7 -48
  74. package/dist/{types-BMRzfELQ.d.cts → types-ChAMwU3q.d.cts} +17 -1
  75. package/dist/{types-BMRzfELQ.d.ts → types-ChAMwU3q.d.ts} +17 -1
  76. package/dist/{types-CES_30qx.d.cts → types-DQW8l7pY.d.cts} +190 -38
  77. package/dist/{queries-CHa2iv_I.d.cts → types-GZ76HZSj.d.ts} +7 -48
  78. package/dist/workflow.cjs +244 -86
  79. package/dist/workflow.cjs.map +1 -1
  80. package/dist/workflow.d.cts +54 -65
  81. package/dist/workflow.d.ts +54 -65
  82. package/dist/workflow.js +243 -83
  83. package/dist/workflow.js.map +1 -1
  84. package/package.json +54 -2
  85. package/src/adapters/sandbox/daytona/filesystem.ts +1 -1
  86. package/src/adapters/sandbox/daytona/index.ts +8 -0
  87. package/src/adapters/sandbox/daytona/proxy.ts +56 -0
  88. package/src/adapters/sandbox/e2b/filesystem.ts +147 -0
  89. package/src/adapters/sandbox/e2b/index.ts +164 -0
  90. package/src/adapters/sandbox/e2b/types.ts +23 -0
  91. package/src/adapters/sandbox/inmemory/index.ts +27 -3
  92. package/src/adapters/sandbox/inmemory/proxy.ts +53 -0
  93. package/src/adapters/sandbox/virtual/filesystem.ts +41 -17
  94. package/src/adapters/sandbox/virtual/provider.ts +9 -1
  95. package/src/adapters/sandbox/virtual/proxy.ts +53 -0
  96. package/src/adapters/sandbox/virtual/types.ts +9 -4
  97. package/src/adapters/thread/google-genai/activities.ts +51 -17
  98. package/src/adapters/thread/google-genai/index.ts +1 -0
  99. package/src/adapters/thread/google-genai/proxy.ts +61 -0
  100. package/src/adapters/thread/langchain/activities.ts +47 -14
  101. package/src/adapters/thread/langchain/index.ts +1 -0
  102. package/src/adapters/thread/langchain/proxy.ts +61 -0
  103. package/src/lib/lifecycle.ts +57 -0
  104. package/src/lib/sandbox/manager.ts +52 -6
  105. package/src/lib/sandbox/sandbox.test.ts +12 -11
  106. package/src/lib/sandbox/types.ts +31 -4
  107. package/src/lib/session/index.ts +4 -5
  108. package/src/lib/session/session-edge-cases.integration.test.ts +491 -66
  109. package/src/lib/session/session.integration.test.ts +92 -80
  110. package/src/lib/session/session.ts +108 -96
  111. package/src/lib/session/types.ts +87 -17
  112. package/src/lib/subagent/define.ts +6 -5
  113. package/src/lib/subagent/handler.ts +148 -16
  114. package/src/lib/subagent/index.ts +4 -0
  115. package/src/lib/subagent/register.ts +10 -3
  116. package/src/lib/subagent/signals.ts +8 -0
  117. package/src/lib/subagent/subagent.integration.test.ts +893 -128
  118. package/src/lib/subagent/tool.ts +2 -2
  119. package/src/lib/subagent/types.ts +84 -21
  120. package/src/lib/subagent/workflow.ts +83 -12
  121. package/src/lib/tool-router/router-edge-cases.integration.test.ts +4 -1
  122. package/src/lib/tool-router/router.integration.test.ts +141 -5
  123. package/src/lib/tool-router/router.ts +13 -3
  124. package/src/lib/tool-router/types.ts +7 -0
  125. package/src/lib/workflow.test.ts +104 -27
  126. package/src/lib/workflow.ts +37 -19
  127. package/src/tools/bash/bash.test.ts +16 -7
  128. package/src/workflow.ts +11 -14
  129. package/tsup.config.ts +6 -0
@@ -1,27 +1,71 @@
1
- import { executeChild, workflowInfo } from "@temporalio/workflow";
1
+ import {
2
+ startChild,
3
+ workflowInfo,
4
+ setHandler,
5
+ condition,
6
+ } from "@temporalio/workflow";
2
7
  import { getShortId } from "../thread/id";
3
8
  import type { ToolHandlerResponse, RouterContext } from "../tool-router";
4
9
  import type { ToolMessageContent } from "../types";
5
10
  import type {
6
11
  InferSubagentResult,
7
12
  SubagentConfig,
13
+ SubagentHandlerResponse,
14
+ SubagentSandboxConfig,
8
15
  SubagentWorkflowInput,
9
16
  } from "./types";
10
17
  import type { SubagentArgs } from "./tool";
11
18
  import type { z } from "zod";
19
+ import type { ThreadInit, SandboxInit, SubagentSandboxShutdown } from "../lifecycle";
20
+ import { childResultSignal, destroySandboxSignal } from "./signals";
21
+
22
+ /**
23
+ * Resolve the shorthand/object `SubagentSandboxConfig` into a normalized form.
24
+ */
25
+ function resolveSandboxConfig(config?: SubagentSandboxConfig): {
26
+ source: "none" | "inherit" | "own";
27
+ shutdown?: SubagentSandboxShutdown;
28
+ } {
29
+ if (!config || config === "none") return { source: "none" };
30
+ if (config === "inherit") return { source: "inherit" };
31
+ if (config === "own") return { source: "own" };
32
+ return { source: "own", shutdown: config.shutdown };
33
+ }
12
34
 
13
35
  /**
14
36
  * Creates a Subagent tool handler that spawns child workflows for configured subagents.
15
37
  *
38
+ * Child workflows signal their result back via `childResultSignal` instead of
39
+ * returning it as the workflow return value. The handler awaits the signal
40
+ * before continuing.
41
+ *
16
42
  * @param subagents - Array of subagent configurations
17
43
  * @returns A tool handler function that can be used with the tool router
18
44
  */
19
45
  export function createSubagentHandler<
20
46
  const T extends readonly SubagentConfig[],
21
- >(subagents: [...T]) {
47
+ >(subagents: [...T]): {
48
+ handler: (
49
+ args: SubagentArgs,
50
+ context: RouterContext
51
+ ) => Promise<ToolHandlerResponse<InferSubagentResult<T[number]> | null>>;
52
+ destroySubagentSandboxes: () => Promise<void>;
53
+ } {
22
54
  const { taskQueue: parentTaskQueue } = workflowInfo();
23
55
 
24
- return async (
56
+ const childResults = new Map<string, SubagentHandlerResponse>();
57
+ const pendingDestroys = new Map<
58
+ string,
59
+ Awaited<ReturnType<typeof startChild>>
60
+ >();
61
+ /** Maps childThreadId → sandboxId for sandbox continuation across invocations */
62
+ const threadSandboxes = new Map<string, string>();
63
+
64
+ setHandler(childResultSignal, ({ childWorkflowId, result }) => {
65
+ childResults.set(childWorkflowId, result);
66
+ });
67
+
68
+ const handler = async (
25
69
  args: SubagentArgs,
26
70
  context: RouterContext
27
71
  ): Promise<ToolHandlerResponse<InferSubagentResult<T[number]> | null>> => {
@@ -36,40 +80,110 @@ export function createSubagentHandler<
36
80
  const childWorkflowId = `${args.subagent}-${getShortId()}`;
37
81
 
38
82
  const { sandboxId: parentSandboxId } = context;
39
- const inheritSandbox = config.sandbox !== "own" && !!parentSandboxId;
83
+ const sandboxCfg = resolveSandboxConfig(config.sandbox);
84
+
85
+ if (sandboxCfg.source === "inherit" && !parentSandboxId) {
86
+ throw new Error(
87
+ `Subagent "${config.agentName}" is configured with sandbox: "inherit" but the parent has no sandbox`
88
+ );
89
+ }
90
+
91
+ const threadMode = config.thread ?? "new";
92
+ const allowsContinuation = threadMode !== "new";
93
+ const continuationThreadId =
94
+ args.threadId && allowsContinuation ? args.threadId : undefined;
95
+
96
+ // --- Build thread init ---
97
+ let thread: ThreadInit | undefined;
98
+ if (continuationThreadId) {
99
+ thread = { mode: threadMode as "fork" | "continue", threadId: continuationThreadId };
100
+
101
+ }
102
+
103
+ // --- Build sandbox init ---
104
+ let sandbox: SandboxInit | undefined;
105
+ if (sandboxCfg.source === "inherit" && parentSandboxId) {
106
+ sandbox = { mode: "inherit", sandboxId: parentSandboxId };
107
+ } else if (sandboxCfg.source === "own") {
108
+ const prevSbId = continuationThreadId
109
+ ? threadSandboxes.get(continuationThreadId)
110
+ : undefined;
111
+ if (prevSbId) {
112
+ sandbox = { mode: "fork", sandboxId: prevSbId };
113
+ }
114
+ // When no previous sandbox, omit — the child will create its own via sandboxOps
115
+ }
40
116
 
41
117
  const workflowInput: SubagentWorkflowInput = {
42
- ...(args.threadId &&
43
- args.threadId !== null &&
44
- config.allowThreadContinuation && {
45
- previousThreadId: args.threadId,
46
- }),
47
- ...(inheritSandbox && { sandboxId: parentSandboxId }),
118
+ ...(thread && { thread }),
119
+ ...(sandbox && { sandbox }),
120
+ ...(sandboxCfg.shutdown && { sandboxShutdown: sandboxCfg.shutdown }),
48
121
  };
49
122
 
123
+ const resolvedContext =
124
+ config.context === undefined
125
+ ? undefined
126
+ : typeof config.context === "function"
127
+ ? config.context()
128
+ : config.context;
129
+
50
130
  const childOpts = {
51
131
  workflowId: childWorkflowId,
52
132
  args:
53
- config.context === undefined
133
+ resolvedContext === undefined
54
134
  ? ([args.prompt, workflowInput] as const)
55
- : ([args.prompt, workflowInput, config.context] as const),
135
+ : ([args.prompt, workflowInput, resolvedContext] as const),
56
136
  taskQueue: config.taskQueue ?? parentTaskQueue,
57
137
  };
58
138
 
139
+ const childHandle = await startChild(config.workflow, childOpts);
140
+
141
+ const usesOwnSandbox =
142
+ sandboxCfg.source === "own" || (allowsContinuation && sandboxCfg.source !== "inherit");
143
+
144
+ if (usesOwnSandbox) {
145
+ pendingDestroys.set(childWorkflowId, childHandle);
146
+ }
147
+
148
+ // Wait for signal from child; race with child completion to propagate failures
149
+ await Promise.race([
150
+ condition(() => childResults.has(childWorkflowId)),
151
+ childHandle.result(),
152
+ ]);
153
+ if (!childResults.has(childWorkflowId)) {
154
+ await condition(() => childResults.has(childWorkflowId));
155
+ }
156
+
157
+ const childResult = childResults.get(childWorkflowId);
158
+ childResults.delete(childWorkflowId);
159
+
160
+ if (!childResult) {
161
+ return {
162
+ toolResponse: "Subagent workflow did not signal a result",
163
+ data: null,
164
+ };
165
+ }
166
+
59
167
  const {
60
168
  toolResponse,
61
169
  data,
62
170
  usage,
63
171
  threadId: childThreadId,
64
- } = typeof config.workflow === "string"
65
- ? await executeChild(config.workflow, childOpts)
66
- : await executeChild(config.workflow, childOpts);
172
+ sandboxId: childSandboxId,
173
+ metadata,
174
+ } = childResult;
175
+
176
+ if (allowsContinuation && childSandboxId && childThreadId) {
177
+ threadSandboxes.set(childThreadId, childSandboxId);
178
+ }
67
179
 
68
180
  if (!toolResponse) {
69
181
  return {
70
182
  toolResponse: "Subagent workflow returned no response",
71
183
  data: null,
72
184
  ...(usage && { usage }),
185
+ ...(childSandboxId && { sandboxId: childSandboxId }),
186
+ ...(metadata && { metadata }),
73
187
  };
74
188
  }
75
189
 
@@ -82,11 +196,14 @@ export function createSubagentHandler<
82
196
  toolResponse: `Subagent workflow returned invalid data: ${validated.error.message}`,
83
197
  data: null,
84
198
  ...(usage && { usage }),
199
+ ...(childSandboxId && { sandboxId: childSandboxId }),
200
+ ...(metadata && { metadata }),
85
201
  };
86
202
  }
87
203
 
88
204
  let finalToolResponse: ToolMessageContent = toolResponse;
89
- if (config.allowThreadContinuation && childThreadId) {
205
+
206
+ if (allowsContinuation && childThreadId) {
90
207
  finalToolResponse =
91
208
  typeof toolResponse === "string"
92
209
  ? `${toolResponse}\n\n[${config.agentName} Thread ID: ${childThreadId}]`
@@ -97,6 +214,21 @@ export function createSubagentHandler<
97
214
  toolResponse: finalToolResponse,
98
215
  data: validated ? validated.data : data,
99
216
  ...(usage && { usage }),
217
+ ...(childSandboxId && { sandboxId: childSandboxId }),
218
+ ...(metadata && { metadata }),
100
219
  };
101
220
  };
221
+
222
+ const destroySubagentSandboxes = async (): Promise<void> => {
223
+ const handles = [...pendingDestroys.values()];
224
+ pendingDestroys.clear();
225
+ await Promise.all(
226
+ handles.map(async (handle) => {
227
+ await handle.signal(destroySandboxSignal);
228
+ await handle.result();
229
+ })
230
+ );
231
+ };
232
+
233
+ return { handler, destroySubagentSandboxes };
102
234
  }
@@ -1,8 +1,11 @@
1
1
  export type {
2
2
  SubagentConfig,
3
+ SubagentContext,
3
4
  SubagentDefinition,
5
+ SubagentFnResult,
4
6
  SubagentHooks,
5
7
  SubagentHandlerResponse,
8
+ SubagentSandboxConfig,
6
9
  SubagentWorkflow,
7
10
  SubagentWorkflowInput,
8
11
  SubagentSessionInput,
@@ -14,3 +17,4 @@ export { createSubagentHandler } from "./handler";
14
17
  export { defineSubagent } from "./define";
15
18
  export { defineSubagentWorkflow } from "./workflow";
16
19
  export { buildSubagentRegistration } from "./register";
20
+ export { childResultSignal, destroySandboxSignal } from "./signals";
@@ -21,7 +21,10 @@ import { createSubagentHandler } from "./handler";
21
21
  */
22
22
  export function buildSubagentRegistration(
23
23
  subagents: SubagentConfig[]
24
- ): ToolMap[string] | null {
24
+ ): {
25
+ registration: ToolMap[string];
26
+ destroySubagentSandboxes: () => Promise<void>;
27
+ } | null {
25
28
  if (subagents.length === 0) return null;
26
29
 
27
30
  const getEnabled = (): SubagentConfig[] =>
@@ -37,12 +40,14 @@ export function buildSubagentRegistration(
37
40
  const resolveSubagentName = (args: unknown): string =>
38
41
  (args as SubagentArgs).subagent;
39
42
 
40
- return {
43
+ const { handler, destroySubagentSandboxes } = createSubagentHandler(subagents);
44
+
45
+ const registration: ToolMap[string] = {
41
46
  name: SUBAGENT_TOOL_NAME,
42
47
  enabled: (): boolean => getEnabled().length > 0,
43
48
  description: (): string => createSubagentTool(getEnabled()).description,
44
49
  schema: (): z.ZodObject<z.ZodRawShape> => createSubagentTool(getEnabled()).schema,
45
- handler: createSubagentHandler(subagents),
50
+ handler,
46
51
  ...(subagentHooksMap.size > 0 && {
47
52
  hooks: {
48
53
  onPreToolUse: async (ctx): Promise<PreToolUseHookResult> => {
@@ -62,4 +67,6 @@ export function buildSubagentRegistration(
62
67
  } satisfies ToolHooks,
63
68
  }),
64
69
  };
70
+
71
+ return { registration, destroySubagentSandboxes };
65
72
  }
@@ -0,0 +1,8 @@
1
+ import { defineSignal } from "@temporalio/workflow";
2
+ import type { ChildResultSignalPayload } from "./types";
3
+
4
+ export const childResultSignal =
5
+ defineSignal<[ChildResultSignalPayload]>("childResult");
6
+
7
+ /** Sent by the parent to tell a subagent it may destroy its sandbox. */
8
+ export const destroySandboxSignal = defineSignal("destroySandbox");