zeitlich 0.2.2 → 0.2.4
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 +34 -31
- package/dist/index.cjs +330 -399
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -43
- package/dist/index.d.ts +24 -43
- package/dist/index.js +301 -373
- package/dist/index.js.map +1 -1
- package/dist/{workflow-BQf5EfNN.d.cts → workflow-PjeURKw4.d.cts} +265 -258
- package/dist/{workflow-BQf5EfNN.d.ts → workflow-PjeURKw4.d.ts} +265 -258
- package/dist/workflow.cjs +223 -281
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +2 -3
- package/dist/workflow.d.ts +2 -3
- package/dist/workflow.js +198 -258
- package/dist/workflow.js.map +1 -1
- package/package.json +3 -2
- package/src/activities.ts +0 -32
- package/src/index.ts +14 -11
- package/src/lib/model-invoker.ts +7 -1
- package/src/lib/session.ts +54 -109
- package/src/lib/thread-manager.ts +45 -37
- package/src/lib/tool-router.ts +148 -108
- package/src/lib/types.ts +35 -26
- package/src/tools/ask-user-question/handler.ts +5 -5
- package/src/tools/ask-user-question/tool.ts +3 -2
- package/src/tools/bash/bash.test.ts +12 -12
- package/src/tools/bash/handler.ts +5 -5
- 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 → subagent}/handler.ts +18 -31
- package/src/tools/{task → subagent}/tool.ts +13 -20
- package/src/tools/task-create/handler.ts +5 -11
- package/src/tools/task-create/tool.ts +3 -2
- package/src/tools/task-get/handler.ts +5 -10
- package/src/tools/task-get/tool.ts +3 -2
- package/src/tools/task-list/handler.ts +5 -10
- package/src/tools/task-list/tool.ts +3 -2
- package/src/tools/task-update/handler.ts +5 -12
- package/src/tools/task-update/tool.ts +3 -2
- package/src/tools/{write → write-file}/tool.ts +5 -6
- package/src/workflow.ts +24 -21
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,50 +10,50 @@ 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
|
|
17
|
-
var
|
|
18
|
-
function
|
|
17
|
+
var SUBAGENT_TOOL = "Subagent";
|
|
18
|
+
function buildSubagentDescription(subagents) {
|
|
19
19
|
const subagentList = subagents.map((s) => `- **${s.name}**: ${s.description}`).join("\n");
|
|
20
|
-
return `Launch a new agent to handle complex
|
|
20
|
+
return `Launch a new agent to handle complex tasks autonomously.
|
|
21
21
|
|
|
22
|
-
The ${
|
|
22
|
+
The ${SUBAGENT_TOOL} tool launches specialized agents (subprocesses) that autonomously handle complex tasks. Each agent type has specific capabilities and tools available to it.
|
|
23
23
|
|
|
24
24
|
Available agent types:
|
|
25
25
|
|
|
26
26
|
${subagentList}
|
|
27
27
|
|
|
28
|
-
When using the ${
|
|
28
|
+
When using the ${SUBAGENT_TOOL} tool, you must specify a subagent parameter to select which agent type to use.
|
|
29
29
|
|
|
30
30
|
Usage notes:
|
|
31
31
|
|
|
32
32
|
- Always include a short description (3-5 words) summarizing what the agent will do
|
|
33
33
|
- Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
|
|
34
|
-
- When the agent is done, it will return a single message back to you.
|
|
34
|
+
- When the agent is done, it will return a single message back to you.
|
|
35
35
|
- Each invocation starts fresh - provide a detailed task description with all necessary context.
|
|
36
36
|
- Provide clear, detailed prompts so the agent can work autonomously and return exactly the information you need.
|
|
37
37
|
- The agent's outputs should generally be trusted
|
|
38
38
|
- Clearly tell the agent what type of work you expect since it is not aware of the user's intent
|
|
39
39
|
- If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.`;
|
|
40
40
|
}
|
|
41
|
-
function
|
|
41
|
+
function createSubagentTool(subagents) {
|
|
42
42
|
if (subagents.length === 0) {
|
|
43
43
|
throw new Error("createTaskTool requires at least one subagent");
|
|
44
44
|
}
|
|
45
45
|
const names = subagents.map((s) => s.name);
|
|
46
46
|
return {
|
|
47
|
-
name:
|
|
48
|
-
description:
|
|
49
|
-
schema:
|
|
50
|
-
subagent:
|
|
51
|
-
description:
|
|
52
|
-
prompt:
|
|
47
|
+
name: SUBAGENT_TOOL,
|
|
48
|
+
description: buildSubagentDescription(subagents),
|
|
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
|
}
|
|
56
|
-
function
|
|
56
|
+
function createSubagentHandler(subagents) {
|
|
57
57
|
const { workflowId: parentWorkflowId, taskQueue: parentTaskQueue } = workflow.workflowInfo();
|
|
58
58
|
return async (args) => {
|
|
59
59
|
const config = subagents.find((s) => s.name === args.subagent);
|
|
@@ -72,128 +72,32 @@ function createTaskHandler(subagents) {
|
|
|
72
72
|
args: [input],
|
|
73
73
|
taskQueue: config.taskQueue ?? parentTaskQueue
|
|
74
74
|
};
|
|
75
|
-
const
|
|
76
|
-
const validated = config.resultSchema ? config.resultSchema.parse(
|
|
77
|
-
const toolResponse = typeof validated === "string" ? validated : JSON.stringify(validated, null, 2);
|
|
75
|
+
const { toolResponse, data } = typeof config.workflow === "string" ? await workflow.executeChild(config.workflow, childOpts) : await workflow.executeChild(config.workflow, childOpts);
|
|
76
|
+
const validated = config.resultSchema ? config.resultSchema.parse(data) : null;
|
|
78
77
|
return {
|
|
79
78
|
toolResponse,
|
|
80
|
-
data:
|
|
81
|
-
result: validated,
|
|
82
|
-
childWorkflowId
|
|
83
|
-
}
|
|
79
|
+
data: validated
|
|
84
80
|
};
|
|
85
81
|
};
|
|
86
82
|
}
|
|
87
|
-
var createBashToolDescription = ({
|
|
88
|
-
fileTree
|
|
89
|
-
}) => `Execute shell commands in a bash environment.
|
|
90
|
-
|
|
91
|
-
Use this tool to:
|
|
92
|
-
- Run shell commands (ls, cat, grep, find, etc.)
|
|
93
|
-
- Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
|
|
94
|
-
- Inspect files and directories
|
|
95
|
-
|
|
96
|
-
Current file tree:
|
|
97
|
-
${fileTree}`;
|
|
98
|
-
var bashTool = {
|
|
99
|
-
name: "Bash",
|
|
100
|
-
description: `Execute shell commands in a sandboxed bash environment.
|
|
101
|
-
|
|
102
|
-
Use this tool to:
|
|
103
|
-
- Run shell commands (ls, cat, grep, find, etc.)
|
|
104
|
-
- Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
|
|
105
|
-
- Inspect files and directories
|
|
106
|
-
`,
|
|
107
|
-
schema: z5__default.default.object({
|
|
108
|
-
command: z5__default.default.string().describe(
|
|
109
|
-
"The bash command to execute. Can include pipes (|), redirects (>, >>), logical operators (&&, ||), and shell features like command substitution $(...)."
|
|
110
|
-
)
|
|
111
|
-
}),
|
|
112
|
-
strict: true
|
|
113
|
-
};
|
|
114
|
-
var taskCreateTool = {
|
|
115
|
-
name: "TaskCreate",
|
|
116
|
-
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.
|
|
117
|
-
It also helps the user understand the progress of the task and overall progress of their requests.
|
|
118
|
-
|
|
119
|
-
## When to Use This Tool
|
|
120
|
-
|
|
121
|
-
Use this tool proactively in these scenarios:
|
|
122
|
-
|
|
123
|
-
- Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
|
|
124
|
-
- Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
|
|
125
|
-
- User explicitly requests todo list - When the user directly asks you to use the todo list
|
|
126
|
-
- User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
|
|
127
|
-
- After receiving new instructions - Immediately capture user requirements as tasks
|
|
128
|
-
- When you start working on a task - Mark it as in_progress BEFORE beginning work
|
|
129
|
-
- After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
|
|
130
|
-
|
|
131
|
-
## When NOT to Use This Tool
|
|
132
|
-
|
|
133
|
-
Skip using this tool when:
|
|
134
|
-
- There is only a single, straightforward task
|
|
135
|
-
- The task is trivial and tracking it provides no organizational benefit
|
|
136
|
-
- The task can be completed in less than 3 trivial steps
|
|
137
|
-
- The task is purely conversational or informational
|
|
138
|
-
|
|
139
|
-
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.
|
|
140
|
-
|
|
141
|
-
## Task Fields
|
|
142
|
-
|
|
143
|
-
- **subject**: A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")
|
|
144
|
-
- **description**: Detailed description of what needs to be done, including context and acceptance criteria
|
|
145
|
-
- **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.
|
|
146
|
-
|
|
147
|
-
**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\`.
|
|
148
|
-
|
|
149
|
-
## Tips
|
|
150
|
-
|
|
151
|
-
- Create tasks with clear, specific subjects that describe the outcome
|
|
152
|
-
- Include enough detail in the description for another agent to understand and complete the task
|
|
153
|
-
- After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
|
|
154
|
-
- Check TaskList first to avoid creating duplicate tasks`,
|
|
155
|
-
schema: z5__default.default.object({
|
|
156
|
-
subject: z5__default.default.string().describe(
|
|
157
|
-
'A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")'
|
|
158
|
-
),
|
|
159
|
-
description: z5__default.default.string().describe(
|
|
160
|
-
"Detailed description of what needs to be done, including context and acceptance criteria"
|
|
161
|
-
),
|
|
162
|
-
activeForm: z5__default.default.string().describe(
|
|
163
|
-
'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.'
|
|
164
|
-
),
|
|
165
|
-
metadata: z5__default.default.record(z5__default.default.string(), z5__default.default.string()).describe("Arbitrary key-value pairs for tracking")
|
|
166
|
-
})
|
|
167
|
-
};
|
|
168
83
|
|
|
169
84
|
// src/lib/tool-router.ts
|
|
170
|
-
var buildIntoolDefinitions = {
|
|
171
|
-
[bashTool.name]: bashTool,
|
|
172
|
-
[taskCreateTool.name]: taskCreateTool
|
|
173
|
-
};
|
|
174
85
|
function createToolRouter(options) {
|
|
175
|
-
const { appendToolResult } =
|
|
176
|
-
startToCloseTimeout: "2m",
|
|
177
|
-
retry: {
|
|
178
|
-
maximumAttempts: 3,
|
|
179
|
-
initialInterval: "5s",
|
|
180
|
-
maximumInterval: "15m",
|
|
181
|
-
backoffCoefficient: 4
|
|
182
|
-
}
|
|
183
|
-
});
|
|
86
|
+
const { appendToolResult } = options;
|
|
184
87
|
const toolMap = /* @__PURE__ */ new Map();
|
|
185
88
|
for (const [_key, tool] of Object.entries(options.tools)) {
|
|
186
89
|
toolMap.set(tool.name, tool);
|
|
187
90
|
}
|
|
91
|
+
const isEnabled = (tool) => tool.enabled !== false;
|
|
188
92
|
if (options.subagents) {
|
|
189
93
|
const subagentHooksMap = /* @__PURE__ */ new Map();
|
|
190
94
|
for (const s of options.subagents) {
|
|
191
95
|
if (s.hooks) subagentHooksMap.set(s.name, s.hooks);
|
|
192
96
|
}
|
|
193
97
|
const resolveSubagentName = (args) => args.subagent;
|
|
194
|
-
toolMap.set("
|
|
195
|
-
...
|
|
196
|
-
handler:
|
|
98
|
+
toolMap.set("Subagent", {
|
|
99
|
+
...createSubagentTool(options.subagents),
|
|
100
|
+
handler: createSubagentHandler(options.subagents),
|
|
197
101
|
...subagentHooksMap.size > 0 && {
|
|
198
102
|
hooks: {
|
|
199
103
|
onPreToolUse: async (ctx) => {
|
|
@@ -212,24 +116,6 @@ function createToolRouter(options) {
|
|
|
212
116
|
}
|
|
213
117
|
});
|
|
214
118
|
}
|
|
215
|
-
if (options.buildInTools) {
|
|
216
|
-
for (const [key, value] of Object.entries(options.buildInTools)) {
|
|
217
|
-
if (key === bashTool.name) {
|
|
218
|
-
toolMap.set(key, {
|
|
219
|
-
...buildIntoolDefinitions[key],
|
|
220
|
-
description: createBashToolDescription({
|
|
221
|
-
fileTree: options.fileTree
|
|
222
|
-
}),
|
|
223
|
-
handler: value
|
|
224
|
-
});
|
|
225
|
-
} else {
|
|
226
|
-
toolMap.set(key, {
|
|
227
|
-
...buildIntoolDefinitions[key],
|
|
228
|
-
handler: value
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
119
|
async function processToolCall(toolCall, turn, handlerContext) {
|
|
234
120
|
const startTime = Date.now();
|
|
235
121
|
const tool = toolMap.get(toolCall.name);
|
|
@@ -245,6 +131,7 @@ function createToolRouter(options) {
|
|
|
245
131
|
await appendToolResult({
|
|
246
132
|
threadId: options.threadId,
|
|
247
133
|
toolCallId: toolCall.id,
|
|
134
|
+
toolName: toolCall.name,
|
|
248
135
|
content: JSON.stringify({
|
|
249
136
|
skipped: true,
|
|
250
137
|
reason: "Skipped by PreToolUse hook"
|
|
@@ -266,6 +153,7 @@ function createToolRouter(options) {
|
|
|
266
153
|
await appendToolResult({
|
|
267
154
|
threadId: options.threadId,
|
|
268
155
|
toolCallId: toolCall.id,
|
|
156
|
+
toolName: toolCall.name,
|
|
269
157
|
content: JSON.stringify({
|
|
270
158
|
skipped: true,
|
|
271
159
|
reason: "Skipped by tool PreToolUse hook"
|
|
@@ -279,14 +167,22 @@ function createToolRouter(options) {
|
|
|
279
167
|
}
|
|
280
168
|
let result;
|
|
281
169
|
let content;
|
|
170
|
+
let resultAppended = false;
|
|
282
171
|
try {
|
|
283
172
|
if (tool) {
|
|
173
|
+
const enrichedContext = {
|
|
174
|
+
...handlerContext ?? {},
|
|
175
|
+
threadId: options.threadId,
|
|
176
|
+
toolCallId: toolCall.id,
|
|
177
|
+
toolName: toolCall.name
|
|
178
|
+
};
|
|
284
179
|
const response = await tool.handler(
|
|
285
180
|
effectiveArgs,
|
|
286
|
-
|
|
181
|
+
enrichedContext
|
|
287
182
|
);
|
|
288
183
|
result = response.data;
|
|
289
184
|
content = response.toolResponse;
|
|
185
|
+
resultAppended = response.resultAppended === true;
|
|
290
186
|
} else {
|
|
291
187
|
result = { error: `Unknown tool: ${toolCall.name}` };
|
|
292
188
|
content = JSON.stringify(result, null, 2);
|
|
@@ -332,11 +228,14 @@ function createToolRouter(options) {
|
|
|
332
228
|
throw error;
|
|
333
229
|
}
|
|
334
230
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
231
|
+
if (!resultAppended) {
|
|
232
|
+
await appendToolResult({
|
|
233
|
+
threadId: options.threadId,
|
|
234
|
+
toolCallId: toolCall.id,
|
|
235
|
+
toolName: toolCall.name,
|
|
236
|
+
content
|
|
237
|
+
});
|
|
238
|
+
}
|
|
340
239
|
const toolResult = {
|
|
341
240
|
toolCallId: toolCall.id,
|
|
342
241
|
name: toolCall.name,
|
|
@@ -366,11 +265,11 @@ function createToolRouter(options) {
|
|
|
366
265
|
return {
|
|
367
266
|
// --- Methods from registry ---
|
|
368
267
|
hasTools() {
|
|
369
|
-
return toolMap.
|
|
268
|
+
return Array.from(toolMap.values()).some(isEnabled);
|
|
370
269
|
},
|
|
371
270
|
parseToolCall(toolCall) {
|
|
372
271
|
const tool = toolMap.get(toolCall.name);
|
|
373
|
-
if (!tool) {
|
|
272
|
+
if (!tool || !isEnabled(tool)) {
|
|
374
273
|
throw new Error(`Tool ${toolCall.name} not found`);
|
|
375
274
|
}
|
|
376
275
|
const parsedArgs = tool.schema.parse(toolCall.args);
|
|
@@ -381,13 +280,14 @@ function createToolRouter(options) {
|
|
|
381
280
|
};
|
|
382
281
|
},
|
|
383
282
|
hasTool(name) {
|
|
384
|
-
|
|
283
|
+
const tool = toolMap.get(name);
|
|
284
|
+
return tool !== void 0 && isEnabled(tool);
|
|
385
285
|
},
|
|
386
286
|
getToolNames() {
|
|
387
|
-
return Array.from(toolMap.
|
|
287
|
+
return Array.from(toolMap.entries()).filter(([, tool]) => isEnabled(tool)).map(([name]) => name);
|
|
388
288
|
},
|
|
389
289
|
getToolDefinitions() {
|
|
390
|
-
return Array.from(toolMap).map(([name, tool]) => ({
|
|
290
|
+
return Array.from(toolMap).filter(([, tool]) => isEnabled(tool)).map(([name, tool]) => ({
|
|
391
291
|
name,
|
|
392
292
|
description: tool.description,
|
|
393
293
|
schema: tool.schema,
|
|
@@ -426,19 +326,28 @@ function createToolRouter(options) {
|
|
|
426
326
|
}
|
|
427
327
|
const handlerContext = context?.handlerContext ?? {};
|
|
428
328
|
const processOne = async (toolCall) => {
|
|
329
|
+
const enrichedContext = {
|
|
330
|
+
...handlerContext ?? {},
|
|
331
|
+
threadId: options.threadId,
|
|
332
|
+
toolCallId: toolCall.id,
|
|
333
|
+
toolName: toolCall.name
|
|
334
|
+
};
|
|
429
335
|
const response = await handler(
|
|
430
336
|
toolCall.args,
|
|
431
|
-
|
|
337
|
+
enrichedContext
|
|
432
338
|
);
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
339
|
+
if (!response.resultAppended) {
|
|
340
|
+
await appendToolResult({
|
|
341
|
+
threadId: options.threadId,
|
|
342
|
+
toolCallId: toolCall.id,
|
|
343
|
+
toolName: toolCall.name,
|
|
344
|
+
content: response.toolResponse
|
|
345
|
+
});
|
|
346
|
+
}
|
|
438
347
|
return {
|
|
439
348
|
toolCallId: toolCall.id,
|
|
440
349
|
name: toolCall.name,
|
|
441
|
-
data: response.data
|
|
350
|
+
data: response.data
|
|
442
351
|
};
|
|
443
352
|
};
|
|
444
353
|
if (options.parallel) {
|
|
@@ -464,6 +373,21 @@ function createToolRouter(options) {
|
|
|
464
373
|
}
|
|
465
374
|
};
|
|
466
375
|
}
|
|
376
|
+
function withAutoAppend(threadHandler, handler) {
|
|
377
|
+
return async (args, context) => {
|
|
378
|
+
const response = await handler(args, context);
|
|
379
|
+
const threadId = context.threadId;
|
|
380
|
+
const toolCallId = context.toolCallId;
|
|
381
|
+
const toolName = context.toolName;
|
|
382
|
+
await threadHandler({
|
|
383
|
+
threadId,
|
|
384
|
+
toolCallId,
|
|
385
|
+
toolName,
|
|
386
|
+
content: response.toolResponse
|
|
387
|
+
});
|
|
388
|
+
return { toolResponse: "", data: response.data, resultAppended: true };
|
|
389
|
+
};
|
|
390
|
+
}
|
|
467
391
|
function defineTool(tool) {
|
|
468
392
|
return tool;
|
|
469
393
|
}
|
|
@@ -475,51 +399,24 @@ function hasNoOtherToolCalls(toolCalls, excludeName) {
|
|
|
475
399
|
}
|
|
476
400
|
|
|
477
401
|
// src/lib/session.ts
|
|
478
|
-
async function resolvePrompt(prompt) {
|
|
479
|
-
if (typeof prompt === "function") {
|
|
480
|
-
return prompt();
|
|
481
|
-
}
|
|
482
|
-
return prompt;
|
|
483
|
-
}
|
|
484
402
|
var createSession = async ({
|
|
485
403
|
threadId,
|
|
486
404
|
agentName,
|
|
487
405
|
maxTurns = 50,
|
|
488
406
|
metadata = {},
|
|
489
407
|
runAgent,
|
|
490
|
-
|
|
491
|
-
instructionsPrompt,
|
|
408
|
+
threadOps,
|
|
492
409
|
buildContextMessage,
|
|
493
|
-
buildFileTree = async () => "",
|
|
494
410
|
subagents,
|
|
495
411
|
tools = {},
|
|
496
412
|
processToolsInParallel = true,
|
|
497
|
-
buildInTools = {},
|
|
498
413
|
hooks = {}
|
|
499
414
|
}) => {
|
|
500
|
-
const {
|
|
501
|
-
initializeThread,
|
|
502
|
-
appendHumanMessage,
|
|
503
|
-
parseToolCalls,
|
|
504
|
-
appendToolResult,
|
|
505
|
-
appendSystemMessage
|
|
506
|
-
} = workflow.proxyActivities({
|
|
507
|
-
startToCloseTimeout: "30m",
|
|
508
|
-
retry: {
|
|
509
|
-
maximumAttempts: 6,
|
|
510
|
-
initialInterval: "5s",
|
|
511
|
-
maximumInterval: "15m",
|
|
512
|
-
backoffCoefficient: 4
|
|
513
|
-
},
|
|
514
|
-
heartbeatTimeout: "5m"
|
|
515
|
-
});
|
|
516
|
-
const fileTree = await buildFileTree();
|
|
517
415
|
const toolRouter = createToolRouter({
|
|
518
416
|
tools,
|
|
417
|
+
appendToolResult: threadOps.appendToolResult,
|
|
519
418
|
threadId,
|
|
520
419
|
hooks,
|
|
521
|
-
buildInTools,
|
|
522
|
-
fileTree,
|
|
523
420
|
subagents,
|
|
524
421
|
parallel: processToolsInParallel
|
|
525
422
|
});
|
|
@@ -544,83 +441,41 @@ var createSession = async ({
|
|
|
544
441
|
});
|
|
545
442
|
}
|
|
546
443
|
stateManager.setTools(toolRouter.getToolDefinitions());
|
|
547
|
-
await initializeThread(threadId);
|
|
548
|
-
await
|
|
549
|
-
threadId,
|
|
550
|
-
[
|
|
551
|
-
await resolvePrompt(baseSystemPrompt),
|
|
552
|
-
await resolvePrompt(instructionsPrompt)
|
|
553
|
-
].join("\n")
|
|
554
|
-
);
|
|
555
|
-
await appendHumanMessage(threadId, await buildContextMessage());
|
|
444
|
+
await threadOps.initializeThread(threadId);
|
|
445
|
+
await threadOps.appendHumanMessage(threadId, await buildContextMessage());
|
|
556
446
|
let exitReason = "completed";
|
|
557
447
|
try {
|
|
558
448
|
while (stateManager.isRunning() && !stateManager.isTerminal() && stateManager.getTurns() < maxTurns) {
|
|
559
449
|
stateManager.incrementTurns();
|
|
560
450
|
const currentTurn = stateManager.getTurns();
|
|
561
|
-
const { message,
|
|
451
|
+
const { message, rawToolCalls } = await runAgent({
|
|
562
452
|
threadId,
|
|
563
453
|
agentName,
|
|
564
454
|
metadata
|
|
565
455
|
});
|
|
566
|
-
if (
|
|
567
|
-
stateManager.complete();
|
|
568
|
-
exitReason = "completed";
|
|
569
|
-
return message;
|
|
570
|
-
}
|
|
571
|
-
if (!toolRouter.hasTools()) {
|
|
456
|
+
if (!toolRouter.hasTools() || rawToolCalls.length === 0) {
|
|
572
457
|
stateManager.complete();
|
|
573
458
|
exitReason = "completed";
|
|
574
459
|
return message;
|
|
575
460
|
}
|
|
576
|
-
const rawToolCalls = await parseToolCalls(message);
|
|
577
461
|
const parsedToolCalls = [];
|
|
578
|
-
for (const tc of rawToolCalls
|
|
579
|
-
(tc2) => tc2.name !== "Task"
|
|
580
|
-
)) {
|
|
462
|
+
for (const tc of rawToolCalls) {
|
|
581
463
|
try {
|
|
582
464
|
parsedToolCalls.push(toolRouter.parseToolCall(tc));
|
|
583
465
|
} catch (error) {
|
|
584
|
-
await appendToolResult({
|
|
466
|
+
await threadOps.appendToolResult({
|
|
585
467
|
threadId,
|
|
586
468
|
toolCallId: tc.id ?? "",
|
|
469
|
+
toolName: tc.name,
|
|
587
470
|
content: JSON.stringify({
|
|
588
471
|
error: `Invalid tool call for "${tc.name}": ${error instanceof Error ? error.message : String(error)}`
|
|
589
472
|
})
|
|
590
473
|
});
|
|
591
474
|
}
|
|
592
475
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
(tc2) => tc2.name === "Task"
|
|
597
|
-
)) {
|
|
598
|
-
try {
|
|
599
|
-
const parsedArgs = createTaskTool(subagents).schema.parse(
|
|
600
|
-
tc.args
|
|
601
|
-
);
|
|
602
|
-
taskToolCalls.push({
|
|
603
|
-
id: tc.id ?? "",
|
|
604
|
-
name: tc.name,
|
|
605
|
-
args: parsedArgs
|
|
606
|
-
});
|
|
607
|
-
} catch (error) {
|
|
608
|
-
await appendToolResult({
|
|
609
|
-
threadId,
|
|
610
|
-
toolCallId: tc.id ?? "",
|
|
611
|
-
content: JSON.stringify({
|
|
612
|
-
error: `Invalid tool call for "Task": ${error instanceof Error ? error.message : String(error)}`
|
|
613
|
-
})
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
await toolRouter.processToolCalls(
|
|
619
|
-
[...parsedToolCalls, ...taskToolCalls],
|
|
620
|
-
{
|
|
621
|
-
turn: currentTurn
|
|
622
|
-
}
|
|
623
|
-
);
|
|
476
|
+
await toolRouter.processToolCalls(parsedToolCalls, {
|
|
477
|
+
turn: currentTurn
|
|
478
|
+
});
|
|
624
479
|
if (stateManager.getStatus() === "WAITING_FOR_INPUT") {
|
|
625
480
|
exitReason = "waiting_for_input";
|
|
626
481
|
break;
|
|
@@ -639,6 +494,25 @@ var createSession = async ({
|
|
|
639
494
|
}
|
|
640
495
|
};
|
|
641
496
|
};
|
|
497
|
+
function proxyDefaultThreadOps(options) {
|
|
498
|
+
const activities = workflow.proxyActivities(
|
|
499
|
+
options ?? {
|
|
500
|
+
startToCloseTimeout: "30m",
|
|
501
|
+
retry: {
|
|
502
|
+
maximumAttempts: 6,
|
|
503
|
+
initialInterval: "5s",
|
|
504
|
+
maximumInterval: "15m",
|
|
505
|
+
backoffCoefficient: 4
|
|
506
|
+
},
|
|
507
|
+
heartbeatTimeout: "5m"
|
|
508
|
+
}
|
|
509
|
+
);
|
|
510
|
+
return {
|
|
511
|
+
initializeThread: activities.initializeThread,
|
|
512
|
+
appendHumanMessage: activities.appendHumanMessage,
|
|
513
|
+
appendToolResult: activities.appendToolResult
|
|
514
|
+
};
|
|
515
|
+
}
|
|
642
516
|
|
|
643
517
|
// src/lib/types.ts
|
|
644
518
|
function isTerminalStatus(status) {
|
|
@@ -741,7 +615,7 @@ function createAgentStateManager(initialState) {
|
|
|
741
615
|
tools = newTools.map((tool) => ({
|
|
742
616
|
name: tool.name,
|
|
743
617
|
description: tool.description,
|
|
744
|
-
schema:
|
|
618
|
+
schema: z3.z.toJSONSchema(tool.schema),
|
|
745
619
|
strict: tool.strict,
|
|
746
620
|
max_uses: tool.max_uses
|
|
747
621
|
}));
|
|
@@ -775,18 +649,18 @@ Usage notes:
|
|
|
775
649
|
* Use multiSelect: true to allow multiple answers to be selected for a question
|
|
776
650
|
* If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
|
|
777
651
|
`,
|
|
778
|
-
schema:
|
|
779
|
-
questions:
|
|
780
|
-
|
|
781
|
-
question:
|
|
782
|
-
header:
|
|
783
|
-
options:
|
|
784
|
-
|
|
785
|
-
label:
|
|
786
|
-
description:
|
|
652
|
+
schema: z3__default.default.object({
|
|
653
|
+
questions: z3__default.default.array(
|
|
654
|
+
z3__default.default.object({
|
|
655
|
+
question: z3__default.default.string().describe("The full question text to display"),
|
|
656
|
+
header: z3__default.default.string().describe("Short label for the question (max 12 characters)"),
|
|
657
|
+
options: z3__default.default.array(
|
|
658
|
+
z3__default.default.object({
|
|
659
|
+
label: z3__default.default.string(),
|
|
660
|
+
description: z3__default.default.string()
|
|
787
661
|
})
|
|
788
662
|
).min(0).max(4).describe("Array of 0-4 choices, each with label and description"),
|
|
789
|
-
multiSelect:
|
|
663
|
+
multiSelect: z3__default.default.boolean().describe("If true, users can select multiple options")
|
|
790
664
|
})
|
|
791
665
|
)
|
|
792
666
|
}),
|
|
@@ -806,9 +680,9 @@ Examples:
|
|
|
806
680
|
- "**/*.test.ts" - Find all test files recursively
|
|
807
681
|
- "src/**/*.ts" - Find all TypeScript files in src directory
|
|
808
682
|
`,
|
|
809
|
-
schema:
|
|
810
|
-
pattern:
|
|
811
|
-
root:
|
|
683
|
+
schema: z3.z.object({
|
|
684
|
+
pattern: z3.z.string().describe("Glob pattern to match files against"),
|
|
685
|
+
root: z3.z.string().optional().describe("Optional root directory to search from")
|
|
812
686
|
}),
|
|
813
687
|
strict: true
|
|
814
688
|
};
|
|
@@ -826,13 +700,13 @@ Examples:
|
|
|
826
700
|
- Search for function definitions with "function.*handleClick"
|
|
827
701
|
- Search case-insensitively with ignoreCase: true
|
|
828
702
|
`,
|
|
829
|
-
schema:
|
|
830
|
-
pattern:
|
|
831
|
-
ignoreCase:
|
|
832
|
-
maxMatches:
|
|
833
|
-
includePatterns:
|
|
834
|
-
excludePatterns:
|
|
835
|
-
contextLines:
|
|
703
|
+
schema: z3.z.object({
|
|
704
|
+
pattern: z3.z.string().describe("Regex pattern to search for in file contents"),
|
|
705
|
+
ignoreCase: z3.z.boolean().optional().describe("Case-insensitive search (default: false)"),
|
|
706
|
+
maxMatches: z3.z.number().optional().describe("Maximum number of matches to return (default: 50)"),
|
|
707
|
+
includePatterns: z3.z.array(z3.z.string()).optional().describe("Glob patterns to include (e.g., ['*.ts', '*.js'])"),
|
|
708
|
+
excludePatterns: z3.z.array(z3.z.string()).optional().describe("Glob patterns to exclude (e.g., ['*.test.ts'])"),
|
|
709
|
+
contextLines: z3.z.number().optional().describe("Number of context lines to show around matches")
|
|
836
710
|
}),
|
|
837
711
|
strict: true
|
|
838
712
|
};
|
|
@@ -850,12 +724,12 @@ The tool returns the file content in an appropriate format:
|
|
|
850
724
|
- Images: Base64-encoded image data
|
|
851
725
|
- PDFs: Extracted text content
|
|
852
726
|
`,
|
|
853
|
-
schema:
|
|
854
|
-
path:
|
|
855
|
-
offset:
|
|
727
|
+
schema: z3.z.object({
|
|
728
|
+
path: z3.z.string().describe("Virtual path to the file to read"),
|
|
729
|
+
offset: z3.z.number().optional().describe(
|
|
856
730
|
"Line number to start reading from (1-indexed, for text files)"
|
|
857
731
|
),
|
|
858
|
-
limit:
|
|
732
|
+
limit: z3.z.number().optional().describe("Maximum number of lines to read (for text files)")
|
|
859
733
|
}),
|
|
860
734
|
strict: true
|
|
861
735
|
};
|
|
@@ -864,7 +738,7 @@ var writeTool = {
|
|
|
864
738
|
description: `Create or overwrite a file with new content.
|
|
865
739
|
|
|
866
740
|
Usage:
|
|
867
|
-
- Provide the absolute
|
|
741
|
+
- Provide the absolute path to the file
|
|
868
742
|
- The file will be created if it doesn't exist
|
|
869
743
|
- If the file exists, it will be completely overwritten
|
|
870
744
|
|
|
@@ -873,9 +747,9 @@ IMPORTANT:
|
|
|
873
747
|
- This is an atomic write operation - the entire file is replaced
|
|
874
748
|
- Path must be absolute (e.g., "/docs/readme.md", not "docs/readme.md")
|
|
875
749
|
`,
|
|
876
|
-
schema:
|
|
877
|
-
file_path:
|
|
878
|
-
content:
|
|
750
|
+
schema: z3.z.object({
|
|
751
|
+
file_path: z3.z.string().describe("The absolute path to the file to write"),
|
|
752
|
+
content: z3.z.string().describe("The content to write to the file")
|
|
879
753
|
}),
|
|
880
754
|
strict: true
|
|
881
755
|
};
|
|
@@ -895,18 +769,72 @@ IMPORTANT:
|
|
|
895
769
|
- The operation fails if old_string is not found
|
|
896
770
|
- old_string and new_string must be different
|
|
897
771
|
`,
|
|
898
|
-
schema:
|
|
899
|
-
file_path:
|
|
900
|
-
old_string:
|
|
901
|
-
new_string:
|
|
772
|
+
schema: z3.z.object({
|
|
773
|
+
file_path: z3.z.string().describe("The absolute virtual path to the file to modify"),
|
|
774
|
+
old_string: z3.z.string().describe("The exact text to replace"),
|
|
775
|
+
new_string: z3.z.string().describe(
|
|
902
776
|
"The text to replace it with (must be different from old_string)"
|
|
903
777
|
),
|
|
904
|
-
replace_all:
|
|
778
|
+
replace_all: z3.z.boolean().optional().describe(
|
|
905
779
|
"If true, replace all occurrences of old_string (default: false)"
|
|
906
780
|
)
|
|
907
781
|
}),
|
|
908
782
|
strict: true
|
|
909
783
|
};
|
|
784
|
+
var taskCreateTool = {
|
|
785
|
+
name: "TaskCreate",
|
|
786
|
+
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.
|
|
787
|
+
It also helps the user understand the progress of the task and overall progress of their requests.
|
|
788
|
+
|
|
789
|
+
## When to Use This Tool
|
|
790
|
+
|
|
791
|
+
Use this tool proactively in these scenarios:
|
|
792
|
+
|
|
793
|
+
- Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
|
|
794
|
+
- Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
|
|
795
|
+
- User explicitly requests todo list - When the user directly asks you to use the todo list
|
|
796
|
+
- User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
|
|
797
|
+
- After receiving new instructions - Immediately capture user requirements as tasks
|
|
798
|
+
- When you start working on a task - Mark it as in_progress BEFORE beginning work
|
|
799
|
+
- After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
|
|
800
|
+
|
|
801
|
+
## When NOT to Use This Tool
|
|
802
|
+
|
|
803
|
+
Skip using this tool when:
|
|
804
|
+
- There is only a single, straightforward task
|
|
805
|
+
- The task is trivial and tracking it provides no organizational benefit
|
|
806
|
+
- The task can be completed in less than 3 trivial steps
|
|
807
|
+
- The task is purely conversational or informational
|
|
808
|
+
|
|
809
|
+
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.
|
|
810
|
+
|
|
811
|
+
## Task Fields
|
|
812
|
+
|
|
813
|
+
- **subject**: A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")
|
|
814
|
+
- **description**: Detailed description of what needs to be done, including context and acceptance criteria
|
|
815
|
+
- **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.
|
|
816
|
+
|
|
817
|
+
**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\`.
|
|
818
|
+
|
|
819
|
+
## Tips
|
|
820
|
+
|
|
821
|
+
- Create tasks with clear, specific subjects that describe the outcome
|
|
822
|
+
- Include enough detail in the description for another agent to understand and complete the task
|
|
823
|
+
- After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
|
|
824
|
+
- Check TaskList first to avoid creating duplicate tasks`,
|
|
825
|
+
schema: z3__default.default.object({
|
|
826
|
+
subject: z3__default.default.string().describe(
|
|
827
|
+
'A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")'
|
|
828
|
+
),
|
|
829
|
+
description: z3__default.default.string().describe(
|
|
830
|
+
"Detailed description of what needs to be done, including context and acceptance criteria"
|
|
831
|
+
),
|
|
832
|
+
activeForm: z3__default.default.string().describe(
|
|
833
|
+
'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.'
|
|
834
|
+
),
|
|
835
|
+
metadata: z3__default.default.record(z3__default.default.string(), z3__default.default.string()).describe("Arbitrary key-value pairs for tracking")
|
|
836
|
+
})
|
|
837
|
+
};
|
|
910
838
|
function createTaskCreateHandler(stateManager) {
|
|
911
839
|
return (args) => {
|
|
912
840
|
const task = {
|
|
@@ -929,8 +857,8 @@ function createTaskCreateHandler(stateManager) {
|
|
|
929
857
|
var taskGetTool = {
|
|
930
858
|
name: "TaskGet",
|
|
931
859
|
description: `Retrieve full task details including dependencies.`,
|
|
932
|
-
schema:
|
|
933
|
-
taskId:
|
|
860
|
+
schema: z3__default.default.object({
|
|
861
|
+
taskId: z3__default.default.string().describe("The ID of the task to get")
|
|
934
862
|
})
|
|
935
863
|
};
|
|
936
864
|
|
|
@@ -953,12 +881,12 @@ function createTaskGetHandler(stateManager) {
|
|
|
953
881
|
var taskListTool = {
|
|
954
882
|
name: "TaskList",
|
|
955
883
|
description: `List all tasks with current state.`,
|
|
956
|
-
schema:
|
|
884
|
+
schema: z3__default.default.object({})
|
|
957
885
|
};
|
|
958
886
|
|
|
959
887
|
// src/tools/task-list/handler.ts
|
|
960
888
|
function createTaskListHandler(stateManager) {
|
|
961
|
-
return (
|
|
889
|
+
return () => {
|
|
962
890
|
const taskList = stateManager.getTasks();
|
|
963
891
|
return {
|
|
964
892
|
toolResponse: JSON.stringify(taskList, null, 2),
|
|
@@ -969,11 +897,11 @@ function createTaskListHandler(stateManager) {
|
|
|
969
897
|
var taskUpdateTool = {
|
|
970
898
|
name: "TaskUpdate",
|
|
971
899
|
description: `Update status, add blockers, modify details.`,
|
|
972
|
-
schema:
|
|
973
|
-
taskId:
|
|
974
|
-
status:
|
|
975
|
-
addBlockedBy:
|
|
976
|
-
addBlocks:
|
|
900
|
+
schema: z3__default.default.object({
|
|
901
|
+
taskId: z3__default.default.string().describe("The ID of the task to get"),
|
|
902
|
+
status: z3__default.default.enum(["pending", "in_progress", "completed"]).describe("The status of the task"),
|
|
903
|
+
addBlockedBy: z3__default.default.array(z3__default.default.string()).describe("The IDs of the tasks that are blocking this task"),
|
|
904
|
+
addBlocks: z3__default.default.array(z3__default.default.string()).describe("The IDs of the tasks that this task is blocking")
|
|
977
905
|
})
|
|
978
906
|
};
|
|
979
907
|
|
|
@@ -1021,6 +949,33 @@ function createTaskUpdateHandler(stateManager) {
|
|
|
1021
949
|
};
|
|
1022
950
|
};
|
|
1023
951
|
}
|
|
952
|
+
var createBashToolDescription = ({
|
|
953
|
+
fileTree
|
|
954
|
+
}) => `Execute shell commands in a bash environment.
|
|
955
|
+
|
|
956
|
+
Use this tool to:
|
|
957
|
+
- Run shell commands (ls, cat, grep, find, etc.)
|
|
958
|
+
- Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
|
|
959
|
+
- Inspect files and directories
|
|
960
|
+
|
|
961
|
+
Current file tree:
|
|
962
|
+
${fileTree}`;
|
|
963
|
+
var bashTool = {
|
|
964
|
+
name: "Bash",
|
|
965
|
+
description: `Execute shell commands in a sandboxed 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
|
+
schema: z3__default.default.object({
|
|
973
|
+
command: z3__default.default.string().describe(
|
|
974
|
+
"The bash command to execute. Can include pipes (|), redirects (>, >>), logical operators (&&, ||), and shell features like command substitution $(...)."
|
|
975
|
+
)
|
|
976
|
+
}),
|
|
977
|
+
strict: true
|
|
978
|
+
};
|
|
1024
979
|
|
|
1025
980
|
// node_modules/uuid/dist/esm-node/stringify.js
|
|
1026
981
|
var byteToHex = [];
|
|
@@ -1069,25 +1024,33 @@ function getThreadKey(threadId, key) {
|
|
|
1069
1024
|
return `thread:${threadId}:${key}`;
|
|
1070
1025
|
}
|
|
1071
1026
|
function createThreadManager(config) {
|
|
1072
|
-
const {
|
|
1027
|
+
const {
|
|
1028
|
+
redis,
|
|
1029
|
+
threadId,
|
|
1030
|
+
key = "messages",
|
|
1031
|
+
serialize = (m) => JSON.stringify(m),
|
|
1032
|
+
deserialize = (raw) => JSON.parse(raw)
|
|
1033
|
+
} = config;
|
|
1073
1034
|
const redisKey = getThreadKey(threadId, key);
|
|
1074
|
-
|
|
1035
|
+
const base = {
|
|
1075
1036
|
async initialize() {
|
|
1076
1037
|
await redis.del(redisKey);
|
|
1077
1038
|
},
|
|
1078
1039
|
async load() {
|
|
1079
1040
|
const data = await redis.lrange(redisKey, 0, -1);
|
|
1080
|
-
return data.map(
|
|
1041
|
+
return data.map(deserialize);
|
|
1081
1042
|
},
|
|
1082
1043
|
async append(messages) {
|
|
1083
1044
|
if (messages.length > 0) {
|
|
1084
|
-
await redis.rpush(redisKey, ...messages.map(
|
|
1045
|
+
await redis.rpush(redisKey, ...messages.map(serialize));
|
|
1085
1046
|
await redis.expire(redisKey, THREAD_TTL_SECONDS);
|
|
1086
1047
|
}
|
|
1087
1048
|
},
|
|
1088
1049
|
async delete() {
|
|
1089
1050
|
await redis.del(redisKey);
|
|
1090
|
-
}
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
const helpers = {
|
|
1091
1054
|
createHumanMessage(content) {
|
|
1092
1055
|
return new messages.HumanMessage({
|
|
1093
1056
|
id: v4_default(),
|
|
@@ -1107,40 +1070,29 @@ function createThreadManager(config) {
|
|
|
1107
1070
|
},
|
|
1108
1071
|
createToolMessage(content, toolCallId) {
|
|
1109
1072
|
return new messages.ToolMessage({
|
|
1110
|
-
// Cast needed due to langchain type compatibility
|
|
1111
1073
|
content,
|
|
1112
1074
|
tool_call_id: toolCallId
|
|
1113
1075
|
}).toDict();
|
|
1114
1076
|
},
|
|
1115
|
-
createSystemMessage(content) {
|
|
1116
|
-
return new messages.SystemMessage({
|
|
1117
|
-
content
|
|
1118
|
-
}).toDict();
|
|
1119
|
-
},
|
|
1120
|
-
async appendSystemMessage(content) {
|
|
1121
|
-
const message = this.createSystemMessage(content);
|
|
1122
|
-
await this.append([message]);
|
|
1123
|
-
},
|
|
1124
1077
|
async appendHumanMessage(content) {
|
|
1125
|
-
const message =
|
|
1126
|
-
await
|
|
1078
|
+
const message = helpers.createHumanMessage(content);
|
|
1079
|
+
await base.append([message]);
|
|
1127
1080
|
},
|
|
1128
1081
|
async appendToolMessage(content, toolCallId) {
|
|
1129
|
-
const message =
|
|
1130
|
-
await
|
|
1082
|
+
const message = helpers.createToolMessage(content, toolCallId);
|
|
1083
|
+
await base.append([message]);
|
|
1131
1084
|
},
|
|
1132
1085
|
async appendAIMessage(content) {
|
|
1133
|
-
const message =
|
|
1134
|
-
await
|
|
1086
|
+
const message = helpers.createAIMessage(content);
|
|
1087
|
+
await base.append([message]);
|
|
1135
1088
|
}
|
|
1136
1089
|
};
|
|
1090
|
+
return Object.assign(base, helpers);
|
|
1137
1091
|
}
|
|
1092
|
+
|
|
1093
|
+
// src/activities.ts
|
|
1138
1094
|
function createSharedActivities(redis) {
|
|
1139
1095
|
return {
|
|
1140
|
-
async appendSystemMessage(threadId, content) {
|
|
1141
|
-
const thread = createThreadManager({ redis, threadId });
|
|
1142
|
-
await thread.appendSystemMessage(content);
|
|
1143
|
-
},
|
|
1144
1096
|
async appendToolResult(config) {
|
|
1145
1097
|
const { threadId, toolCallId, content } = config;
|
|
1146
1098
|
const thread = createThreadManager({ redis, threadId });
|
|
@@ -1157,15 +1109,6 @@ function createSharedActivities(redis) {
|
|
|
1157
1109
|
async appendHumanMessage(threadId, content) {
|
|
1158
1110
|
const thread = createThreadManager({ redis, threadId });
|
|
1159
1111
|
await thread.appendHumanMessage(content);
|
|
1160
|
-
},
|
|
1161
|
-
async parseToolCalls(storedMessage) {
|
|
1162
|
-
const message = messages.mapStoredMessageToChatMessage(storedMessage);
|
|
1163
|
-
const toolCalls = message.tool_calls ?? [];
|
|
1164
|
-
return toolCalls.map((toolCall) => ({
|
|
1165
|
-
id: toolCall.id,
|
|
1166
|
-
name: toolCall.name,
|
|
1167
|
-
args: toolCall.args
|
|
1168
|
-
}));
|
|
1169
1112
|
}
|
|
1170
1113
|
};
|
|
1171
1114
|
}
|
|
@@ -1203,9 +1146,14 @@ async function invokeModel({
|
|
|
1203
1146
|
}
|
|
1204
1147
|
);
|
|
1205
1148
|
await thread.append([response.toDict()]);
|
|
1149
|
+
const toolCalls = response.tool_calls ?? [];
|
|
1206
1150
|
return {
|
|
1207
1151
|
message: response.toDict(),
|
|
1208
|
-
|
|
1152
|
+
rawToolCalls: toolCalls.map((tc) => ({
|
|
1153
|
+
id: tc.id,
|
|
1154
|
+
name: tc.name,
|
|
1155
|
+
args: tc.args
|
|
1156
|
+
})),
|
|
1209
1157
|
usage: {
|
|
1210
1158
|
input_tokens: response.usage_metadata?.input_tokens,
|
|
1211
1159
|
output_tokens: response.usage_metadata?.output_tokens,
|
|
@@ -1213,7 +1161,7 @@ async function invokeModel({
|
|
|
1213
1161
|
}
|
|
1214
1162
|
};
|
|
1215
1163
|
}
|
|
1216
|
-
var
|
|
1164
|
+
var createAskUserQuestionHandler = () => async (args) => {
|
|
1217
1165
|
const messages$1 = args.questions.map(
|
|
1218
1166
|
({ question, header, options, multiSelect }) => new messages.AIMessage({
|
|
1219
1167
|
content: question,
|
|
@@ -1226,99 +1174,79 @@ var handleAskUserQuestionToolResult = async (args) => {
|
|
|
1226
1174
|
);
|
|
1227
1175
|
return { toolResponse: "Question submitted", data: { chatMessages: messages$1 } };
|
|
1228
1176
|
};
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1177
|
+
function createGlobHandler(fs) {
|
|
1178
|
+
return async (_args) => {
|
|
1179
|
+
new justBash.Bash({ fs });
|
|
1180
|
+
return {
|
|
1181
|
+
toolResponse: "Hello, world!",
|
|
1182
|
+
data: { files: [] }
|
|
1183
|
+
};
|
|
1184
|
+
};
|
|
1235
1185
|
}
|
|
1236
1186
|
|
|
1237
1187
|
// src/tools/edit/handler.ts
|
|
1238
1188
|
function escapeRegExp(str) {
|
|
1239
1189
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1240
1190
|
}
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
toolResponse: `Error: old_string and new_string must be different.`,
|
|
1246
|
-
data: {
|
|
1247
|
-
path: file_path,
|
|
1248
|
-
success: false,
|
|
1249
|
-
replacements: 0
|
|
1250
|
-
}
|
|
1251
|
-
};
|
|
1252
|
-
}
|
|
1253
|
-
try {
|
|
1254
|
-
const exists = await fs.exists(file_path);
|
|
1255
|
-
if (!exists) {
|
|
1191
|
+
function createEditHandler(fs) {
|
|
1192
|
+
return async (args) => {
|
|
1193
|
+
const { file_path, old_string, new_string, replace_all = false } = args;
|
|
1194
|
+
if (old_string === new_string) {
|
|
1256
1195
|
return {
|
|
1257
|
-
toolResponse: `Error:
|
|
1258
|
-
data: {
|
|
1259
|
-
path: file_path,
|
|
1260
|
-
success: false,
|
|
1261
|
-
replacements: 0
|
|
1262
|
-
}
|
|
1196
|
+
toolResponse: `Error: old_string and new_string must be different.`,
|
|
1197
|
+
data: { path: file_path, success: false, replacements: 0 }
|
|
1263
1198
|
};
|
|
1264
1199
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1200
|
+
try {
|
|
1201
|
+
const exists = await fs.exists(file_path);
|
|
1202
|
+
if (!exists) {
|
|
1203
|
+
return {
|
|
1204
|
+
toolResponse: `Error: File "${file_path}" does not exist.`,
|
|
1205
|
+
data: { path: file_path, success: false, replacements: 0 }
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
const content = await fs.readFile(file_path);
|
|
1209
|
+
if (!content.includes(old_string)) {
|
|
1210
|
+
return {
|
|
1211
|
+
toolResponse: `Error: Could not find the specified text in "${file_path}". Make sure old_string matches exactly (whitespace-sensitive).`,
|
|
1212
|
+
data: { path: file_path, success: false, replacements: 0 }
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
const escapedOldString = escapeRegExp(old_string);
|
|
1216
|
+
const globalRegex = new RegExp(escapedOldString, "g");
|
|
1217
|
+
const occurrences = (content.match(globalRegex) || []).length;
|
|
1218
|
+
if (!replace_all && occurrences > 1) {
|
|
1219
|
+
return {
|
|
1220
|
+
toolResponse: `Error: old_string appears ${occurrences} times in "${file_path}". Either provide more context to make it unique, or use replace_all: true.`,
|
|
1221
|
+
data: { path: file_path, success: false, replacements: 0 }
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
let newContent;
|
|
1225
|
+
let replacements;
|
|
1226
|
+
if (replace_all) {
|
|
1227
|
+
newContent = content.split(old_string).join(new_string);
|
|
1228
|
+
replacements = occurrences;
|
|
1229
|
+
} else {
|
|
1230
|
+
const index = content.indexOf(old_string);
|
|
1231
|
+
newContent = content.slice(0, index) + new_string + content.slice(index + old_string.length);
|
|
1232
|
+
replacements = 1;
|
|
1233
|
+
}
|
|
1234
|
+
await fs.writeFile(file_path, newContent);
|
|
1235
|
+
const summary = replace_all ? `Replaced ${replacements} occurrence(s)` : `Replaced 1 occurrence`;
|
|
1267
1236
|
return {
|
|
1268
|
-
toolResponse:
|
|
1269
|
-
data: {
|
|
1270
|
-
path: file_path,
|
|
1271
|
-
success: false,
|
|
1272
|
-
replacements: 0
|
|
1273
|
-
}
|
|
1237
|
+
toolResponse: `${summary} in ${file_path}`,
|
|
1238
|
+
data: { path: file_path, success: true, replacements }
|
|
1274
1239
|
};
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
const globalRegex = new RegExp(escapedOldString, "g");
|
|
1278
|
-
const occurrences = (content.match(globalRegex) || []).length;
|
|
1279
|
-
if (!replace_all && occurrences > 1) {
|
|
1240
|
+
} catch (error) {
|
|
1241
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1280
1242
|
return {
|
|
1281
|
-
toolResponse: `Error
|
|
1282
|
-
data: {
|
|
1283
|
-
path: file_path,
|
|
1284
|
-
success: false,
|
|
1285
|
-
replacements: 0
|
|
1286
|
-
}
|
|
1243
|
+
toolResponse: `Error editing file "${file_path}": ${message}`,
|
|
1244
|
+
data: { path: file_path, success: false, replacements: 0 }
|
|
1287
1245
|
};
|
|
1288
1246
|
}
|
|
1289
|
-
|
|
1290
|
-
let replacements;
|
|
1291
|
-
if (replace_all) {
|
|
1292
|
-
newContent = content.split(old_string).join(new_string);
|
|
1293
|
-
replacements = occurrences;
|
|
1294
|
-
} else {
|
|
1295
|
-
const index = content.indexOf(old_string);
|
|
1296
|
-
newContent = content.slice(0, index) + new_string + content.slice(index + old_string.length);
|
|
1297
|
-
replacements = 1;
|
|
1298
|
-
}
|
|
1299
|
-
await fs.writeFile(file_path, newContent);
|
|
1300
|
-
const summary = replace_all ? `Replaced ${replacements} occurrence(s)` : `Replaced 1 occurrence`;
|
|
1301
|
-
return {
|
|
1302
|
-
toolResponse: `${summary} in ${file_path}`,
|
|
1303
|
-
data: {
|
|
1304
|
-
path: file_path,
|
|
1305
|
-
success: true,
|
|
1306
|
-
replacements
|
|
1307
|
-
}
|
|
1308
|
-
};
|
|
1309
|
-
} catch (error) {
|
|
1310
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1311
|
-
return {
|
|
1312
|
-
toolResponse: `Error editing file "${file_path}": ${message}`,
|
|
1313
|
-
data: {
|
|
1314
|
-
path: file_path,
|
|
1315
|
-
success: false,
|
|
1316
|
-
replacements: 0
|
|
1317
|
-
}
|
|
1318
|
-
};
|
|
1319
|
-
}
|
|
1247
|
+
};
|
|
1320
1248
|
}
|
|
1321
|
-
var
|
|
1249
|
+
var createBashHandler = (bashOptions) => async (args, _context) => {
|
|
1322
1250
|
const { command } = args;
|
|
1323
1251
|
const mergedOptions = {
|
|
1324
1252
|
...bashOptions,
|
|
@@ -1420,34 +1348,37 @@ exports.ZeitlichPlugin = ZeitlichPlugin;
|
|
|
1420
1348
|
exports.askUserQuestionTool = askUserQuestionTool;
|
|
1421
1349
|
exports.bashTool = bashTool;
|
|
1422
1350
|
exports.createAgentStateManager = createAgentStateManager;
|
|
1351
|
+
exports.createAskUserQuestionHandler = createAskUserQuestionHandler;
|
|
1352
|
+
exports.createBashHandler = createBashHandler;
|
|
1353
|
+
exports.createBashToolDescription = createBashToolDescription;
|
|
1354
|
+
exports.createEditHandler = createEditHandler;
|
|
1355
|
+
exports.createGlobHandler = createGlobHandler;
|
|
1423
1356
|
exports.createSession = createSession;
|
|
1424
1357
|
exports.createSharedActivities = createSharedActivities;
|
|
1358
|
+
exports.createSubagentTool = createSubagentTool;
|
|
1425
1359
|
exports.createTaskCreateHandler = createTaskCreateHandler;
|
|
1426
1360
|
exports.createTaskGetHandler = createTaskGetHandler;
|
|
1427
1361
|
exports.createTaskListHandler = createTaskListHandler;
|
|
1428
|
-
exports.createTaskTool = createTaskTool;
|
|
1429
1362
|
exports.createTaskUpdateHandler = createTaskUpdateHandler;
|
|
1430
1363
|
exports.createThreadManager = createThreadManager;
|
|
1431
1364
|
exports.createToolRouter = createToolRouter;
|
|
1432
1365
|
exports.defineSubagent = defineSubagent;
|
|
1433
1366
|
exports.defineTool = defineTool;
|
|
1434
|
-
exports.editHandler = editHandler;
|
|
1435
1367
|
exports.editTool = editTool;
|
|
1436
1368
|
exports.getStateQuery = getStateQuery;
|
|
1437
|
-
exports.globHandler = globHandler;
|
|
1438
1369
|
exports.globTool = globTool;
|
|
1439
1370
|
exports.grepTool = grepTool;
|
|
1440
|
-
exports.handleAskUserQuestionToolResult = handleAskUserQuestionToolResult;
|
|
1441
|
-
exports.handleBashTool = handleBashTool;
|
|
1442
1371
|
exports.hasNoOtherToolCalls = hasNoOtherToolCalls;
|
|
1443
1372
|
exports.invokeModel = invokeModel;
|
|
1444
1373
|
exports.isTerminalStatus = isTerminalStatus;
|
|
1374
|
+
exports.proxyDefaultThreadOps = proxyDefaultThreadOps;
|
|
1445
1375
|
exports.readTool = readTool;
|
|
1446
1376
|
exports.taskCreateTool = taskCreateTool;
|
|
1447
1377
|
exports.taskGetTool = taskGetTool;
|
|
1448
1378
|
exports.taskListTool = taskListTool;
|
|
1449
1379
|
exports.taskUpdateTool = taskUpdateTool;
|
|
1450
1380
|
exports.toTree = toTree;
|
|
1381
|
+
exports.withAutoAppend = withAutoAppend;
|
|
1451
1382
|
exports.writeTool = writeTool;
|
|
1452
1383
|
//# sourceMappingURL=index.cjs.map
|
|
1453
1384
|
//# sourceMappingURL=index.cjs.map
|