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/index.cjs CHANGED
@@ -1,7 +1,7 @@
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
  var plugin = require('@temporalio/plugin');
6
6
  var messages = require('@langchain/core/messages');
7
7
  var crypto = require('crypto');
@@ -10,7 +10,7 @@ var justBash = require('just-bash');
10
10
 
11
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
12
 
13
- var z4__default = /*#__PURE__*/_interopDefault(z4);
13
+ var z3__default = /*#__PURE__*/_interopDefault(z3);
14
14
  var crypto__default = /*#__PURE__*/_interopDefault(crypto);
15
15
 
16
16
  // src/lib/session.ts
@@ -46,10 +46,10 @@ function createTaskTool(subagents) {
46
46
  return {
47
47
  name: TASK_TOOL,
48
48
  description: buildTaskDescription(subagents),
49
- schema: z4__default.default.object({
50
- subagent: z4__default.default.enum(names).describe("The type of subagent to launch"),
51
- description: z4__default.default.string().describe("A short (3-5 word) description of the task"),
52
- prompt: z4__default.default.string().describe("The task for the agent to perform")
49
+ schema: z3__default.default.object({
50
+ subagent: z3__default.default.enum(names).describe("The type of subagent to launch"),
51
+ description: z3__default.default.string().describe("A short (3-5 word) description of the task"),
52
+ prompt: z3__default.default.string().describe("The task for the agent to perform")
53
53
  })
54
54
  };
55
55
  }
@@ -63,149 +63,67 @@ function createTaskHandler(subagents) {
63
63
  );
64
64
  }
65
65
  const childWorkflowId = `${parentWorkflowId}-${args.subagent}-${workflow.uuid4()}`;
66
- const childResult = await workflow.executeChild(config.workflowType, {
66
+ const input = {
67
+ prompt: args.prompt,
68
+ ...config.context && { context: config.context }
69
+ };
70
+ const childOpts = {
67
71
  workflowId: childWorkflowId,
68
- args: [{ prompt: args.prompt }],
72
+ args: [input],
69
73
  taskQueue: config.taskQueue ?? parentTaskQueue
70
- });
74
+ };
75
+ const childResult = typeof config.workflow === "string" ? await workflow.executeChild(config.workflow, childOpts) : await workflow.executeChild(config.workflow, childOpts);
71
76
  const validated = config.resultSchema ? config.resultSchema.parse(childResult) : childResult;
72
- const content = typeof validated === "string" ? validated : JSON.stringify(validated, null, 2);
77
+ const toolResponse = typeof validated === "string" ? validated : JSON.stringify(validated, null, 2);
73
78
  return {
74
- content,
75
- result: {
79
+ toolResponse,
80
+ data: {
76
81
  result: validated,
77
82
  childWorkflowId
78
83
  }
79
84
  };
80
85
  };
81
86
  }
82
- var createBashToolDescription = ({
83
- fileTree
84
- }) => `Execute shell commands in a bash environment.
85
-
86
- Use this tool to:
87
- - Run shell commands (ls, cat, grep, find, etc.)
88
- - Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
89
- - Inspect files and directories
90
-
91
- Current file tree:
92
- ${fileTree}`;
93
- var bashTool = {
94
- name: "Bash",
95
- description: `Execute shell commands in a sandboxed bash environment.
96
-
97
- Use this tool to:
98
- - Run shell commands (ls, cat, grep, find, etc.)
99
- - Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
100
- - Inspect files and directories
101
- `,
102
- schema: z4__default.default.object({
103
- command: z4__default.default.string().describe(
104
- "The bash command to execute. Can include pipes (|), redirects (>, >>), logical operators (&&, ||), and shell features like command substitution $(...)."
105
- )
106
- }),
107
- strict: true
108
- };
109
- var taskCreateTool = {
110
- name: "TaskCreate",
111
- 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.
112
- It also helps the user understand the progress of the task and overall progress of their requests.
113
-
114
- ## When to Use This Tool
115
-
116
- Use this tool proactively in these scenarios:
117
-
118
- - Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
119
- - Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
120
- - User explicitly requests todo list - When the user directly asks you to use the todo list
121
- - User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
122
- - After receiving new instructions - Immediately capture user requirements as tasks
123
- - When you start working on a task - Mark it as in_progress BEFORE beginning work
124
- - After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
125
-
126
- ## When NOT to Use This Tool
127
-
128
- Skip using this tool when:
129
- - There is only a single, straightforward task
130
- - The task is trivial and tracking it provides no organizational benefit
131
- - The task can be completed in less than 3 trivial steps
132
- - The task is purely conversational or informational
133
-
134
- 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.
135
-
136
- ## Task Fields
137
-
138
- - **subject**: A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")
139
- - **description**: Detailed description of what needs to be done, including context and acceptance criteria
140
- - **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.
141
-
142
- **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\`.
143
-
144
- ## Tips
145
-
146
- - Create tasks with clear, specific subjects that describe the outcome
147
- - Include enough detail in the description for another agent to understand and complete the task
148
- - After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
149
- - Check TaskList first to avoid creating duplicate tasks`,
150
- schema: z4__default.default.object({
151
- subject: z4__default.default.string().describe(
152
- 'A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")'
153
- ),
154
- description: z4__default.default.string().describe(
155
- "Detailed description of what needs to be done, including context and acceptance criteria"
156
- ),
157
- activeForm: z4__default.default.string().describe(
158
- '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.'
159
- ),
160
- metadata: z4__default.default.record(z4__default.default.string(), z4__default.default.string()).describe("Arbitrary key-value pairs for tracking")
161
- })
162
- };
163
87
 
164
88
  // src/lib/tool-router.ts
165
- var buildIntoolDefinitions = {
166
- [bashTool.name]: bashTool,
167
- [taskCreateTool.name]: taskCreateTool
168
- };
169
89
  function createToolRouter(options) {
170
- const { appendToolResult } = workflow.proxyActivities({
171
- startToCloseTimeout: "2m",
172
- retry: {
173
- maximumAttempts: 3,
174
- initialInterval: "5s",
175
- maximumInterval: "15m",
176
- backoffCoefficient: 4
177
- }
178
- });
90
+ const { appendToolResult } = options;
179
91
  const toolMap = /* @__PURE__ */ new Map();
180
92
  for (const [_key, tool] of Object.entries(options.tools)) {
181
93
  toolMap.set(tool.name, tool);
182
94
  }
95
+ const isEnabled = (tool) => tool.enabled !== false;
183
96
  if (options.subagents) {
97
+ const subagentHooksMap = /* @__PURE__ */ new Map();
98
+ for (const s of options.subagents) {
99
+ if (s.hooks) subagentHooksMap.set(s.name, s.hooks);
100
+ }
101
+ const resolveSubagentName = (args) => args.subagent;
184
102
  toolMap.set("Task", {
185
103
  ...createTaskTool(options.subagents),
186
- handler: createTaskHandler(options.subagents)
187
- });
188
- }
189
- if (options.buildInTools) {
190
- for (const [key, value] of Object.entries(options.buildInTools)) {
191
- if (key === bashTool.name) {
192
- toolMap.set(key, {
193
- ...buildIntoolDefinitions[key],
194
- description: createBashToolDescription({
195
- fileTree: options.fileTree
196
- }),
197
- handler: value
198
- });
199
- } else {
200
- toolMap.set(key, {
201
- ...buildIntoolDefinitions[key],
202
- handler: value
203
- });
104
+ handler: createTaskHandler(options.subagents),
105
+ ...subagentHooksMap.size > 0 && {
106
+ hooks: {
107
+ onPreToolUse: async (ctx) => {
108
+ const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
109
+ return hooks?.onPreExecution?.(ctx) ?? {};
110
+ },
111
+ onPostToolUse: async (ctx) => {
112
+ const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
113
+ await hooks?.onPostExecution?.(ctx);
114
+ },
115
+ onPostToolUseFailure: async (ctx) => {
116
+ const hooks = subagentHooksMap.get(resolveSubagentName(ctx.args));
117
+ return hooks?.onExecutionFailure?.(ctx) ?? {};
118
+ }
119
+ }
204
120
  }
205
- }
121
+ });
206
122
  }
207
123
  async function processToolCall(toolCall, turn, handlerContext) {
208
124
  const startTime = Date.now();
125
+ const tool = toolMap.get(toolCall.name);
126
+ const toolHooks = tool?.hooks;
209
127
  let effectiveArgs = toolCall.args;
210
128
  if (options.hooks?.onPreToolUse) {
211
129
  const preResult = await options.hooks.onPreToolUse({
@@ -217,6 +135,7 @@ function createToolRouter(options) {
217
135
  await appendToolResult({
218
136
  threadId: options.threadId,
219
137
  toolCallId: toolCall.id,
138
+ toolName: toolCall.name,
220
139
  content: JSON.stringify({
221
140
  skipped: true,
222
141
  reason: "Skipped by PreToolUse hook"
@@ -228,54 +147,115 @@ function createToolRouter(options) {
228
147
  effectiveArgs = preResult.modifiedArgs;
229
148
  }
230
149
  }
231
- const tool = toolMap.get(toolCall.name);
150
+ if (toolHooks?.onPreToolUse) {
151
+ const preResult = await toolHooks.onPreToolUse({
152
+ args: effectiveArgs,
153
+ threadId: options.threadId,
154
+ turn
155
+ });
156
+ if (preResult?.skip) {
157
+ await appendToolResult({
158
+ threadId: options.threadId,
159
+ toolCallId: toolCall.id,
160
+ toolName: toolCall.name,
161
+ content: JSON.stringify({
162
+ skipped: true,
163
+ reason: "Skipped by tool PreToolUse hook"
164
+ })
165
+ });
166
+ return null;
167
+ }
168
+ if (preResult?.modifiedArgs !== void 0) {
169
+ effectiveArgs = preResult.modifiedArgs;
170
+ }
171
+ }
232
172
  let result;
233
173
  let content;
174
+ let resultAppended = false;
234
175
  try {
235
176
  if (tool) {
177
+ const enrichedContext = {
178
+ ...handlerContext ?? {},
179
+ threadId: options.threadId,
180
+ toolCallId: toolCall.id,
181
+ toolName: toolCall.name
182
+ };
236
183
  const response = await tool.handler(
237
184
  effectiveArgs,
238
- handlerContext ?? {}
185
+ enrichedContext
239
186
  );
240
- result = response.result;
241
- content = response.content;
187
+ result = response.data;
188
+ content = response.toolResponse;
189
+ resultAppended = response.resultAppended === true;
242
190
  } else {
243
191
  result = { error: `Unknown tool: ${toolCall.name}` };
244
192
  content = JSON.stringify(result, null, 2);
245
193
  }
246
194
  } catch (error) {
247
- if (options.hooks?.onPostToolUseFailure) {
195
+ const err = error instanceof Error ? error : new Error(String(error));
196
+ let recovered = false;
197
+ if (toolHooks?.onPostToolUseFailure) {
198
+ const failureResult = await toolHooks.onPostToolUseFailure({
199
+ args: effectiveArgs,
200
+ error: err,
201
+ threadId: options.threadId,
202
+ turn
203
+ });
204
+ if (failureResult?.fallbackContent !== void 0) {
205
+ content = failureResult.fallbackContent;
206
+ result = { error: String(error), recovered: true };
207
+ recovered = true;
208
+ } else if (failureResult?.suppress) {
209
+ content = JSON.stringify({ error: String(error), suppressed: true });
210
+ result = { error: String(error), suppressed: true };
211
+ recovered = true;
212
+ }
213
+ }
214
+ if (!recovered && options.hooks?.onPostToolUseFailure) {
248
215
  const failureResult = await options.hooks.onPostToolUseFailure({
249
216
  toolCall,
250
- error: error instanceof Error ? error : new Error(String(error)),
217
+ error: err,
251
218
  threadId: options.threadId,
252
219
  turn
253
220
  });
254
221
  if (failureResult?.fallbackContent !== void 0) {
255
222
  content = failureResult.fallbackContent;
256
223
  result = { error: String(error), recovered: true };
224
+ recovered = true;
257
225
  } else if (failureResult?.suppress) {
258
226
  content = JSON.stringify({ error: String(error), suppressed: true });
259
227
  result = { error: String(error), suppressed: true };
260
- } else {
261
- throw error;
228
+ recovered = true;
262
229
  }
263
- } else {
230
+ }
231
+ if (!recovered) {
264
232
  throw error;
265
233
  }
266
234
  }
267
- await appendToolResult({
268
- threadId: options.threadId,
269
- toolCallId: toolCall.id,
270
- content
271
- });
235
+ if (!resultAppended) {
236
+ await appendToolResult({
237
+ threadId: options.threadId,
238
+ toolCallId: toolCall.id,
239
+ toolName: toolCall.name,
240
+ content
241
+ });
242
+ }
272
243
  const toolResult = {
273
244
  toolCallId: toolCall.id,
274
245
  name: toolCall.name,
275
- result
246
+ data: result
276
247
  };
248
+ const durationMs = Date.now() - startTime;
249
+ if (toolHooks?.onPostToolUse) {
250
+ await toolHooks.onPostToolUse({
251
+ args: effectiveArgs,
252
+ result,
253
+ threadId: options.threadId,
254
+ turn,
255
+ durationMs
256
+ });
257
+ }
277
258
  if (options.hooks?.onPostToolUse) {
278
- const durationMs = Date.now() - startTime;
279
259
  await options.hooks.onPostToolUse({
280
260
  toolCall,
281
261
  result: toolResult,
@@ -289,11 +269,11 @@ function createToolRouter(options) {
289
269
  return {
290
270
  // --- Methods from registry ---
291
271
  hasTools() {
292
- return toolMap.size > 0;
272
+ return Array.from(toolMap.values()).some(isEnabled);
293
273
  },
294
274
  parseToolCall(toolCall) {
295
275
  const tool = toolMap.get(toolCall.name);
296
- if (!tool) {
276
+ if (!tool || !isEnabled(tool)) {
297
277
  throw new Error(`Tool ${toolCall.name} not found`);
298
278
  }
299
279
  const parsedArgs = tool.schema.parse(toolCall.args);
@@ -304,13 +284,14 @@ function createToolRouter(options) {
304
284
  };
305
285
  },
306
286
  hasTool(name) {
307
- return toolMap.has(name);
287
+ const tool = toolMap.get(name);
288
+ return tool !== void 0 && isEnabled(tool);
308
289
  },
309
290
  getToolNames() {
310
- return Array.from(toolMap.keys());
291
+ return Array.from(toolMap.entries()).filter(([, tool]) => isEnabled(tool)).map(([name]) => name);
311
292
  },
312
293
  getToolDefinitions() {
313
- return Array.from(toolMap).map(([name, tool]) => ({
294
+ return Array.from(toolMap).filter(([, tool]) => isEnabled(tool)).map(([name, tool]) => ({
314
295
  name,
315
296
  description: tool.description,
316
297
  schema: tool.schema,
@@ -349,19 +330,28 @@ function createToolRouter(options) {
349
330
  }
350
331
  const handlerContext = context?.handlerContext ?? {};
351
332
  const processOne = async (toolCall) => {
333
+ const enrichedContext = {
334
+ ...handlerContext ?? {},
335
+ threadId: options.threadId,
336
+ toolCallId: toolCall.id,
337
+ toolName: toolCall.name
338
+ };
352
339
  const response = await handler(
353
340
  toolCall.args,
354
- handlerContext
341
+ enrichedContext
355
342
  );
356
- await appendToolResult({
357
- threadId: options.threadId,
358
- toolCallId: toolCall.id,
359
- content: response.content
360
- });
343
+ if (!response.resultAppended) {
344
+ await appendToolResult({
345
+ threadId: options.threadId,
346
+ toolCallId: toolCall.id,
347
+ toolName: toolCall.name,
348
+ content: response.toolResponse
349
+ });
350
+ }
361
351
  return {
362
352
  toolCallId: toolCall.id,
363
353
  name: toolCall.name,
364
- result: response.result
354
+ data: response.data
365
355
  };
366
356
  };
367
357
  if (options.parallel) {
@@ -387,56 +377,50 @@ function createToolRouter(options) {
387
377
  }
388
378
  };
389
379
  }
380
+ function withAutoAppend(threadHandler, handler) {
381
+ return async (args, context) => {
382
+ const response = await handler(args, context);
383
+ const threadId = context.threadId;
384
+ const toolCallId = context.toolCallId;
385
+ const toolName = context.toolName;
386
+ await threadHandler({
387
+ threadId,
388
+ toolCallId,
389
+ toolName,
390
+ content: response.toolResponse
391
+ });
392
+ return { toolResponse: "", data: response.data, resultAppended: true };
393
+ };
394
+ }
395
+ function defineTool(tool) {
396
+ return tool;
397
+ }
398
+ function defineSubagent(config) {
399
+ return config;
400
+ }
390
401
  function hasNoOtherToolCalls(toolCalls, excludeName) {
391
402
  return toolCalls.filter((tc) => tc.name !== excludeName).length === 0;
392
403
  }
393
404
 
394
405
  // src/lib/session.ts
395
- async function resolvePrompt(prompt) {
396
- if (typeof prompt === "function") {
397
- return prompt();
398
- }
399
- return prompt;
400
- }
401
406
  var createSession = async ({
402
407
  threadId,
403
408
  agentName,
404
409
  maxTurns = 50,
405
410
  metadata = {},
406
411
  runAgent,
407
- baseSystemPrompt,
408
- instructionsPrompt,
412
+ threadOps,
409
413
  buildContextMessage,
410
- buildFileTree = async () => "",
411
414
  subagents,
412
415
  tools = {},
413
416
  processToolsInParallel = true,
414
- buildInTools = {},
415
417
  hooks = {}
416
418
  }) => {
417
- const {
418
- initializeThread,
419
- appendHumanMessage,
420
- parseToolCalls,
421
- appendToolResult,
422
- appendSystemMessage
423
- } = workflow.proxyActivities({
424
- startToCloseTimeout: "30m",
425
- retry: {
426
- maximumAttempts: 6,
427
- initialInterval: "5s",
428
- maximumInterval: "15m",
429
- backoffCoefficient: 4
430
- },
431
- heartbeatTimeout: "5m"
432
- });
433
- const fileTree = await buildFileTree();
434
419
  const toolRouter = createToolRouter({
435
420
  tools,
421
+ appendToolResult: threadOps.appendToolResult,
436
422
  threadId,
437
423
  hooks,
438
- buildInTools,
439
- fileTree,
440
424
  subagents,
441
425
  parallel: processToolsInParallel
442
426
  });
@@ -461,15 +445,8 @@ var createSession = async ({
461
445
  });
462
446
  }
463
447
  stateManager.setTools(toolRouter.getToolDefinitions());
464
- await initializeThread(threadId);
465
- await appendSystemMessage(
466
- threadId,
467
- [
468
- await resolvePrompt(baseSystemPrompt),
469
- await resolvePrompt(instructionsPrompt)
470
- ].join("\n")
471
- );
472
- await appendHumanMessage(threadId, await buildContextMessage());
448
+ await threadOps.initializeThread(threadId);
449
+ await threadOps.appendHumanMessage(threadId, await buildContextMessage());
473
450
  let exitReason = "completed";
474
451
  try {
475
452
  while (stateManager.isRunning() && !stateManager.isTerminal() && stateManager.getTurns() < maxTurns) {
@@ -490,24 +467,25 @@ var createSession = async ({
490
467
  exitReason = "completed";
491
468
  return message;
492
469
  }
493
- const rawToolCalls = await parseToolCalls(message);
494
- const parsedToolCalls = rawToolCalls.filter((tc) => tc.name !== "Task").map((tc) => toolRouter.parseToolCall(tc));
495
- const taskToolCalls = subagents && subagents.length > 0 ? rawToolCalls.filter((tc) => tc.name === "Task").map((tc) => {
496
- const parsedArgs = createTaskTool(subagents).schema.parse(
497
- tc.args
498
- );
499
- return {
500
- id: tc.id ?? "",
501
- name: tc.name,
502
- args: parsedArgs
503
- };
504
- }) : [];
505
- await toolRouter.processToolCalls(
506
- [...parsedToolCalls, ...taskToolCalls],
507
- {
508
- turn: currentTurn
470
+ const rawToolCalls = await threadOps.parseToolCalls(message);
471
+ const parsedToolCalls = [];
472
+ for (const tc of rawToolCalls) {
473
+ try {
474
+ parsedToolCalls.push(toolRouter.parseToolCall(tc));
475
+ } catch (error) {
476
+ await threadOps.appendToolResult({
477
+ threadId,
478
+ toolCallId: tc.id ?? "",
479
+ toolName: tc.name,
480
+ content: JSON.stringify({
481
+ error: `Invalid tool call for "${tc.name}": ${error instanceof Error ? error.message : String(error)}`
482
+ })
483
+ });
509
484
  }
510
- );
485
+ }
486
+ await toolRouter.processToolCalls(parsedToolCalls, {
487
+ turn: currentTurn
488
+ });
511
489
  if (stateManager.getStatus() === "WAITING_FOR_INPUT") {
512
490
  exitReason = "waiting_for_input";
513
491
  break;
@@ -526,13 +504,31 @@ var createSession = async ({
526
504
  }
527
505
  };
528
506
  };
507
+ function proxyDefaultThreadOps(options) {
508
+ const activities = workflow.proxyActivities(
509
+ options ?? {
510
+ startToCloseTimeout: "30m",
511
+ retry: {
512
+ maximumAttempts: 6,
513
+ initialInterval: "5s",
514
+ maximumInterval: "15m",
515
+ backoffCoefficient: 4
516
+ },
517
+ heartbeatTimeout: "5m"
518
+ }
519
+ );
520
+ return {
521
+ initializeThread: activities.initializeThread,
522
+ appendHumanMessage: activities.appendHumanMessage,
523
+ appendToolResult: activities.appendToolResult,
524
+ parseToolCalls: activities.parseToolCalls
525
+ };
526
+ }
529
527
 
530
528
  // src/lib/types.ts
531
529
  function isTerminalStatus(status) {
532
530
  return status === "COMPLETED" || status === "FAILED" || status === "CANCELLED";
533
531
  }
534
-
535
- // src/lib/state-manager.ts
536
532
  var getStateQuery = workflow.defineQuery("getState");
537
533
  function createAgentStateManager(initialState) {
538
534
  let status = initialState?.status ?? "RUNNING";
@@ -627,7 +623,13 @@ function createAgentStateManager(initialState) {
627
623
  version++;
628
624
  },
629
625
  setTools(newTools) {
630
- tools = newTools;
626
+ tools = newTools.map((tool) => ({
627
+ name: tool.name,
628
+ description: tool.description,
629
+ schema: z3.z.toJSONSchema(tool.schema),
630
+ strict: tool.strict,
631
+ max_uses: tool.max_uses
632
+ }));
631
633
  },
632
634
  deleteTask(id) {
633
635
  const deleted = tasks.delete(id);
@@ -658,18 +660,18 @@ Usage notes:
658
660
  * Use multiSelect: true to allow multiple answers to be selected for a question
659
661
  * If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
660
662
  `,
661
- schema: z4__default.default.object({
662
- questions: z4__default.default.array(
663
- z4__default.default.object({
664
- question: z4__default.default.string().describe("The full question text to display"),
665
- header: z4__default.default.string().describe("Short label for the question (max 12 characters)"),
666
- options: z4__default.default.array(
667
- z4__default.default.object({
668
- label: z4__default.default.string(),
669
- description: z4__default.default.string()
663
+ schema: z3__default.default.object({
664
+ questions: z3__default.default.array(
665
+ z3__default.default.object({
666
+ question: z3__default.default.string().describe("The full question text to display"),
667
+ header: z3__default.default.string().describe("Short label for the question (max 12 characters)"),
668
+ options: z3__default.default.array(
669
+ z3__default.default.object({
670
+ label: z3__default.default.string(),
671
+ description: z3__default.default.string()
670
672
  })
671
673
  ).min(0).max(4).describe("Array of 0-4 choices, each with label and description"),
672
- multiSelect: z4__default.default.boolean().describe("If true, users can select multiple options")
674
+ multiSelect: z3__default.default.boolean().describe("If true, users can select multiple options")
673
675
  })
674
676
  )
675
677
  }),
@@ -689,9 +691,9 @@ Examples:
689
691
  - "**/*.test.ts" - Find all test files recursively
690
692
  - "src/**/*.ts" - Find all TypeScript files in src directory
691
693
  `,
692
- schema: z4.z.object({
693
- pattern: z4.z.string().describe("Glob pattern to match files against"),
694
- root: z4.z.string().optional().describe("Optional root directory to search from")
694
+ schema: z3.z.object({
695
+ pattern: z3.z.string().describe("Glob pattern to match files against"),
696
+ root: z3.z.string().optional().describe("Optional root directory to search from")
695
697
  }),
696
698
  strict: true
697
699
  };
@@ -709,13 +711,13 @@ Examples:
709
711
  - Search for function definitions with "function.*handleClick"
710
712
  - Search case-insensitively with ignoreCase: true
711
713
  `,
712
- schema: z4.z.object({
713
- pattern: z4.z.string().describe("Regex pattern to search for in file contents"),
714
- ignoreCase: z4.z.boolean().optional().describe("Case-insensitive search (default: false)"),
715
- maxMatches: z4.z.number().optional().describe("Maximum number of matches to return (default: 50)"),
716
- includePatterns: z4.z.array(z4.z.string()).optional().describe("Glob patterns to include (e.g., ['*.ts', '*.js'])"),
717
- excludePatterns: z4.z.array(z4.z.string()).optional().describe("Glob patterns to exclude (e.g., ['*.test.ts'])"),
718
- contextLines: z4.z.number().optional().describe("Number of context lines to show around matches")
714
+ schema: z3.z.object({
715
+ pattern: z3.z.string().describe("Regex pattern to search for in file contents"),
716
+ ignoreCase: z3.z.boolean().optional().describe("Case-insensitive search (default: false)"),
717
+ maxMatches: z3.z.number().optional().describe("Maximum number of matches to return (default: 50)"),
718
+ includePatterns: z3.z.array(z3.z.string()).optional().describe("Glob patterns to include (e.g., ['*.ts', '*.js'])"),
719
+ excludePatterns: z3.z.array(z3.z.string()).optional().describe("Glob patterns to exclude (e.g., ['*.test.ts'])"),
720
+ contextLines: z3.z.number().optional().describe("Number of context lines to show around matches")
719
721
  }),
720
722
  strict: true
721
723
  };
@@ -733,12 +735,12 @@ The tool returns the file content in an appropriate format:
733
735
  - Images: Base64-encoded image data
734
736
  - PDFs: Extracted text content
735
737
  `,
736
- schema: z4.z.object({
737
- path: z4.z.string().describe("Virtual path to the file to read"),
738
- offset: z4.z.number().optional().describe(
738
+ schema: z3.z.object({
739
+ path: z3.z.string().describe("Virtual path to the file to read"),
740
+ offset: z3.z.number().optional().describe(
739
741
  "Line number to start reading from (1-indexed, for text files)"
740
742
  ),
741
- limit: z4.z.number().optional().describe("Maximum number of lines to read (for text files)")
743
+ limit: z3.z.number().optional().describe("Maximum number of lines to read (for text files)")
742
744
  }),
743
745
  strict: true
744
746
  };
@@ -747,7 +749,7 @@ var writeTool = {
747
749
  description: `Create or overwrite a file with new content.
748
750
 
749
751
  Usage:
750
- - Provide the absolute virtual path to the file
752
+ - Provide the absolute path to the file
751
753
  - The file will be created if it doesn't exist
752
754
  - If the file exists, it will be completely overwritten
753
755
 
@@ -756,9 +758,9 @@ IMPORTANT:
756
758
  - This is an atomic write operation - the entire file is replaced
757
759
  - Path must be absolute (e.g., "/docs/readme.md", not "docs/readme.md")
758
760
  `,
759
- schema: z4.z.object({
760
- file_path: z4.z.string().describe("The absolute virtual path to the file to write"),
761
- content: z4.z.string().describe("The content to write to the file")
761
+ schema: z3.z.object({
762
+ file_path: z3.z.string().describe("The absolute path to the file to write"),
763
+ content: z3.z.string().describe("The content to write to the file")
762
764
  }),
763
765
  strict: true
764
766
  };
@@ -778,27 +780,76 @@ IMPORTANT:
778
780
  - The operation fails if old_string is not found
779
781
  - old_string and new_string must be different
780
782
  `,
781
- schema: z4.z.object({
782
- file_path: z4.z.string().describe("The absolute virtual path to the file to modify"),
783
- old_string: z4.z.string().describe("The exact text to replace"),
784
- new_string: z4.z.string().describe(
783
+ schema: z3.z.object({
784
+ file_path: z3.z.string().describe("The absolute virtual path to the file to modify"),
785
+ old_string: z3.z.string().describe("The exact text to replace"),
786
+ new_string: z3.z.string().describe(
785
787
  "The text to replace it with (must be different from old_string)"
786
788
  ),
787
- replace_all: z4.z.boolean().optional().describe(
789
+ replace_all: z3.z.boolean().optional().describe(
788
790
  "If true, replace all occurrences of old_string (default: false)"
789
791
  )
790
792
  }),
791
793
  strict: true
792
794
  };
793
-
794
- // src/tools/task-create/handler.ts
795
- function createTaskCreateHandler({
796
- stateManager,
797
- idGenerator
798
- }) {
795
+ var taskCreateTool = {
796
+ name: "TaskCreate",
797
+ 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.
798
+ It also helps the user understand the progress of the task and overall progress of their requests.
799
+
800
+ ## When to Use This Tool
801
+
802
+ Use this tool proactively in these scenarios:
803
+
804
+ - Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
805
+ - Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
806
+ - User explicitly requests todo list - When the user directly asks you to use the todo list
807
+ - User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
808
+ - After receiving new instructions - Immediately capture user requirements as tasks
809
+ - When you start working on a task - Mark it as in_progress BEFORE beginning work
810
+ - After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
811
+
812
+ ## When NOT to Use This Tool
813
+
814
+ Skip using this tool when:
815
+ - There is only a single, straightforward task
816
+ - The task is trivial and tracking it provides no organizational benefit
817
+ - The task can be completed in less than 3 trivial steps
818
+ - The task is purely conversational or informational
819
+
820
+ 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.
821
+
822
+ ## Task Fields
823
+
824
+ - **subject**: A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")
825
+ - **description**: Detailed description of what needs to be done, including context and acceptance criteria
826
+ - **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.
827
+
828
+ **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\`.
829
+
830
+ ## Tips
831
+
832
+ - Create tasks with clear, specific subjects that describe the outcome
833
+ - Include enough detail in the description for another agent to understand and complete the task
834
+ - After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
835
+ - Check TaskList first to avoid creating duplicate tasks`,
836
+ schema: z3__default.default.object({
837
+ subject: z3__default.default.string().describe(
838
+ 'A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")'
839
+ ),
840
+ description: z3__default.default.string().describe(
841
+ "Detailed description of what needs to be done, including context and acceptance criteria"
842
+ ),
843
+ activeForm: z3__default.default.string().describe(
844
+ '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.'
845
+ ),
846
+ metadata: z3__default.default.record(z3__default.default.string(), z3__default.default.string()).describe("Arbitrary key-value pairs for tracking")
847
+ })
848
+ };
849
+ function createTaskCreateHandler(stateManager) {
799
850
  return (args) => {
800
851
  const task = {
801
- id: idGenerator(),
852
+ id: workflow.uuid4(),
802
853
  subject: args.subject,
803
854
  description: args.description,
804
855
  activeForm: args.activeForm,
@@ -809,16 +860,16 @@ function createTaskCreateHandler({
809
860
  };
810
861
  stateManager.setTask(task);
811
862
  return {
812
- content: JSON.stringify(task, null, 2),
813
- result: task
863
+ toolResponse: JSON.stringify(task, null, 2),
864
+ data: task
814
865
  };
815
866
  };
816
867
  }
817
868
  var taskGetTool = {
818
869
  name: "TaskGet",
819
870
  description: `Retrieve full task details including dependencies.`,
820
- schema: z4__default.default.object({
821
- taskId: z4__default.default.string().describe("The ID of the task to get")
871
+ schema: z3__default.default.object({
872
+ taskId: z3__default.default.string().describe("The ID of the task to get")
822
873
  })
823
874
  };
824
875
 
@@ -828,40 +879,40 @@ function createTaskGetHandler(stateManager) {
828
879
  const task = stateManager.getTask(args.taskId) ?? null;
829
880
  if (!task) {
830
881
  return {
831
- content: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
832
- result: null
882
+ toolResponse: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
883
+ data: null
833
884
  };
834
885
  }
835
886
  return {
836
- content: JSON.stringify(task, null, 2),
837
- result: task
887
+ toolResponse: JSON.stringify(task, null, 2),
888
+ data: task
838
889
  };
839
890
  };
840
891
  }
841
892
  var taskListTool = {
842
893
  name: "TaskList",
843
894
  description: `List all tasks with current state.`,
844
- schema: z4__default.default.object({})
895
+ schema: z3__default.default.object({})
845
896
  };
846
897
 
847
898
  // src/tools/task-list/handler.ts
848
899
  function createTaskListHandler(stateManager) {
849
- return (_args) => {
900
+ return () => {
850
901
  const taskList = stateManager.getTasks();
851
902
  return {
852
- content: JSON.stringify(taskList, null, 2),
853
- result: taskList
903
+ toolResponse: JSON.stringify(taskList, null, 2),
904
+ data: taskList
854
905
  };
855
906
  };
856
907
  }
857
908
  var taskUpdateTool = {
858
909
  name: "TaskUpdate",
859
910
  description: `Update status, add blockers, modify details.`,
860
- schema: z4__default.default.object({
861
- taskId: z4__default.default.string().describe("The ID of the task to get"),
862
- status: z4__default.default.enum(["pending", "in_progress", "completed"]).describe("The status of the task"),
863
- addBlockedBy: z4__default.default.array(z4__default.default.string()).describe("The IDs of the tasks that are blocking this task"),
864
- addBlocks: z4__default.default.array(z4__default.default.string()).describe("The IDs of the tasks that this task is blocking")
911
+ schema: z3__default.default.object({
912
+ taskId: z3__default.default.string().describe("The ID of the task to get"),
913
+ status: z3__default.default.enum(["pending", "in_progress", "completed"]).describe("The status of the task"),
914
+ addBlockedBy: z3__default.default.array(z3__default.default.string()).describe("The IDs of the tasks that are blocking this task"),
915
+ addBlocks: z3__default.default.array(z3__default.default.string()).describe("The IDs of the tasks that this task is blocking")
865
916
  })
866
917
  };
867
918
 
@@ -871,8 +922,8 @@ function createTaskUpdateHandler(stateManager) {
871
922
  const task = stateManager.getTask(args.taskId);
872
923
  if (!task) {
873
924
  return {
874
- content: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
875
- result: null
925
+ toolResponse: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
926
+ data: null
876
927
  };
877
928
  }
878
929
  if (args.status) {
@@ -904,11 +955,38 @@ function createTaskUpdateHandler(stateManager) {
904
955
  }
905
956
  stateManager.setTask(task);
906
957
  return {
907
- content: JSON.stringify(task, null, 2),
908
- result: task
958
+ toolResponse: JSON.stringify(task, null, 2),
959
+ data: task
909
960
  };
910
961
  };
911
962
  }
963
+ var createBashToolDescription = ({
964
+ fileTree
965
+ }) => `Execute shell commands in a bash environment.
966
+
967
+ Use this tool to:
968
+ - Run shell commands (ls, cat, grep, find, etc.)
969
+ - Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
970
+ - Inspect files and directories
971
+
972
+ Current file tree:
973
+ ${fileTree}`;
974
+ var bashTool = {
975
+ name: "Bash",
976
+ description: `Execute shell commands in a sandboxed bash environment.
977
+
978
+ Use this tool to:
979
+ - Run shell commands (ls, cat, grep, find, etc.)
980
+ - Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
981
+ - Inspect files and directories
982
+ `,
983
+ schema: z3__default.default.object({
984
+ command: z3__default.default.string().describe(
985
+ "The bash command to execute. Can include pipes (|), redirects (>, >>), logical operators (&&, ||), and shell features like command substitution $(...)."
986
+ )
987
+ }),
988
+ strict: true
989
+ };
912
990
 
913
991
  // node_modules/uuid/dist/esm-node/stringify.js
914
992
  var byteToHex = [];
@@ -957,25 +1035,33 @@ function getThreadKey(threadId, key) {
957
1035
  return `thread:${threadId}:${key}`;
958
1036
  }
959
1037
  function createThreadManager(config) {
960
- const { redis, threadId, key = "messages" } = config;
1038
+ const {
1039
+ redis,
1040
+ threadId,
1041
+ key = "messages",
1042
+ serialize = (m) => JSON.stringify(m),
1043
+ deserialize = (raw) => JSON.parse(raw)
1044
+ } = config;
961
1045
  const redisKey = getThreadKey(threadId, key);
962
- return {
1046
+ const base = {
963
1047
  async initialize() {
964
1048
  await redis.del(redisKey);
965
1049
  },
966
1050
  async load() {
967
1051
  const data = await redis.lrange(redisKey, 0, -1);
968
- return data.map((item) => JSON.parse(item));
1052
+ return data.map(deserialize);
969
1053
  },
970
1054
  async append(messages) {
971
1055
  if (messages.length > 0) {
972
- await redis.rpush(redisKey, ...messages.map((m) => JSON.stringify(m)));
1056
+ await redis.rpush(redisKey, ...messages.map(serialize));
973
1057
  await redis.expire(redisKey, THREAD_TTL_SECONDS);
974
1058
  }
975
1059
  },
976
1060
  async delete() {
977
1061
  await redis.del(redisKey);
978
- },
1062
+ }
1063
+ };
1064
+ const helpers = {
979
1065
  createHumanMessage(content) {
980
1066
  return new messages.HumanMessage({
981
1067
  id: v4_default(),
@@ -995,40 +1081,27 @@ function createThreadManager(config) {
995
1081
  },
996
1082
  createToolMessage(content, toolCallId) {
997
1083
  return new messages.ToolMessage({
998
- // Cast needed due to langchain type compatibility
999
1084
  content,
1000
1085
  tool_call_id: toolCallId
1001
1086
  }).toDict();
1002
1087
  },
1003
- createSystemMessage(content) {
1004
- return new messages.SystemMessage({
1005
- content
1006
- }).toDict();
1007
- },
1008
- async appendSystemMessage(content) {
1009
- const message = this.createSystemMessage(content);
1010
- await this.append([message]);
1011
- },
1012
1088
  async appendHumanMessage(content) {
1013
- const message = this.createHumanMessage(content);
1014
- await this.append([message]);
1089
+ const message = helpers.createHumanMessage(content);
1090
+ await base.append([message]);
1015
1091
  },
1016
1092
  async appendToolMessage(content, toolCallId) {
1017
- const message = this.createToolMessage(content, toolCallId);
1018
- await this.append([message]);
1093
+ const message = helpers.createToolMessage(content, toolCallId);
1094
+ await base.append([message]);
1019
1095
  },
1020
1096
  async appendAIMessage(content) {
1021
- const message = this.createAIMessage(content);
1022
- await this.append([message]);
1097
+ const message = helpers.createAIMessage(content);
1098
+ await base.append([message]);
1023
1099
  }
1024
1100
  };
1101
+ return Object.assign(base, helpers);
1025
1102
  }
1026
1103
  function createSharedActivities(redis) {
1027
1104
  return {
1028
- async appendSystemMessage(threadId, content) {
1029
- const thread = createThreadManager({ redis, threadId });
1030
- await thread.appendSystemMessage(content);
1031
- },
1032
1105
  async appendToolResult(config) {
1033
1106
  const { threadId, toolCallId, content } = config;
1034
1107
  const thread = createThreadManager({ redis, threadId });
@@ -1101,7 +1174,7 @@ async function invokeModel({
1101
1174
  }
1102
1175
  };
1103
1176
  }
1104
- var handleAskUserQuestionToolResult = async (args) => {
1177
+ var createAskUserQuestionHandler = () => async (args) => {
1105
1178
  const messages$1 = args.questions.map(
1106
1179
  ({ question, header, options, multiSelect }) => new messages.AIMessage({
1107
1180
  content: question,
@@ -1112,101 +1185,81 @@ var handleAskUserQuestionToolResult = async (args) => {
1112
1185
  }
1113
1186
  }).toDict()
1114
1187
  );
1115
- return { content: "Question submitted", result: { chatMessages: messages$1 } };
1188
+ return { toolResponse: "Question submitted", data: { chatMessages: messages$1 } };
1116
1189
  };
1117
- async function globHandler(_args, fs) {
1118
- new justBash.Bash({ fs });
1119
- return Promise.resolve({
1120
- content: "Hello, world!",
1121
- result: { files: [] }
1122
- });
1190
+ function createGlobHandler(fs) {
1191
+ return async (_args) => {
1192
+ new justBash.Bash({ fs });
1193
+ return {
1194
+ toolResponse: "Hello, world!",
1195
+ data: { files: [] }
1196
+ };
1197
+ };
1123
1198
  }
1124
1199
 
1125
1200
  // src/tools/edit/handler.ts
1126
1201
  function escapeRegExp(str) {
1127
1202
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1128
1203
  }
1129
- async function editHandler(args, fs) {
1130
- const { file_path, old_string, new_string, replace_all = false } = args;
1131
- if (old_string === new_string) {
1132
- return {
1133
- content: `Error: old_string and new_string must be different.`,
1134
- result: {
1135
- path: file_path,
1136
- success: false,
1137
- replacements: 0
1138
- }
1139
- };
1140
- }
1141
- try {
1142
- const exists = await fs.exists(file_path);
1143
- if (!exists) {
1204
+ function createEditHandler(fs) {
1205
+ return async (args) => {
1206
+ const { file_path, old_string, new_string, replace_all = false } = args;
1207
+ if (old_string === new_string) {
1144
1208
  return {
1145
- content: `Error: File "${file_path}" does not exist.`,
1146
- result: {
1147
- path: file_path,
1148
- success: false,
1149
- replacements: 0
1150
- }
1209
+ toolResponse: `Error: old_string and new_string must be different.`,
1210
+ data: { path: file_path, success: false, replacements: 0 }
1151
1211
  };
1152
1212
  }
1153
- const content = await fs.readFile(file_path);
1154
- if (!content.includes(old_string)) {
1213
+ try {
1214
+ const exists = await fs.exists(file_path);
1215
+ if (!exists) {
1216
+ return {
1217
+ toolResponse: `Error: File "${file_path}" does not exist.`,
1218
+ data: { path: file_path, success: false, replacements: 0 }
1219
+ };
1220
+ }
1221
+ const content = await fs.readFile(file_path);
1222
+ if (!content.includes(old_string)) {
1223
+ return {
1224
+ toolResponse: `Error: Could not find the specified text in "${file_path}". Make sure old_string matches exactly (whitespace-sensitive).`,
1225
+ data: { path: file_path, success: false, replacements: 0 }
1226
+ };
1227
+ }
1228
+ const escapedOldString = escapeRegExp(old_string);
1229
+ const globalRegex = new RegExp(escapedOldString, "g");
1230
+ const occurrences = (content.match(globalRegex) || []).length;
1231
+ if (!replace_all && occurrences > 1) {
1232
+ return {
1233
+ toolResponse: `Error: old_string appears ${occurrences} times in "${file_path}". Either provide more context to make it unique, or use replace_all: true.`,
1234
+ data: { path: file_path, success: false, replacements: 0 }
1235
+ };
1236
+ }
1237
+ let newContent;
1238
+ let replacements;
1239
+ if (replace_all) {
1240
+ newContent = content.split(old_string).join(new_string);
1241
+ replacements = occurrences;
1242
+ } else {
1243
+ const index = content.indexOf(old_string);
1244
+ newContent = content.slice(0, index) + new_string + content.slice(index + old_string.length);
1245
+ replacements = 1;
1246
+ }
1247
+ await fs.writeFile(file_path, newContent);
1248
+ const summary = replace_all ? `Replaced ${replacements} occurrence(s)` : `Replaced 1 occurrence`;
1155
1249
  return {
1156
- content: `Error: Could not find the specified text in "${file_path}". Make sure old_string matches exactly (whitespace-sensitive).`,
1157
- result: {
1158
- path: file_path,
1159
- success: false,
1160
- replacements: 0
1161
- }
1250
+ toolResponse: `${summary} in ${file_path}`,
1251
+ data: { path: file_path, success: true, replacements }
1162
1252
  };
1163
- }
1164
- const escapedOldString = escapeRegExp(old_string);
1165
- const globalRegex = new RegExp(escapedOldString, "g");
1166
- const occurrences = (content.match(globalRegex) || []).length;
1167
- if (!replace_all && occurrences > 1) {
1253
+ } catch (error) {
1254
+ const message = error instanceof Error ? error.message : "Unknown error";
1168
1255
  return {
1169
- content: `Error: old_string appears ${occurrences} times in "${file_path}". Either provide more context to make it unique, or use replace_all: true.`,
1170
- result: {
1171
- path: file_path,
1172
- success: false,
1173
- replacements: 0
1174
- }
1256
+ toolResponse: `Error editing file "${file_path}": ${message}`,
1257
+ data: { path: file_path, success: false, replacements: 0 }
1175
1258
  };
1176
1259
  }
1177
- let newContent;
1178
- let replacements;
1179
- if (replace_all) {
1180
- newContent = content.split(old_string).join(new_string);
1181
- replacements = occurrences;
1182
- } else {
1183
- const index = content.indexOf(old_string);
1184
- newContent = content.slice(0, index) + new_string + content.slice(index + old_string.length);
1185
- replacements = 1;
1186
- }
1187
- await fs.writeFile(file_path, newContent);
1188
- const summary = replace_all ? `Replaced ${replacements} occurrence(s)` : `Replaced 1 occurrence`;
1189
- return {
1190
- content: `${summary} in ${file_path}`,
1191
- result: {
1192
- path: file_path,
1193
- success: true,
1194
- replacements
1195
- }
1196
- };
1197
- } catch (error) {
1198
- const message = error instanceof Error ? error.message : "Unknown error";
1199
- return {
1200
- content: `Error editing file "${file_path}": ${message}`,
1201
- result: {
1202
- path: file_path,
1203
- success: false,
1204
- replacements: 0
1205
- }
1206
- };
1207
- }
1260
+ };
1208
1261
  }
1209
- var handleBashTool = (bashOptions) => async (args, _context) => {
1262
+ var createBashHandler = (bashOptions) => async (args, _context) => {
1210
1263
  const { command } = args;
1211
1264
  const mergedOptions = {
1212
1265
  ...bashOptions,
@@ -1221,20 +1274,20 @@ var handleBashTool = (bashOptions) => async (args, _context) => {
1221
1274
  const { exitCode, stderr, stdout } = await bash.exec(command);
1222
1275
  const bashExecOut = { exitCode, stderr, stdout };
1223
1276
  return {
1224
- content: `Exit code: ${exitCode}
1277
+ toolResponse: `Exit code: ${exitCode}
1225
1278
 
1226
1279
  stdout:
1227
1280
  ${stdout}
1228
1281
 
1229
1282
  stderr:
1230
1283
  ${stderr}`,
1231
- result: bashExecOut
1284
+ data: bashExecOut
1232
1285
  };
1233
1286
  } catch (error) {
1234
1287
  const err = error instanceof Error ? error : new Error("Unknown error");
1235
1288
  return {
1236
- content: `Error executing bash command: ${err.message}`,
1237
- result: null
1289
+ toolResponse: `Error executing bash command: ${err.message}`,
1290
+ data: null
1238
1291
  };
1239
1292
  }
1240
1293
  };
@@ -1308,6 +1361,11 @@ exports.ZeitlichPlugin = ZeitlichPlugin;
1308
1361
  exports.askUserQuestionTool = askUserQuestionTool;
1309
1362
  exports.bashTool = bashTool;
1310
1363
  exports.createAgentStateManager = createAgentStateManager;
1364
+ exports.createAskUserQuestionHandler = createAskUserQuestionHandler;
1365
+ exports.createBashHandler = createBashHandler;
1366
+ exports.createBashToolDescription = createBashToolDescription;
1367
+ exports.createEditHandler = createEditHandler;
1368
+ exports.createGlobHandler = createGlobHandler;
1311
1369
  exports.createSession = createSession;
1312
1370
  exports.createSharedActivities = createSharedActivities;
1313
1371
  exports.createTaskCreateHandler = createTaskCreateHandler;
@@ -1315,23 +1373,25 @@ exports.createTaskGetHandler = createTaskGetHandler;
1315
1373
  exports.createTaskListHandler = createTaskListHandler;
1316
1374
  exports.createTaskTool = createTaskTool;
1317
1375
  exports.createTaskUpdateHandler = createTaskUpdateHandler;
1376
+ exports.createThreadManager = createThreadManager;
1318
1377
  exports.createToolRouter = createToolRouter;
1319
- exports.editHandler = editHandler;
1378
+ exports.defineSubagent = defineSubagent;
1379
+ exports.defineTool = defineTool;
1320
1380
  exports.editTool = editTool;
1321
- exports.globHandler = globHandler;
1381
+ exports.getStateQuery = getStateQuery;
1322
1382
  exports.globTool = globTool;
1323
1383
  exports.grepTool = grepTool;
1324
- exports.handleAskUserQuestionToolResult = handleAskUserQuestionToolResult;
1325
- exports.handleBashTool = handleBashTool;
1326
1384
  exports.hasNoOtherToolCalls = hasNoOtherToolCalls;
1327
1385
  exports.invokeModel = invokeModel;
1328
1386
  exports.isTerminalStatus = isTerminalStatus;
1387
+ exports.proxyDefaultThreadOps = proxyDefaultThreadOps;
1329
1388
  exports.readTool = readTool;
1330
1389
  exports.taskCreateTool = taskCreateTool;
1331
1390
  exports.taskGetTool = taskGetTool;
1332
1391
  exports.taskListTool = taskListTool;
1333
1392
  exports.taskUpdateTool = taskUpdateTool;
1334
1393
  exports.toTree = toTree;
1394
+ exports.withAutoAppend = withAutoAppend;
1335
1395
  exports.writeTool = writeTool;
1336
1396
  //# sourceMappingURL=index.cjs.map
1337
1397
  //# sourceMappingURL=index.cjs.map