zeitlich 0.2.1 → 0.2.3

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 (46) hide show
  1. package/README.md +36 -33
  2. package/dist/index.cjs +445 -385
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +25 -42
  5. package/dist/index.d.ts +25 -42
  6. package/dist/index.js +415 -362
  7. package/dist/index.js.map +1 -1
  8. package/dist/{workflow-CCoHnc3B.d.cts → workflow-D-2vp4Pq.d.cts} +456 -253
  9. package/dist/{workflow-CCoHnc3B.d.ts → workflow-D-2vp4Pq.d.ts} +456 -253
  10. package/dist/workflow.cjs +339 -272
  11. package/dist/workflow.cjs.map +1 -1
  12. package/dist/workflow.d.cts +4 -3
  13. package/dist/workflow.d.ts +4 -3
  14. package/dist/workflow.js +315 -252
  15. package/dist/workflow.js.map +1 -1
  16. package/package.json +3 -2
  17. package/src/activities.ts +1 -14
  18. package/src/index.ts +17 -11
  19. package/src/lib/session.ts +69 -86
  20. package/src/lib/state-manager.ts +9 -2
  21. package/src/lib/thread-manager.ts +45 -37
  22. package/src/lib/tool-router.ts +338 -116
  23. package/src/lib/types.ts +110 -28
  24. package/src/tools/ask-user-question/handler.ts +6 -6
  25. package/src/tools/ask-user-question/tool.ts +3 -2
  26. package/src/tools/bash/bash.test.ts +32 -32
  27. package/src/tools/bash/handler.ts +9 -9
  28. package/src/tools/bash/tool.ts +3 -2
  29. package/src/tools/edit/handler.ts +78 -123
  30. package/src/tools/edit/tool.ts +3 -2
  31. package/src/tools/glob/handler.ts +17 -48
  32. package/src/tools/glob/tool.ts +3 -2
  33. package/src/tools/grep/tool.ts +3 -2
  34. package/src/tools/{read → read-file}/tool.ts +3 -2
  35. package/src/tools/task/handler.ts +19 -9
  36. package/src/tools/task/tool.ts +3 -10
  37. package/src/tools/task-create/handler.ts +11 -20
  38. package/src/tools/task-create/tool.ts +3 -2
  39. package/src/tools/task-get/handler.ts +9 -14
  40. package/src/tools/task-get/tool.ts +3 -2
  41. package/src/tools/task-list/handler.ts +7 -12
  42. package/src/tools/task-list/tool.ts +3 -2
  43. package/src/tools/task-update/handler.ts +9 -16
  44. package/src/tools/task-update/tool.ts +3 -2
  45. package/src/tools/{write → write-file}/tool.ts +5 -6
  46. package/src/workflow.ts +25 -19
package/dist/workflow.cjs CHANGED
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
3
  var workflow = require('@temporalio/workflow');
4
- var z4 = require('zod');
4
+ var z3 = require('zod');
5
5
 
6
6
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
7
 
8
- var z4__default = /*#__PURE__*/_interopDefault(z4);
8
+ var z3__default = /*#__PURE__*/_interopDefault(z3);
9
9
 
10
10
  // src/lib/session.ts
11
11
  var TASK_TOOL = "Task";
@@ -40,10 +40,10 @@ function createTaskTool(subagents) {
40
40
  return {
41
41
  name: TASK_TOOL,
42
42
  description: buildTaskDescription(subagents),
43
- schema: z4__default.default.object({
44
- subagent: z4__default.default.enum(names).describe("The type of subagent to launch"),
45
- description: z4__default.default.string().describe("A short (3-5 word) description of the task"),
46
- prompt: z4__default.default.string().describe("The task for the agent to perform")
43
+ schema: z3__default.default.object({
44
+ subagent: z3__default.default.enum(names).describe("The type of subagent to launch"),
45
+ description: z3__default.default.string().describe("A short (3-5 word) description of the task"),
46
+ prompt: z3__default.default.string().describe("The task for the agent to perform")
47
47
  })
48
48
  };
49
49
  }
@@ -57,149 +57,67 @@ function createTaskHandler(subagents) {
57
57
  );
58
58
  }
59
59
  const childWorkflowId = `${parentWorkflowId}-${args.subagent}-${workflow.uuid4()}`;
60
- const childResult = await workflow.executeChild(config.workflowType, {
60
+ const input = {
61
+ prompt: args.prompt,
62
+ ...config.context && { context: config.context }
63
+ };
64
+ const childOpts = {
61
65
  workflowId: childWorkflowId,
62
- args: [{ prompt: args.prompt }],
66
+ args: [input],
63
67
  taskQueue: config.taskQueue ?? parentTaskQueue
64
- });
68
+ };
69
+ const childResult = typeof config.workflow === "string" ? await workflow.executeChild(config.workflow, childOpts) : await workflow.executeChild(config.workflow, childOpts);
65
70
  const validated = config.resultSchema ? config.resultSchema.parse(childResult) : childResult;
66
- const content = typeof validated === "string" ? validated : JSON.stringify(validated, null, 2);
71
+ const toolResponse = typeof validated === "string" ? validated : JSON.stringify(validated, null, 2);
67
72
  return {
68
- content,
69
- result: {
73
+ toolResponse,
74
+ data: {
70
75
  result: validated,
71
76
  childWorkflowId
72
77
  }
73
78
  };
74
79
  };
75
80
  }
76
- var createBashToolDescription = ({
77
- fileTree
78
- }) => `Execute shell commands in a bash environment.
79
-
80
- Use this tool to:
81
- - Run shell commands (ls, cat, grep, find, etc.)
82
- - Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
83
- - Inspect files and directories
84
-
85
- Current file tree:
86
- ${fileTree}`;
87
- var bashTool = {
88
- name: "Bash",
89
- description: `Execute shell commands in a sandboxed bash environment.
90
-
91
- Use this tool to:
92
- - Run shell commands (ls, cat, grep, find, etc.)
93
- - Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
94
- - Inspect files and directories
95
- `,
96
- schema: z4__default.default.object({
97
- command: z4__default.default.string().describe(
98
- "The bash command to execute. Can include pipes (|), redirects (>, >>), logical operators (&&, ||), and shell features like command substitution $(...)."
99
- )
100
- }),
101
- strict: true
102
- };
103
- var taskCreateTool = {
104
- name: "TaskCreate",
105
- description: `Use this tool to create a structured task list for the control test. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
106
- It also helps the user understand the progress of the task and overall progress of their requests.
107
-
108
- ## When to Use This Tool
109
-
110
- Use this tool proactively in these scenarios:
111
-
112
- - Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
113
- - Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
114
- - User explicitly requests todo list - When the user directly asks you to use the todo list
115
- - User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
116
- - After receiving new instructions - Immediately capture user requirements as tasks
117
- - When you start working on a task - Mark it as in_progress BEFORE beginning work
118
- - After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
119
-
120
- ## When NOT to Use This Tool
121
-
122
- Skip using this tool when:
123
- - There is only a single, straightforward task
124
- - The task is trivial and tracking it provides no organizational benefit
125
- - The task can be completed in less than 3 trivial steps
126
- - The task is purely conversational or informational
127
-
128
- NOTE that you should not use this tool if there is only one trivial task to do. In this case you are better off just doing the task directly.
129
-
130
- ## Task Fields
131
-
132
- - **subject**: A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")
133
- - **description**: Detailed description of what needs to be done, including context and acceptance criteria
134
- - **activeForm**: Present continuous form shown in spinner when task is in_progress (e.g., "Fixing authentication bug"). This is displayed to the user while you work on the task.
135
-
136
- **IMPORTANT**: Always provide activeForm when creating tasks. The subject should be imperative ("Run tests") while activeForm should be present continuous ("Running tests"). All tasks are created with status \`pending\`.
137
-
138
- ## Tips
139
-
140
- - Create tasks with clear, specific subjects that describe the outcome
141
- - Include enough detail in the description for another agent to understand and complete the task
142
- - After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
143
- - Check TaskList first to avoid creating duplicate tasks`,
144
- schema: z4__default.default.object({
145
- subject: z4__default.default.string().describe(
146
- 'A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")'
147
- ),
148
- description: z4__default.default.string().describe(
149
- "Detailed description of what needs to be done, including context and acceptance criteria"
150
- ),
151
- activeForm: z4__default.default.string().describe(
152
- 'Present continuous form shown in spinner when task is in_progress (e.g., "Fixing authentication bug"). This is displayed to the user while you work on the task.'
153
- ),
154
- metadata: z4__default.default.record(z4__default.default.string(), z4__default.default.string()).describe("Arbitrary key-value pairs for tracking")
155
- })
156
- };
157
81
 
158
82
  // src/lib/tool-router.ts
159
- var buildIntoolDefinitions = {
160
- [bashTool.name]: bashTool,
161
- [taskCreateTool.name]: taskCreateTool
162
- };
163
83
  function createToolRouter(options) {
164
- const { appendToolResult } = workflow.proxyActivities({
165
- startToCloseTimeout: "2m",
166
- retry: {
167
- maximumAttempts: 3,
168
- initialInterval: "5s",
169
- maximumInterval: "15m",
170
- backoffCoefficient: 4
171
- }
172
- });
84
+ const { appendToolResult } = options;
173
85
  const toolMap = /* @__PURE__ */ new Map();
174
86
  for (const [_key, tool] of Object.entries(options.tools)) {
175
87
  toolMap.set(tool.name, tool);
176
88
  }
89
+ const isEnabled = (tool) => tool.enabled !== false;
177
90
  if (options.subagents) {
91
+ const subagentHooksMap = /* @__PURE__ */ new Map();
92
+ for (const s of options.subagents) {
93
+ if (s.hooks) subagentHooksMap.set(s.name, s.hooks);
94
+ }
95
+ const resolveSubagentName = (args) => args.subagent;
178
96
  toolMap.set("Task", {
179
97
  ...createTaskTool(options.subagents),
180
- handler: createTaskHandler(options.subagents)
181
- });
182
- }
183
- if (options.buildInTools) {
184
- for (const [key, value] of Object.entries(options.buildInTools)) {
185
- if (key === bashTool.name) {
186
- toolMap.set(key, {
187
- ...buildIntoolDefinitions[key],
188
- description: createBashToolDescription({
189
- fileTree: options.fileTree
190
- }),
191
- handler: value
192
- });
193
- } else {
194
- toolMap.set(key, {
195
- ...buildIntoolDefinitions[key],
196
- handler: value
197
- });
98
+ handler: createTaskHandler(options.subagents),
99
+ ...subagentHooksMap.size > 0 && {
100
+ hooks: {
101
+ onPreToolUse: async (ctx) => {
102
+ const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
103
+ return hooks?.onPreExecution?.(ctx) ?? {};
104
+ },
105
+ onPostToolUse: async (ctx) => {
106
+ const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
107
+ await hooks?.onPostExecution?.(ctx);
108
+ },
109
+ onPostToolUseFailure: async (ctx) => {
110
+ const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
111
+ return hooks?.onExecutionFailure?.(ctx) ?? {};
112
+ }
113
+ }
198
114
  }
199
- }
115
+ });
200
116
  }
201
117
  async function processToolCall(toolCall, turn, handlerContext) {
202
118
  const startTime = Date.now();
119
+ const tool = toolMap.get(toolCall.name);
120
+ const toolHooks = tool?.hooks;
203
121
  let effectiveArgs = toolCall.args;
204
122
  if (options.hooks?.onPreToolUse) {
205
123
  const preResult = await options.hooks.onPreToolUse({
@@ -211,6 +129,7 @@ function createToolRouter(options) {
211
129
  await appendToolResult({
212
130
  threadId: options.threadId,
213
131
  toolCallId: toolCall.id,
132
+ toolName: toolCall.name,
214
133
  content: JSON.stringify({
215
134
  skipped: true,
216
135
  reason: "Skipped by PreToolUse hook"
@@ -222,54 +141,115 @@ function createToolRouter(options) {
222
141
  effectiveArgs = preResult.modifiedArgs;
223
142
  }
224
143
  }
225
- const tool = toolMap.get(toolCall.name);
144
+ if (toolHooks?.onPreToolUse) {
145
+ const preResult = await toolHooks.onPreToolUse({
146
+ args: effectiveArgs,
147
+ threadId: options.threadId,
148
+ turn
149
+ });
150
+ if (preResult?.skip) {
151
+ await appendToolResult({
152
+ threadId: options.threadId,
153
+ toolCallId: toolCall.id,
154
+ toolName: toolCall.name,
155
+ content: JSON.stringify({
156
+ skipped: true,
157
+ reason: "Skipped by tool PreToolUse hook"
158
+ })
159
+ });
160
+ return null;
161
+ }
162
+ if (preResult?.modifiedArgs !== void 0) {
163
+ effectiveArgs = preResult.modifiedArgs;
164
+ }
165
+ }
226
166
  let result;
227
167
  let content;
168
+ let resultAppended = false;
228
169
  try {
229
170
  if (tool) {
171
+ const enrichedContext = {
172
+ ...handlerContext ?? {},
173
+ threadId: options.threadId,
174
+ toolCallId: toolCall.id,
175
+ toolName: toolCall.name
176
+ };
230
177
  const response = await tool.handler(
231
178
  effectiveArgs,
232
- handlerContext ?? {}
179
+ enrichedContext
233
180
  );
234
- result = response.result;
235
- content = response.content;
181
+ result = response.data;
182
+ content = response.toolResponse;
183
+ resultAppended = response.resultAppended === true;
236
184
  } else {
237
185
  result = { error: `Unknown tool: ${toolCall.name}` };
238
186
  content = JSON.stringify(result, null, 2);
239
187
  }
240
188
  } catch (error) {
241
- if (options.hooks?.onPostToolUseFailure) {
189
+ const err = error instanceof Error ? error : new Error(String(error));
190
+ let recovered = false;
191
+ if (toolHooks?.onPostToolUseFailure) {
192
+ const failureResult = await toolHooks.onPostToolUseFailure({
193
+ args: effectiveArgs,
194
+ error: err,
195
+ threadId: options.threadId,
196
+ turn
197
+ });
198
+ if (failureResult?.fallbackContent !== void 0) {
199
+ content = failureResult.fallbackContent;
200
+ result = { error: String(error), recovered: true };
201
+ recovered = true;
202
+ } else if (failureResult?.suppress) {
203
+ content = JSON.stringify({ error: String(error), suppressed: true });
204
+ result = { error: String(error), suppressed: true };
205
+ recovered = true;
206
+ }
207
+ }
208
+ if (!recovered && options.hooks?.onPostToolUseFailure) {
242
209
  const failureResult = await options.hooks.onPostToolUseFailure({
243
210
  toolCall,
244
- error: error instanceof Error ? error : new Error(String(error)),
211
+ error: err,
245
212
  threadId: options.threadId,
246
213
  turn
247
214
  });
248
215
  if (failureResult?.fallbackContent !== void 0) {
249
216
  content = failureResult.fallbackContent;
250
217
  result = { error: String(error), recovered: true };
218
+ recovered = true;
251
219
  } else if (failureResult?.suppress) {
252
220
  content = JSON.stringify({ error: String(error), suppressed: true });
253
221
  result = { error: String(error), suppressed: true };
254
- } else {
255
- throw error;
222
+ recovered = true;
256
223
  }
257
- } else {
224
+ }
225
+ if (!recovered) {
258
226
  throw error;
259
227
  }
260
228
  }
261
- await appendToolResult({
262
- threadId: options.threadId,
263
- toolCallId: toolCall.id,
264
- content
265
- });
229
+ if (!resultAppended) {
230
+ await appendToolResult({
231
+ threadId: options.threadId,
232
+ toolCallId: toolCall.id,
233
+ toolName: toolCall.name,
234
+ content
235
+ });
236
+ }
266
237
  const toolResult = {
267
238
  toolCallId: toolCall.id,
268
239
  name: toolCall.name,
269
- result
240
+ data: result
270
241
  };
242
+ const durationMs = Date.now() - startTime;
243
+ if (toolHooks?.onPostToolUse) {
244
+ await toolHooks.onPostToolUse({
245
+ args: effectiveArgs,
246
+ result,
247
+ threadId: options.threadId,
248
+ turn,
249
+ durationMs
250
+ });
251
+ }
271
252
  if (options.hooks?.onPostToolUse) {
272
- const durationMs = Date.now() - startTime;
273
253
  await options.hooks.onPostToolUse({
274
254
  toolCall,
275
255
  result: toolResult,
@@ -283,11 +263,11 @@ function createToolRouter(options) {
283
263
  return {
284
264
  // --- Methods from registry ---
285
265
  hasTools() {
286
- return toolMap.size > 0;
266
+ return Array.from(toolMap.values()).some(isEnabled);
287
267
  },
288
268
  parseToolCall(toolCall) {
289
269
  const tool = toolMap.get(toolCall.name);
290
- if (!tool) {
270
+ if (!tool || !isEnabled(tool)) {
291
271
  throw new Error(`Tool ${toolCall.name} not found`);
292
272
  }
293
273
  const parsedArgs = tool.schema.parse(toolCall.args);
@@ -298,13 +278,14 @@ function createToolRouter(options) {
298
278
  };
299
279
  },
300
280
  hasTool(name) {
301
- return toolMap.has(name);
281
+ const tool = toolMap.get(name);
282
+ return tool !== void 0 && isEnabled(tool);
302
283
  },
303
284
  getToolNames() {
304
- return Array.from(toolMap.keys());
285
+ return Array.from(toolMap.entries()).filter(([, tool]) => isEnabled(tool)).map(([name]) => name);
305
286
  },
306
287
  getToolDefinitions() {
307
- return Array.from(toolMap).map(([name, tool]) => ({
288
+ return Array.from(toolMap).filter(([, tool]) => isEnabled(tool)).map(([name, tool]) => ({
308
289
  name,
309
290
  description: tool.description,
310
291
  schema: tool.schema,
@@ -343,19 +324,28 @@ function createToolRouter(options) {
343
324
  }
344
325
  const handlerContext = context?.handlerContext ?? {};
345
326
  const processOne = async (toolCall) => {
327
+ const enrichedContext = {
328
+ ...handlerContext ?? {},
329
+ threadId: options.threadId,
330
+ toolCallId: toolCall.id,
331
+ toolName: toolCall.name
332
+ };
346
333
  const response = await handler(
347
334
  toolCall.args,
348
- handlerContext
335
+ enrichedContext
349
336
  );
350
- await appendToolResult({
351
- threadId: options.threadId,
352
- toolCallId: toolCall.id,
353
- content: response.content
354
- });
337
+ if (!response.resultAppended) {
338
+ await appendToolResult({
339
+ threadId: options.threadId,
340
+ toolCallId: toolCall.id,
341
+ toolName: toolCall.name,
342
+ content: response.toolResponse
343
+ });
344
+ }
355
345
  return {
356
346
  toolCallId: toolCall.id,
357
347
  name: toolCall.name,
358
- result: response.result
348
+ data: response.data
359
349
  };
360
350
  };
361
351
  if (options.parallel) {
@@ -381,56 +371,35 @@ function createToolRouter(options) {
381
371
  }
382
372
  };
383
373
  }
374
+ function defineTool(tool) {
375
+ return tool;
376
+ }
377
+ function defineSubagent(config) {
378
+ return config;
379
+ }
384
380
  function hasNoOtherToolCalls(toolCalls, excludeName) {
385
381
  return toolCalls.filter((tc) => tc.name !== excludeName).length === 0;
386
382
  }
387
383
 
388
384
  // src/lib/session.ts
389
- async function resolvePrompt(prompt) {
390
- if (typeof prompt === "function") {
391
- return prompt();
392
- }
393
- return prompt;
394
- }
395
385
  var createSession = async ({
396
386
  threadId,
397
387
  agentName,
398
388
  maxTurns = 50,
399
389
  metadata = {},
400
390
  runAgent,
401
- baseSystemPrompt,
402
- instructionsPrompt,
391
+ threadOps,
403
392
  buildContextMessage,
404
- buildFileTree = async () => "",
405
393
  subagents,
406
394
  tools = {},
407
395
  processToolsInParallel = true,
408
- buildInTools = {},
409
396
  hooks = {}
410
397
  }) => {
411
- const {
412
- initializeThread,
413
- appendHumanMessage,
414
- parseToolCalls,
415
- appendToolResult,
416
- appendSystemMessage
417
- } = workflow.proxyActivities({
418
- startToCloseTimeout: "30m",
419
- retry: {
420
- maximumAttempts: 6,
421
- initialInterval: "5s",
422
- maximumInterval: "15m",
423
- backoffCoefficient: 4
424
- },
425
- heartbeatTimeout: "5m"
426
- });
427
- const fileTree = await buildFileTree();
428
398
  const toolRouter = createToolRouter({
429
399
  tools,
400
+ appendToolResult: threadOps.appendToolResult,
430
401
  threadId,
431
402
  hooks,
432
- buildInTools,
433
- fileTree,
434
403
  subagents,
435
404
  parallel: processToolsInParallel
436
405
  });
@@ -455,15 +424,8 @@ var createSession = async ({
455
424
  });
456
425
  }
457
426
  stateManager.setTools(toolRouter.getToolDefinitions());
458
- await initializeThread(threadId);
459
- await appendSystemMessage(
460
- threadId,
461
- [
462
- await resolvePrompt(baseSystemPrompt),
463
- await resolvePrompt(instructionsPrompt)
464
- ].join("\n")
465
- );
466
- await appendHumanMessage(threadId, await buildContextMessage());
427
+ await threadOps.initializeThread(threadId);
428
+ await threadOps.appendHumanMessage(threadId, await buildContextMessage());
467
429
  let exitReason = "completed";
468
430
  try {
469
431
  while (stateManager.isRunning() && !stateManager.isTerminal() && stateManager.getTurns() < maxTurns) {
@@ -484,24 +446,25 @@ var createSession = async ({
484
446
  exitReason = "completed";
485
447
  return message;
486
448
  }
487
- const rawToolCalls = await parseToolCalls(message);
488
- const parsedToolCalls = rawToolCalls.filter((tc) => tc.name !== "Task").map((tc) => toolRouter.parseToolCall(tc));
489
- const taskToolCalls = subagents && subagents.length > 0 ? rawToolCalls.filter((tc) => tc.name === "Task").map((tc) => {
490
- const parsedArgs = createTaskTool(subagents).schema.parse(
491
- tc.args
492
- );
493
- return {
494
- id: tc.id ?? "",
495
- name: tc.name,
496
- args: parsedArgs
497
- };
498
- }) : [];
499
- await toolRouter.processToolCalls(
500
- [...parsedToolCalls, ...taskToolCalls],
501
- {
502
- turn: currentTurn
449
+ const rawToolCalls = await threadOps.parseToolCalls(message);
450
+ const parsedToolCalls = [];
451
+ for (const tc of rawToolCalls) {
452
+ try {
453
+ parsedToolCalls.push(toolRouter.parseToolCall(tc));
454
+ } catch (error) {
455
+ await threadOps.appendToolResult({
456
+ threadId,
457
+ toolCallId: tc.id ?? "",
458
+ toolName: tc.name,
459
+ content: JSON.stringify({
460
+ error: `Invalid tool call for "${tc.name}": ${error instanceof Error ? error.message : String(error)}`
461
+ })
462
+ });
503
463
  }
504
- );
464
+ }
465
+ await toolRouter.processToolCalls(parsedToolCalls, {
466
+ turn: currentTurn
467
+ });
505
468
  if (stateManager.getStatus() === "WAITING_FOR_INPUT") {
506
469
  exitReason = "waiting_for_input";
507
470
  break;
@@ -520,13 +483,31 @@ var createSession = async ({
520
483
  }
521
484
  };
522
485
  };
486
+ function proxyDefaultThreadOps(options) {
487
+ const activities = workflow.proxyActivities(
488
+ options ?? {
489
+ startToCloseTimeout: "30m",
490
+ retry: {
491
+ maximumAttempts: 6,
492
+ initialInterval: "5s",
493
+ maximumInterval: "15m",
494
+ backoffCoefficient: 4
495
+ },
496
+ heartbeatTimeout: "5m"
497
+ }
498
+ );
499
+ return {
500
+ initializeThread: activities.initializeThread,
501
+ appendHumanMessage: activities.appendHumanMessage,
502
+ appendToolResult: activities.appendToolResult,
503
+ parseToolCalls: activities.parseToolCalls
504
+ };
505
+ }
523
506
 
524
507
  // src/lib/types.ts
525
508
  function isTerminalStatus(status) {
526
509
  return status === "COMPLETED" || status === "FAILED" || status === "CANCELLED";
527
510
  }
528
-
529
- // src/lib/state-manager.ts
530
511
  var getStateQuery = workflow.defineQuery("getState");
531
512
  function createAgentStateManager(initialState) {
532
513
  let status = initialState?.status ?? "RUNNING";
@@ -621,7 +602,13 @@ function createAgentStateManager(initialState) {
621
602
  version++;
622
603
  },
623
604
  setTools(newTools) {
624
- tools = newTools;
605
+ tools = newTools.map((tool) => ({
606
+ name: tool.name,
607
+ description: tool.description,
608
+ schema: z3.z.toJSONSchema(tool.schema),
609
+ strict: tool.strict,
610
+ max_uses: tool.max_uses
611
+ }));
625
612
  },
626
613
  deleteTask(id) {
627
614
  const deleted = tasks.delete(id);
@@ -652,18 +639,18 @@ Usage notes:
652
639
  * Use multiSelect: true to allow multiple answers to be selected for a question
653
640
  * If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
654
641
  `,
655
- schema: z4__default.default.object({
656
- questions: z4__default.default.array(
657
- z4__default.default.object({
658
- question: z4__default.default.string().describe("The full question text to display"),
659
- header: z4__default.default.string().describe("Short label for the question (max 12 characters)"),
660
- options: z4__default.default.array(
661
- z4__default.default.object({
662
- label: z4__default.default.string(),
663
- description: z4__default.default.string()
642
+ schema: z3__default.default.object({
643
+ questions: z3__default.default.array(
644
+ z3__default.default.object({
645
+ question: z3__default.default.string().describe("The full question text to display"),
646
+ header: z3__default.default.string().describe("Short label for the question (max 12 characters)"),
647
+ options: z3__default.default.array(
648
+ z3__default.default.object({
649
+ label: z3__default.default.string(),
650
+ description: z3__default.default.string()
664
651
  })
665
652
  ).min(0).max(4).describe("Array of 0-4 choices, each with label and description"),
666
- multiSelect: z4__default.default.boolean().describe("If true, users can select multiple options")
653
+ multiSelect: z3__default.default.boolean().describe("If true, users can select multiple options")
667
654
  })
668
655
  )
669
656
  }),
@@ -683,9 +670,9 @@ Examples:
683
670
  - "**/*.test.ts" - Find all test files recursively
684
671
  - "src/**/*.ts" - Find all TypeScript files in src directory
685
672
  `,
686
- schema: z4.z.object({
687
- pattern: z4.z.string().describe("Glob pattern to match files against"),
688
- root: z4.z.string().optional().describe("Optional root directory to search from")
673
+ schema: z3.z.object({
674
+ pattern: z3.z.string().describe("Glob pattern to match files against"),
675
+ root: z3.z.string().optional().describe("Optional root directory to search from")
689
676
  }),
690
677
  strict: true
691
678
  };
@@ -703,13 +690,13 @@ Examples:
703
690
  - Search for function definitions with "function.*handleClick"
704
691
  - Search case-insensitively with ignoreCase: true
705
692
  `,
706
- schema: z4.z.object({
707
- pattern: z4.z.string().describe("Regex pattern to search for in file contents"),
708
- ignoreCase: z4.z.boolean().optional().describe("Case-insensitive search (default: false)"),
709
- maxMatches: z4.z.number().optional().describe("Maximum number of matches to return (default: 50)"),
710
- includePatterns: z4.z.array(z4.z.string()).optional().describe("Glob patterns to include (e.g., ['*.ts', '*.js'])"),
711
- excludePatterns: z4.z.array(z4.z.string()).optional().describe("Glob patterns to exclude (e.g., ['*.test.ts'])"),
712
- contextLines: z4.z.number().optional().describe("Number of context lines to show around matches")
693
+ schema: z3.z.object({
694
+ pattern: z3.z.string().describe("Regex pattern to search for in file contents"),
695
+ ignoreCase: z3.z.boolean().optional().describe("Case-insensitive search (default: false)"),
696
+ maxMatches: z3.z.number().optional().describe("Maximum number of matches to return (default: 50)"),
697
+ includePatterns: z3.z.array(z3.z.string()).optional().describe("Glob patterns to include (e.g., ['*.ts', '*.js'])"),
698
+ excludePatterns: z3.z.array(z3.z.string()).optional().describe("Glob patterns to exclude (e.g., ['*.test.ts'])"),
699
+ contextLines: z3.z.number().optional().describe("Number of context lines to show around matches")
713
700
  }),
714
701
  strict: true
715
702
  };
@@ -727,12 +714,12 @@ The tool returns the file content in an appropriate format:
727
714
  - Images: Base64-encoded image data
728
715
  - PDFs: Extracted text content
729
716
  `,
730
- schema: z4.z.object({
731
- path: z4.z.string().describe("Virtual path to the file to read"),
732
- offset: z4.z.number().optional().describe(
717
+ schema: z3.z.object({
718
+ path: z3.z.string().describe("Virtual path to the file to read"),
719
+ offset: z3.z.number().optional().describe(
733
720
  "Line number to start reading from (1-indexed, for text files)"
734
721
  ),
735
- limit: z4.z.number().optional().describe("Maximum number of lines to read (for text files)")
722
+ limit: z3.z.number().optional().describe("Maximum number of lines to read (for text files)")
736
723
  }),
737
724
  strict: true
738
725
  };
@@ -741,7 +728,7 @@ var writeTool = {
741
728
  description: `Create or overwrite a file with new content.
742
729
 
743
730
  Usage:
744
- - Provide the absolute virtual path to the file
731
+ - Provide the absolute path to the file
745
732
  - The file will be created if it doesn't exist
746
733
  - If the file exists, it will be completely overwritten
747
734
 
@@ -750,9 +737,9 @@ IMPORTANT:
750
737
  - This is an atomic write operation - the entire file is replaced
751
738
  - Path must be absolute (e.g., "/docs/readme.md", not "docs/readme.md")
752
739
  `,
753
- schema: z4.z.object({
754
- file_path: z4.z.string().describe("The absolute virtual path to the file to write"),
755
- content: z4.z.string().describe("The content to write to the file")
740
+ schema: z3.z.object({
741
+ file_path: z3.z.string().describe("The absolute path to the file to write"),
742
+ content: z3.z.string().describe("The content to write to the file")
756
743
  }),
757
744
  strict: true
758
745
  };
@@ -772,27 +759,76 @@ IMPORTANT:
772
759
  - The operation fails if old_string is not found
773
760
  - old_string and new_string must be different
774
761
  `,
775
- schema: z4.z.object({
776
- file_path: z4.z.string().describe("The absolute virtual path to the file to modify"),
777
- old_string: z4.z.string().describe("The exact text to replace"),
778
- new_string: z4.z.string().describe(
762
+ schema: z3.z.object({
763
+ file_path: z3.z.string().describe("The absolute virtual path to the file to modify"),
764
+ old_string: z3.z.string().describe("The exact text to replace"),
765
+ new_string: z3.z.string().describe(
779
766
  "The text to replace it with (must be different from old_string)"
780
767
  ),
781
- replace_all: z4.z.boolean().optional().describe(
768
+ replace_all: z3.z.boolean().optional().describe(
782
769
  "If true, replace all occurrences of old_string (default: false)"
783
770
  )
784
771
  }),
785
772
  strict: true
786
773
  };
787
-
788
- // src/tools/task-create/handler.ts
789
- function createTaskCreateHandler({
790
- stateManager,
791
- idGenerator
792
- }) {
774
+ var taskCreateTool = {
775
+ name: "TaskCreate",
776
+ description: `Use this tool to create a structured task list for the control test. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
777
+ It also helps the user understand the progress of the task and overall progress of their requests.
778
+
779
+ ## When to Use This Tool
780
+
781
+ Use this tool proactively in these scenarios:
782
+
783
+ - Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
784
+ - Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
785
+ - User explicitly requests todo list - When the user directly asks you to use the todo list
786
+ - User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
787
+ - After receiving new instructions - Immediately capture user requirements as tasks
788
+ - When you start working on a task - Mark it as in_progress BEFORE beginning work
789
+ - After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
790
+
791
+ ## When NOT to Use This Tool
792
+
793
+ Skip using this tool when:
794
+ - There is only a single, straightforward task
795
+ - The task is trivial and tracking it provides no organizational benefit
796
+ - The task can be completed in less than 3 trivial steps
797
+ - The task is purely conversational or informational
798
+
799
+ NOTE that you should not use this tool if there is only one trivial task to do. In this case you are better off just doing the task directly.
800
+
801
+ ## Task Fields
802
+
803
+ - **subject**: A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")
804
+ - **description**: Detailed description of what needs to be done, including context and acceptance criteria
805
+ - **activeForm**: Present continuous form shown in spinner when task is in_progress (e.g., "Fixing authentication bug"). This is displayed to the user while you work on the task.
806
+
807
+ **IMPORTANT**: Always provide activeForm when creating tasks. The subject should be imperative ("Run tests") while activeForm should be present continuous ("Running tests"). All tasks are created with status \`pending\`.
808
+
809
+ ## Tips
810
+
811
+ - Create tasks with clear, specific subjects that describe the outcome
812
+ - Include enough detail in the description for another agent to understand and complete the task
813
+ - After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
814
+ - Check TaskList first to avoid creating duplicate tasks`,
815
+ schema: z3__default.default.object({
816
+ subject: z3__default.default.string().describe(
817
+ 'A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")'
818
+ ),
819
+ description: z3__default.default.string().describe(
820
+ "Detailed description of what needs to be done, including context and acceptance criteria"
821
+ ),
822
+ activeForm: z3__default.default.string().describe(
823
+ 'Present continuous form shown in spinner when task is in_progress (e.g., "Fixing authentication bug"). This is displayed to the user while you work on the task.'
824
+ ),
825
+ metadata: z3__default.default.record(z3__default.default.string(), z3__default.default.string()).describe("Arbitrary key-value pairs for tracking")
826
+ })
827
+ };
828
+ function createTaskCreateHandler(stateManager) {
793
829
  return (args) => {
794
830
  const task = {
795
- id: idGenerator(),
831
+ id: workflow.uuid4(),
796
832
  subject: args.subject,
797
833
  description: args.description,
798
834
  activeForm: args.activeForm,
@@ -803,16 +839,16 @@ function createTaskCreateHandler({
803
839
  };
804
840
  stateManager.setTask(task);
805
841
  return {
806
- content: JSON.stringify(task, null, 2),
807
- result: task
842
+ toolResponse: JSON.stringify(task, null, 2),
843
+ data: task
808
844
  };
809
845
  };
810
846
  }
811
847
  var taskGetTool = {
812
848
  name: "TaskGet",
813
849
  description: `Retrieve full task details including dependencies.`,
814
- schema: z4__default.default.object({
815
- taskId: z4__default.default.string().describe("The ID of the task to get")
850
+ schema: z3__default.default.object({
851
+ taskId: z3__default.default.string().describe("The ID of the task to get")
816
852
  })
817
853
  };
818
854
 
@@ -822,40 +858,40 @@ function createTaskGetHandler(stateManager) {
822
858
  const task = stateManager.getTask(args.taskId) ?? null;
823
859
  if (!task) {
824
860
  return {
825
- content: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
826
- result: null
861
+ toolResponse: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
862
+ data: null
827
863
  };
828
864
  }
829
865
  return {
830
- content: JSON.stringify(task, null, 2),
831
- result: task
866
+ toolResponse: JSON.stringify(task, null, 2),
867
+ data: task
832
868
  };
833
869
  };
834
870
  }
835
871
  var taskListTool = {
836
872
  name: "TaskList",
837
873
  description: `List all tasks with current state.`,
838
- schema: z4__default.default.object({})
874
+ schema: z3__default.default.object({})
839
875
  };
840
876
 
841
877
  // src/tools/task-list/handler.ts
842
878
  function createTaskListHandler(stateManager) {
843
- return (_args) => {
879
+ return () => {
844
880
  const taskList = stateManager.getTasks();
845
881
  return {
846
- content: JSON.stringify(taskList, null, 2),
847
- result: taskList
882
+ toolResponse: JSON.stringify(taskList, null, 2),
883
+ data: taskList
848
884
  };
849
885
  };
850
886
  }
851
887
  var taskUpdateTool = {
852
888
  name: "TaskUpdate",
853
889
  description: `Update status, add blockers, modify details.`,
854
- schema: z4__default.default.object({
855
- taskId: z4__default.default.string().describe("The ID of the task to get"),
856
- status: z4__default.default.enum(["pending", "in_progress", "completed"]).describe("The status of the task"),
857
- addBlockedBy: z4__default.default.array(z4__default.default.string()).describe("The IDs of the tasks that are blocking this task"),
858
- addBlocks: z4__default.default.array(z4__default.default.string()).describe("The IDs of the tasks that this task is blocking")
890
+ schema: z3__default.default.object({
891
+ taskId: z3__default.default.string().describe("The ID of the task to get"),
892
+ status: z3__default.default.enum(["pending", "in_progress", "completed"]).describe("The status of the task"),
893
+ addBlockedBy: z3__default.default.array(z3__default.default.string()).describe("The IDs of the tasks that are blocking this task"),
894
+ addBlocks: z3__default.default.array(z3__default.default.string()).describe("The IDs of the tasks that this task is blocking")
859
895
  })
860
896
  };
861
897
 
@@ -865,8 +901,8 @@ function createTaskUpdateHandler(stateManager) {
865
901
  const task = stateManager.getTask(args.taskId);
866
902
  if (!task) {
867
903
  return {
868
- content: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
869
- result: null
904
+ toolResponse: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
905
+ data: null
870
906
  };
871
907
  }
872
908
  if (args.status) {
@@ -898,16 +934,44 @@ function createTaskUpdateHandler(stateManager) {
898
934
  }
899
935
  stateManager.setTask(task);
900
936
  return {
901
- content: JSON.stringify(task, null, 2),
902
- result: task
937
+ toolResponse: JSON.stringify(task, null, 2),
938
+ data: task
903
939
  };
904
940
  };
905
941
  }
942
+ var createBashToolDescription = ({
943
+ fileTree
944
+ }) => `Execute shell commands in a bash environment.
945
+
946
+ Use this tool to:
947
+ - Run shell commands (ls, cat, grep, find, etc.)
948
+ - Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
949
+ - Inspect files and directories
950
+
951
+ Current file tree:
952
+ ${fileTree}`;
953
+ var bashTool = {
954
+ name: "Bash",
955
+ description: `Execute shell commands in a sandboxed bash environment.
956
+
957
+ Use this tool to:
958
+ - Run shell commands (ls, cat, grep, find, etc.)
959
+ - Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
960
+ - Inspect files and directories
961
+ `,
962
+ schema: z3__default.default.object({
963
+ command: z3__default.default.string().describe(
964
+ "The bash command to execute. Can include pipes (|), redirects (>, >>), logical operators (&&, ||), and shell features like command substitution $(...)."
965
+ )
966
+ }),
967
+ strict: true
968
+ };
906
969
 
907
970
  exports.AGENT_HANDLER_NAMES = AGENT_HANDLER_NAMES;
908
971
  exports.askUserQuestionTool = askUserQuestionTool;
909
972
  exports.bashTool = bashTool;
910
973
  exports.createAgentStateManager = createAgentStateManager;
974
+ exports.createBashToolDescription = createBashToolDescription;
911
975
  exports.createSession = createSession;
912
976
  exports.createTaskCreateHandler = createTaskCreateHandler;
913
977
  exports.createTaskGetHandler = createTaskGetHandler;
@@ -915,11 +979,14 @@ exports.createTaskListHandler = createTaskListHandler;
915
979
  exports.createTaskTool = createTaskTool;
916
980
  exports.createTaskUpdateHandler = createTaskUpdateHandler;
917
981
  exports.createToolRouter = createToolRouter;
982
+ exports.defineSubagent = defineSubagent;
983
+ exports.defineTool = defineTool;
918
984
  exports.editTool = editTool;
919
985
  exports.globTool = globTool;
920
986
  exports.grepTool = grepTool;
921
987
  exports.hasNoOtherToolCalls = hasNoOtherToolCalls;
922
988
  exports.isTerminalStatus = isTerminalStatus;
989
+ exports.proxyDefaultThreadOps = proxyDefaultThreadOps;
923
990
  exports.readTool = readTool;
924
991
  exports.taskCreateTool = taskCreateTool;
925
992
  exports.taskGetTool = taskGetTool;