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.
- package/README.md +36 -33
- package/dist/index.cjs +445 -385
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -42
- package/dist/index.d.ts +25 -42
- package/dist/index.js +415 -362
- package/dist/index.js.map +1 -1
- package/dist/{workflow-CCoHnc3B.d.cts → workflow-D-2vp4Pq.d.cts} +456 -253
- package/dist/{workflow-CCoHnc3B.d.ts → workflow-D-2vp4Pq.d.ts} +456 -253
- package/dist/workflow.cjs +339 -272
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +4 -3
- package/dist/workflow.d.ts +4 -3
- package/dist/workflow.js +315 -252
- package/dist/workflow.js.map +1 -1
- package/package.json +3 -2
- package/src/activities.ts +1 -14
- package/src/index.ts +17 -11
- package/src/lib/session.ts +69 -86
- package/src/lib/state-manager.ts +9 -2
- package/src/lib/thread-manager.ts +45 -37
- package/src/lib/tool-router.ts +338 -116
- package/src/lib/types.ts +110 -28
- package/src/tools/ask-user-question/handler.ts +6 -6
- package/src/tools/ask-user-question/tool.ts +3 -2
- package/src/tools/bash/bash.test.ts +32 -32
- package/src/tools/bash/handler.ts +9 -9
- package/src/tools/bash/tool.ts +3 -2
- package/src/tools/edit/handler.ts +78 -123
- package/src/tools/edit/tool.ts +3 -2
- package/src/tools/glob/handler.ts +17 -48
- package/src/tools/glob/tool.ts +3 -2
- package/src/tools/grep/tool.ts +3 -2
- package/src/tools/{read → read-file}/tool.ts +3 -2
- package/src/tools/task/handler.ts +19 -9
- package/src/tools/task/tool.ts +3 -10
- package/src/tools/task-create/handler.ts +11 -20
- package/src/tools/task-create/tool.ts +3 -2
- package/src/tools/task-get/handler.ts +9 -14
- package/src/tools/task-get/tool.ts +3 -2
- package/src/tools/task-list/handler.ts +7 -12
- package/src/tools/task-list/tool.ts +3 -2
- package/src/tools/task-update/handler.ts +9 -16
- package/src/tools/task-update/tool.ts +3 -2
- package/src/tools/{write → write-file}/tool.ts +5 -6
- 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
|
|
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
|
|
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:
|
|
50
|
-
subagent:
|
|
51
|
-
description:
|
|
52
|
-
prompt:
|
|
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
|
|
66
|
+
const input = {
|
|
67
|
+
prompt: args.prompt,
|
|
68
|
+
...config.context && { context: config.context }
|
|
69
|
+
};
|
|
70
|
+
const childOpts = {
|
|
67
71
|
workflowId: childWorkflowId,
|
|
68
|
-
args: [
|
|
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
|
|
77
|
+
const toolResponse = typeof validated === "string" ? validated : JSON.stringify(validated, null, 2);
|
|
73
78
|
return {
|
|
74
|
-
|
|
75
|
-
|
|
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 } =
|
|
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
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
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
|
-
|
|
185
|
+
enrichedContext
|
|
239
186
|
);
|
|
240
|
-
result = response.
|
|
241
|
-
content = response.
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
261
|
-
throw error;
|
|
228
|
+
recovered = true;
|
|
262
229
|
}
|
|
263
|
-
}
|
|
230
|
+
}
|
|
231
|
+
if (!recovered) {
|
|
264
232
|
throw error;
|
|
265
233
|
}
|
|
266
234
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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.
|
|
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
|
-
|
|
287
|
+
const tool = toolMap.get(name);
|
|
288
|
+
return tool !== void 0 && isEnabled(tool);
|
|
308
289
|
},
|
|
309
290
|
getToolNames() {
|
|
310
|
-
return Array.from(toolMap.
|
|
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
|
-
|
|
341
|
+
enrichedContext
|
|
355
342
|
);
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
tc
|
|
498
|
-
)
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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:
|
|
662
|
-
questions:
|
|
663
|
-
|
|
664
|
-
question:
|
|
665
|
-
header:
|
|
666
|
-
options:
|
|
667
|
-
|
|
668
|
-
label:
|
|
669
|
-
description:
|
|
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:
|
|
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:
|
|
693
|
-
pattern:
|
|
694
|
-
root:
|
|
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:
|
|
713
|
-
pattern:
|
|
714
|
-
ignoreCase:
|
|
715
|
-
maxMatches:
|
|
716
|
-
includePatterns:
|
|
717
|
-
excludePatterns:
|
|
718
|
-
contextLines:
|
|
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:
|
|
737
|
-
path:
|
|
738
|
-
offset:
|
|
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:
|
|
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
|
|
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:
|
|
760
|
-
file_path:
|
|
761
|
-
content:
|
|
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:
|
|
782
|
-
file_path:
|
|
783
|
-
old_string:
|
|
784
|
-
new_string:
|
|
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:
|
|
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
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
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:
|
|
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
|
-
|
|
813
|
-
|
|
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:
|
|
821
|
-
taskId:
|
|
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
|
-
|
|
832
|
-
|
|
882
|
+
toolResponse: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
|
|
883
|
+
data: null
|
|
833
884
|
};
|
|
834
885
|
}
|
|
835
886
|
return {
|
|
836
|
-
|
|
837
|
-
|
|
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:
|
|
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 (
|
|
900
|
+
return () => {
|
|
850
901
|
const taskList = stateManager.getTasks();
|
|
851
902
|
return {
|
|
852
|
-
|
|
853
|
-
|
|
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:
|
|
861
|
-
taskId:
|
|
862
|
-
status:
|
|
863
|
-
addBlockedBy:
|
|
864
|
-
addBlocks:
|
|
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
|
-
|
|
875
|
-
|
|
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
|
-
|
|
908
|
-
|
|
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 {
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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 =
|
|
1014
|
-
await
|
|
1089
|
+
const message = helpers.createHumanMessage(content);
|
|
1090
|
+
await base.append([message]);
|
|
1015
1091
|
},
|
|
1016
1092
|
async appendToolMessage(content, toolCallId) {
|
|
1017
|
-
const message =
|
|
1018
|
-
await
|
|
1093
|
+
const message = helpers.createToolMessage(content, toolCallId);
|
|
1094
|
+
await base.append([message]);
|
|
1019
1095
|
},
|
|
1020
1096
|
async appendAIMessage(content) {
|
|
1021
|
-
const message =
|
|
1022
|
-
await
|
|
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
|
|
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 {
|
|
1188
|
+
return { toolResponse: "Question submitted", data: { chatMessages: messages$1 } };
|
|
1116
1189
|
};
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
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
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
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
|
-
|
|
1146
|
-
|
|
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
|
-
|
|
1154
|
-
|
|
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
|
-
|
|
1157
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1170
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1277
|
+
toolResponse: `Exit code: ${exitCode}
|
|
1225
1278
|
|
|
1226
1279
|
stdout:
|
|
1227
1280
|
${stdout}
|
|
1228
1281
|
|
|
1229
1282
|
stderr:
|
|
1230
1283
|
${stderr}`,
|
|
1231
|
-
|
|
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
|
-
|
|
1237
|
-
|
|
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.
|
|
1378
|
+
exports.defineSubagent = defineSubagent;
|
|
1379
|
+
exports.defineTool = defineTool;
|
|
1320
1380
|
exports.editTool = editTool;
|
|
1321
|
-
exports.
|
|
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
|