zeitlich 0.1.1 → 0.2.0
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 +165 -180
- package/dist/index.cjs +1314 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +128 -0
- package/dist/index.d.ts +51 -75
- package/dist/index.js +741 -1091
- package/dist/index.js.map +1 -1
- package/dist/workflow-uVNF7zoe.d.cts +941 -0
- package/dist/workflow-uVNF7zoe.d.ts +941 -0
- package/dist/workflow.cjs +914 -0
- package/dist/workflow.cjs.map +1 -0
- package/dist/workflow.d.cts +5 -0
- package/dist/workflow.d.ts +2 -1
- package/dist/workflow.js +543 -423
- package/dist/workflow.js.map +1 -1
- package/package.json +19 -17
- package/src/activities.ts +112 -0
- package/src/index.ts +49 -0
- package/src/lib/fs.ts +80 -0
- package/src/lib/model-invoker.ts +75 -0
- package/src/lib/session.ts +216 -0
- package/src/lib/state-manager.ts +268 -0
- package/src/lib/thread-manager.ts +169 -0
- package/src/lib/tool-router.ts +717 -0
- package/src/lib/types.ts +354 -0
- package/src/plugin.ts +28 -0
- package/src/tools/ask-user-question/handler.ts +25 -0
- package/src/tools/ask-user-question/tool.ts +46 -0
- package/src/tools/bash/bash.test.ts +104 -0
- package/src/tools/bash/handler.ts +36 -0
- package/src/tools/bash/tool.ts +20 -0
- package/src/tools/edit/handler.ts +156 -0
- package/src/tools/edit/tool.ts +39 -0
- package/src/tools/glob/handler.ts +62 -0
- package/src/tools/glob/tool.ts +27 -0
- package/src/tools/grep/tool.ts +45 -0
- package/src/tools/read/tool.ts +33 -0
- package/src/tools/task/handler.ts +75 -0
- package/src/tools/task/tool.ts +96 -0
- package/src/tools/task-create/handler.ts +49 -0
- package/src/tools/task-create/tool.ts +66 -0
- package/src/tools/task-get/handler.ts +38 -0
- package/src/tools/task-get/tool.ts +11 -0
- package/src/tools/task-list/handler.ts +33 -0
- package/src/tools/task-list/tool.ts +9 -0
- package/src/tools/task-update/handler.ts +79 -0
- package/src/tools/task-update/tool.ts +20 -0
- package/src/tools/write/tool.ts +26 -0
- package/src/workflow.ts +138 -0
- package/tsup.config.ts +20 -0
- package/dist/index.d.mts +0 -152
- package/dist/index.mjs +0 -1587
- package/dist/index.mjs.map +0 -1
- package/dist/workflow-7_MT-5-w.d.mts +0 -1203
- package/dist/workflow-7_MT-5-w.d.ts +0 -1203
- package/dist/workflow.d.mts +0 -4
- package/dist/workflow.mjs +0 -739
- package/dist/workflow.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
var crypto = require('crypto');
|
|
9
|
-
|
|
10
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
-
|
|
12
|
-
var z2__default = /*#__PURE__*/_interopDefault(z2);
|
|
13
|
-
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
1
|
+
import { defineQuery, proxyActivities, setHandler, workflowInfo, uuid4, executeChild } from '@temporalio/workflow';
|
|
2
|
+
import z4, { z } from 'zod';
|
|
3
|
+
import { SimplePlugin } from '@temporalio/plugin';
|
|
4
|
+
import { mapStoredMessageToChatMessage, mapStoredMessagesToChatMessages, AIMessage, SystemMessage, ToolMessage, HumanMessage } from '@langchain/core/messages';
|
|
5
|
+
import crypto from 'crypto';
|
|
6
|
+
import { Context } from '@temporalio/activity';
|
|
7
|
+
import { Bash } from 'just-bash';
|
|
14
8
|
|
|
15
9
|
// src/lib/session.ts
|
|
16
10
|
var TASK_TOOL = "Task";
|
|
@@ -45,24 +39,24 @@ function createTaskTool(subagents) {
|
|
|
45
39
|
return {
|
|
46
40
|
name: TASK_TOOL,
|
|
47
41
|
description: buildTaskDescription(subagents),
|
|
48
|
-
schema:
|
|
49
|
-
subagent:
|
|
50
|
-
description:
|
|
51
|
-
prompt:
|
|
42
|
+
schema: z4.object({
|
|
43
|
+
subagent: z4.enum(names).describe("The type of subagent to launch"),
|
|
44
|
+
description: z4.string().describe("A short (3-5 word) description of the task"),
|
|
45
|
+
prompt: z4.string().describe("The task for the agent to perform")
|
|
52
46
|
})
|
|
53
47
|
};
|
|
54
48
|
}
|
|
55
49
|
function createTaskHandler(subagents) {
|
|
56
|
-
const { workflowId: parentWorkflowId, taskQueue: parentTaskQueue } =
|
|
57
|
-
return async (args
|
|
50
|
+
const { workflowId: parentWorkflowId, taskQueue: parentTaskQueue } = workflowInfo();
|
|
51
|
+
return async (args) => {
|
|
58
52
|
const config = subagents.find((s) => s.name === args.subagent);
|
|
59
53
|
if (!config) {
|
|
60
54
|
throw new Error(
|
|
61
55
|
`Unknown subagent: ${args.subagent}. Available: ${subagents.map((s) => s.name).join(", ")}`
|
|
62
56
|
);
|
|
63
57
|
}
|
|
64
|
-
const childWorkflowId = `${parentWorkflowId}-${args.subagent}-${
|
|
65
|
-
const childResult = await
|
|
58
|
+
const childWorkflowId = `${parentWorkflowId}-${args.subagent}-${uuid4()}`;
|
|
59
|
+
const childResult = await executeChild(config.workflowType, {
|
|
66
60
|
workflowId: childWorkflowId,
|
|
67
61
|
args: [{ prompt: args.prompt }],
|
|
68
62
|
taskQueue: config.taskQueue ?? parentTaskQueue
|
|
@@ -78,35 +72,332 @@ function createTaskHandler(subagents) {
|
|
|
78
72
|
};
|
|
79
73
|
};
|
|
80
74
|
}
|
|
75
|
+
var createBashToolDescription = ({
|
|
76
|
+
fileTree
|
|
77
|
+
}) => `tool to execute bash commands, the file tree is: ${fileTree}`;
|
|
78
|
+
var bashTool = {
|
|
79
|
+
name: "Bash",
|
|
80
|
+
description: "tool to execute bash commands",
|
|
81
|
+
schema: z4.object({
|
|
82
|
+
command: z4.string().describe("stringified command to be executed inside the Bash")
|
|
83
|
+
}),
|
|
84
|
+
strict: true
|
|
85
|
+
};
|
|
86
|
+
var taskCreateTool = {
|
|
87
|
+
name: "TaskCreate",
|
|
88
|
+
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.
|
|
89
|
+
It also helps the user understand the progress of the task and overall progress of their requests.
|
|
90
|
+
|
|
91
|
+
## When to Use This Tool
|
|
92
|
+
|
|
93
|
+
Use this tool proactively in these scenarios:
|
|
94
|
+
|
|
95
|
+
- Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
|
|
96
|
+
- Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
|
|
97
|
+
- User explicitly requests todo list - When the user directly asks you to use the todo list
|
|
98
|
+
- User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
|
|
99
|
+
- After receiving new instructions - Immediately capture user requirements as tasks
|
|
100
|
+
- When you start working on a task - Mark it as in_progress BEFORE beginning work
|
|
101
|
+
- After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
|
|
102
|
+
|
|
103
|
+
## When NOT to Use This Tool
|
|
104
|
+
|
|
105
|
+
Skip using this tool when:
|
|
106
|
+
- There is only a single, straightforward task
|
|
107
|
+
- The task is trivial and tracking it provides no organizational benefit
|
|
108
|
+
- The task can be completed in less than 3 trivial steps
|
|
109
|
+
- The task is purely conversational or informational
|
|
110
|
+
|
|
111
|
+
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.
|
|
112
|
+
|
|
113
|
+
## Task Fields
|
|
114
|
+
|
|
115
|
+
- **subject**: A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")
|
|
116
|
+
- **description**: Detailed description of what needs to be done, including context and acceptance criteria
|
|
117
|
+
- **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.
|
|
118
|
+
|
|
119
|
+
**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\`.
|
|
120
|
+
|
|
121
|
+
## Tips
|
|
122
|
+
|
|
123
|
+
- Create tasks with clear, specific subjects that describe the outcome
|
|
124
|
+
- Include enough detail in the description for another agent to understand and complete the task
|
|
125
|
+
- After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
|
|
126
|
+
- Check TaskList first to avoid creating duplicate tasks`,
|
|
127
|
+
schema: z4.object({
|
|
128
|
+
subject: z4.string().describe(
|
|
129
|
+
'A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")'
|
|
130
|
+
),
|
|
131
|
+
description: z4.string().describe(
|
|
132
|
+
"Detailed description of what needs to be done, including context and acceptance criteria"
|
|
133
|
+
),
|
|
134
|
+
activeForm: z4.string().describe(
|
|
135
|
+
'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.'
|
|
136
|
+
),
|
|
137
|
+
metadata: z4.record(z4.string(), z4.string()).describe("Arbitrary key-value pairs for tracking")
|
|
138
|
+
})
|
|
139
|
+
};
|
|
81
140
|
|
|
82
|
-
// src/lib/
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
141
|
+
// src/lib/tool-router.ts
|
|
142
|
+
var buildIntoolDefinitions = {
|
|
143
|
+
[bashTool.name]: bashTool,
|
|
144
|
+
[taskCreateTool.name]: taskCreateTool
|
|
145
|
+
};
|
|
146
|
+
function createToolRouter(options) {
|
|
147
|
+
const { appendToolResult } = proxyActivities({
|
|
148
|
+
startToCloseTimeout: "2m",
|
|
149
|
+
retry: {
|
|
150
|
+
maximumAttempts: 3,
|
|
151
|
+
initialInterval: "5s",
|
|
152
|
+
maximumInterval: "15m",
|
|
153
|
+
backoffCoefficient: 4
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
const toolMap = /* @__PURE__ */ new Map();
|
|
157
|
+
for (const [_key, tool] of Object.entries(options.tools)) {
|
|
158
|
+
toolMap.set(tool.name, tool);
|
|
159
|
+
}
|
|
160
|
+
if (options.subagents) {
|
|
161
|
+
toolMap.set("Task", {
|
|
162
|
+
...createTaskTool(options.subagents),
|
|
163
|
+
handler: createTaskHandler(options.subagents)
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
if (options.buildInTools) {
|
|
167
|
+
for (const [key, value] of Object.entries(options.buildInTools)) {
|
|
168
|
+
if (key === bashTool.name) {
|
|
169
|
+
toolMap.set(key, {
|
|
170
|
+
...buildIntoolDefinitions[key],
|
|
171
|
+
description: createBashToolDescription({
|
|
172
|
+
fileTree: options.fileTree
|
|
173
|
+
}),
|
|
174
|
+
handler: value
|
|
175
|
+
});
|
|
176
|
+
} else {
|
|
177
|
+
toolMap.set(key, {
|
|
178
|
+
...buildIntoolDefinitions[key],
|
|
179
|
+
handler: value
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async function processToolCall(toolCall, turn, handlerContext) {
|
|
185
|
+
const startTime = Date.now();
|
|
186
|
+
let effectiveArgs = toolCall.args;
|
|
187
|
+
if (options.hooks?.onPreToolUse) {
|
|
188
|
+
const preResult = await options.hooks.onPreToolUse({
|
|
189
|
+
toolCall,
|
|
190
|
+
threadId: options.threadId,
|
|
191
|
+
turn
|
|
192
|
+
});
|
|
193
|
+
if (preResult?.skip) {
|
|
194
|
+
await appendToolResult({
|
|
195
|
+
threadId: options.threadId,
|
|
196
|
+
toolCallId: toolCall.id,
|
|
197
|
+
content: JSON.stringify({
|
|
198
|
+
skipped: true,
|
|
199
|
+
reason: "Skipped by PreToolUse hook"
|
|
200
|
+
})
|
|
201
|
+
});
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
if (preResult?.modifiedArgs !== void 0) {
|
|
205
|
+
effectiveArgs = preResult.modifiedArgs;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const tool = toolMap.get(toolCall.name);
|
|
209
|
+
let result;
|
|
210
|
+
let content;
|
|
211
|
+
try {
|
|
212
|
+
if (tool) {
|
|
213
|
+
const response = await tool.handler(
|
|
214
|
+
effectiveArgs,
|
|
215
|
+
handlerContext ?? {}
|
|
216
|
+
);
|
|
217
|
+
result = response.result;
|
|
218
|
+
content = response.content;
|
|
219
|
+
} else {
|
|
220
|
+
result = { error: `Unknown tool: ${toolCall.name}` };
|
|
221
|
+
content = JSON.stringify(result, null, 2);
|
|
222
|
+
}
|
|
223
|
+
} catch (error) {
|
|
224
|
+
if (options.hooks?.onPostToolUseFailure) {
|
|
225
|
+
const failureResult = await options.hooks.onPostToolUseFailure({
|
|
226
|
+
toolCall,
|
|
227
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
228
|
+
threadId: options.threadId,
|
|
229
|
+
turn
|
|
230
|
+
});
|
|
231
|
+
if (failureResult?.fallbackContent !== void 0) {
|
|
232
|
+
content = failureResult.fallbackContent;
|
|
233
|
+
result = { error: String(error), recovered: true };
|
|
234
|
+
} else if (failureResult?.suppress) {
|
|
235
|
+
content = JSON.stringify({ error: String(error), suppressed: true });
|
|
236
|
+
result = { error: String(error), suppressed: true };
|
|
237
|
+
} else {
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
await appendToolResult({
|
|
245
|
+
threadId: options.threadId,
|
|
246
|
+
toolCallId: toolCall.id,
|
|
247
|
+
content
|
|
248
|
+
});
|
|
249
|
+
const toolResult = {
|
|
250
|
+
toolCallId: toolCall.id,
|
|
251
|
+
name: toolCall.name,
|
|
252
|
+
result
|
|
253
|
+
};
|
|
254
|
+
if (options.hooks?.onPostToolUse) {
|
|
255
|
+
const durationMs = Date.now() - startTime;
|
|
256
|
+
await options.hooks.onPostToolUse({
|
|
257
|
+
toolCall,
|
|
258
|
+
result: toolResult,
|
|
259
|
+
threadId: options.threadId,
|
|
260
|
+
turn,
|
|
261
|
+
durationMs
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
return toolResult;
|
|
86
265
|
}
|
|
87
|
-
const taskTool = createTaskTool(config.subagents);
|
|
88
|
-
const taskHandler = createTaskHandler(config.subagents);
|
|
89
266
|
return {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
267
|
+
// --- Methods from registry ---
|
|
268
|
+
hasTools() {
|
|
269
|
+
return toolMap.size > 0;
|
|
270
|
+
},
|
|
271
|
+
parseToolCall(toolCall) {
|
|
272
|
+
const tool = toolMap.get(toolCall.name);
|
|
273
|
+
if (!tool) {
|
|
274
|
+
throw new Error(`Tool ${toolCall.name} not found`);
|
|
275
|
+
}
|
|
276
|
+
const parsedArgs = tool.schema.parse(toolCall.args);
|
|
277
|
+
return {
|
|
278
|
+
id: toolCall.id ?? "",
|
|
279
|
+
name: toolCall.name,
|
|
280
|
+
args: parsedArgs
|
|
281
|
+
};
|
|
282
|
+
},
|
|
283
|
+
hasTool(name) {
|
|
284
|
+
return toolMap.has(name);
|
|
285
|
+
},
|
|
286
|
+
getToolNames() {
|
|
287
|
+
return Array.from(toolMap.keys());
|
|
288
|
+
},
|
|
289
|
+
getToolDefinitions() {
|
|
290
|
+
return Array.from(toolMap).map(([name, tool]) => ({
|
|
291
|
+
name,
|
|
292
|
+
description: tool.description,
|
|
293
|
+
schema: tool.schema,
|
|
294
|
+
strict: tool.strict,
|
|
295
|
+
max_uses: tool.max_uses
|
|
296
|
+
}));
|
|
297
|
+
},
|
|
298
|
+
// --- Methods for processing tool calls ---
|
|
299
|
+
async processToolCalls(toolCalls, context) {
|
|
300
|
+
if (toolCalls.length === 0) {
|
|
301
|
+
return [];
|
|
302
|
+
}
|
|
303
|
+
const turn = context?.turn ?? 0;
|
|
304
|
+
const handlerContext = context?.handlerContext;
|
|
305
|
+
if (options.parallel) {
|
|
306
|
+
const results2 = await Promise.all(
|
|
307
|
+
toolCalls.map((tc) => processToolCall(tc, turn, handlerContext))
|
|
308
|
+
);
|
|
309
|
+
return results2.filter(
|
|
310
|
+
(r) => r !== null
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
const results = [];
|
|
314
|
+
for (const toolCall of toolCalls) {
|
|
315
|
+
const result = await processToolCall(toolCall, turn, handlerContext);
|
|
316
|
+
if (result !== null) {
|
|
317
|
+
results.push(result);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return results;
|
|
321
|
+
},
|
|
322
|
+
async processToolCallsByName(toolCalls, toolName, handler, context) {
|
|
323
|
+
const matchingCalls = toolCalls.filter((tc) => tc.name === toolName);
|
|
324
|
+
if (matchingCalls.length === 0) {
|
|
325
|
+
return [];
|
|
326
|
+
}
|
|
327
|
+
const handlerContext = context?.handlerContext ?? {};
|
|
328
|
+
const processOne = async (toolCall) => {
|
|
329
|
+
const response = await handler(
|
|
330
|
+
toolCall.args,
|
|
331
|
+
handlerContext
|
|
332
|
+
);
|
|
333
|
+
await appendToolResult({
|
|
334
|
+
threadId: options.threadId,
|
|
335
|
+
toolCallId: toolCall.id,
|
|
336
|
+
content: response.content
|
|
337
|
+
});
|
|
338
|
+
return {
|
|
339
|
+
toolCallId: toolCall.id,
|
|
340
|
+
name: toolCall.name,
|
|
341
|
+
result: response.result
|
|
342
|
+
};
|
|
343
|
+
};
|
|
344
|
+
if (options.parallel) {
|
|
345
|
+
return Promise.all(matchingCalls.map(processOne));
|
|
346
|
+
}
|
|
347
|
+
const results = [];
|
|
348
|
+
for (const toolCall of matchingCalls) {
|
|
349
|
+
results.push(await processOne(toolCall));
|
|
350
|
+
}
|
|
351
|
+
return results;
|
|
352
|
+
},
|
|
353
|
+
// --- Utility methods ---
|
|
354
|
+
filterByName(toolCalls, name) {
|
|
355
|
+
return toolCalls.filter(
|
|
356
|
+
(tc) => tc.name === name
|
|
357
|
+
);
|
|
358
|
+
},
|
|
359
|
+
hasToolCall(toolCalls, name) {
|
|
360
|
+
return toolCalls.some((tc) => tc.name === name);
|
|
93
361
|
},
|
|
94
|
-
|
|
362
|
+
getResultsByName(results, name) {
|
|
363
|
+
return results.filter((r) => r.name === name);
|
|
364
|
+
}
|
|
95
365
|
};
|
|
96
366
|
}
|
|
97
|
-
function
|
|
98
|
-
return
|
|
367
|
+
function hasNoOtherToolCalls(toolCalls, excludeName) {
|
|
368
|
+
return toolCalls.filter((tc) => tc.name !== excludeName).length === 0;
|
|
99
369
|
}
|
|
100
370
|
|
|
101
371
|
// src/lib/session.ts
|
|
102
|
-
|
|
372
|
+
async function resolvePrompt(prompt) {
|
|
373
|
+
if (typeof prompt === "function") {
|
|
374
|
+
return prompt();
|
|
375
|
+
}
|
|
376
|
+
return prompt;
|
|
377
|
+
}
|
|
378
|
+
var createSession = async ({
|
|
379
|
+
threadId,
|
|
380
|
+
agentName,
|
|
381
|
+
maxTurns = 50,
|
|
382
|
+
metadata = {},
|
|
103
383
|
runAgent,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
384
|
+
baseSystemPrompt,
|
|
385
|
+
instructionsPrompt,
|
|
386
|
+
buildContextMessage,
|
|
387
|
+
buildFileTree = async () => "",
|
|
388
|
+
subagents,
|
|
389
|
+
tools = {},
|
|
390
|
+
processToolsInParallel = true,
|
|
391
|
+
buildInTools = {},
|
|
107
392
|
hooks = {}
|
|
108
393
|
}) => {
|
|
109
|
-
const {
|
|
394
|
+
const {
|
|
395
|
+
initializeThread,
|
|
396
|
+
appendHumanMessage,
|
|
397
|
+
parseToolCalls,
|
|
398
|
+
appendToolResult,
|
|
399
|
+
appendSystemMessage
|
|
400
|
+
} = proxyActivities({
|
|
110
401
|
startToCloseTimeout: "30m",
|
|
111
402
|
retry: {
|
|
112
403
|
maximumAttempts: 6,
|
|
@@ -116,6 +407,16 @@ var createSession = async ({ threadId, agentName, maxTurns = 50, metadata = {} }
|
|
|
116
407
|
},
|
|
117
408
|
heartbeatTimeout: "5m"
|
|
118
409
|
});
|
|
410
|
+
const fileTree = await buildFileTree();
|
|
411
|
+
const toolRouter = createToolRouter({
|
|
412
|
+
tools,
|
|
413
|
+
threadId,
|
|
414
|
+
hooks,
|
|
415
|
+
buildInTools,
|
|
416
|
+
fileTree,
|
|
417
|
+
subagents,
|
|
418
|
+
parallel: processToolsInParallel
|
|
419
|
+
});
|
|
119
420
|
const callSessionEnd = async (exitReason, turns) => {
|
|
120
421
|
if (hooks.onSessionEnd) {
|
|
121
422
|
await hooks.onSessionEnd({
|
|
@@ -128,7 +429,7 @@ var createSession = async ({ threadId, agentName, maxTurns = 50, metadata = {} }
|
|
|
128
429
|
}
|
|
129
430
|
};
|
|
130
431
|
return {
|
|
131
|
-
runSession: async (
|
|
432
|
+
runSession: async ({ stateManager }) => {
|
|
132
433
|
if (hooks.onSessionStart) {
|
|
133
434
|
await hooks.onSessionStart({
|
|
134
435
|
threadId,
|
|
@@ -136,43 +437,54 @@ var createSession = async ({ threadId, agentName, maxTurns = 50, metadata = {} }
|
|
|
136
437
|
metadata
|
|
137
438
|
});
|
|
138
439
|
}
|
|
440
|
+
stateManager.setTools(toolRouter.getToolDefinitions());
|
|
139
441
|
await initializeThread(threadId);
|
|
140
|
-
await
|
|
442
|
+
await appendSystemMessage(
|
|
141
443
|
threadId,
|
|
142
|
-
|
|
444
|
+
[
|
|
445
|
+
await resolvePrompt(baseSystemPrompt),
|
|
446
|
+
await resolvePrompt(instructionsPrompt)
|
|
447
|
+
].join("\n")
|
|
143
448
|
);
|
|
449
|
+
await appendHumanMessage(threadId, await buildContextMessage());
|
|
144
450
|
let exitReason = "completed";
|
|
145
451
|
try {
|
|
146
452
|
while (stateManager.isRunning() && !stateManager.isTerminal() && stateManager.getTurns() < maxTurns) {
|
|
147
453
|
stateManager.incrementTurns();
|
|
148
454
|
const currentTurn = stateManager.getTurns();
|
|
149
|
-
const { message, stopReason } = await runAgent(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
systemPrompt: await promptManager.getSystemPrompt()
|
|
157
|
-
}
|
|
158
|
-
);
|
|
455
|
+
const { message, stopReason } = await runAgent({
|
|
456
|
+
threadId,
|
|
457
|
+
agentName,
|
|
458
|
+
metadata
|
|
459
|
+
});
|
|
159
460
|
if (stopReason === "end_turn") {
|
|
160
461
|
stateManager.complete();
|
|
161
462
|
exitReason = "completed";
|
|
162
463
|
return message;
|
|
163
464
|
}
|
|
164
|
-
if (!toolRouter
|
|
465
|
+
if (!toolRouter.hasTools()) {
|
|
165
466
|
stateManager.complete();
|
|
166
467
|
exitReason = "completed";
|
|
167
468
|
return message;
|
|
168
469
|
}
|
|
169
470
|
const rawToolCalls = await parseToolCalls(message);
|
|
170
|
-
const parsedToolCalls = rawToolCalls.map(
|
|
171
|
-
|
|
471
|
+
const parsedToolCalls = rawToolCalls.filter((tc) => tc.name !== "Task").map((tc) => toolRouter.parseToolCall(tc));
|
|
472
|
+
const taskToolCalls = subagents && subagents.length > 0 ? rawToolCalls.filter((tc) => tc.name === "Task").map((tc) => {
|
|
473
|
+
const parsedArgs = createTaskTool(subagents).schema.parse(
|
|
474
|
+
tc.args
|
|
475
|
+
);
|
|
476
|
+
return {
|
|
477
|
+
id: tc.id ?? "",
|
|
478
|
+
name: tc.name,
|
|
479
|
+
args: parsedArgs
|
|
480
|
+
};
|
|
481
|
+
}) : [];
|
|
482
|
+
await toolRouter.processToolCalls(
|
|
483
|
+
[...parsedToolCalls, ...taskToolCalls],
|
|
484
|
+
{
|
|
485
|
+
turn: currentTurn
|
|
486
|
+
}
|
|
172
487
|
);
|
|
173
|
-
await toolRouter.processToolCalls(parsedToolCalls, {
|
|
174
|
-
turn: currentTurn
|
|
175
|
-
});
|
|
176
488
|
if (stateManager.getStatus() === "WAITING_FOR_INPUT") {
|
|
177
489
|
exitReason = "waiting_for_input";
|
|
178
490
|
break;
|
|
@@ -198,19 +510,34 @@ function isTerminalStatus(status) {
|
|
|
198
510
|
}
|
|
199
511
|
|
|
200
512
|
// src/lib/state-manager.ts
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
let
|
|
204
|
-
let
|
|
205
|
-
|
|
513
|
+
var getStateQuery = defineQuery("getState");
|
|
514
|
+
function createAgentStateManager(initialState) {
|
|
515
|
+
let status = initialState?.status ?? "RUNNING";
|
|
516
|
+
let version = initialState?.version ?? 0;
|
|
517
|
+
let turns = initialState?.turns ?? 0;
|
|
518
|
+
let tools = initialState?.tools ?? [];
|
|
519
|
+
const tasks = new Map(initialState?.tasks);
|
|
520
|
+
const {
|
|
521
|
+
status: _,
|
|
522
|
+
version: __,
|
|
523
|
+
turns: ___,
|
|
524
|
+
tasks: ____,
|
|
525
|
+
tools: _____,
|
|
526
|
+
...custom
|
|
527
|
+
} = initialState ?? {};
|
|
528
|
+
const customState = custom;
|
|
206
529
|
function buildState() {
|
|
207
530
|
return {
|
|
208
531
|
status,
|
|
209
532
|
version,
|
|
210
533
|
turns,
|
|
534
|
+
tools,
|
|
211
535
|
...customState
|
|
212
536
|
};
|
|
213
537
|
}
|
|
538
|
+
setHandler(getStateQuery, () => {
|
|
539
|
+
return buildState();
|
|
540
|
+
});
|
|
214
541
|
return {
|
|
215
542
|
getStatus() {
|
|
216
543
|
return status;
|
|
@@ -265,6 +592,26 @@ function createAgentStateManager(config) {
|
|
|
265
592
|
},
|
|
266
593
|
shouldReturnFromWait(lastKnownVersion) {
|
|
267
594
|
return version > lastKnownVersion || isTerminalStatus(status);
|
|
595
|
+
},
|
|
596
|
+
getTasks() {
|
|
597
|
+
return Array.from(tasks.values());
|
|
598
|
+
},
|
|
599
|
+
getTask(id) {
|
|
600
|
+
return tasks.get(id);
|
|
601
|
+
},
|
|
602
|
+
setTask(task) {
|
|
603
|
+
tasks.set(task.id, task);
|
|
604
|
+
version++;
|
|
605
|
+
},
|
|
606
|
+
setTools(newTools) {
|
|
607
|
+
tools = newTools;
|
|
608
|
+
},
|
|
609
|
+
deleteTask(id) {
|
|
610
|
+
const deleted = tasks.delete(id);
|
|
611
|
+
if (deleted) {
|
|
612
|
+
version++;
|
|
613
|
+
}
|
|
614
|
+
return deleted;
|
|
268
615
|
}
|
|
269
616
|
};
|
|
270
617
|
}
|
|
@@ -273,241 +620,33 @@ var AGENT_HANDLER_NAMES = {
|
|
|
273
620
|
waitForStateChange: "waitForStateChange",
|
|
274
621
|
addMessage: "addMessage"
|
|
275
622
|
};
|
|
623
|
+
var askUserQuestionTool = {
|
|
624
|
+
name: "AskUserQuestion",
|
|
625
|
+
description: `Use this tool when you need to ask the user questions during execution. This allows you to:
|
|
276
626
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if (typeof prompt === "function") {
|
|
282
|
-
return prompt();
|
|
283
|
-
}
|
|
284
|
-
return prompt;
|
|
285
|
-
}
|
|
286
|
-
return {
|
|
287
|
-
async getSystemPrompt() {
|
|
288
|
-
const base = await resolvePrompt(baseSystemPrompt);
|
|
289
|
-
const instructions = await resolvePrompt(instructionsPrompt);
|
|
290
|
-
return [base, instructions].join("\n");
|
|
291
|
-
},
|
|
292
|
-
async buildContextMessage(context) {
|
|
293
|
-
return buildContextMessage(context);
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
}
|
|
627
|
+
1. Gather user preferences or requirements
|
|
628
|
+
2. Clarify ambiguous instructions
|
|
629
|
+
3. Get decisions on implementation choices as you work
|
|
630
|
+
4. Offer choices to the user about what direction to take.
|
|
297
631
|
|
|
298
|
-
|
|
299
|
-
function createToolRegistry(tools) {
|
|
300
|
-
const toolMap = /* @__PURE__ */ new Map();
|
|
301
|
-
for (const [_key, tool] of Object.entries(tools)) {
|
|
302
|
-
toolMap.set(tool.name, tool);
|
|
303
|
-
}
|
|
304
|
-
return {
|
|
305
|
-
parseToolCall(toolCall) {
|
|
306
|
-
const tool = toolMap.get(toolCall.name);
|
|
307
|
-
if (!tool) {
|
|
308
|
-
throw new Error(`Tool ${toolCall.name} not found`);
|
|
309
|
-
}
|
|
310
|
-
const parsedArgs = tool.schema.parse(toolCall.args);
|
|
311
|
-
return {
|
|
312
|
-
id: toolCall.id ?? "",
|
|
313
|
-
name: toolCall.name,
|
|
314
|
-
args: parsedArgs
|
|
315
|
-
};
|
|
316
|
-
},
|
|
317
|
-
getToolList() {
|
|
318
|
-
return Object.values(tools);
|
|
319
|
-
},
|
|
320
|
-
getTool(name) {
|
|
321
|
-
return tools[name];
|
|
322
|
-
},
|
|
323
|
-
hasTool(name) {
|
|
324
|
-
return toolMap.has(name);
|
|
325
|
-
},
|
|
326
|
-
getToolNames() {
|
|
327
|
-
return Array.from(toolMap.keys());
|
|
328
|
-
}
|
|
329
|
-
};
|
|
330
|
-
}
|
|
632
|
+
Usage notes:
|
|
331
633
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
await appendToolResult({
|
|
346
|
-
threadId,
|
|
347
|
-
toolCallId: toolCall.id,
|
|
348
|
-
content: JSON.stringify({
|
|
349
|
-
skipped: true,
|
|
350
|
-
reason: "Skipped by PreToolUse hook"
|
|
351
|
-
})
|
|
352
|
-
});
|
|
353
|
-
return null;
|
|
354
|
-
}
|
|
355
|
-
if (preResult?.modifiedArgs !== void 0) {
|
|
356
|
-
effectiveArgs = preResult.modifiedArgs;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
const handler = handlers[toolCall.name];
|
|
360
|
-
let result;
|
|
361
|
-
let content;
|
|
362
|
-
try {
|
|
363
|
-
if (handler) {
|
|
364
|
-
const response = await handler(
|
|
365
|
-
effectiveArgs,
|
|
366
|
-
toolCall.id
|
|
367
|
-
);
|
|
368
|
-
result = response.result;
|
|
369
|
-
content = response.content;
|
|
370
|
-
} else {
|
|
371
|
-
result = { error: `Unknown tool: ${toolCall.name}` };
|
|
372
|
-
content = JSON.stringify(result, null, 2);
|
|
373
|
-
}
|
|
374
|
-
} catch (error) {
|
|
375
|
-
if (hooks?.onPostToolUseFailure) {
|
|
376
|
-
const failureResult = await hooks.onPostToolUseFailure({
|
|
377
|
-
toolCall,
|
|
378
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
379
|
-
threadId,
|
|
380
|
-
turn
|
|
381
|
-
});
|
|
382
|
-
if (failureResult?.fallbackContent !== void 0) {
|
|
383
|
-
content = failureResult.fallbackContent;
|
|
384
|
-
result = { error: String(error), recovered: true };
|
|
385
|
-
} else if (failureResult?.suppress) {
|
|
386
|
-
content = JSON.stringify({ error: String(error), suppressed: true });
|
|
387
|
-
result = { error: String(error), suppressed: true };
|
|
388
|
-
} else {
|
|
389
|
-
throw error;
|
|
390
|
-
}
|
|
391
|
-
} else {
|
|
392
|
-
throw error;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
await appendToolResult({ threadId, toolCallId: toolCall.id, content });
|
|
396
|
-
const toolResult = {
|
|
397
|
-
toolCallId: toolCall.id,
|
|
398
|
-
name: toolCall.name,
|
|
399
|
-
result
|
|
400
|
-
};
|
|
401
|
-
if (hooks?.onPostToolUse) {
|
|
402
|
-
const durationMs = Date.now() - startTime;
|
|
403
|
-
await hooks.onPostToolUse({
|
|
404
|
-
toolCall,
|
|
405
|
-
result: toolResult,
|
|
406
|
-
threadId,
|
|
407
|
-
turn,
|
|
408
|
-
durationMs
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
return toolResult;
|
|
412
|
-
}
|
|
413
|
-
return {
|
|
414
|
-
async processToolCalls(toolCalls, context) {
|
|
415
|
-
if (toolCalls.length === 0) {
|
|
416
|
-
return [];
|
|
417
|
-
}
|
|
418
|
-
const turn = context?.turn ?? 0;
|
|
419
|
-
if (parallel) {
|
|
420
|
-
const results2 = await Promise.all(
|
|
421
|
-
toolCalls.map((tc) => processToolCall(tc, turn))
|
|
422
|
-
);
|
|
423
|
-
return results2.filter(
|
|
424
|
-
(r) => r !== null
|
|
425
|
-
);
|
|
426
|
-
}
|
|
427
|
-
const results = [];
|
|
428
|
-
for (const toolCall of toolCalls) {
|
|
429
|
-
const result = await processToolCall(toolCall, turn);
|
|
430
|
-
if (result !== null) {
|
|
431
|
-
results.push(result);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
return results;
|
|
435
|
-
},
|
|
436
|
-
async processToolCallsByName(toolCalls, toolName, handler) {
|
|
437
|
-
const matchingCalls = toolCalls.filter((tc) => tc.name === toolName);
|
|
438
|
-
if (matchingCalls.length === 0) {
|
|
439
|
-
return [];
|
|
440
|
-
}
|
|
441
|
-
const processOne = async (toolCall) => {
|
|
442
|
-
const response = await handler(
|
|
443
|
-
toolCall.args,
|
|
444
|
-
toolCall.id
|
|
445
|
-
);
|
|
446
|
-
await appendToolResult({
|
|
447
|
-
threadId,
|
|
448
|
-
toolCallId: toolCall.id,
|
|
449
|
-
content: response.content
|
|
450
|
-
});
|
|
451
|
-
return {
|
|
452
|
-
toolCallId: toolCall.id,
|
|
453
|
-
name: toolCall.name,
|
|
454
|
-
result: response.result
|
|
455
|
-
};
|
|
456
|
-
};
|
|
457
|
-
if (parallel) {
|
|
458
|
-
return Promise.all(matchingCalls.map(processOne));
|
|
459
|
-
}
|
|
460
|
-
const results = [];
|
|
461
|
-
for (const toolCall of matchingCalls) {
|
|
462
|
-
results.push(await processOne(toolCall));
|
|
463
|
-
}
|
|
464
|
-
return results;
|
|
465
|
-
},
|
|
466
|
-
filterByName(toolCalls, name) {
|
|
467
|
-
return toolCalls.filter(
|
|
468
|
-
(tc) => tc.name === name
|
|
469
|
-
);
|
|
470
|
-
},
|
|
471
|
-
hasToolCall(toolCalls, name) {
|
|
472
|
-
return toolCalls.some((tc) => tc.name === name);
|
|
473
|
-
},
|
|
474
|
-
getResultsByName(results, name) {
|
|
475
|
-
return results.filter(
|
|
476
|
-
(r) => r.name === name
|
|
477
|
-
);
|
|
478
|
-
}
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
function hasNoOtherToolCalls(toolCalls, excludeName) {
|
|
482
|
-
return toolCalls.filter((tc) => tc.name !== excludeName).length === 0;
|
|
483
|
-
}
|
|
484
|
-
var askUserQuestionTool = {
|
|
485
|
-
name: "AskUserQuestion",
|
|
486
|
-
description: `Use this tool when you need to ask the user questions during execution. This allows you to:
|
|
487
|
-
|
|
488
|
-
1. Gather user preferences or requirements
|
|
489
|
-
2. Clarify ambiguous instructions
|
|
490
|
-
3. Get decisions on implementation choices as you work
|
|
491
|
-
4. Offer choices to the user about what direction to take.
|
|
492
|
-
|
|
493
|
-
Usage notes:
|
|
494
|
-
|
|
495
|
-
* Users will always be able to select "Other" to provide custom text input
|
|
496
|
-
* Use multiSelect: true to allow multiple answers to be selected for a question
|
|
497
|
-
* If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
|
|
498
|
-
`,
|
|
499
|
-
schema: z2__default.default.object({
|
|
500
|
-
questions: z2__default.default.array(
|
|
501
|
-
z2__default.default.object({
|
|
502
|
-
question: z2__default.default.string().describe("The full question text to display"),
|
|
503
|
-
header: z2__default.default.string().describe("Short label for the question (max 12 characters)"),
|
|
504
|
-
options: z2__default.default.array(
|
|
505
|
-
z2__default.default.object({
|
|
506
|
-
label: z2__default.default.string(),
|
|
507
|
-
description: z2__default.default.string()
|
|
634
|
+
* Users will always be able to select "Other" to provide custom text input
|
|
635
|
+
* Use multiSelect: true to allow multiple answers to be selected for a question
|
|
636
|
+
* If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
|
|
637
|
+
`,
|
|
638
|
+
schema: z4.object({
|
|
639
|
+
questions: z4.array(
|
|
640
|
+
z4.object({
|
|
641
|
+
question: z4.string().describe("The full question text to display"),
|
|
642
|
+
header: z4.string().describe("Short label for the question (max 12 characters)"),
|
|
643
|
+
options: z4.array(
|
|
644
|
+
z4.object({
|
|
645
|
+
label: z4.string(),
|
|
646
|
+
description: z4.string()
|
|
508
647
|
})
|
|
509
648
|
).min(0).max(4).describe("Array of 0-4 choices, each with label and description"),
|
|
510
|
-
multiSelect:
|
|
649
|
+
multiSelect: z4.boolean().describe("If true, users can select multiple options")
|
|
511
650
|
})
|
|
512
651
|
)
|
|
513
652
|
}),
|
|
@@ -527,9 +666,9 @@ Examples:
|
|
|
527
666
|
- "**/*.test.ts" - Find all test files recursively
|
|
528
667
|
- "src/**/*.ts" - Find all TypeScript files in src directory
|
|
529
668
|
`,
|
|
530
|
-
schema:
|
|
531
|
-
pattern:
|
|
532
|
-
root:
|
|
669
|
+
schema: z.object({
|
|
670
|
+
pattern: z.string().describe("Glob pattern to match files against"),
|
|
671
|
+
root: z.string().optional().describe("Optional root directory to search from")
|
|
533
672
|
}),
|
|
534
673
|
strict: true
|
|
535
674
|
};
|
|
@@ -547,13 +686,13 @@ Examples:
|
|
|
547
686
|
- Search for function definitions with "function.*handleClick"
|
|
548
687
|
- Search case-insensitively with ignoreCase: true
|
|
549
688
|
`,
|
|
550
|
-
schema:
|
|
551
|
-
pattern:
|
|
552
|
-
ignoreCase:
|
|
553
|
-
maxMatches:
|
|
554
|
-
includePatterns:
|
|
555
|
-
excludePatterns:
|
|
556
|
-
contextLines:
|
|
689
|
+
schema: z.object({
|
|
690
|
+
pattern: z.string().describe("Regex pattern to search for in file contents"),
|
|
691
|
+
ignoreCase: z.boolean().optional().describe("Case-insensitive search (default: false)"),
|
|
692
|
+
maxMatches: z.number().optional().describe("Maximum number of matches to return (default: 50)"),
|
|
693
|
+
includePatterns: z.array(z.string()).optional().describe("Glob patterns to include (e.g., ['*.ts', '*.js'])"),
|
|
694
|
+
excludePatterns: z.array(z.string()).optional().describe("Glob patterns to exclude (e.g., ['*.test.ts'])"),
|
|
695
|
+
contextLines: z.number().optional().describe("Number of context lines to show around matches")
|
|
557
696
|
}),
|
|
558
697
|
strict: true
|
|
559
698
|
};
|
|
@@ -571,12 +710,12 @@ The tool returns the file content in an appropriate format:
|
|
|
571
710
|
- Images: Base64-encoded image data
|
|
572
711
|
- PDFs: Extracted text content
|
|
573
712
|
`,
|
|
574
|
-
schema:
|
|
575
|
-
path:
|
|
576
|
-
offset:
|
|
713
|
+
schema: z.object({
|
|
714
|
+
path: z.string().describe("Virtual path to the file to read"),
|
|
715
|
+
offset: z.number().optional().describe(
|
|
577
716
|
"Line number to start reading from (1-indexed, for text files)"
|
|
578
717
|
),
|
|
579
|
-
limit:
|
|
718
|
+
limit: z.number().optional().describe("Maximum number of lines to read (for text files)")
|
|
580
719
|
}),
|
|
581
720
|
strict: true
|
|
582
721
|
};
|
|
@@ -594,9 +733,9 @@ IMPORTANT:
|
|
|
594
733
|
- This is an atomic write operation - the entire file is replaced
|
|
595
734
|
- Path must be absolute (e.g., "/docs/readme.md", not "docs/readme.md")
|
|
596
735
|
`,
|
|
597
|
-
schema:
|
|
598
|
-
file_path:
|
|
599
|
-
content:
|
|
736
|
+
schema: z.object({
|
|
737
|
+
file_path: z.string().describe("The absolute virtual path to the file to write"),
|
|
738
|
+
content: z.string().describe("The content to write to the file")
|
|
600
739
|
}),
|
|
601
740
|
strict: true
|
|
602
741
|
};
|
|
@@ -616,392 +755,137 @@ IMPORTANT:
|
|
|
616
755
|
- The operation fails if old_string is not found
|
|
617
756
|
- old_string and new_string must be different
|
|
618
757
|
`,
|
|
619
|
-
schema:
|
|
620
|
-
file_path:
|
|
621
|
-
old_string:
|
|
622
|
-
new_string:
|
|
758
|
+
schema: z.object({
|
|
759
|
+
file_path: z.string().describe("The absolute virtual path to the file to modify"),
|
|
760
|
+
old_string: z.string().describe("The exact text to replace"),
|
|
761
|
+
new_string: z.string().describe(
|
|
623
762
|
"The text to replace it with (must be different from old_string)"
|
|
624
763
|
),
|
|
625
|
-
replace_all:
|
|
764
|
+
replace_all: z.boolean().optional().describe(
|
|
626
765
|
"If true, replace all occurrences of old_string (default: false)"
|
|
627
766
|
)
|
|
628
767
|
}),
|
|
629
768
|
strict: true
|
|
630
769
|
};
|
|
631
770
|
|
|
632
|
-
// src/
|
|
633
|
-
function
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
]
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
return false;
|
|
655
|
-
}
|
|
656
|
-
return excludePatterns.some((pattern) => minimatch.minimatch(path, pattern));
|
|
657
|
-
}
|
|
658
|
-
function renderNode(node, options, depth, indent) {
|
|
659
|
-
const lines = [];
|
|
660
|
-
if (options.maxDepth !== void 0 && depth > options.maxDepth) {
|
|
661
|
-
return lines;
|
|
662
|
-
}
|
|
663
|
-
if (isExcluded(node.path, options.excludePatterns)) {
|
|
664
|
-
return lines;
|
|
665
|
-
}
|
|
666
|
-
const parts = node.path.split("/");
|
|
667
|
-
const name = parts[parts.length - 1] || node.path;
|
|
668
|
-
let line = indent;
|
|
669
|
-
if (node.type === "directory") {
|
|
670
|
-
line += `${name}/`;
|
|
671
|
-
} else {
|
|
672
|
-
line += name;
|
|
673
|
-
}
|
|
674
|
-
if (options.showMimeTypes && node.mimeType) {
|
|
675
|
-
line += ` [${node.mimeType}]`;
|
|
676
|
-
}
|
|
677
|
-
if (options.showDescriptions !== false && node.description) {
|
|
678
|
-
line += ` - ${node.description}`;
|
|
679
|
-
}
|
|
680
|
-
lines.push(line);
|
|
681
|
-
if (node.type === "directory" && node.children) {
|
|
682
|
-
const childIndent = indent + " ";
|
|
683
|
-
for (const child of node.children) {
|
|
684
|
-
lines.push(...renderNode(child, options, depth + 1, childIndent));
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
return lines;
|
|
771
|
+
// src/tools/task-create/handler.ts
|
|
772
|
+
function createTaskCreateHandler({
|
|
773
|
+
stateManager,
|
|
774
|
+
idGenerator
|
|
775
|
+
}) {
|
|
776
|
+
return (args) => {
|
|
777
|
+
const task = {
|
|
778
|
+
id: idGenerator(),
|
|
779
|
+
subject: args.subject,
|
|
780
|
+
description: args.description,
|
|
781
|
+
activeForm: args.activeForm,
|
|
782
|
+
status: "pending",
|
|
783
|
+
metadata: args.metadata ?? {},
|
|
784
|
+
blockedBy: [],
|
|
785
|
+
blocks: []
|
|
786
|
+
};
|
|
787
|
+
stateManager.setTask(task);
|
|
788
|
+
return {
|
|
789
|
+
content: JSON.stringify(task, null, 2),
|
|
790
|
+
result: task
|
|
791
|
+
};
|
|
792
|
+
};
|
|
688
793
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
if (lines.length === 0) {
|
|
697
|
-
return `<file_system>
|
|
698
|
-
${header}
|
|
699
|
-
|
|
700
|
-
${description}
|
|
701
|
-
|
|
702
|
-
(no files available)
|
|
703
|
-
</file_system>`;
|
|
704
|
-
}
|
|
705
|
-
return `<file_system>
|
|
706
|
-
${header}
|
|
794
|
+
var taskGetTool = {
|
|
795
|
+
name: "TaskGet",
|
|
796
|
+
description: `Retrieve full task details including dependencies.`,
|
|
797
|
+
schema: z4.object({
|
|
798
|
+
taskId: z4.string().describe("The ID of the task to get")
|
|
799
|
+
})
|
|
800
|
+
};
|
|
707
801
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
if (node.children) {
|
|
718
|
-
for (const child of node.children) {
|
|
719
|
-
traverse(child);
|
|
720
|
-
}
|
|
802
|
+
// src/tools/task-get/handler.ts
|
|
803
|
+
function createTaskGetHandler(stateManager) {
|
|
804
|
+
return (args) => {
|
|
805
|
+
const task = stateManager.getTask(args.taskId) ?? null;
|
|
806
|
+
if (!task) {
|
|
807
|
+
return {
|
|
808
|
+
content: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
|
|
809
|
+
result: null
|
|
810
|
+
};
|
|
721
811
|
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
812
|
+
return {
|
|
813
|
+
content: JSON.stringify(task, null, 2),
|
|
814
|
+
result: task
|
|
815
|
+
};
|
|
816
|
+
};
|
|
727
817
|
}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
818
|
+
var taskListTool = {
|
|
819
|
+
name: "TaskList",
|
|
820
|
+
description: `List all tasks with current state.`,
|
|
821
|
+
schema: z4.object({})
|
|
822
|
+
};
|
|
823
|
+
|
|
824
|
+
// src/tools/task-list/handler.ts
|
|
825
|
+
function createTaskListHandler(stateManager) {
|
|
826
|
+
return (_args) => {
|
|
827
|
+
const taskList = stateManager.getTasks();
|
|
828
|
+
return {
|
|
829
|
+
content: JSON.stringify(taskList, null, 2),
|
|
830
|
+
result: taskList
|
|
831
|
+
};
|
|
832
|
+
};
|
|
731
833
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
834
|
+
var taskUpdateTool = {
|
|
835
|
+
name: "TaskUpdate",
|
|
836
|
+
description: `Update status, add blockers, modify details.`,
|
|
837
|
+
schema: z4.object({
|
|
838
|
+
taskId: z4.string().describe("The ID of the task to get"),
|
|
839
|
+
status: z4.enum(["pending", "in_progress", "completed"]).describe("The status of the task"),
|
|
840
|
+
addBlockedBy: z4.array(z4.string()).describe("The IDs of the tasks that are blocking this task"),
|
|
841
|
+
addBlocks: z4.array(z4.string()).describe("The IDs of the tasks that this task is blocking")
|
|
842
|
+
})
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
// src/tools/task-update/handler.ts
|
|
846
|
+
function createTaskUpdateHandler(stateManager) {
|
|
847
|
+
return (args) => {
|
|
848
|
+
const task = stateManager.getTask(args.taskId);
|
|
849
|
+
if (!task) {
|
|
850
|
+
return {
|
|
851
|
+
content: JSON.stringify({ error: `Task not found: ${args.taskId}` }),
|
|
852
|
+
result: null
|
|
853
|
+
};
|
|
742
854
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
}
|
|
746
|
-
var BaseFileSystemProvider = class {
|
|
747
|
-
scopedNodes;
|
|
748
|
-
allowedPaths;
|
|
749
|
-
constructor(scopedNodes) {
|
|
750
|
-
this.scopedNodes = scopedNodes;
|
|
751
|
-
this.allowedPaths = new Set(flattenFileTree(scopedNodes));
|
|
752
|
-
}
|
|
753
|
-
/**
|
|
754
|
-
* Validate that a path is within the allowed scope.
|
|
755
|
-
* Throws an error if the path is not allowed.
|
|
756
|
-
*/
|
|
757
|
-
validatePath(path) {
|
|
758
|
-
if (!this.allowedPaths.has(path)) {
|
|
759
|
-
throw new Error(`Path "${path}" is not within the allowed scope`);
|
|
855
|
+
if (args.status) {
|
|
856
|
+
task.status = args.status;
|
|
760
857
|
}
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
filterByPattern(paths, pattern, root) {
|
|
766
|
-
const effectivePattern = root ? `${root}/${pattern}` : pattern;
|
|
767
|
-
return paths.filter((path) => {
|
|
768
|
-
if (root && !path.startsWith(root)) {
|
|
769
|
-
return false;
|
|
770
|
-
}
|
|
771
|
-
return minimatch.minimatch(path, effectivePattern, { matchBase: true });
|
|
772
|
-
});
|
|
773
|
-
}
|
|
774
|
-
/**
|
|
775
|
-
* Get all file paths in scope
|
|
776
|
-
*/
|
|
777
|
-
getAllPaths() {
|
|
778
|
-
return Array.from(this.allowedPaths);
|
|
779
|
-
}
|
|
780
|
-
/**
|
|
781
|
-
* Find FileNode by path
|
|
782
|
-
*/
|
|
783
|
-
findNode(path) {
|
|
784
|
-
const findInNodes = (nodes) => {
|
|
785
|
-
for (const node of nodes) {
|
|
786
|
-
if (node.path === path) {
|
|
787
|
-
return node;
|
|
858
|
+
if (args.addBlockedBy) {
|
|
859
|
+
for (const blockerId of args.addBlockedBy) {
|
|
860
|
+
if (!task.blockedBy.includes(blockerId)) {
|
|
861
|
+
task.blockedBy.push(blockerId);
|
|
788
862
|
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
863
|
+
const blockerTask = stateManager.getTask(blockerId);
|
|
864
|
+
if (blockerTask && !blockerTask.blocks.includes(task.id)) {
|
|
865
|
+
blockerTask.blocks.push(task.id);
|
|
866
|
+
stateManager.setTask(blockerTask);
|
|
792
867
|
}
|
|
793
868
|
}
|
|
794
|
-
return void 0;
|
|
795
|
-
};
|
|
796
|
-
return findInNodes(this.scopedNodes);
|
|
797
|
-
}
|
|
798
|
-
/**
|
|
799
|
-
* Read file as text for grep operations.
|
|
800
|
-
* Default implementation uses readFile, but can be overridden for efficiency.
|
|
801
|
-
*/
|
|
802
|
-
async readFileAsText(node) {
|
|
803
|
-
try {
|
|
804
|
-
const content = await this.readFile(node);
|
|
805
|
-
if (content.type === "text") {
|
|
806
|
-
return content.content;
|
|
807
|
-
}
|
|
808
|
-
if (content.type === "pdf") {
|
|
809
|
-
return content.content;
|
|
810
|
-
}
|
|
811
|
-
return null;
|
|
812
|
-
} catch {
|
|
813
|
-
return null;
|
|
814
869
|
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
async grep(pattern, options) {
|
|
825
|
-
const matches = [];
|
|
826
|
-
const maxMatches = options?.maxMatches ?? 50;
|
|
827
|
-
const flags = options?.ignoreCase ? "gi" : "g";
|
|
828
|
-
let regex;
|
|
829
|
-
try {
|
|
830
|
-
regex = new RegExp(pattern, flags);
|
|
831
|
-
} catch {
|
|
832
|
-
throw new Error(`Invalid regex pattern: ${pattern}`);
|
|
833
|
-
}
|
|
834
|
-
let paths = this.getAllPaths();
|
|
835
|
-
if (options?.includePatterns?.length) {
|
|
836
|
-
const includePatterns = options.includePatterns;
|
|
837
|
-
paths = paths.filter(
|
|
838
|
-
(path) => includePatterns.some((p) => minimatch.minimatch(path, p, { matchBase: true }))
|
|
839
|
-
);
|
|
840
|
-
}
|
|
841
|
-
if (options?.excludePatterns?.length) {
|
|
842
|
-
const excludePatterns = options.excludePatterns;
|
|
843
|
-
paths = paths.filter(
|
|
844
|
-
(path) => !excludePatterns.some((p) => minimatch.minimatch(path, p, { matchBase: true }))
|
|
845
|
-
);
|
|
846
|
-
}
|
|
847
|
-
for (const path of paths) {
|
|
848
|
-
if (matches.length >= maxMatches) break;
|
|
849
|
-
const node = this.findNode(path);
|
|
850
|
-
if (!node || node.type !== "file") continue;
|
|
851
|
-
const text = await this.readFileAsText(node);
|
|
852
|
-
if (!text) continue;
|
|
853
|
-
const lines = text.split("\n");
|
|
854
|
-
for (let i = 0; i < lines.length; i++) {
|
|
855
|
-
if (matches.length >= maxMatches) break;
|
|
856
|
-
const line = lines[i];
|
|
857
|
-
if (line === void 0) continue;
|
|
858
|
-
if (regex.test(line)) {
|
|
859
|
-
regex.lastIndex = 0;
|
|
860
|
-
const match = {
|
|
861
|
-
path,
|
|
862
|
-
lineNumber: i + 1,
|
|
863
|
-
line: line.trim()
|
|
864
|
-
};
|
|
865
|
-
if (options?.contextLines && options.contextLines > 0) {
|
|
866
|
-
const contextBefore = [];
|
|
867
|
-
const contextAfter = [];
|
|
868
|
-
for (let j = Math.max(0, i - options.contextLines); j < i; j++) {
|
|
869
|
-
const contextLine = lines[j];
|
|
870
|
-
if (contextLine !== void 0) {
|
|
871
|
-
contextBefore.push(contextLine.trim());
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
for (let j = i + 1; j <= Math.min(lines.length - 1, i + options.contextLines); j++) {
|
|
875
|
-
const contextLine = lines[j];
|
|
876
|
-
if (contextLine !== void 0) {
|
|
877
|
-
contextAfter.push(contextLine.trim());
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
match.contextBefore = contextBefore;
|
|
881
|
-
match.contextAfter = contextAfter;
|
|
882
|
-
}
|
|
883
|
-
matches.push(match);
|
|
870
|
+
if (args.addBlocks) {
|
|
871
|
+
for (const blockedId of args.addBlocks) {
|
|
872
|
+
if (!task.blocks.includes(blockedId)) {
|
|
873
|
+
task.blocks.push(blockedId);
|
|
874
|
+
}
|
|
875
|
+
const blockedTask = stateManager.getTask(blockedId);
|
|
876
|
+
if (blockedTask && !blockedTask.blockedBy.includes(task.id)) {
|
|
877
|
+
blockedTask.blockedBy.push(task.id);
|
|
878
|
+
stateManager.setTask(blockedTask);
|
|
884
879
|
}
|
|
885
880
|
}
|
|
886
881
|
}
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
}
|
|
895
|
-
if (node.type !== "file") {
|
|
896
|
-
throw new Error(`Path is a directory, not a file: ${path}`);
|
|
897
|
-
}
|
|
898
|
-
return this.readFile(node);
|
|
899
|
-
}
|
|
900
|
-
async exists(path) {
|
|
901
|
-
return this.allowedPaths.has(path);
|
|
902
|
-
}
|
|
903
|
-
};
|
|
904
|
-
var InMemoryFileSystemProvider = class _InMemoryFileSystemProvider extends BaseFileSystemProvider {
|
|
905
|
-
files;
|
|
906
|
-
constructor(scopedNodes, files) {
|
|
907
|
-
super(scopedNodes);
|
|
908
|
-
this.files = files;
|
|
909
|
-
}
|
|
910
|
-
async readFile(node) {
|
|
911
|
-
const content = this.files.get(node.path);
|
|
912
|
-
if (!content) {
|
|
913
|
-
throw new Error(`File not found in storage: ${node.path}`);
|
|
914
|
-
}
|
|
915
|
-
return content;
|
|
916
|
-
}
|
|
917
|
-
/**
|
|
918
|
-
* Add or update a file in the in-memory storage
|
|
919
|
-
*/
|
|
920
|
-
setFile(path, content) {
|
|
921
|
-
this.files.set(path, content);
|
|
922
|
-
}
|
|
923
|
-
/**
|
|
924
|
-
* Write text content to a file
|
|
925
|
-
*/
|
|
926
|
-
async write(path, content) {
|
|
927
|
-
this.validatePath(path);
|
|
928
|
-
this.files.set(path, { type: "text", content });
|
|
929
|
-
}
|
|
930
|
-
/**
|
|
931
|
-
* Create an InMemoryFileSystemProvider from a simple object map
|
|
932
|
-
*/
|
|
933
|
-
static fromTextFiles(scopedNodes, files) {
|
|
934
|
-
const fileMap = /* @__PURE__ */ new Map();
|
|
935
|
-
for (const [path, content] of Object.entries(files)) {
|
|
936
|
-
fileMap.set(path, { type: "text", content });
|
|
937
|
-
}
|
|
938
|
-
return new _InMemoryFileSystemProvider(scopedNodes, fileMap);
|
|
939
|
-
}
|
|
940
|
-
};
|
|
941
|
-
var CompositeFileSystemProvider = class extends BaseFileSystemProvider {
|
|
942
|
-
backends;
|
|
943
|
-
defaultBackend;
|
|
944
|
-
defaultResolver;
|
|
945
|
-
constructor(scopedNodes, config) {
|
|
946
|
-
super(scopedNodes);
|
|
947
|
-
this.backends = new Map(Object.entries(config.backends));
|
|
948
|
-
this.defaultBackend = config.defaultBackend;
|
|
949
|
-
this.defaultResolver = config.defaultResolver;
|
|
950
|
-
}
|
|
951
|
-
/**
|
|
952
|
-
* Get the backend name for a file node
|
|
953
|
-
*/
|
|
954
|
-
getBackendName(node) {
|
|
955
|
-
const backend = node.metadata?.backend;
|
|
956
|
-
if (typeof backend === "string") {
|
|
957
|
-
return backend;
|
|
958
|
-
}
|
|
959
|
-
return this.defaultBackend;
|
|
960
|
-
}
|
|
961
|
-
/**
|
|
962
|
-
* Resolve content using a resolver (function or provider)
|
|
963
|
-
*/
|
|
964
|
-
async resolveContent(resolver, node) {
|
|
965
|
-
if (typeof resolver === "function") {
|
|
966
|
-
return resolver(node);
|
|
967
|
-
}
|
|
968
|
-
return resolver.read(node.path);
|
|
969
|
-
}
|
|
970
|
-
async readFile(node) {
|
|
971
|
-
const backendName = this.getBackendName(node);
|
|
972
|
-
if (backendName) {
|
|
973
|
-
const config = this.backends.get(backendName);
|
|
974
|
-
if (config) {
|
|
975
|
-
return this.resolveContent(config.resolver, node);
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
if (this.defaultResolver) {
|
|
979
|
-
return this.defaultResolver(node);
|
|
980
|
-
}
|
|
981
|
-
const availableBackends = Array.from(this.backends.keys()).join(", ");
|
|
982
|
-
throw new Error(
|
|
983
|
-
`No resolver for file "${node.path}". Backend: ${backendName ?? "(none)"}. Available backends: ${availableBackends || "(none)"}`
|
|
984
|
-
);
|
|
985
|
-
}
|
|
986
|
-
/**
|
|
987
|
-
* Add or update a backend configuration
|
|
988
|
-
*/
|
|
989
|
-
setBackend(name, config) {
|
|
990
|
-
this.backends.set(name, config);
|
|
991
|
-
}
|
|
992
|
-
/**
|
|
993
|
-
* Remove a backend
|
|
994
|
-
*/
|
|
995
|
-
removeBackend(name) {
|
|
996
|
-
return this.backends.delete(name);
|
|
997
|
-
}
|
|
998
|
-
/**
|
|
999
|
-
* Check if a backend exists
|
|
1000
|
-
*/
|
|
1001
|
-
hasBackend(name) {
|
|
1002
|
-
return this.backends.has(name);
|
|
1003
|
-
}
|
|
1004
|
-
};
|
|
882
|
+
stateManager.setTask(task);
|
|
883
|
+
return {
|
|
884
|
+
content: JSON.stringify(task, null, 2),
|
|
885
|
+
result: task
|
|
886
|
+
};
|
|
887
|
+
};
|
|
888
|
+
}
|
|
1005
889
|
|
|
1006
890
|
// node_modules/uuid/dist/esm-node/stringify.js
|
|
1007
891
|
var byteToHex = [];
|
|
@@ -1015,13 +899,13 @@ var rnds8Pool = new Uint8Array(256);
|
|
|
1015
899
|
var poolPtr = rnds8Pool.length;
|
|
1016
900
|
function rng() {
|
|
1017
901
|
if (poolPtr > rnds8Pool.length - 16) {
|
|
1018
|
-
|
|
902
|
+
crypto.randomFillSync(rnds8Pool);
|
|
1019
903
|
poolPtr = 0;
|
|
1020
904
|
}
|
|
1021
905
|
return rnds8Pool.slice(poolPtr, poolPtr += 16);
|
|
1022
906
|
}
|
|
1023
907
|
var native_default = {
|
|
1024
|
-
randomUUID:
|
|
908
|
+
randomUUID: crypto.randomUUID
|
|
1025
909
|
};
|
|
1026
910
|
|
|
1027
911
|
// node_modules/uuid/dist/esm-node/v4.js
|
|
@@ -1070,13 +954,13 @@ function createThreadManager(config) {
|
|
|
1070
954
|
await redis.del(redisKey);
|
|
1071
955
|
},
|
|
1072
956
|
createHumanMessage(content) {
|
|
1073
|
-
return new
|
|
957
|
+
return new HumanMessage({
|
|
1074
958
|
id: v4_default(),
|
|
1075
959
|
content
|
|
1076
960
|
}).toDict();
|
|
1077
961
|
},
|
|
1078
962
|
createAIMessage(content, kwargs) {
|
|
1079
|
-
return new
|
|
963
|
+
return new AIMessage({
|
|
1080
964
|
id: v4_default(),
|
|
1081
965
|
content,
|
|
1082
966
|
additional_kwargs: kwargs ? {
|
|
@@ -1087,12 +971,21 @@ function createThreadManager(config) {
|
|
|
1087
971
|
}).toDict();
|
|
1088
972
|
},
|
|
1089
973
|
createToolMessage(content, toolCallId) {
|
|
1090
|
-
return new
|
|
974
|
+
return new ToolMessage({
|
|
1091
975
|
// Cast needed due to langchain type compatibility
|
|
1092
976
|
content,
|
|
1093
977
|
tool_call_id: toolCallId
|
|
1094
978
|
}).toDict();
|
|
1095
979
|
},
|
|
980
|
+
createSystemMessage(content) {
|
|
981
|
+
return new SystemMessage({
|
|
982
|
+
content
|
|
983
|
+
}).toDict();
|
|
984
|
+
},
|
|
985
|
+
async appendSystemMessage(content) {
|
|
986
|
+
const message = this.createSystemMessage(content);
|
|
987
|
+
await this.append([message]);
|
|
988
|
+
},
|
|
1096
989
|
async appendHumanMessage(content) {
|
|
1097
990
|
const message = this.createHumanMessage(content);
|
|
1098
991
|
await this.append([message]);
|
|
@@ -1109,6 +1002,10 @@ function createThreadManager(config) {
|
|
|
1109
1002
|
}
|
|
1110
1003
|
function createSharedActivities(redis) {
|
|
1111
1004
|
return {
|
|
1005
|
+
async appendSystemMessage(threadId, content) {
|
|
1006
|
+
const thread = createThreadManager({ redis, threadId });
|
|
1007
|
+
await thread.appendSystemMessage(content);
|
|
1008
|
+
},
|
|
1112
1009
|
async appendToolResult(config) {
|
|
1113
1010
|
const { threadId, toolCallId, content } = config;
|
|
1114
1011
|
const thread = createThreadManager({ redis, threadId });
|
|
@@ -1127,7 +1024,7 @@ function createSharedActivities(redis) {
|
|
|
1127
1024
|
await thread.appendHumanMessage(content);
|
|
1128
1025
|
},
|
|
1129
1026
|
async parseToolCalls(storedMessage) {
|
|
1130
|
-
const message =
|
|
1027
|
+
const message = mapStoredMessageToChatMessage(storedMessage);
|
|
1131
1028
|
const toolCalls = message.tool_calls ?? [];
|
|
1132
1029
|
return toolCalls.map((toolCall) => ({
|
|
1133
1030
|
id: toolCall.id,
|
|
@@ -1139,7 +1036,7 @@ function createSharedActivities(redis) {
|
|
|
1139
1036
|
}
|
|
1140
1037
|
|
|
1141
1038
|
// src/plugin.ts
|
|
1142
|
-
var ZeitlichPlugin = class extends
|
|
1039
|
+
var ZeitlichPlugin = class extends SimplePlugin {
|
|
1143
1040
|
constructor(options) {
|
|
1144
1041
|
super({
|
|
1145
1042
|
name: "ZeitlichPlugin",
|
|
@@ -1147,15 +1044,22 @@ var ZeitlichPlugin = class extends plugin.SimplePlugin {
|
|
|
1147
1044
|
});
|
|
1148
1045
|
}
|
|
1149
1046
|
};
|
|
1150
|
-
async function invokeModel(
|
|
1047
|
+
async function invokeModel({
|
|
1048
|
+
redis,
|
|
1049
|
+
model,
|
|
1050
|
+
client,
|
|
1051
|
+
config: { threadId, agentName }
|
|
1052
|
+
}) {
|
|
1151
1053
|
const thread = createThreadManager({ redis, threadId });
|
|
1152
1054
|
const runId = v4_default();
|
|
1153
|
-
const
|
|
1055
|
+
const info = Context.current().info;
|
|
1056
|
+
const parentWorkflowId = info.workflowExecution.workflowId;
|
|
1057
|
+
const parentRunId = info.workflowExecution.runId;
|
|
1058
|
+
const handle = client.getHandle(parentWorkflowId, parentRunId);
|
|
1059
|
+
const { tools } = await handle.query(getStateQuery);
|
|
1060
|
+
const messages = await thread.load();
|
|
1154
1061
|
const response = await model.invoke(
|
|
1155
|
-
[
|
|
1156
|
-
new messages.SystemMessage(systemPrompt),
|
|
1157
|
-
...messages.mapStoredMessagesToChatMessages(messages$1)
|
|
1158
|
-
],
|
|
1062
|
+
[...mapStoredMessagesToChatMessages(messages)],
|
|
1159
1063
|
{
|
|
1160
1064
|
runName: agentName,
|
|
1161
1065
|
runId,
|
|
@@ -1175,8 +1079,8 @@ async function invokeModel(redis, { threadId, agentName, tools }, model, { syste
|
|
|
1175
1079
|
};
|
|
1176
1080
|
}
|
|
1177
1081
|
var handleAskUserQuestionToolResult = async (args) => {
|
|
1178
|
-
const messages
|
|
1179
|
-
({ question, header, options, multiSelect }) => new
|
|
1082
|
+
const messages = args.questions.map(
|
|
1083
|
+
({ question, header, options, multiSelect }) => new AIMessage({
|
|
1180
1084
|
content: question,
|
|
1181
1085
|
additional_kwargs: {
|
|
1182
1086
|
header,
|
|
@@ -1185,292 +1089,37 @@ var handleAskUserQuestionToolResult = async (args) => {
|
|
|
1185
1089
|
}
|
|
1186
1090
|
}).toDict()
|
|
1187
1091
|
);
|
|
1188
|
-
return { content: "Question submitted", result: { chatMessages: messages
|
|
1092
|
+
return { content: "Question submitted", result: { chatMessages: messages } };
|
|
1189
1093
|
};
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
const matches = await config.provider.glob(pattern, root);
|
|
1197
|
-
if (matches.length === 0) {
|
|
1198
|
-
return {
|
|
1199
|
-
content: `No files found matching pattern: ${pattern}`,
|
|
1200
|
-
result: { files: [] }
|
|
1201
|
-
};
|
|
1202
|
-
}
|
|
1203
|
-
const paths = matches.map((node) => node.path);
|
|
1204
|
-
const fileList = paths.map((p) => ` ${p}`).join("\n");
|
|
1205
|
-
return {
|
|
1206
|
-
content: `Found ${matches.length} file(s) matching "${pattern}":
|
|
1207
|
-
${fileList}`,
|
|
1208
|
-
result: { files: matches }
|
|
1209
|
-
};
|
|
1210
|
-
} catch (error) {
|
|
1211
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1212
|
-
return {
|
|
1213
|
-
content: `Error searching for files: ${message}`,
|
|
1214
|
-
result: { files: [] }
|
|
1215
|
-
};
|
|
1216
|
-
}
|
|
1217
|
-
};
|
|
1218
|
-
}
|
|
1219
|
-
|
|
1220
|
-
// src/tools/grep/handler.ts
|
|
1221
|
-
function formatMatch(match, showContext) {
|
|
1222
|
-
const lines = [];
|
|
1223
|
-
if (showContext && match.contextBefore?.length) {
|
|
1224
|
-
for (let i = 0; i < match.contextBefore.length; i++) {
|
|
1225
|
-
const lineNum = match.lineNumber - match.contextBefore.length + i;
|
|
1226
|
-
lines.push(`${match.path}:${lineNum}-${match.contextBefore[i]}`);
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
lines.push(`${match.path}:${match.lineNumber}:${match.line}`);
|
|
1230
|
-
if (showContext && match.contextAfter?.length) {
|
|
1231
|
-
for (let i = 0; i < match.contextAfter.length; i++) {
|
|
1232
|
-
const lineNum = match.lineNumber + 1 + i;
|
|
1233
|
-
lines.push(`${match.path}:${lineNum}-${match.contextAfter[i]}`);
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
return lines.join("\n");
|
|
1237
|
-
}
|
|
1238
|
-
function createGrepHandler(config) {
|
|
1239
|
-
return async (args) => {
|
|
1240
|
-
const {
|
|
1241
|
-
pattern,
|
|
1242
|
-
ignoreCase,
|
|
1243
|
-
maxMatches,
|
|
1244
|
-
includePatterns,
|
|
1245
|
-
excludePatterns,
|
|
1246
|
-
contextLines
|
|
1247
|
-
} = args;
|
|
1248
|
-
try {
|
|
1249
|
-
const matches = await config.provider.grep(pattern, {
|
|
1250
|
-
ignoreCase,
|
|
1251
|
-
maxMatches: maxMatches ?? 50,
|
|
1252
|
-
includePatterns,
|
|
1253
|
-
excludePatterns,
|
|
1254
|
-
contextLines
|
|
1255
|
-
});
|
|
1256
|
-
if (matches.length === 0) {
|
|
1257
|
-
return {
|
|
1258
|
-
content: `No matches found for pattern: ${pattern}`,
|
|
1259
|
-
result: { matches: [] }
|
|
1260
|
-
};
|
|
1261
|
-
}
|
|
1262
|
-
const showContext = contextLines !== void 0 && contextLines > 0;
|
|
1263
|
-
const formattedMatches = matches.map((m) => formatMatch(m, showContext)).join("\n");
|
|
1264
|
-
return {
|
|
1265
|
-
content: `Found ${matches.length} match(es) for "${pattern}":
|
|
1266
|
-
|
|
1267
|
-
${formattedMatches}`,
|
|
1268
|
-
result: { matches }
|
|
1269
|
-
};
|
|
1270
|
-
} catch (error) {
|
|
1271
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1272
|
-
return {
|
|
1273
|
-
content: `Error searching file contents: ${message}`,
|
|
1274
|
-
result: { matches: [] }
|
|
1275
|
-
};
|
|
1276
|
-
}
|
|
1277
|
-
};
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
|
-
// src/tools/read/handler.ts
|
|
1281
|
-
function applyTextRange(content, offset, limit) {
|
|
1282
|
-
if (offset === void 0 && limit === void 0) {
|
|
1283
|
-
return content;
|
|
1284
|
-
}
|
|
1285
|
-
const lines = content.split("\n");
|
|
1286
|
-
const startLine = offset !== void 0 ? Math.max(0, offset - 1) : 0;
|
|
1287
|
-
const endLine = limit !== void 0 ? startLine + limit : lines.length;
|
|
1288
|
-
const selectedLines = lines.slice(startLine, endLine);
|
|
1289
|
-
return selectedLines.map((line, i) => {
|
|
1290
|
-
const lineNum = (startLine + i + 1).toString().padStart(6, " ");
|
|
1291
|
-
return `${lineNum}|${line}`;
|
|
1292
|
-
}).join("\n");
|
|
1293
|
-
}
|
|
1294
|
-
function createReadHandler(config) {
|
|
1295
|
-
return async (args) => {
|
|
1296
|
-
const { path, offset, limit } = args;
|
|
1297
|
-
if (!isPathInScope(path, config.scopedNodes)) {
|
|
1298
|
-
return {
|
|
1299
|
-
content: [
|
|
1300
|
-
{
|
|
1301
|
-
type: "text",
|
|
1302
|
-
text: `Error: Path "${path}" is not within the available file system scope.`
|
|
1303
|
-
}
|
|
1304
|
-
],
|
|
1305
|
-
result: {
|
|
1306
|
-
path,
|
|
1307
|
-
content: {
|
|
1308
|
-
type: "text",
|
|
1309
|
-
content: "Error: Path is not within the available file system scope."
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
};
|
|
1313
|
-
}
|
|
1314
|
-
try {
|
|
1315
|
-
const exists = await config.provider.exists(path);
|
|
1316
|
-
if (!exists) {
|
|
1317
|
-
return {
|
|
1318
|
-
content: [
|
|
1319
|
-
{
|
|
1320
|
-
type: "text",
|
|
1321
|
-
text: `Error: File "${path}" does not exist.`
|
|
1322
|
-
}
|
|
1323
|
-
],
|
|
1324
|
-
result: {
|
|
1325
|
-
path,
|
|
1326
|
-
content: { type: "text", content: "Error: File does not exist." }
|
|
1327
|
-
}
|
|
1328
|
-
};
|
|
1329
|
-
}
|
|
1330
|
-
const fileContent = await config.provider.read(path);
|
|
1331
|
-
if (fileContent.type === "text") {
|
|
1332
|
-
const processedContent = applyTextRange(
|
|
1333
|
-
fileContent.content,
|
|
1334
|
-
offset,
|
|
1335
|
-
limit
|
|
1336
|
-
);
|
|
1337
|
-
let header = `File: ${path}`;
|
|
1338
|
-
if (offset !== void 0 || limit !== void 0) {
|
|
1339
|
-
const startLine = offset ?? 1;
|
|
1340
|
-
const endInfo = limit ? `, showing ${limit} lines` : "";
|
|
1341
|
-
header += ` (from line ${startLine}${endInfo})`;
|
|
1342
|
-
}
|
|
1343
|
-
return {
|
|
1344
|
-
content: [
|
|
1345
|
-
{
|
|
1346
|
-
type: "text",
|
|
1347
|
-
text: `${header}
|
|
1348
|
-
|
|
1349
|
-
${processedContent}`
|
|
1350
|
-
}
|
|
1351
|
-
],
|
|
1352
|
-
result: {
|
|
1353
|
-
path,
|
|
1354
|
-
content: {
|
|
1355
|
-
type: "text",
|
|
1356
|
-
content: `${header}
|
|
1357
|
-
|
|
1358
|
-
${processedContent}`
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
};
|
|
1362
|
-
}
|
|
1363
|
-
const messageContent = fileContentToMessageContent(fileContent);
|
|
1364
|
-
return {
|
|
1365
|
-
content: [
|
|
1366
|
-
{
|
|
1367
|
-
type: "text",
|
|
1368
|
-
text: `File: ${path} (${fileContent.type})`
|
|
1369
|
-
},
|
|
1370
|
-
...messageContent
|
|
1371
|
-
],
|
|
1372
|
-
result: { path, content: fileContent }
|
|
1373
|
-
};
|
|
1374
|
-
} catch (error) {
|
|
1375
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1376
|
-
return {
|
|
1377
|
-
content: [
|
|
1378
|
-
{
|
|
1379
|
-
type: "text",
|
|
1380
|
-
text: `Error reading file "${path}": ${message}`
|
|
1381
|
-
}
|
|
1382
|
-
],
|
|
1383
|
-
result: {
|
|
1384
|
-
path,
|
|
1385
|
-
content: {
|
|
1386
|
-
type: "text",
|
|
1387
|
-
content: `Error reading file "${path}": ${message}`
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
};
|
|
1391
|
-
}
|
|
1392
|
-
};
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
// src/tools/write/handler.ts
|
|
1396
|
-
function createWriteHandler(config) {
|
|
1397
|
-
return async (args) => {
|
|
1398
|
-
const { file_path, content } = args;
|
|
1399
|
-
if (!isPathInScope(file_path, config.scopedNodes)) {
|
|
1400
|
-
return {
|
|
1401
|
-
content: `Error: Path "${file_path}" is not within the available file system scope.`,
|
|
1402
|
-
result: {
|
|
1403
|
-
path: file_path,
|
|
1404
|
-
success: false,
|
|
1405
|
-
created: false,
|
|
1406
|
-
bytesWritten: 0
|
|
1407
|
-
}
|
|
1408
|
-
};
|
|
1409
|
-
}
|
|
1410
|
-
if (!config.skipReadCheck && !config.readFiles.has(file_path)) {
|
|
1411
|
-
const exists = await config.provider.exists(file_path);
|
|
1412
|
-
if (exists) {
|
|
1413
|
-
return {
|
|
1414
|
-
content: `Error: You must read "${file_path}" before writing to it. Use FileRead first.`,
|
|
1415
|
-
result: {
|
|
1416
|
-
path: file_path,
|
|
1417
|
-
success: false,
|
|
1418
|
-
created: false,
|
|
1419
|
-
bytesWritten: 0
|
|
1420
|
-
}
|
|
1421
|
-
};
|
|
1422
|
-
}
|
|
1423
|
-
}
|
|
1424
|
-
try {
|
|
1425
|
-
const exists = await config.provider.exists(file_path);
|
|
1426
|
-
if (!config.provider.write) {
|
|
1427
|
-
return {
|
|
1428
|
-
content: `Error: The file system provider does not support write operations.`,
|
|
1429
|
-
result: {
|
|
1430
|
-
path: file_path,
|
|
1431
|
-
success: false,
|
|
1432
|
-
created: false,
|
|
1433
|
-
bytesWritten: 0
|
|
1434
|
-
}
|
|
1435
|
-
};
|
|
1436
|
-
}
|
|
1437
|
-
await config.provider.write(file_path, content);
|
|
1438
|
-
const bytesWritten = Buffer.byteLength(content, "utf-8");
|
|
1439
|
-
const action = exists ? "Updated" : "Created";
|
|
1440
|
-
return {
|
|
1441
|
-
content: `${action} file: ${file_path} (${bytesWritten} bytes)`,
|
|
1442
|
-
result: {
|
|
1443
|
-
path: file_path,
|
|
1444
|
-
success: true,
|
|
1445
|
-
created: !exists,
|
|
1446
|
-
bytesWritten
|
|
1447
|
-
}
|
|
1448
|
-
};
|
|
1449
|
-
} catch (error) {
|
|
1450
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1451
|
-
return {
|
|
1452
|
-
content: `Error writing file "${file_path}": ${message}`,
|
|
1453
|
-
result: {
|
|
1454
|
-
path: file_path,
|
|
1455
|
-
success: false,
|
|
1456
|
-
created: false,
|
|
1457
|
-
bytesWritten: 0
|
|
1458
|
-
}
|
|
1459
|
-
};
|
|
1460
|
-
}
|
|
1461
|
-
};
|
|
1094
|
+
async function globHandler(_args, fs) {
|
|
1095
|
+
new Bash({ fs });
|
|
1096
|
+
return Promise.resolve({
|
|
1097
|
+
content: "Hello, world!",
|
|
1098
|
+
result: { files: [] }
|
|
1099
|
+
});
|
|
1462
1100
|
}
|
|
1463
1101
|
|
|
1464
1102
|
// src/tools/edit/handler.ts
|
|
1465
1103
|
function escapeRegExp(str) {
|
|
1466
1104
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1467
1105
|
}
|
|
1468
|
-
function
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1106
|
+
async function editHandler(args, fs) {
|
|
1107
|
+
const { file_path, old_string, new_string, replace_all = false } = args;
|
|
1108
|
+
if (old_string === new_string) {
|
|
1109
|
+
return {
|
|
1110
|
+
content: `Error: old_string and new_string must be different.`,
|
|
1111
|
+
result: {
|
|
1112
|
+
path: file_path,
|
|
1113
|
+
success: false,
|
|
1114
|
+
replacements: 0
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
try {
|
|
1119
|
+
const exists = await fs.exists(file_path);
|
|
1120
|
+
if (!exists) {
|
|
1472
1121
|
return {
|
|
1473
|
-
content: `Error:
|
|
1122
|
+
content: `Error: File "${file_path}" does not exist.`,
|
|
1474
1123
|
result: {
|
|
1475
1124
|
path: file_path,
|
|
1476
1125
|
success: false,
|
|
@@ -1478,9 +1127,10 @@ function createEditHandler(config) {
|
|
|
1478
1127
|
}
|
|
1479
1128
|
};
|
|
1480
1129
|
}
|
|
1481
|
-
|
|
1130
|
+
const content = await fs.readFile(file_path);
|
|
1131
|
+
if (!content.includes(old_string)) {
|
|
1482
1132
|
return {
|
|
1483
|
-
content: `Error:
|
|
1133
|
+
content: `Error: Could not find the specified text in "${file_path}". Make sure old_string matches exactly (whitespace-sensitive).`,
|
|
1484
1134
|
result: {
|
|
1485
1135
|
path: file_path,
|
|
1486
1136
|
success: false,
|
|
@@ -1488,9 +1138,12 @@ function createEditHandler(config) {
|
|
|
1488
1138
|
}
|
|
1489
1139
|
};
|
|
1490
1140
|
}
|
|
1491
|
-
|
|
1141
|
+
const escapedOldString = escapeRegExp(old_string);
|
|
1142
|
+
const globalRegex = new RegExp(escapedOldString, "g");
|
|
1143
|
+
const occurrences = (content.match(globalRegex) || []).length;
|
|
1144
|
+
if (!replace_all && occurrences > 1) {
|
|
1492
1145
|
return {
|
|
1493
|
-
content: `Error:
|
|
1146
|
+
content: `Error: old_string appears ${occurrences} times in "${file_path}". Either provide more context to make it unique, or use replace_all: true.`,
|
|
1494
1147
|
result: {
|
|
1495
1148
|
path: file_path,
|
|
1496
1149
|
success: false,
|
|
@@ -1498,131 +1151,128 @@ function createEditHandler(config) {
|
|
|
1498
1151
|
}
|
|
1499
1152
|
};
|
|
1500
1153
|
}
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
replacements: 0
|
|
1520
|
-
}
|
|
1521
|
-
};
|
|
1522
|
-
}
|
|
1523
|
-
const fileContent = await config.provider.read(file_path);
|
|
1524
|
-
if (fileContent.type !== "text") {
|
|
1525
|
-
return {
|
|
1526
|
-
content: `Error: FileEdit only works with text files. "${file_path}" is ${fileContent.type}.`,
|
|
1527
|
-
result: {
|
|
1528
|
-
path: file_path,
|
|
1529
|
-
success: false,
|
|
1530
|
-
replacements: 0
|
|
1531
|
-
}
|
|
1532
|
-
};
|
|
1533
|
-
}
|
|
1534
|
-
const content = fileContent.content;
|
|
1535
|
-
if (!content.includes(old_string)) {
|
|
1536
|
-
return {
|
|
1537
|
-
content: `Error: Could not find the specified text in "${file_path}". Make sure old_string matches exactly (whitespace-sensitive).`,
|
|
1538
|
-
result: {
|
|
1539
|
-
path: file_path,
|
|
1540
|
-
success: false,
|
|
1541
|
-
replacements: 0
|
|
1542
|
-
}
|
|
1543
|
-
};
|
|
1544
|
-
}
|
|
1545
|
-
const escapedOldString = escapeRegExp(old_string);
|
|
1546
|
-
const globalRegex = new RegExp(escapedOldString, "g");
|
|
1547
|
-
const occurrences = (content.match(globalRegex) || []).length;
|
|
1548
|
-
if (!replace_all && occurrences > 1) {
|
|
1549
|
-
return {
|
|
1550
|
-
content: `Error: old_string appears ${occurrences} times in "${file_path}". Either provide more context to make it unique, or use replace_all: true.`,
|
|
1551
|
-
result: {
|
|
1552
|
-
path: file_path,
|
|
1553
|
-
success: false,
|
|
1554
|
-
replacements: 0
|
|
1555
|
-
}
|
|
1556
|
-
};
|
|
1154
|
+
let newContent;
|
|
1155
|
+
let replacements;
|
|
1156
|
+
if (replace_all) {
|
|
1157
|
+
newContent = content.split(old_string).join(new_string);
|
|
1158
|
+
replacements = occurrences;
|
|
1159
|
+
} else {
|
|
1160
|
+
const index = content.indexOf(old_string);
|
|
1161
|
+
newContent = content.slice(0, index) + new_string + content.slice(index + old_string.length);
|
|
1162
|
+
replacements = 1;
|
|
1163
|
+
}
|
|
1164
|
+
await fs.writeFile(file_path, newContent);
|
|
1165
|
+
const summary = replace_all ? `Replaced ${replacements} occurrence(s)` : `Replaced 1 occurrence`;
|
|
1166
|
+
return {
|
|
1167
|
+
content: `${summary} in ${file_path}`,
|
|
1168
|
+
result: {
|
|
1169
|
+
path: file_path,
|
|
1170
|
+
success: true,
|
|
1171
|
+
replacements
|
|
1557
1172
|
}
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
replacements
|
|
1173
|
+
};
|
|
1174
|
+
} catch (error) {
|
|
1175
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1176
|
+
return {
|
|
1177
|
+
content: `Error editing file "${file_path}": ${message}`,
|
|
1178
|
+
result: {
|
|
1179
|
+
path: file_path,
|
|
1180
|
+
success: false,
|
|
1181
|
+
replacements: 0
|
|
1567
1182
|
}
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
var handleBashTool = (fs) => async (args, _context) => {
|
|
1187
|
+
const { command } = args;
|
|
1188
|
+
const bashOptions = fs ? { fs } : {};
|
|
1189
|
+
const bash = new Bash(bashOptions);
|
|
1190
|
+
try {
|
|
1191
|
+
const { exitCode, stderr, stdout } = await bash.exec(command);
|
|
1192
|
+
const bashExecOut = { exitCode, stderr, stdout };
|
|
1193
|
+
return {
|
|
1194
|
+
content: `Exit code: ${exitCode}
|
|
1195
|
+
|
|
1196
|
+
stdout:
|
|
1197
|
+
${stdout}
|
|
1198
|
+
|
|
1199
|
+
stderr:
|
|
1200
|
+
${stderr}`,
|
|
1201
|
+
result: bashExecOut
|
|
1202
|
+
};
|
|
1203
|
+
} catch (error) {
|
|
1204
|
+
const err = error instanceof Error ? error : new Error("Unknown error");
|
|
1205
|
+
return {
|
|
1206
|
+
content: `Error executing bash command: ${err.message}`,
|
|
1207
|
+
result: null
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
};
|
|
1211
|
+
|
|
1212
|
+
// src/lib/fs.ts
|
|
1213
|
+
var basename = (path, separator) => {
|
|
1214
|
+
if (path[path.length - 1] === separator) path = path.slice(0, -1);
|
|
1215
|
+
const lastSlashIndex = path.lastIndexOf(separator);
|
|
1216
|
+
return lastSlashIndex === -1 ? path : path.slice(lastSlashIndex + 1);
|
|
1217
|
+
};
|
|
1218
|
+
var printTree = async (tab = "", children) => {
|
|
1219
|
+
let str = "";
|
|
1220
|
+
let last = children.length - 1;
|
|
1221
|
+
for (; last >= 0; last--) if (children[last]) break;
|
|
1222
|
+
for (let i = 0; i <= last; i++) {
|
|
1223
|
+
const fn = children[i];
|
|
1224
|
+
if (!fn) continue;
|
|
1225
|
+
const isLast = i === last;
|
|
1226
|
+
const child = await fn(tab + (isLast ? " " : "\u2502") + " ");
|
|
1227
|
+
const branch = child ? isLast ? "\u2514\u2500" : "\u251C\u2500" : "\u2502";
|
|
1228
|
+
str += "\n" + tab + branch + (child ? " " + child : "");
|
|
1229
|
+
}
|
|
1230
|
+
return str;
|
|
1231
|
+
};
|
|
1232
|
+
var toTree = async (fs, opts = {}) => {
|
|
1233
|
+
const separator = opts.separator || "/";
|
|
1234
|
+
let dir = opts.dir || separator;
|
|
1235
|
+
if (dir[dir.length - 1] !== separator) dir += separator;
|
|
1236
|
+
const tab = opts.tab || "";
|
|
1237
|
+
const depth = opts.depth ?? 10;
|
|
1238
|
+
const sort = opts.sort ?? true;
|
|
1239
|
+
let subtree = " (...)";
|
|
1240
|
+
if (depth > 0) {
|
|
1241
|
+
const list = await fs.readdirWithFileTypes?.(dir) || [];
|
|
1242
|
+
if (sort) {
|
|
1243
|
+
list.sort((a, b) => {
|
|
1244
|
+
if (a.isDirectory && b.isDirectory) {
|
|
1245
|
+
return a.name.toString().localeCompare(b.name.toString());
|
|
1246
|
+
} else if (a.isDirectory) {
|
|
1247
|
+
return -1;
|
|
1248
|
+
} else if (b.isDirectory) {
|
|
1249
|
+
return 1;
|
|
1250
|
+
} else {
|
|
1251
|
+
return a.name.toString().localeCompare(b.name.toString());
|
|
1586
1252
|
}
|
|
1587
|
-
};
|
|
1253
|
+
});
|
|
1588
1254
|
}
|
|
1589
|
-
|
|
1590
|
-
|
|
1255
|
+
subtree = await printTree(
|
|
1256
|
+
tab,
|
|
1257
|
+
list.map((entry) => async (tab2) => {
|
|
1258
|
+
if (entry.isDirectory) {
|
|
1259
|
+
return toTree(fs, {
|
|
1260
|
+
dir: dir + entry.name,
|
|
1261
|
+
depth: depth - 1,
|
|
1262
|
+
tab: tab2
|
|
1263
|
+
});
|
|
1264
|
+
} else if (entry.isSymbolicLink) {
|
|
1265
|
+
return "" + entry.name + " \u2192 " + await fs.readlink(dir + entry.name);
|
|
1266
|
+
} else {
|
|
1267
|
+
return "" + entry.name;
|
|
1268
|
+
}
|
|
1269
|
+
})
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
const base = basename(dir, separator) + separator;
|
|
1273
|
+
return base + subtree;
|
|
1274
|
+
};
|
|
1591
1275
|
|
|
1592
|
-
|
|
1593
|
-
exports.BaseFileSystemProvider = BaseFileSystemProvider;
|
|
1594
|
-
exports.CompositeFileSystemProvider = CompositeFileSystemProvider;
|
|
1595
|
-
exports.InMemoryFileSystemProvider = InMemoryFileSystemProvider;
|
|
1596
|
-
exports.ZeitlichPlugin = ZeitlichPlugin;
|
|
1597
|
-
exports.askUserQuestionTool = askUserQuestionTool;
|
|
1598
|
-
exports.buildFileTreePrompt = buildFileTreePrompt;
|
|
1599
|
-
exports.createAgentStateManager = createAgentStateManager;
|
|
1600
|
-
exports.createEditHandler = createEditHandler;
|
|
1601
|
-
exports.createGlobHandler = createGlobHandler;
|
|
1602
|
-
exports.createGrepHandler = createGrepHandler;
|
|
1603
|
-
exports.createPromptManager = createPromptManager;
|
|
1604
|
-
exports.createReadHandler = createReadHandler;
|
|
1605
|
-
exports.createSession = createSession;
|
|
1606
|
-
exports.createSharedActivities = createSharedActivities;
|
|
1607
|
-
exports.createTaskHandler = createTaskHandler;
|
|
1608
|
-
exports.createTaskTool = createTaskTool;
|
|
1609
|
-
exports.createToolRegistry = createToolRegistry;
|
|
1610
|
-
exports.createToolRouter = createToolRouter;
|
|
1611
|
-
exports.createWriteHandler = createWriteHandler;
|
|
1612
|
-
exports.editTool = editTool;
|
|
1613
|
-
exports.fileContentToMessageContent = fileContentToMessageContent;
|
|
1614
|
-
exports.findNodeByPath = findNodeByPath;
|
|
1615
|
-
exports.flattenFileTree = flattenFileTree;
|
|
1616
|
-
exports.globTool = globTool;
|
|
1617
|
-
exports.grepTool = grepTool;
|
|
1618
|
-
exports.handleAskUserQuestionToolResult = handleAskUserQuestionToolResult;
|
|
1619
|
-
exports.hasNoOtherToolCalls = hasNoOtherToolCalls;
|
|
1620
|
-
exports.hasTaskTool = hasTaskTool;
|
|
1621
|
-
exports.invokeModel = invokeModel;
|
|
1622
|
-
exports.isPathInScope = isPathInScope;
|
|
1623
|
-
exports.isTerminalStatus = isTerminalStatus;
|
|
1624
|
-
exports.readTool = readTool;
|
|
1625
|
-
exports.withSubagentSupport = withSubagentSupport;
|
|
1626
|
-
exports.writeTool = writeTool;
|
|
1276
|
+
export { AGENT_HANDLER_NAMES, ZeitlichPlugin, askUserQuestionTool, bashTool, createAgentStateManager, createSession, createSharedActivities, createTaskCreateHandler, createTaskGetHandler, createTaskListHandler, createTaskTool, createTaskUpdateHandler, createToolRouter, editHandler, editTool, globHandler, globTool, grepTool, handleAskUserQuestionToolResult, handleBashTool, hasNoOtherToolCalls, invokeModel, isTerminalStatus, readTool, taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, toTree, writeTool };
|
|
1627
1277
|
//# sourceMappingURL=index.js.map
|
|
1628
1278
|
//# sourceMappingURL=index.js.map
|