@polka-codes/core 0.7.2 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_tsup-dts-rollup.d.cts +2453 -0
- package/dist/index.cjs +3457 -0
- package/dist/index.d.cts +97 -0
- package/package.json +2 -2
- package/dist/index.js +0 -16241
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3457 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
AgentBase: () => AgentBase,
|
|
34
|
+
AiServiceProvider: () => AiServiceProvider,
|
|
35
|
+
AnalyzerAgent: () => AnalyzerAgent,
|
|
36
|
+
ArchitectAgent: () => ArchitectAgent,
|
|
37
|
+
CodeFixerAgent: () => CodeFixerAgent,
|
|
38
|
+
CoderAgent: () => CoderAgent,
|
|
39
|
+
MockProvider: () => MockProvider,
|
|
40
|
+
MultiAgent: () => MultiAgent,
|
|
41
|
+
PermissionLevel: () => PermissionLevel,
|
|
42
|
+
TaskEventKind: () => TaskEventKind,
|
|
43
|
+
ToolResponseType: () => ToolResponseType,
|
|
44
|
+
UsageMeter: () => UsageMeter,
|
|
45
|
+
allAgents: () => allAgents,
|
|
46
|
+
allTools: () => allTools_exports,
|
|
47
|
+
analyzerAgentInfo: () => analyzerAgentInfo,
|
|
48
|
+
anthropicDefaultModelId: () => anthropicDefaultModelId,
|
|
49
|
+
anthropicModels: () => anthropicModels,
|
|
50
|
+
architectAgentInfo: () => architectAgentInfo,
|
|
51
|
+
askFollowupQuestion: () => askFollowupQuestion_default,
|
|
52
|
+
attemptCompletion: () => attemptCompletion_default,
|
|
53
|
+
codeFixerAgentInfo: () => codeFixerAgentInfo,
|
|
54
|
+
coderAgentInfo: () => coderAgentInfo,
|
|
55
|
+
createNewProject: () => createNewProject,
|
|
56
|
+
createService: () => createService,
|
|
57
|
+
deepSeekDefaultModelId: () => deepSeekDefaultModelId,
|
|
58
|
+
deepSeekModels: () => deepSeekModels,
|
|
59
|
+
defaultModels: () => defaultModels,
|
|
60
|
+
delegate: () => delegate_default,
|
|
61
|
+
executeAgentTool: () => executeAgentTool,
|
|
62
|
+
executeCommand: () => executeCommand_default,
|
|
63
|
+
executeTool: () => executeTool,
|
|
64
|
+
generateGitCommitMessage: () => generateGitCommitMessage,
|
|
65
|
+
generateGithubPullRequestDetails: () => generateGithubPullRequestDetails,
|
|
66
|
+
generateProjectConfig: () => generateProjectConfig,
|
|
67
|
+
getAvailableTools: () => getAvailableTools,
|
|
68
|
+
handOver: () => handOver_default,
|
|
69
|
+
listCodeDefinitionNames: () => listCodeDefinitionNames_default,
|
|
70
|
+
listFiles: () => listFiles_default,
|
|
71
|
+
makeAgentTool: () => makeAgentTool,
|
|
72
|
+
makeTool: () => makeTool,
|
|
73
|
+
modelInfos: () => modelInfos,
|
|
74
|
+
openAiModelInfoSaneDefaults: () => openAiModelInfoSaneDefaults,
|
|
75
|
+
readFile: () => readFile_default,
|
|
76
|
+
removeFile: () => removeFile_default,
|
|
77
|
+
renameFile: () => renameFile_default,
|
|
78
|
+
replaceInFile: () => replaceInFile_default,
|
|
79
|
+
searchFiles: () => searchFiles_default,
|
|
80
|
+
writeToFile: () => writeToFile_default
|
|
81
|
+
});
|
|
82
|
+
module.exports = __toCommonJS(index_exports);
|
|
83
|
+
|
|
84
|
+
// src/AiService/AnthropicService.ts
|
|
85
|
+
var import_sdk = require("@anthropic-ai/sdk");
|
|
86
|
+
|
|
87
|
+
// src/AiService/AiServiceBase.ts
|
|
88
|
+
var AiServiceBase = class {
|
|
89
|
+
usageMeter;
|
|
90
|
+
constructor(usageMeter) {
|
|
91
|
+
this.usageMeter = usageMeter;
|
|
92
|
+
}
|
|
93
|
+
async *send(systemPrompt, messages) {
|
|
94
|
+
this.usageMeter.incrementMessageCount();
|
|
95
|
+
const stream = this.sendImpl(systemPrompt, messages);
|
|
96
|
+
for await (const chunk of stream) {
|
|
97
|
+
switch (chunk.type) {
|
|
98
|
+
case "usage":
|
|
99
|
+
this.usageMeter.addUsage(chunk, this.model);
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
yield chunk;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async request(systemPrompt, messages) {
|
|
106
|
+
this.usageMeter.incrementMessageCount();
|
|
107
|
+
const stream = this.sendImpl(systemPrompt, messages);
|
|
108
|
+
const usage = {
|
|
109
|
+
inputTokens: 0,
|
|
110
|
+
outputTokens: 0,
|
|
111
|
+
cacheWriteTokens: 0,
|
|
112
|
+
cacheReadTokens: 0,
|
|
113
|
+
totalCost: 0
|
|
114
|
+
};
|
|
115
|
+
let resp = "";
|
|
116
|
+
let reasoning = "";
|
|
117
|
+
for await (const chunk of stream) {
|
|
118
|
+
switch (chunk.type) {
|
|
119
|
+
case "usage":
|
|
120
|
+
usage.inputTokens = chunk.inputTokens ?? 0;
|
|
121
|
+
usage.outputTokens = chunk.outputTokens ?? 0;
|
|
122
|
+
usage.cacheWriteTokens = chunk.cacheWriteTokens ?? 0;
|
|
123
|
+
usage.cacheReadTokens = chunk.cacheReadTokens ?? 0;
|
|
124
|
+
usage.totalCost = chunk.totalCost;
|
|
125
|
+
break;
|
|
126
|
+
case "text":
|
|
127
|
+
resp += chunk.text;
|
|
128
|
+
break;
|
|
129
|
+
case "reasoning":
|
|
130
|
+
reasoning += chunk.text;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
this.usageMeter.addUsage(usage, this.model);
|
|
134
|
+
return {
|
|
135
|
+
response: resp,
|
|
136
|
+
reasoning,
|
|
137
|
+
usage
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// src/AiService/ModelInfo.ts
|
|
143
|
+
var anthropicDefaultModelId = "claude-3-7-sonnet-20250219";
|
|
144
|
+
var anthropicModels = {
|
|
145
|
+
"claude-3-7-sonnet-20250219": {
|
|
146
|
+
maxTokens: 8192,
|
|
147
|
+
contextWindow: 2e5,
|
|
148
|
+
supportsImages: true,
|
|
149
|
+
supportsComputerUse: true,
|
|
150
|
+
supportsPromptCache: true,
|
|
151
|
+
inputPrice: 3,
|
|
152
|
+
outputPrice: 15,
|
|
153
|
+
cacheWritesPrice: 3.75,
|
|
154
|
+
cacheReadsPrice: 0.3
|
|
155
|
+
},
|
|
156
|
+
"claude-3-5-sonnet-20241022": {
|
|
157
|
+
maxTokens: 8192,
|
|
158
|
+
contextWindow: 2e5,
|
|
159
|
+
supportsImages: true,
|
|
160
|
+
supportsComputerUse: true,
|
|
161
|
+
supportsPromptCache: true,
|
|
162
|
+
inputPrice: 3,
|
|
163
|
+
// $3 per million input tokens
|
|
164
|
+
outputPrice: 15,
|
|
165
|
+
// $15 per million output tokens
|
|
166
|
+
cacheWritesPrice: 3.75,
|
|
167
|
+
// $3.75 per million tokens
|
|
168
|
+
cacheReadsPrice: 0.3
|
|
169
|
+
// $0.30 per million tokens
|
|
170
|
+
},
|
|
171
|
+
"claude-3-5-haiku-20241022": {
|
|
172
|
+
maxTokens: 8192,
|
|
173
|
+
contextWindow: 2e5,
|
|
174
|
+
supportsImages: false,
|
|
175
|
+
supportsPromptCache: true,
|
|
176
|
+
inputPrice: 0.8,
|
|
177
|
+
outputPrice: 4,
|
|
178
|
+
cacheWritesPrice: 1,
|
|
179
|
+
cacheReadsPrice: 0.08
|
|
180
|
+
},
|
|
181
|
+
"claude-3-opus-20240229": {
|
|
182
|
+
maxTokens: 4096,
|
|
183
|
+
contextWindow: 2e5,
|
|
184
|
+
supportsImages: true,
|
|
185
|
+
supportsPromptCache: true,
|
|
186
|
+
inputPrice: 15,
|
|
187
|
+
outputPrice: 75,
|
|
188
|
+
cacheWritesPrice: 18.75,
|
|
189
|
+
cacheReadsPrice: 1.5
|
|
190
|
+
},
|
|
191
|
+
"claude-3-haiku-20240307": {
|
|
192
|
+
maxTokens: 4096,
|
|
193
|
+
contextWindow: 2e5,
|
|
194
|
+
supportsImages: true,
|
|
195
|
+
supportsPromptCache: true,
|
|
196
|
+
inputPrice: 0.25,
|
|
197
|
+
outputPrice: 1.25,
|
|
198
|
+
cacheWritesPrice: 0.3,
|
|
199
|
+
cacheReadsPrice: 0.03
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
var openAiModelInfoSaneDefaults = {
|
|
203
|
+
maxTokens: -1,
|
|
204
|
+
contextWindow: 128e3,
|
|
205
|
+
supportsImages: true,
|
|
206
|
+
supportsPromptCache: false,
|
|
207
|
+
inputPrice: 0,
|
|
208
|
+
outputPrice: 0
|
|
209
|
+
};
|
|
210
|
+
var deepSeekDefaultModelId = "deepseek-chat";
|
|
211
|
+
var deepSeekModels = {
|
|
212
|
+
"deepseek-chat": {
|
|
213
|
+
maxTokens: 8e3,
|
|
214
|
+
contextWindow: 64e3,
|
|
215
|
+
supportsImages: false,
|
|
216
|
+
supportsPromptCache: true,
|
|
217
|
+
// supports context caching, but not in the way anthropic does it (deepseek reports input tokens and reads/writes in the same usage report) FIXME: we need to show users cache stats how deepseek does it
|
|
218
|
+
inputPrice: 0,
|
|
219
|
+
// technically there is no input price, it's all either a cache hit or miss (ApiOptions will not show this)
|
|
220
|
+
outputPrice: 1.1,
|
|
221
|
+
cacheWritesPrice: 0.27,
|
|
222
|
+
cacheReadsPrice: 0.07
|
|
223
|
+
},
|
|
224
|
+
"deepseek-reasoner": {
|
|
225
|
+
maxTokens: 8e3,
|
|
226
|
+
contextWindow: 64e3,
|
|
227
|
+
supportsImages: false,
|
|
228
|
+
supportsPromptCache: true,
|
|
229
|
+
inputPrice: 0,
|
|
230
|
+
outputPrice: 2.19,
|
|
231
|
+
cacheWritesPrice: 0.55,
|
|
232
|
+
cacheReadsPrice: 0.14
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
var modelInfos = {
|
|
236
|
+
anthropic: anthropicModels,
|
|
237
|
+
deepseek: deepSeekModels
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// src/AiService/AnthropicService.ts
|
|
241
|
+
var AnthropicService = class extends AiServiceBase {
|
|
242
|
+
#options;
|
|
243
|
+
#client;
|
|
244
|
+
model;
|
|
245
|
+
constructor(options) {
|
|
246
|
+
super(options.usageMeter);
|
|
247
|
+
this.#options = options;
|
|
248
|
+
this.#client = new import_sdk.Anthropic({
|
|
249
|
+
apiKey: options.apiKey,
|
|
250
|
+
baseURL: options.baseUrl || void 0
|
|
251
|
+
});
|
|
252
|
+
const id = this.#options.model ?? anthropicDefaultModelId;
|
|
253
|
+
this.model = {
|
|
254
|
+
provider: "anthropic",
|
|
255
|
+
id,
|
|
256
|
+
info: anthropicModels[id] ?? anthropicModels[anthropicDefaultModelId]
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
async *sendImpl(systemPrompt, messages) {
|
|
260
|
+
let stream;
|
|
261
|
+
const modelId = this.model.id;
|
|
262
|
+
const cacheControl = this.#options.enableCache ? { type: "ephemeral" } : void 0;
|
|
263
|
+
switch (modelId) {
|
|
264
|
+
// 'latest' alias does not support cache_control
|
|
265
|
+
case "claude-3-7-sonnet-20250219":
|
|
266
|
+
case "claude-3-5-sonnet-20241022":
|
|
267
|
+
case "claude-3-5-haiku-20241022":
|
|
268
|
+
case "claude-3-opus-20240229":
|
|
269
|
+
case "claude-3-haiku-20240307": {
|
|
270
|
+
const userMsgIndices = messages.reduce((acc, msg, index) => {
|
|
271
|
+
if (msg.role === "user") {
|
|
272
|
+
acc.push(index);
|
|
273
|
+
}
|
|
274
|
+
return acc;
|
|
275
|
+
}, []);
|
|
276
|
+
const lastUserMsgIndex = userMsgIndices[userMsgIndices.length - 1] ?? -1;
|
|
277
|
+
const secondLastMsgUserIndex = userMsgIndices[userMsgIndices.length - 2] ?? -1;
|
|
278
|
+
stream = await this.#client.messages.create({
|
|
279
|
+
model: modelId,
|
|
280
|
+
max_tokens: this.model.info.maxTokens || 8192,
|
|
281
|
+
temperature: 0,
|
|
282
|
+
system: [
|
|
283
|
+
{
|
|
284
|
+
text: systemPrompt,
|
|
285
|
+
type: "text",
|
|
286
|
+
cache_control: cacheControl
|
|
287
|
+
}
|
|
288
|
+
],
|
|
289
|
+
// setting cache breakpoint for system prompt so new tasks can reuse it
|
|
290
|
+
messages: messages.map((message, index) => {
|
|
291
|
+
if (index === lastUserMsgIndex || index === secondLastMsgUserIndex) {
|
|
292
|
+
return {
|
|
293
|
+
...message,
|
|
294
|
+
content: typeof message.content === "string" ? [
|
|
295
|
+
{
|
|
296
|
+
type: "text",
|
|
297
|
+
text: message.content,
|
|
298
|
+
cache_control: cacheControl
|
|
299
|
+
}
|
|
300
|
+
] : message.content.map(
|
|
301
|
+
(content, contentIndex) => contentIndex === message.content.length - 1 ? {
|
|
302
|
+
...content,
|
|
303
|
+
cache_control: cacheControl
|
|
304
|
+
} : content
|
|
305
|
+
)
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
return message;
|
|
309
|
+
}),
|
|
310
|
+
stream: true
|
|
311
|
+
});
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
default: {
|
|
315
|
+
stream = await this.#client.messages.create({
|
|
316
|
+
model: modelId,
|
|
317
|
+
max_tokens: this.model.info.maxTokens || 8192,
|
|
318
|
+
temperature: 0,
|
|
319
|
+
system: [{ text: systemPrompt, type: "text" }],
|
|
320
|
+
messages,
|
|
321
|
+
// tools,
|
|
322
|
+
// tool_choice: { type: "auto" },
|
|
323
|
+
stream: true
|
|
324
|
+
});
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
for await (const chunk of stream) {
|
|
329
|
+
switch (chunk.type) {
|
|
330
|
+
case "message_start": {
|
|
331
|
+
const usage = chunk.message.usage;
|
|
332
|
+
yield {
|
|
333
|
+
type: "usage",
|
|
334
|
+
inputTokens: usage.input_tokens,
|
|
335
|
+
outputTokens: usage.output_tokens,
|
|
336
|
+
cacheWriteTokens: usage.cache_creation_input_tokens || 0,
|
|
337
|
+
cacheReadTokens: usage.cache_read_input_tokens || 0
|
|
338
|
+
};
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
case "message_delta": {
|
|
342
|
+
yield {
|
|
343
|
+
type: "usage",
|
|
344
|
+
inputTokens: 0,
|
|
345
|
+
outputTokens: chunk.usage.output_tokens
|
|
346
|
+
};
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
case "message_stop":
|
|
350
|
+
break;
|
|
351
|
+
case "content_block_start":
|
|
352
|
+
switch (chunk.content_block.type) {
|
|
353
|
+
case "text":
|
|
354
|
+
if (chunk.index > 0) {
|
|
355
|
+
yield {
|
|
356
|
+
type: "text",
|
|
357
|
+
text: "\n"
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
yield {
|
|
361
|
+
type: "text",
|
|
362
|
+
text: chunk.content_block.text
|
|
363
|
+
};
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
break;
|
|
367
|
+
case "content_block_delta":
|
|
368
|
+
switch (chunk.delta.type) {
|
|
369
|
+
case "text_delta":
|
|
370
|
+
yield {
|
|
371
|
+
type: "text",
|
|
372
|
+
text: chunk.delta.text
|
|
373
|
+
};
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
break;
|
|
377
|
+
case "content_block_stop":
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// src/AiService/DeepSeekService.ts
|
|
385
|
+
var import_openai = __toESM(require("openai"), 1);
|
|
386
|
+
|
|
387
|
+
// src/AiService/utils.ts
|
|
388
|
+
function convertToOpenAiMessages(anthropicMessages) {
|
|
389
|
+
const openAiMessages = [];
|
|
390
|
+
for (const anthropicMessage of anthropicMessages) {
|
|
391
|
+
if (typeof anthropicMessage.content === "string") {
|
|
392
|
+
openAiMessages.push({
|
|
393
|
+
role: anthropicMessage.role,
|
|
394
|
+
content: anthropicMessage.content
|
|
395
|
+
});
|
|
396
|
+
} else {
|
|
397
|
+
if (anthropicMessage.role === "user") {
|
|
398
|
+
const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce(
|
|
399
|
+
(acc, part) => {
|
|
400
|
+
if (part.type === "tool_result") {
|
|
401
|
+
acc.toolMessages.push(part);
|
|
402
|
+
} else if (part.type === "text" || part.type === "image") {
|
|
403
|
+
acc.nonToolMessages.push(part);
|
|
404
|
+
}
|
|
405
|
+
return acc;
|
|
406
|
+
},
|
|
407
|
+
{ nonToolMessages: [], toolMessages: [] }
|
|
408
|
+
);
|
|
409
|
+
const toolResultImages = [];
|
|
410
|
+
for (const toolMessage of toolMessages) {
|
|
411
|
+
let content;
|
|
412
|
+
if (typeof toolMessage.content === "string") {
|
|
413
|
+
content = toolMessage.content;
|
|
414
|
+
} else {
|
|
415
|
+
content = toolMessage.content?.map((part) => {
|
|
416
|
+
if (part.type === "image") {
|
|
417
|
+
toolResultImages.push(part);
|
|
418
|
+
return "(see following user message for image)";
|
|
419
|
+
}
|
|
420
|
+
return part.text;
|
|
421
|
+
}).join("\n") ?? "";
|
|
422
|
+
}
|
|
423
|
+
openAiMessages.push({
|
|
424
|
+
role: "tool",
|
|
425
|
+
tool_call_id: toolMessage.tool_use_id,
|
|
426
|
+
content
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
if (nonToolMessages.length > 0) {
|
|
430
|
+
openAiMessages.push({
|
|
431
|
+
role: "user",
|
|
432
|
+
content: nonToolMessages.map((part) => {
|
|
433
|
+
if (part.type === "image") {
|
|
434
|
+
return {
|
|
435
|
+
type: "image_url",
|
|
436
|
+
image_url: {
|
|
437
|
+
url: `data:${part.source.media_type};base64,${part.source.data}`
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
return { type: "text", text: part.text };
|
|
442
|
+
})
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
} else if (anthropicMessage.role === "assistant") {
|
|
446
|
+
const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce(
|
|
447
|
+
(acc, part) => {
|
|
448
|
+
if (part.type === "tool_use") {
|
|
449
|
+
acc.toolMessages.push(part);
|
|
450
|
+
} else if (part.type === "text" || part.type === "image") {
|
|
451
|
+
acc.nonToolMessages.push(part);
|
|
452
|
+
}
|
|
453
|
+
return acc;
|
|
454
|
+
},
|
|
455
|
+
{ nonToolMessages: [], toolMessages: [] }
|
|
456
|
+
);
|
|
457
|
+
let content;
|
|
458
|
+
if (nonToolMessages.length > 0) {
|
|
459
|
+
content = nonToolMessages.map((part) => {
|
|
460
|
+
if (part.type === "image") {
|
|
461
|
+
return "";
|
|
462
|
+
}
|
|
463
|
+
return part.text;
|
|
464
|
+
}).join("\n");
|
|
465
|
+
}
|
|
466
|
+
const tool_calls = toolMessages.map((toolMessage) => ({
|
|
467
|
+
id: toolMessage.id,
|
|
468
|
+
type: "function",
|
|
469
|
+
function: {
|
|
470
|
+
name: toolMessage.name,
|
|
471
|
+
// json string
|
|
472
|
+
arguments: JSON.stringify(toolMessage.input)
|
|
473
|
+
}
|
|
474
|
+
}));
|
|
475
|
+
openAiMessages.push({
|
|
476
|
+
role: "assistant",
|
|
477
|
+
content,
|
|
478
|
+
// Cannot be an empty array. API expects an array with minimum length 1, and will respond with an error if it's empty
|
|
479
|
+
tool_calls: tool_calls.length > 0 ? tool_calls : void 0
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return openAiMessages;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// src/AiService/DeepSeekService.ts
|
|
488
|
+
var DeepSeekService = class extends AiServiceBase {
|
|
489
|
+
#client;
|
|
490
|
+
model;
|
|
491
|
+
constructor(options) {
|
|
492
|
+
super(options.usageMeter);
|
|
493
|
+
this.#client = new import_openai.default({
|
|
494
|
+
baseURL: "https://api.deepseek.com/v1",
|
|
495
|
+
apiKey: options.apiKey
|
|
496
|
+
});
|
|
497
|
+
const id = options.model || deepSeekDefaultModelId;
|
|
498
|
+
this.model = {
|
|
499
|
+
provider: "deepseek",
|
|
500
|
+
id,
|
|
501
|
+
info: deepSeekModels[id] ?? deepSeekModels[deepSeekDefaultModelId]
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
async *sendImpl(systemPrompt, messages) {
|
|
505
|
+
const openAiMessages = [
|
|
506
|
+
{ role: "system", content: systemPrompt },
|
|
507
|
+
...convertToOpenAiMessages(messages)
|
|
508
|
+
];
|
|
509
|
+
const stream = await this.#client.chat.completions.create({
|
|
510
|
+
model: this.model.id,
|
|
511
|
+
max_completion_tokens: this.model.info.maxTokens,
|
|
512
|
+
messages: openAiMessages,
|
|
513
|
+
temperature: 0,
|
|
514
|
+
stream: true,
|
|
515
|
+
stream_options: { include_usage: true }
|
|
516
|
+
});
|
|
517
|
+
for await (const chunk of stream) {
|
|
518
|
+
const delta = chunk.choices[0]?.delta;
|
|
519
|
+
if (delta?.reasoning_content) {
|
|
520
|
+
yield {
|
|
521
|
+
type: "reasoning",
|
|
522
|
+
text: delta.reasoning_content
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
if (delta?.content) {
|
|
526
|
+
yield {
|
|
527
|
+
type: "text",
|
|
528
|
+
text: delta.content
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
if (chunk.usage) {
|
|
532
|
+
yield {
|
|
533
|
+
type: "usage",
|
|
534
|
+
// deepseek reports total input AND cache reads/writes, see context caching: https://api-docs.deepseek.com/guides/kv_cache
|
|
535
|
+
// where the input tokens is the sum of the cache hits/misses, while anthropic reports them as separate tokens.
|
|
536
|
+
// This is important to know for
|
|
537
|
+
// 1) context management truncation algorithm, and
|
|
538
|
+
// 2) cost calculation (NOTE: we report both input and cache stats but for now set input price to 0 since all the cost calculation will be done using cache hits/misses)
|
|
539
|
+
inputTokens: chunk.usage.prompt_tokens,
|
|
540
|
+
outputTokens: chunk.usage.completion_tokens,
|
|
541
|
+
cacheWriteTokens: chunk.usage.prompt_cache_hit_tokens || 0,
|
|
542
|
+
cacheReadTokens: chunk.usage.prompt_cache_miss_tokens || 0
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
// src/AiService/OllamaService.ts
|
|
550
|
+
var import_openai2 = __toESM(require("openai"), 1);
|
|
551
|
+
var OllamaService = class extends AiServiceBase {
|
|
552
|
+
#client;
|
|
553
|
+
model;
|
|
554
|
+
constructor(options) {
|
|
555
|
+
super(options.usageMeter);
|
|
556
|
+
this.#client = new import_openai2.default({
|
|
557
|
+
baseURL: `${options.baseUrl || "http://localhost:11434"}/v1`,
|
|
558
|
+
apiKey: "ollama"
|
|
559
|
+
});
|
|
560
|
+
this.model = {
|
|
561
|
+
provider: "ollama",
|
|
562
|
+
id: options.model || "maryasov/qwen2.5-coder-cline:7b",
|
|
563
|
+
info: openAiModelInfoSaneDefaults
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
async *sendImpl(systemPrompt, messages) {
|
|
567
|
+
const openAiMessages = [
|
|
568
|
+
{ role: "system", content: systemPrompt },
|
|
569
|
+
...convertToOpenAiMessages(messages)
|
|
570
|
+
];
|
|
571
|
+
const stream = await this.#client.chat.completions.create({
|
|
572
|
+
model: this.model.id,
|
|
573
|
+
messages: openAiMessages,
|
|
574
|
+
temperature: 0,
|
|
575
|
+
stream: true
|
|
576
|
+
});
|
|
577
|
+
for await (const chunk of stream) {
|
|
578
|
+
const delta = chunk.choices[0]?.delta;
|
|
579
|
+
if (delta?.content) {
|
|
580
|
+
yield {
|
|
581
|
+
type: "text",
|
|
582
|
+
text: delta.content
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
// src/AiService/OpenRouterService.ts
|
|
590
|
+
var import_openai3 = __toESM(require("openai"), 1);
|
|
591
|
+
var OpenRouterService = class extends AiServiceBase {
|
|
592
|
+
#client;
|
|
593
|
+
#apiKey;
|
|
594
|
+
#options;
|
|
595
|
+
#modelProviderInfo;
|
|
596
|
+
model;
|
|
597
|
+
constructor(options) {
|
|
598
|
+
super(options.usageMeter);
|
|
599
|
+
if (!options.model) {
|
|
600
|
+
throw new Error("OpenRouter requires a model");
|
|
601
|
+
}
|
|
602
|
+
if (!options.apiKey) {
|
|
603
|
+
throw new Error("OpenRouter requires an API key");
|
|
604
|
+
}
|
|
605
|
+
this.#apiKey = options.apiKey;
|
|
606
|
+
this.#client = new import_openai3.default({
|
|
607
|
+
baseURL: "https://openrouter.ai/api/v1",
|
|
608
|
+
apiKey: options.apiKey,
|
|
609
|
+
defaultHeaders: {
|
|
610
|
+
"HTTP-Referer": "https://polka.codes",
|
|
611
|
+
// Optional, for including your app on openrouter.ai rankings.
|
|
612
|
+
"X-Title": "Polka Codes"
|
|
613
|
+
// Optional. Shows in rankings on openrouter.ai.
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
this.#options = options;
|
|
617
|
+
this.model = {
|
|
618
|
+
provider: "openrouter",
|
|
619
|
+
id: options.model,
|
|
620
|
+
info: {}
|
|
621
|
+
};
|
|
622
|
+
fetch(`https://openrouter.ai/api/v1/models/${this.model.id}/endpoints`).then((res) => res.json()).then((data) => {
|
|
623
|
+
this.#modelProviderInfo = data.data;
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
async *sendImpl(systemPrompt, messages) {
|
|
627
|
+
const openAiMessages = [
|
|
628
|
+
{ role: "system", content: systemPrompt },
|
|
629
|
+
...convertToOpenAiMessages(messages)
|
|
630
|
+
];
|
|
631
|
+
const cacheControl = this.#options.enableCache ? { type: "ephemeral" } : void 0;
|
|
632
|
+
switch (this.model.id) {
|
|
633
|
+
case "anthropic/claude-3.7-sonnet:thinking":
|
|
634
|
+
case "anthropic/claude-3.7-sonnet":
|
|
635
|
+
case "anthropic/claude-3.7-sonnet:beta":
|
|
636
|
+
case "anthropic/claude-3-7-sonnet":
|
|
637
|
+
case "anthropic/claude-3-7-sonnet:beta":
|
|
638
|
+
case "anthropic/claude-3.5-sonnet":
|
|
639
|
+
case "anthropic/claude-3.5-sonnet:beta":
|
|
640
|
+
case "anthropic/claude-3.5-sonnet-20240620":
|
|
641
|
+
case "anthropic/claude-3.5-sonnet-20240620:beta":
|
|
642
|
+
case "anthropic/claude-3-5-haiku":
|
|
643
|
+
case "anthropic/claude-3-5-haiku:beta":
|
|
644
|
+
case "anthropic/claude-3-5-haiku-20241022":
|
|
645
|
+
case "anthropic/claude-3-5-haiku-20241022:beta":
|
|
646
|
+
case "anthropic/claude-3-haiku":
|
|
647
|
+
case "anthropic/claude-3-haiku:beta":
|
|
648
|
+
case "anthropic/claude-3-opus":
|
|
649
|
+
case "anthropic/claude-3-opus:beta": {
|
|
650
|
+
openAiMessages[0] = {
|
|
651
|
+
role: "system",
|
|
652
|
+
content: [
|
|
653
|
+
{
|
|
654
|
+
type: "text",
|
|
655
|
+
text: systemPrompt,
|
|
656
|
+
// @ts-ignore-next-line
|
|
657
|
+
cache_control: cacheControl
|
|
658
|
+
}
|
|
659
|
+
]
|
|
660
|
+
};
|
|
661
|
+
const lastTwoUserMessages = openAiMessages.filter((msg) => msg.role === "user").slice(-2);
|
|
662
|
+
for (const msg of lastTwoUserMessages) {
|
|
663
|
+
if (typeof msg.content === "string") {
|
|
664
|
+
msg.content = [{ type: "text", text: msg.content }];
|
|
665
|
+
}
|
|
666
|
+
if (Array.isArray(msg.content)) {
|
|
667
|
+
let lastTextPart = msg.content.filter((part) => part.type === "text").pop();
|
|
668
|
+
if (!lastTextPart) {
|
|
669
|
+
lastTextPart = { type: "text", text: "..." };
|
|
670
|
+
msg.content.push(lastTextPart);
|
|
671
|
+
}
|
|
672
|
+
lastTextPart.cache_control = cacheControl;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
break;
|
|
676
|
+
}
|
|
677
|
+
default:
|
|
678
|
+
break;
|
|
679
|
+
}
|
|
680
|
+
let maxTokens;
|
|
681
|
+
switch (this.model.id) {
|
|
682
|
+
case "anthropic/claude-3.7-sonnet:thinking":
|
|
683
|
+
case "anthropic/claude-3.7-sonnet":
|
|
684
|
+
case "anthropic/claude-3.7-sonnet:beta":
|
|
685
|
+
case "anthropic/claude-3-7-sonnet":
|
|
686
|
+
case "anthropic/claude-3-7-sonnet:beta":
|
|
687
|
+
case "anthropic/claude-3.5-sonnet":
|
|
688
|
+
case "anthropic/claude-3.5-sonnet:beta":
|
|
689
|
+
case "anthropic/claude-3.5-sonnet-20240620":
|
|
690
|
+
case "anthropic/claude-3.5-sonnet-20240620:beta":
|
|
691
|
+
case "anthropic/claude-3-5-haiku":
|
|
692
|
+
case "anthropic/claude-3-5-haiku:beta":
|
|
693
|
+
case "anthropic/claude-3-5-haiku-20241022":
|
|
694
|
+
case "anthropic/claude-3-5-haiku-20241022:beta":
|
|
695
|
+
maxTokens = 8192;
|
|
696
|
+
break;
|
|
697
|
+
}
|
|
698
|
+
let shouldApplyMiddleOutTransform = !this.model.info.supportsPromptCache;
|
|
699
|
+
if (this.model.id === "deepseek/deepseek-chat") {
|
|
700
|
+
shouldApplyMiddleOutTransform = true;
|
|
701
|
+
}
|
|
702
|
+
const stream = await this.#client.chat.completions.create({
|
|
703
|
+
model: this.model.id,
|
|
704
|
+
max_completion_tokens: maxTokens,
|
|
705
|
+
messages: openAiMessages,
|
|
706
|
+
temperature: 0,
|
|
707
|
+
stream: true,
|
|
708
|
+
transforms: shouldApplyMiddleOutTransform ? ["middle-out"] : void 0,
|
|
709
|
+
include_reasoning: true
|
|
710
|
+
});
|
|
711
|
+
let genId;
|
|
712
|
+
for await (const chunk of stream) {
|
|
713
|
+
if ("error" in chunk) {
|
|
714
|
+
const error = chunk.error;
|
|
715
|
+
console.error(`OpenRouter API Error: ${error?.code} - ${error?.message}`);
|
|
716
|
+
throw new Error(`OpenRouter API Error ${error?.code}: ${error?.message}`);
|
|
717
|
+
}
|
|
718
|
+
if (!genId && chunk.id) {
|
|
719
|
+
genId = chunk.id;
|
|
720
|
+
}
|
|
721
|
+
const delta = chunk.choices[0]?.delta;
|
|
722
|
+
if (delta?.reasoning) {
|
|
723
|
+
yield {
|
|
724
|
+
type: "reasoning",
|
|
725
|
+
text: delta.reasoning
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
if (delta?.content) {
|
|
729
|
+
yield {
|
|
730
|
+
type: "text",
|
|
731
|
+
text: delta.content
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
736
|
+
const controller = new AbortController();
|
|
737
|
+
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
738
|
+
try {
|
|
739
|
+
const response = await fetch(`https://openrouter.ai/api/v1/generation?id=${genId}`, {
|
|
740
|
+
headers: {
|
|
741
|
+
Authorization: `Bearer ${this.#apiKey}`
|
|
742
|
+
},
|
|
743
|
+
signal: controller.signal
|
|
744
|
+
// this request hangs sometimes
|
|
745
|
+
});
|
|
746
|
+
const responseBody = await response.json();
|
|
747
|
+
const generation = responseBody.data ?? {};
|
|
748
|
+
let totalCost = generation.total_cost || 0;
|
|
749
|
+
if (generation.is_byok && this.#modelProviderInfo) {
|
|
750
|
+
const price = this.#modelProviderInfo.endpoints.find((e) => e.provider_name === generation.provider_name)?.pricing;
|
|
751
|
+
if (price) {
|
|
752
|
+
totalCost += (generation.native_tokens_prompt || 0) * price.request;
|
|
753
|
+
totalCost += (generation.native_tokens_completion || 0) * price.completion;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
yield {
|
|
757
|
+
type: "usage",
|
|
758
|
+
// cacheWriteTokens: 0,
|
|
759
|
+
// cacheReadTokens: 0,
|
|
760
|
+
// openrouter generation endpoint fails often
|
|
761
|
+
inputTokens: generation.native_tokens_prompt || 0,
|
|
762
|
+
outputTokens: generation.native_tokens_completion || 0,
|
|
763
|
+
totalCost
|
|
764
|
+
};
|
|
765
|
+
} catch (error) {
|
|
766
|
+
console.error("Error fetching OpenRouter generation details:", error);
|
|
767
|
+
} finally {
|
|
768
|
+
clearTimeout(timeout);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
// src/AiService/UsageMeter.ts
|
|
774
|
+
var import_lodash = require("lodash");
|
|
775
|
+
var UsageMeter = class {
|
|
776
|
+
#usage = {
|
|
777
|
+
inputTokens: 0,
|
|
778
|
+
outputTokens: 0,
|
|
779
|
+
cacheWriteTokens: 0,
|
|
780
|
+
cacheReadTokens: 0,
|
|
781
|
+
totalCost: 0
|
|
782
|
+
};
|
|
783
|
+
#messageCount = 0;
|
|
784
|
+
#prices = {};
|
|
785
|
+
maxCost;
|
|
786
|
+
maxMessageCount;
|
|
787
|
+
constructor(options = {}) {
|
|
788
|
+
this.maxCost = options.maxCost || 1e3;
|
|
789
|
+
this.maxMessageCount = options.maxMessageCount || 1e3;
|
|
790
|
+
this.#prices = (0, import_lodash.merge)({}, modelInfos, options.prices ?? {});
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Add usage metrics to the current totals
|
|
794
|
+
*/
|
|
795
|
+
addUsage(usage, model) {
|
|
796
|
+
this.#usage.inputTokens += usage.inputTokens ?? 0;
|
|
797
|
+
this.#usage.outputTokens += usage.outputTokens ?? 0;
|
|
798
|
+
this.#usage.cacheWriteTokens += usage.cacheWriteTokens ?? 0;
|
|
799
|
+
this.#usage.cacheReadTokens += usage.cacheReadTokens ?? 0;
|
|
800
|
+
if (!usage.totalCost && model) {
|
|
801
|
+
const modelInfo = this.#prices[model.provider]?.[model.id] ?? {};
|
|
802
|
+
usage.totalCost = ((modelInfo.inputPrice ?? 0) * (usage.inputTokens ?? 0) + (modelInfo.outputPrice ?? 0) * (usage.outputTokens ?? 0) + (modelInfo.cacheWritesPrice ?? 0) * (usage.cacheWriteTokens ?? 0) + (modelInfo.cacheReadsPrice ?? 0) * (usage.cacheReadTokens ?? 0)) / 1e6;
|
|
803
|
+
}
|
|
804
|
+
this.#usage.totalCost += usage.totalCost ?? 0;
|
|
805
|
+
}
|
|
806
|
+
incrementMessageCount(count = 1) {
|
|
807
|
+
this.#messageCount += count;
|
|
808
|
+
}
|
|
809
|
+
isLimitExceeded() {
|
|
810
|
+
const messageCount = this.#messageCount >= this.maxMessageCount;
|
|
811
|
+
const cost = this.#usage.totalCost >= this.maxCost;
|
|
812
|
+
return {
|
|
813
|
+
messageCount,
|
|
814
|
+
cost,
|
|
815
|
+
result: messageCount || cost
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* Get current usage totals
|
|
820
|
+
*/
|
|
821
|
+
get usage() {
|
|
822
|
+
return { ...this.#usage };
|
|
823
|
+
}
|
|
824
|
+
printUsage() {
|
|
825
|
+
const { inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens } = this.#usage;
|
|
826
|
+
const allTokensZero = inputTokens === 0 && outputTokens === 0 && cacheReadTokens === 0 && cacheWriteTokens === 0;
|
|
827
|
+
console.log("Usages:");
|
|
828
|
+
if (!allTokensZero) {
|
|
829
|
+
console.log(`Input tokens: ${this.#usage.inputTokens}`);
|
|
830
|
+
console.log(`Output tokens: ${this.#usage.outputTokens}`);
|
|
831
|
+
console.log(`Cache read tokens: ${this.#usage.cacheReadTokens}`);
|
|
832
|
+
console.log(`Cache write tokens: ${this.#usage.cacheWriteTokens}`);
|
|
833
|
+
}
|
|
834
|
+
console.log(`Total cost: ${this.#usage.totalCost}`);
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
// src/AiService/index.ts
|
|
839
|
+
var AiServiceProvider = /* @__PURE__ */ ((AiServiceProvider2) => {
|
|
840
|
+
AiServiceProvider2["Anthropic"] = "anthropic";
|
|
841
|
+
AiServiceProvider2["Ollama"] = "ollama";
|
|
842
|
+
AiServiceProvider2["DeepSeek"] = "deepseek";
|
|
843
|
+
AiServiceProvider2["OpenRouter"] = "openrouter";
|
|
844
|
+
return AiServiceProvider2;
|
|
845
|
+
})(AiServiceProvider || {});
|
|
846
|
+
var defaultModels = {
|
|
847
|
+
["anthropic" /* Anthropic */]: "claude-3-7-sonnet-20250219",
|
|
848
|
+
["ollama" /* Ollama */]: "maryasov/qwen2.5-coder-cline:7b",
|
|
849
|
+
["deepseek" /* DeepSeek */]: "deepseek-chat",
|
|
850
|
+
["openrouter" /* OpenRouter */]: "anthropic/claude-3.7-sonnet"
|
|
851
|
+
};
|
|
852
|
+
var createService = (provider, options) => {
|
|
853
|
+
switch (provider) {
|
|
854
|
+
case "anthropic" /* Anthropic */:
|
|
855
|
+
return new AnthropicService(options);
|
|
856
|
+
case "ollama" /* Ollama */:
|
|
857
|
+
return new OllamaService(options);
|
|
858
|
+
case "deepseek" /* DeepSeek */:
|
|
859
|
+
return new DeepSeekService(options);
|
|
860
|
+
case "openrouter" /* OpenRouter */:
|
|
861
|
+
return new OpenRouterService(options);
|
|
862
|
+
}
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
// src/tools/provider.ts
|
|
866
|
+
var MockProvider = class {
|
|
867
|
+
async readFile(path) {
|
|
868
|
+
return "mock content";
|
|
869
|
+
}
|
|
870
|
+
async writeFile(path, content) {
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
async removeFile(path) {
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
async renameFile(sourcePath, targetPath) {
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
async listFiles(path, recursive, maxCount) {
|
|
880
|
+
return [["mock-file.txt"], false];
|
|
881
|
+
}
|
|
882
|
+
async searchFiles(path, regex, filePattern) {
|
|
883
|
+
return ["mock-file.txt"];
|
|
884
|
+
}
|
|
885
|
+
async listCodeDefinitionNames(path) {
|
|
886
|
+
return "mockDefinition";
|
|
887
|
+
}
|
|
888
|
+
async executeCommand(command, needApprove) {
|
|
889
|
+
return { stdout: "mock output", stderr: "", exitCode: 0 };
|
|
890
|
+
}
|
|
891
|
+
async askFollowupQuestion(question, options) {
|
|
892
|
+
return "mock answer";
|
|
893
|
+
}
|
|
894
|
+
async attemptCompletion(result) {
|
|
895
|
+
return "mock completion";
|
|
896
|
+
}
|
|
897
|
+
};
|
|
898
|
+
|
|
899
|
+
// src/tools/allTools.ts
|
|
900
|
+
var allTools_exports = {};
|
|
901
|
+
__export(allTools_exports, {
|
|
902
|
+
askFollowupQuestion: () => askFollowupQuestion_default,
|
|
903
|
+
attemptCompletion: () => attemptCompletion_default,
|
|
904
|
+
delegate: () => delegate_default,
|
|
905
|
+
executeCommand: () => executeCommand_default,
|
|
906
|
+
handOver: () => handOver_default,
|
|
907
|
+
listCodeDefinitionNames: () => listCodeDefinitionNames_default,
|
|
908
|
+
listFiles: () => listFiles_default,
|
|
909
|
+
readFile: () => readFile_default,
|
|
910
|
+
removeFile: () => removeFile_default,
|
|
911
|
+
renameFile: () => renameFile_default,
|
|
912
|
+
replaceInFile: () => replaceInFile_default,
|
|
913
|
+
searchFiles: () => searchFiles_default,
|
|
914
|
+
writeToFile: () => writeToFile_default
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
// src/tool.ts
|
|
918
|
+
var PermissionLevel = /* @__PURE__ */ ((PermissionLevel2) => {
|
|
919
|
+
PermissionLevel2[PermissionLevel2["None"] = 0] = "None";
|
|
920
|
+
PermissionLevel2[PermissionLevel2["Read"] = 1] = "Read";
|
|
921
|
+
PermissionLevel2[PermissionLevel2["Write"] = 2] = "Write";
|
|
922
|
+
PermissionLevel2[PermissionLevel2["Arbitrary"] = 3] = "Arbitrary";
|
|
923
|
+
return PermissionLevel2;
|
|
924
|
+
})(PermissionLevel || {});
|
|
925
|
+
var ToolResponseType = /* @__PURE__ */ ((ToolResponseType2) => {
|
|
926
|
+
ToolResponseType2["Reply"] = "Reply";
|
|
927
|
+
ToolResponseType2["Exit"] = "Exit";
|
|
928
|
+
ToolResponseType2["Invalid"] = "Invalid";
|
|
929
|
+
ToolResponseType2["Error"] = "Error";
|
|
930
|
+
ToolResponseType2["Interrupted"] = "Interrupted";
|
|
931
|
+
ToolResponseType2["HandOver"] = "HandOver";
|
|
932
|
+
ToolResponseType2["Delegate"] = "Delegate";
|
|
933
|
+
return ToolResponseType2;
|
|
934
|
+
})(ToolResponseType || {});
|
|
935
|
+
|
|
936
|
+
// src/tools/utils/replaceInFile.ts
|
|
937
|
+
var replaceInFile = async (fileContent, diff) => {
|
|
938
|
+
const blockPattern = /<<<<<+ SEARCH\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
|
|
939
|
+
const blocks = [];
|
|
940
|
+
for (let match = blockPattern.exec(diff); match !== null; match = blockPattern.exec(diff)) {
|
|
941
|
+
blocks.push({ search: match[1], replace: match[2] });
|
|
942
|
+
}
|
|
943
|
+
if (blocks.length === 0) {
|
|
944
|
+
throw new Error("No valid diff blocks found.");
|
|
945
|
+
}
|
|
946
|
+
const findAndReplace = (content, search, replace) => {
|
|
947
|
+
let index = content.indexOf(search);
|
|
948
|
+
if (index !== -1) {
|
|
949
|
+
return content.slice(0, index) + replace + content.slice(index + search.length);
|
|
950
|
+
}
|
|
951
|
+
const trimmedSearch = search.trim();
|
|
952
|
+
const trimmedContent = content.trim();
|
|
953
|
+
const offset = content.indexOf(trimmedContent);
|
|
954
|
+
index = trimmedContent.indexOf(trimmedSearch);
|
|
955
|
+
if (index !== -1) {
|
|
956
|
+
const absoluteIndex = offset + index;
|
|
957
|
+
return content.slice(0, absoluteIndex) + replace + content.slice(absoluteIndex + trimmedSearch.length);
|
|
958
|
+
}
|
|
959
|
+
const normalizedSearch = trimmedSearch.replace(/\s+/g, " ");
|
|
960
|
+
const normalizedContent = trimmedContent.replace(/\s+/g, " ");
|
|
961
|
+
index = normalizedContent.indexOf(normalizedSearch);
|
|
962
|
+
if (index !== -1) {
|
|
963
|
+
let runningIndex = 0;
|
|
964
|
+
let actualPos = offset;
|
|
965
|
+
for (const segment of trimmedSearch.replace(/\s+/g, " ").split(" ")) {
|
|
966
|
+
const segIndex = content.indexOf(segment, actualPos);
|
|
967
|
+
if (segIndex === -1) {
|
|
968
|
+
break;
|
|
969
|
+
}
|
|
970
|
+
if (runningIndex === 0) {
|
|
971
|
+
actualPos = segIndex;
|
|
972
|
+
} else {
|
|
973
|
+
actualPos = segIndex + segment.length;
|
|
974
|
+
}
|
|
975
|
+
runningIndex++;
|
|
976
|
+
}
|
|
977
|
+
const strippedSearch = trimmedSearch.replace(/\s+/g, "");
|
|
978
|
+
const endPos = actualPos;
|
|
979
|
+
const startPos = endPos - strippedSearch.length;
|
|
980
|
+
return content.slice(0, startPos) + replace + content.slice(endPos);
|
|
981
|
+
}
|
|
982
|
+
throw new Error(`Could not find the following text in file:
|
|
983
|
+
${search}`);
|
|
984
|
+
};
|
|
985
|
+
let updatedFile = fileContent;
|
|
986
|
+
for (const { search, replace } of blocks) {
|
|
987
|
+
updatedFile = findAndReplace(updatedFile, search, replace);
|
|
988
|
+
}
|
|
989
|
+
return updatedFile;
|
|
990
|
+
};
|
|
991
|
+
|
|
992
|
+
// src/tools/utils/getArg.ts
|
|
993
|
+
var getString = (args, name, defaultValue) => {
|
|
994
|
+
const ret = args[name] ?? defaultValue;
|
|
995
|
+
if (ret === void 0) {
|
|
996
|
+
throw new Error(`Missing required argument: ${name}`);
|
|
997
|
+
}
|
|
998
|
+
return ret;
|
|
999
|
+
};
|
|
1000
|
+
var getStringArray = (args, name, defaultValue) => {
|
|
1001
|
+
const ret = args[name];
|
|
1002
|
+
if (ret === void 0) {
|
|
1003
|
+
if (defaultValue === void 0) {
|
|
1004
|
+
throw new Error(`Missing required argument: ${name}`);
|
|
1005
|
+
}
|
|
1006
|
+
return defaultValue;
|
|
1007
|
+
}
|
|
1008
|
+
if (ret === "") {
|
|
1009
|
+
return [];
|
|
1010
|
+
}
|
|
1011
|
+
return ret.split(",").map((s) => s.trim());
|
|
1012
|
+
};
|
|
1013
|
+
var getBoolean = (args, name, defaultValue) => {
|
|
1014
|
+
const ret = args[name];
|
|
1015
|
+
if (ret === void 0) {
|
|
1016
|
+
if (defaultValue === void 0) {
|
|
1017
|
+
throw new Error(`Missing required argument: ${name}`);
|
|
1018
|
+
}
|
|
1019
|
+
return defaultValue;
|
|
1020
|
+
}
|
|
1021
|
+
switch (ret.toLowerCase()) {
|
|
1022
|
+
case "true":
|
|
1023
|
+
return true;
|
|
1024
|
+
case "false":
|
|
1025
|
+
return false;
|
|
1026
|
+
default:
|
|
1027
|
+
throw new Error(`Invalid argument value: ${name}`);
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
var getInt = (args, name, defaultValue) => {
|
|
1031
|
+
const ret = args[name];
|
|
1032
|
+
if (ret === void 0) {
|
|
1033
|
+
if (defaultValue === void 0) {
|
|
1034
|
+
throw new Error(`Missing required argument: ${name}`);
|
|
1035
|
+
}
|
|
1036
|
+
return defaultValue;
|
|
1037
|
+
}
|
|
1038
|
+
const parsed = Number.parseInt(ret);
|
|
1039
|
+
if (Number.isNaN(parsed)) {
|
|
1040
|
+
throw new Error(`Invalid argument value: ${name}`);
|
|
1041
|
+
}
|
|
1042
|
+
return parsed;
|
|
1043
|
+
};
|
|
1044
|
+
|
|
1045
|
+
// src/tools/askFollowupQuestion.ts
|
|
1046
|
+
var toolInfo = {
|
|
1047
|
+
name: "ask_followup_question",
|
|
1048
|
+
description: "Whenever you need extra details or clarification to complete the task, pose a direct question to the user. Use this tool sparingly to avoid excessive back-and-forth. If helpful, offer multiple-choice options or examples to guide the user\u2019s response.",
|
|
1049
|
+
parameters: [
|
|
1050
|
+
{
|
|
1051
|
+
name: "question",
|
|
1052
|
+
description: "The question to ask the user. This should be a clear, specific question that addresses the information you need.",
|
|
1053
|
+
required: true,
|
|
1054
|
+
usageValue: "Your question here"
|
|
1055
|
+
},
|
|
1056
|
+
{
|
|
1057
|
+
name: "options",
|
|
1058
|
+
description: "A comma separated list of possible answers to the question. Ordered by preference. If not provided, the user will be prompted to provide an answer.",
|
|
1059
|
+
required: false,
|
|
1060
|
+
usageValue: "A comma separated list of possible answers (optional)"
|
|
1061
|
+
}
|
|
1062
|
+
],
|
|
1063
|
+
examples: [
|
|
1064
|
+
{
|
|
1065
|
+
description: "Request to ask a question",
|
|
1066
|
+
parameters: [
|
|
1067
|
+
{
|
|
1068
|
+
name: "question",
|
|
1069
|
+
value: "What is the name of the project?"
|
|
1070
|
+
}
|
|
1071
|
+
]
|
|
1072
|
+
},
|
|
1073
|
+
{
|
|
1074
|
+
description: "Request to ask a question with options",
|
|
1075
|
+
parameters: [
|
|
1076
|
+
{
|
|
1077
|
+
name: "question",
|
|
1078
|
+
value: "What framework do you use?"
|
|
1079
|
+
},
|
|
1080
|
+
{
|
|
1081
|
+
name: "options",
|
|
1082
|
+
value: "React,Angular,Vue,Svelte"
|
|
1083
|
+
}
|
|
1084
|
+
]
|
|
1085
|
+
}
|
|
1086
|
+
],
|
|
1087
|
+
permissionLevel: 0 /* None */
|
|
1088
|
+
};
|
|
1089
|
+
var handler = async (provider, args) => {
|
|
1090
|
+
if (!provider.askFollowupQuestion) {
|
|
1091
|
+
return {
|
|
1092
|
+
type: "Error" /* Error */,
|
|
1093
|
+
message: "Not possible to ask followup question. Abort."
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
const question = getString(args, "question");
|
|
1097
|
+
const options = getStringArray(args, "options", []);
|
|
1098
|
+
const answer = await provider.askFollowupQuestion(question, options);
|
|
1099
|
+
return {
|
|
1100
|
+
type: "Reply" /* Reply */,
|
|
1101
|
+
message: `<ask_followup_question_question>${question}</ask_followup_question_question>
|
|
1102
|
+
<ask_followup_question_answer>${answer}</ask_followup_question_answer>`
|
|
1103
|
+
};
|
|
1104
|
+
};
|
|
1105
|
+
var isAvailable = (provider) => {
|
|
1106
|
+
return !!provider.askFollowupQuestion;
|
|
1107
|
+
};
|
|
1108
|
+
var askFollowupQuestion_default = {
|
|
1109
|
+
...toolInfo,
|
|
1110
|
+
handler,
|
|
1111
|
+
isAvailable
|
|
1112
|
+
};
|
|
1113
|
+
|
|
1114
|
+
// src/tools/attemptCompletion.ts
|
|
1115
|
+
var toolInfo2 = {
|
|
1116
|
+
name: "attempt_completion",
|
|
1117
|
+
description: "Use this tool when you believe the user\u2019s requested task is complete. Indicate that your work is finished, but acknowledge the user may still provide additional instructions or questions if they want to continue. This tool MUST NOT to be used with any other tool.",
|
|
1118
|
+
parameters: [
|
|
1119
|
+
{
|
|
1120
|
+
name: "result",
|
|
1121
|
+
description: "The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.",
|
|
1122
|
+
required: true,
|
|
1123
|
+
usageValue: "Your final result description here"
|
|
1124
|
+
}
|
|
1125
|
+
],
|
|
1126
|
+
examples: [
|
|
1127
|
+
{
|
|
1128
|
+
description: "Request to present the result of the task",
|
|
1129
|
+
parameters: [
|
|
1130
|
+
{
|
|
1131
|
+
name: "result",
|
|
1132
|
+
value: "Your final result description here"
|
|
1133
|
+
}
|
|
1134
|
+
]
|
|
1135
|
+
}
|
|
1136
|
+
],
|
|
1137
|
+
permissionLevel: 0 /* None */
|
|
1138
|
+
};
|
|
1139
|
+
var handler2 = async (provider, args) => {
|
|
1140
|
+
const result = getString(args, "result");
|
|
1141
|
+
const moreMessage = await provider.attemptCompletion?.(result);
|
|
1142
|
+
if (!moreMessage) {
|
|
1143
|
+
return {
|
|
1144
|
+
type: "Exit" /* Exit */,
|
|
1145
|
+
message: result
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
return {
|
|
1149
|
+
type: "Reply" /* Reply */,
|
|
1150
|
+
message: `<user_message>${moreMessage}</user_message>`
|
|
1151
|
+
};
|
|
1152
|
+
};
|
|
1153
|
+
var isAvailable2 = (provider) => {
|
|
1154
|
+
return true;
|
|
1155
|
+
};
|
|
1156
|
+
var attemptCompletion_default = {
|
|
1157
|
+
...toolInfo2,
|
|
1158
|
+
handler: handler2,
|
|
1159
|
+
isAvailable: isAvailable2
|
|
1160
|
+
};
|
|
1161
|
+
|
|
1162
|
+
// src/tools/delegate.ts
|
|
1163
|
+
var toolInfo3 = {
|
|
1164
|
+
name: "delegate",
|
|
1165
|
+
description: "Temporarily delegate a task to another agent and receive the result back. This tool MUST NOT to be used with any other tool.",
|
|
1166
|
+
parameters: [
|
|
1167
|
+
{
|
|
1168
|
+
name: "agent_name",
|
|
1169
|
+
description: "The name of the agent to delegate the task to",
|
|
1170
|
+
required: true,
|
|
1171
|
+
usageValue: "Name of the target agent"
|
|
1172
|
+
},
|
|
1173
|
+
{
|
|
1174
|
+
name: "task",
|
|
1175
|
+
description: "The task to be completed by the target agent",
|
|
1176
|
+
required: true,
|
|
1177
|
+
usageValue: "Task description"
|
|
1178
|
+
},
|
|
1179
|
+
{
|
|
1180
|
+
name: "context",
|
|
1181
|
+
description: "The context information for the task",
|
|
1182
|
+
required: true,
|
|
1183
|
+
usageValue: "Context information"
|
|
1184
|
+
},
|
|
1185
|
+
{
|
|
1186
|
+
name: "files",
|
|
1187
|
+
description: "The files relevant to the task. Comma separated paths",
|
|
1188
|
+
required: false,
|
|
1189
|
+
usageValue: "Relevant files"
|
|
1190
|
+
}
|
|
1191
|
+
],
|
|
1192
|
+
examples: [
|
|
1193
|
+
{
|
|
1194
|
+
description: "Delegate a code analysis task to the analyzer agent",
|
|
1195
|
+
parameters: [
|
|
1196
|
+
{
|
|
1197
|
+
name: "agent_name",
|
|
1198
|
+
value: "analyzer"
|
|
1199
|
+
},
|
|
1200
|
+
{
|
|
1201
|
+
name: "task",
|
|
1202
|
+
value: "Analyze the authentication implementation"
|
|
1203
|
+
},
|
|
1204
|
+
{
|
|
1205
|
+
name: "context",
|
|
1206
|
+
value: "Need to understand the security implications of the current auth system"
|
|
1207
|
+
},
|
|
1208
|
+
{
|
|
1209
|
+
name: "files",
|
|
1210
|
+
value: "src/auth/login.ts,src/auth/types.ts"
|
|
1211
|
+
}
|
|
1212
|
+
]
|
|
1213
|
+
}
|
|
1214
|
+
],
|
|
1215
|
+
permissionLevel: 0 /* None */
|
|
1216
|
+
};
|
|
1217
|
+
var handler3 = async (_provider, args) => {
|
|
1218
|
+
const agentName = getString(args, "agent_name");
|
|
1219
|
+
const task = getString(args, "task");
|
|
1220
|
+
const context = getString(args, "context", void 0);
|
|
1221
|
+
const files = getStringArray(args, "files", []);
|
|
1222
|
+
return {
|
|
1223
|
+
type: "Delegate" /* Delegate */,
|
|
1224
|
+
agentName,
|
|
1225
|
+
task,
|
|
1226
|
+
context,
|
|
1227
|
+
files
|
|
1228
|
+
};
|
|
1229
|
+
};
|
|
1230
|
+
var isAvailable3 = (_provider) => {
|
|
1231
|
+
return true;
|
|
1232
|
+
};
|
|
1233
|
+
var delegate_default = {
|
|
1234
|
+
...toolInfo3,
|
|
1235
|
+
handler: handler3,
|
|
1236
|
+
isAvailable: isAvailable3
|
|
1237
|
+
};
|
|
1238
|
+
|
|
1239
|
+
// src/tools/executeCommand.ts
|
|
1240
|
+
var toolInfo4 = {
|
|
1241
|
+
name: "execute_command",
|
|
1242
|
+
description: `Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will also be executed in the project root directory regardless of executed commands in previous tool uses.`,
|
|
1243
|
+
parameters: [
|
|
1244
|
+
{
|
|
1245
|
+
name: "command",
|
|
1246
|
+
description: "The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.",
|
|
1247
|
+
required: true,
|
|
1248
|
+
usageValue: "Your command here"
|
|
1249
|
+
},
|
|
1250
|
+
{
|
|
1251
|
+
name: "requires_approval",
|
|
1252
|
+
description: `A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.`,
|
|
1253
|
+
required: false,
|
|
1254
|
+
usageValue: "true or false"
|
|
1255
|
+
}
|
|
1256
|
+
],
|
|
1257
|
+
examples: [
|
|
1258
|
+
{
|
|
1259
|
+
description: "Request to execute a command",
|
|
1260
|
+
parameters: [
|
|
1261
|
+
{
|
|
1262
|
+
name: "command",
|
|
1263
|
+
value: "npm run dev"
|
|
1264
|
+
},
|
|
1265
|
+
{
|
|
1266
|
+
name: "requires_approval",
|
|
1267
|
+
value: "false"
|
|
1268
|
+
}
|
|
1269
|
+
]
|
|
1270
|
+
}
|
|
1271
|
+
],
|
|
1272
|
+
permissionLevel: 3 /* Arbitrary */
|
|
1273
|
+
};
|
|
1274
|
+
var handler4 = async (provider, args) => {
|
|
1275
|
+
if (!provider.executeCommand) {
|
|
1276
|
+
return {
|
|
1277
|
+
type: "Error" /* Error */,
|
|
1278
|
+
message: "Not possible to execute command. Abort."
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
const command = getString(args, "command");
|
|
1282
|
+
const requiresApproval = getBoolean(args, "requires_approval", false);
|
|
1283
|
+
const result = await provider.executeCommand?.(command, requiresApproval);
|
|
1284
|
+
const message = `<command>${command}</command>
|
|
1285
|
+
<command_exit_code>${result.exitCode}</command_exit_code>
|
|
1286
|
+
<command_stdout>
|
|
1287
|
+
${result.stdout}
|
|
1288
|
+
</command_stdout>
|
|
1289
|
+
<command_stderr>
|
|
1290
|
+
${result.stderr}
|
|
1291
|
+
</command_stderr>`;
|
|
1292
|
+
if (result.exitCode === 0) {
|
|
1293
|
+
return {
|
|
1294
|
+
type: "Reply" /* Reply */,
|
|
1295
|
+
message
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
return {
|
|
1299
|
+
type: "Error" /* Error */,
|
|
1300
|
+
message
|
|
1301
|
+
};
|
|
1302
|
+
};
|
|
1303
|
+
var isAvailable4 = (provider) => {
|
|
1304
|
+
return !!provider.executeCommand;
|
|
1305
|
+
};
|
|
1306
|
+
var executeCommand_default = {
|
|
1307
|
+
...toolInfo4,
|
|
1308
|
+
handler: handler4,
|
|
1309
|
+
isAvailable: isAvailable4
|
|
1310
|
+
};
|
|
1311
|
+
|
|
1312
|
+
// src/tools/listCodeDefinitionNames.ts
|
|
1313
|
+
var toolInfo5 = {
|
|
1314
|
+
name: "list_code_definition_names",
|
|
1315
|
+
description: "Request to list definition names (classes, functions, methods, etc.) used for all files in a directory. This tool provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.",
|
|
1316
|
+
parameters: [
|
|
1317
|
+
{
|
|
1318
|
+
name: "path",
|
|
1319
|
+
description: "The path of a code file to list top level source code definitions for.",
|
|
1320
|
+
required: true,
|
|
1321
|
+
usageValue: "Directory path here"
|
|
1322
|
+
}
|
|
1323
|
+
],
|
|
1324
|
+
examples: [
|
|
1325
|
+
{
|
|
1326
|
+
description: "Request to list code definition names in a directory",
|
|
1327
|
+
parameters: [
|
|
1328
|
+
{
|
|
1329
|
+
name: "path",
|
|
1330
|
+
value: "src/utils"
|
|
1331
|
+
}
|
|
1332
|
+
]
|
|
1333
|
+
}
|
|
1334
|
+
],
|
|
1335
|
+
permissionLevel: 1 /* Read */
|
|
1336
|
+
};
|
|
1337
|
+
var handler5 = async (provider, args) => {
|
|
1338
|
+
if (!provider.listCodeDefinitionNames) {
|
|
1339
|
+
return {
|
|
1340
|
+
type: "Error" /* Error */,
|
|
1341
|
+
message: "Not possible to list code definition names. Abort."
|
|
1342
|
+
};
|
|
1343
|
+
}
|
|
1344
|
+
const path = getString(args, "path");
|
|
1345
|
+
const result = await provider.listCodeDefinitionNames(path);
|
|
1346
|
+
return {
|
|
1347
|
+
type: "Reply" /* Reply */,
|
|
1348
|
+
message: `<list_code_definition_names_path>${path}</list_code_definition_names_path>
|
|
1349
|
+
<list_code_definition_names_result>
|
|
1350
|
+
${result}
|
|
1351
|
+
</list_code_definition_names_result>`
|
|
1352
|
+
};
|
|
1353
|
+
};
|
|
1354
|
+
var isAvailable5 = (provider) => {
|
|
1355
|
+
return !!provider.listCodeDefinitionNames;
|
|
1356
|
+
};
|
|
1357
|
+
var listCodeDefinitionNames_default = {
|
|
1358
|
+
...toolInfo5,
|
|
1359
|
+
handler: handler5,
|
|
1360
|
+
isAvailable: isAvailable5
|
|
1361
|
+
};
|
|
1362
|
+
|
|
1363
|
+
// src/tools/listFiles.ts
|
|
1364
|
+
var toolInfo6 = {
|
|
1365
|
+
name: "list_files",
|
|
1366
|
+
description: "Request to list files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. Do not use this tool to confirm the existence of files you may have created, as the user will let you know if the files were created successfully or not.",
|
|
1367
|
+
parameters: [
|
|
1368
|
+
{
|
|
1369
|
+
name: "path",
|
|
1370
|
+
description: "The path of the directory to list contents for (relative to the current working directory)",
|
|
1371
|
+
required: true,
|
|
1372
|
+
usageValue: "Directory path here"
|
|
1373
|
+
},
|
|
1374
|
+
{
|
|
1375
|
+
name: "max_count",
|
|
1376
|
+
description: "The maximum number of files to list. Default to 2000",
|
|
1377
|
+
required: false,
|
|
1378
|
+
usageValue: "Maximum number of files to list (optional)"
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
name: "recursive",
|
|
1382
|
+
description: "Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.",
|
|
1383
|
+
required: false,
|
|
1384
|
+
usageValue: "true or false (optional)"
|
|
1385
|
+
}
|
|
1386
|
+
],
|
|
1387
|
+
examples: [
|
|
1388
|
+
{
|
|
1389
|
+
description: "Request to list files",
|
|
1390
|
+
parameters: [
|
|
1391
|
+
{
|
|
1392
|
+
name: "path",
|
|
1393
|
+
value: "src"
|
|
1394
|
+
},
|
|
1395
|
+
{
|
|
1396
|
+
name: "max_count",
|
|
1397
|
+
value: "100"
|
|
1398
|
+
}
|
|
1399
|
+
]
|
|
1400
|
+
}
|
|
1401
|
+
],
|
|
1402
|
+
permissionLevel: 1 /* Read */
|
|
1403
|
+
};
|
|
1404
|
+
var handler6 = async (provider, args) => {
|
|
1405
|
+
if (!provider.listFiles) {
|
|
1406
|
+
return {
|
|
1407
|
+
type: "Error" /* Error */,
|
|
1408
|
+
message: "Not possible to list files. Abort."
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
const path = getString(args, "path");
|
|
1412
|
+
const maxCount = getInt(args, "max_count", 2e3);
|
|
1413
|
+
const recursive = getBoolean(args, "recursive", true);
|
|
1414
|
+
const [files, limitReached] = await provider.listFiles(path, recursive, maxCount);
|
|
1415
|
+
return {
|
|
1416
|
+
type: "Reply" /* Reply */,
|
|
1417
|
+
message: `<list_files_path>${path}</list_files_path>
|
|
1418
|
+
<list_files_files>
|
|
1419
|
+
${files.join("\n")}
|
|
1420
|
+
</list_files_files>
|
|
1421
|
+
<list_files_truncated>${limitReached}</list_files_truncated>`
|
|
1422
|
+
};
|
|
1423
|
+
};
|
|
1424
|
+
var isAvailable6 = (provider) => {
|
|
1425
|
+
return !!provider.listFiles;
|
|
1426
|
+
};
|
|
1427
|
+
var listFiles_default = {
|
|
1428
|
+
...toolInfo6,
|
|
1429
|
+
handler: handler6,
|
|
1430
|
+
isAvailable: isAvailable6
|
|
1431
|
+
};
|
|
1432
|
+
|
|
1433
|
+
// src/tools/readFile.ts
|
|
1434
|
+
var toolInfo7 = {
|
|
1435
|
+
name: "read_file",
|
|
1436
|
+
description: "Request to read the contents of one or multiple files at the specified paths. Use comma separated paths to read multiple files. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. May not be suitable for other types of binary files, as it returns the raw content as a string. Try to list all the potential files are relevent to the task, and then use this tool to read all the relevant files.",
|
|
1437
|
+
parameters: [
|
|
1438
|
+
{
|
|
1439
|
+
name: "path",
|
|
1440
|
+
description: "The path of the file to read",
|
|
1441
|
+
required: true,
|
|
1442
|
+
usageValue: "Comma separated paths here"
|
|
1443
|
+
}
|
|
1444
|
+
],
|
|
1445
|
+
examples: [
|
|
1446
|
+
{
|
|
1447
|
+
description: "Request to read the contents of a file",
|
|
1448
|
+
parameters: [
|
|
1449
|
+
{
|
|
1450
|
+
name: "path",
|
|
1451
|
+
value: "src/main.js"
|
|
1452
|
+
}
|
|
1453
|
+
]
|
|
1454
|
+
},
|
|
1455
|
+
{
|
|
1456
|
+
description: "Request to read multiple files",
|
|
1457
|
+
parameters: [
|
|
1458
|
+
{
|
|
1459
|
+
name: "path",
|
|
1460
|
+
value: "src/main.js,src/index.js"
|
|
1461
|
+
}
|
|
1462
|
+
]
|
|
1463
|
+
}
|
|
1464
|
+
],
|
|
1465
|
+
permissionLevel: 1 /* Read */
|
|
1466
|
+
};
|
|
1467
|
+
var handler7 = async (provider, args) => {
|
|
1468
|
+
if (!provider.readFile) {
|
|
1469
|
+
return {
|
|
1470
|
+
type: "Error" /* Error */,
|
|
1471
|
+
message: "Not possible to read file. Abort."
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
const paths = getStringArray(args, "path");
|
|
1475
|
+
const resp = [];
|
|
1476
|
+
for (const path of paths) {
|
|
1477
|
+
const fileContent = await provider.readFile(path);
|
|
1478
|
+
const isEmpty = fileContent.trim().length === 0;
|
|
1479
|
+
if (isEmpty) {
|
|
1480
|
+
resp.push(`<read_file_file_content path="${path}" is_empty="true" />`);
|
|
1481
|
+
} else {
|
|
1482
|
+
resp.push(`<read_file_file_conten path="${path}">${fileContent}</read_file_file_content>`);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
return {
|
|
1486
|
+
type: "Reply" /* Reply */,
|
|
1487
|
+
message: resp.join("\n")
|
|
1488
|
+
};
|
|
1489
|
+
};
|
|
1490
|
+
var isAvailable7 = (provider) => {
|
|
1491
|
+
return !!provider.readFile;
|
|
1492
|
+
};
|
|
1493
|
+
var readFile_default = {
|
|
1494
|
+
...toolInfo7,
|
|
1495
|
+
handler: handler7,
|
|
1496
|
+
isAvailable: isAvailable7
|
|
1497
|
+
};
|
|
1498
|
+
|
|
1499
|
+
// src/tools/replaceInFile.ts
|
|
1500
|
+
var toolInfo8 = {
|
|
1501
|
+
name: "replace_in_file",
|
|
1502
|
+
description: "Request to replace sections of content in an existing file using SEARCH/REPLACE blocks that define exact changes to specific parts of the file. This tool should be used when you need to make targeted changes to specific parts of a file.",
|
|
1503
|
+
parameters: [
|
|
1504
|
+
{
|
|
1505
|
+
name: "path",
|
|
1506
|
+
description: "The path of the file to modify",
|
|
1507
|
+
required: true,
|
|
1508
|
+
usageValue: "File path here"
|
|
1509
|
+
},
|
|
1510
|
+
{
|
|
1511
|
+
name: "diff",
|
|
1512
|
+
description: `One or more SEARCH/REPLACE blocks following this exact format:
|
|
1513
|
+
\`\`\`
|
|
1514
|
+
<<<<<<< SEARCH
|
|
1515
|
+
[exact content to find]
|
|
1516
|
+
=======
|
|
1517
|
+
[new content to replace with]
|
|
1518
|
+
>>>>>>> REPLACE
|
|
1519
|
+
\`\`\`
|
|
1520
|
+
Critical rules:
|
|
1521
|
+
1. SEARCH content must match the associated file section to find EXACTLY:
|
|
1522
|
+
* Match character-for-character including whitespace, indentation, line endings
|
|
1523
|
+
* Include all comments, docstrings, etc.
|
|
1524
|
+
2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.
|
|
1525
|
+
* Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.
|
|
1526
|
+
* Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.
|
|
1527
|
+
* When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.
|
|
1528
|
+
3. Keep SEARCH/REPLACE blocks concise:
|
|
1529
|
+
* Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.
|
|
1530
|
+
* Include just the changing lines, and a few surrounding lines if needed for uniqueness.
|
|
1531
|
+
* Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.
|
|
1532
|
+
* Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.
|
|
1533
|
+
4. Special operations:
|
|
1534
|
+
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
|
1535
|
+
* To delete code: Use empty REPLACE section`,
|
|
1536
|
+
required: true,
|
|
1537
|
+
usageValue: "Search and replace blocks here"
|
|
1538
|
+
}
|
|
1539
|
+
],
|
|
1540
|
+
examples: [
|
|
1541
|
+
{
|
|
1542
|
+
description: "Request to replace sections of content in a file",
|
|
1543
|
+
parameters: [
|
|
1544
|
+
{
|
|
1545
|
+
name: "path",
|
|
1546
|
+
value: "src/main.js"
|
|
1547
|
+
},
|
|
1548
|
+
{
|
|
1549
|
+
name: "diff",
|
|
1550
|
+
value: `
|
|
1551
|
+
<<<<<<< SEARCH
|
|
1552
|
+
import React from 'react';
|
|
1553
|
+
=======
|
|
1554
|
+
import React, { useState } from 'react';
|
|
1555
|
+
>>>>>>> REPLACE
|
|
1556
|
+
|
|
1557
|
+
<<<<<<< SEARCH
|
|
1558
|
+
function handleSubmit() {
|
|
1559
|
+
saveData();
|
|
1560
|
+
setLoading(false);
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
=======
|
|
1564
|
+
>>>>>>> REPLACE
|
|
1565
|
+
|
|
1566
|
+
<<<<<<< SEARCH
|
|
1567
|
+
return (
|
|
1568
|
+
<div>
|
|
1569
|
+
=======
|
|
1570
|
+
function handleSubmit() {
|
|
1571
|
+
saveData();
|
|
1572
|
+
setLoading(false);
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
return (
|
|
1576
|
+
<div>
|
|
1577
|
+
>>>>>>> REPLACE
|
|
1578
|
+
`
|
|
1579
|
+
}
|
|
1580
|
+
]
|
|
1581
|
+
}
|
|
1582
|
+
],
|
|
1583
|
+
permissionLevel: 2 /* Write */
|
|
1584
|
+
};
|
|
1585
|
+
var handler8 = async (provider, args) => {
|
|
1586
|
+
if (!provider.readFile || !provider.writeFile) {
|
|
1587
|
+
return {
|
|
1588
|
+
type: "Error" /* Error */,
|
|
1589
|
+
message: "Not possible to replace in file. Abort."
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
const path = getString(args, "path");
|
|
1593
|
+
const diff = getString(args, "diff");
|
|
1594
|
+
const fileContent = await provider.readFile(path);
|
|
1595
|
+
const result = await replaceInFile(fileContent, diff);
|
|
1596
|
+
await provider.writeFile(path, result);
|
|
1597
|
+
return {
|
|
1598
|
+
type: "Reply" /* Reply */,
|
|
1599
|
+
message: `<replace_in_file_path>${path}</replace_in_file_path>`
|
|
1600
|
+
};
|
|
1601
|
+
};
|
|
1602
|
+
var isAvailable8 = (provider) => {
|
|
1603
|
+
return !!provider.readFile && !!provider.writeFile;
|
|
1604
|
+
};
|
|
1605
|
+
var replaceInFile_default = {
|
|
1606
|
+
...toolInfo8,
|
|
1607
|
+
handler: handler8,
|
|
1608
|
+
isAvailable: isAvailable8
|
|
1609
|
+
};
|
|
1610
|
+
|
|
1611
|
+
// src/tools/searchFiles.ts
|
|
1612
|
+
var toolInfo9 = {
|
|
1613
|
+
name: "search_files",
|
|
1614
|
+
description: "Request to perform a regex search across files in a specified directory, outputting context-rich results that include surrounding lines. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context.",
|
|
1615
|
+
parameters: [
|
|
1616
|
+
{
|
|
1617
|
+
name: "path",
|
|
1618
|
+
description: "The path of the directory to search in (relative to the current working directory). This directory will be recursively searched.",
|
|
1619
|
+
required: true,
|
|
1620
|
+
usageValue: "Directory path here"
|
|
1621
|
+
},
|
|
1622
|
+
{
|
|
1623
|
+
name: "regex",
|
|
1624
|
+
description: "The regular expression pattern to search for. Uses Rust regex syntax.",
|
|
1625
|
+
required: true,
|
|
1626
|
+
usageValue: "Your regex pattern here"
|
|
1627
|
+
},
|
|
1628
|
+
{
|
|
1629
|
+
name: "file_pattern",
|
|
1630
|
+
description: 'Glob pattern to filter files (e.g., "*.ts" for TypeScript files). If not provided, it will search all files (*).',
|
|
1631
|
+
required: false,
|
|
1632
|
+
usageValue: "file pattern here (optional)"
|
|
1633
|
+
}
|
|
1634
|
+
],
|
|
1635
|
+
examples: [
|
|
1636
|
+
{
|
|
1637
|
+
description: "Request to perform a regex search across files",
|
|
1638
|
+
parameters: [
|
|
1639
|
+
{
|
|
1640
|
+
name: "path",
|
|
1641
|
+
value: "src"
|
|
1642
|
+
},
|
|
1643
|
+
{
|
|
1644
|
+
name: "regex",
|
|
1645
|
+
value: "^components/"
|
|
1646
|
+
},
|
|
1647
|
+
{
|
|
1648
|
+
name: "file_pattern",
|
|
1649
|
+
value: "*.ts"
|
|
1650
|
+
}
|
|
1651
|
+
]
|
|
1652
|
+
}
|
|
1653
|
+
],
|
|
1654
|
+
permissionLevel: 1 /* Read */
|
|
1655
|
+
};
|
|
1656
|
+
var handler9 = async (provider, args) => {
|
|
1657
|
+
if (!provider.searchFiles) {
|
|
1658
|
+
return {
|
|
1659
|
+
type: "Error" /* Error */,
|
|
1660
|
+
message: "Not possible to search files. Abort."
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1663
|
+
const path = getString(args, "path");
|
|
1664
|
+
const regex = getString(args, "regex");
|
|
1665
|
+
const filePattern = getString(args, "file_pattern", "*");
|
|
1666
|
+
const files = await provider.searchFiles(path, regex, filePattern);
|
|
1667
|
+
return {
|
|
1668
|
+
type: "Reply" /* Reply */,
|
|
1669
|
+
message: `<search_files_path>${path}</search_files_path>
|
|
1670
|
+
<search_files_regex>${regex}</search_files_regex>
|
|
1671
|
+
<search_files_file_pattern>${filePattern}</search_files_file_pattern>
|
|
1672
|
+
<search_files_files>
|
|
1673
|
+
${files.join("\n")}
|
|
1674
|
+
</search_files_files>
|
|
1675
|
+
`
|
|
1676
|
+
};
|
|
1677
|
+
};
|
|
1678
|
+
var isAvailable9 = (provider) => {
|
|
1679
|
+
return !!provider.searchFiles;
|
|
1680
|
+
};
|
|
1681
|
+
var searchFiles_default = {
|
|
1682
|
+
...toolInfo9,
|
|
1683
|
+
handler: handler9,
|
|
1684
|
+
isAvailable: isAvailable9
|
|
1685
|
+
};
|
|
1686
|
+
|
|
1687
|
+
// src/tools/writeToFile.ts
|
|
1688
|
+
var toolInfo10 = {
|
|
1689
|
+
name: "write_to_file",
|
|
1690
|
+
description: "Request to write content to a file at the specified path. If the file exists, it will be overwritten with the provided content. If the file doesn't exist, it will be created. This tool will automatically create any directories needed to write the file.",
|
|
1691
|
+
parameters: [
|
|
1692
|
+
{
|
|
1693
|
+
name: "path",
|
|
1694
|
+
description: "The path of the file to write to",
|
|
1695
|
+
required: true,
|
|
1696
|
+
usageValue: "File path here"
|
|
1697
|
+
},
|
|
1698
|
+
{
|
|
1699
|
+
name: "content",
|
|
1700
|
+
description: "The content to write to the file. ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified.",
|
|
1701
|
+
required: true,
|
|
1702
|
+
usageValue: "Your file content here"
|
|
1703
|
+
}
|
|
1704
|
+
],
|
|
1705
|
+
examples: [
|
|
1706
|
+
{
|
|
1707
|
+
description: "Request to write content to a file",
|
|
1708
|
+
parameters: [
|
|
1709
|
+
{
|
|
1710
|
+
name: "path",
|
|
1711
|
+
value: "src/main.js"
|
|
1712
|
+
},
|
|
1713
|
+
{
|
|
1714
|
+
name: "content",
|
|
1715
|
+
value: `import React from 'react';
|
|
1716
|
+
|
|
1717
|
+
function App() {
|
|
1718
|
+
return (
|
|
1719
|
+
<div>
|
|
1720
|
+
<h1>Hello, World!</h1>
|
|
1721
|
+
</div>
|
|
1722
|
+
);
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
export default App;
|
|
1726
|
+
`
|
|
1727
|
+
}
|
|
1728
|
+
]
|
|
1729
|
+
}
|
|
1730
|
+
],
|
|
1731
|
+
permissionLevel: 2 /* Write */
|
|
1732
|
+
};
|
|
1733
|
+
var handler10 = async (provider, args) => {
|
|
1734
|
+
if (!provider.writeFile) {
|
|
1735
|
+
return {
|
|
1736
|
+
type: "Error" /* Error */,
|
|
1737
|
+
message: "Not possible to write file. Abort."
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
const path = getString(args, "path");
|
|
1741
|
+
const content = getString(args, "content");
|
|
1742
|
+
await provider.writeFile(path, content);
|
|
1743
|
+
return {
|
|
1744
|
+
type: "Reply" /* Reply */,
|
|
1745
|
+
message: `<write_to_file_path>${path}</write_to_file_path><status>Success</status>`
|
|
1746
|
+
};
|
|
1747
|
+
};
|
|
1748
|
+
var isAvailable10 = (provider) => {
|
|
1749
|
+
return !!provider.writeFile;
|
|
1750
|
+
};
|
|
1751
|
+
var writeToFile_default = {
|
|
1752
|
+
...toolInfo10,
|
|
1753
|
+
handler: handler10,
|
|
1754
|
+
isAvailable: isAvailable10
|
|
1755
|
+
};
|
|
1756
|
+
|
|
1757
|
+
// src/tools/handOver.ts
|
|
1758
|
+
var toolInfo11 = {
|
|
1759
|
+
name: "hand_over",
|
|
1760
|
+
description: "Hand over the current task to another agent to complete. This tool MUST NOT to be used with any other tool.",
|
|
1761
|
+
parameters: [
|
|
1762
|
+
{
|
|
1763
|
+
name: "agent_name",
|
|
1764
|
+
description: "The name of the agent to hand over the task to",
|
|
1765
|
+
required: true,
|
|
1766
|
+
usageValue: "Name of the target agent"
|
|
1767
|
+
},
|
|
1768
|
+
{
|
|
1769
|
+
name: "task",
|
|
1770
|
+
description: "The task to be completed by the target agent",
|
|
1771
|
+
required: true,
|
|
1772
|
+
usageValue: "Task description"
|
|
1773
|
+
},
|
|
1774
|
+
{
|
|
1775
|
+
name: "context",
|
|
1776
|
+
description: "The context information for the task",
|
|
1777
|
+
required: true,
|
|
1778
|
+
usageValue: "Context information"
|
|
1779
|
+
},
|
|
1780
|
+
{
|
|
1781
|
+
name: "files",
|
|
1782
|
+
description: "The files relevant to the task. Comma separated paths",
|
|
1783
|
+
required: false,
|
|
1784
|
+
usageValue: "Relevant files"
|
|
1785
|
+
}
|
|
1786
|
+
],
|
|
1787
|
+
examples: [
|
|
1788
|
+
{
|
|
1789
|
+
description: "Hand over a coding task to the coder agent",
|
|
1790
|
+
parameters: [
|
|
1791
|
+
{
|
|
1792
|
+
name: "agent_name",
|
|
1793
|
+
value: "coder"
|
|
1794
|
+
},
|
|
1795
|
+
{
|
|
1796
|
+
name: "task",
|
|
1797
|
+
value: "Implement the login feature"
|
|
1798
|
+
},
|
|
1799
|
+
{
|
|
1800
|
+
name: "context",
|
|
1801
|
+
value: "We need a secure login system with email and password"
|
|
1802
|
+
},
|
|
1803
|
+
{
|
|
1804
|
+
name: "files",
|
|
1805
|
+
value: "src/auth/login.ts,src/auth/types.ts"
|
|
1806
|
+
}
|
|
1807
|
+
]
|
|
1808
|
+
}
|
|
1809
|
+
],
|
|
1810
|
+
permissionLevel: 0 /* None */
|
|
1811
|
+
};
|
|
1812
|
+
var handler11 = async (_provider, args) => {
|
|
1813
|
+
const agentName = getString(args, "agent_name");
|
|
1814
|
+
const task = getString(args, "task");
|
|
1815
|
+
const context = getString(args, "context", void 0);
|
|
1816
|
+
const files = getStringArray(args, "files", []);
|
|
1817
|
+
return {
|
|
1818
|
+
type: "HandOver" /* HandOver */,
|
|
1819
|
+
agentName,
|
|
1820
|
+
task,
|
|
1821
|
+
context,
|
|
1822
|
+
files
|
|
1823
|
+
};
|
|
1824
|
+
};
|
|
1825
|
+
var isAvailable11 = (_provider) => {
|
|
1826
|
+
return true;
|
|
1827
|
+
};
|
|
1828
|
+
var handOver_default = {
|
|
1829
|
+
...toolInfo11,
|
|
1830
|
+
handler: handler11,
|
|
1831
|
+
isAvailable: isAvailable11
|
|
1832
|
+
};
|
|
1833
|
+
|
|
1834
|
+
// src/tools/removeFile.ts
|
|
1835
|
+
var toolInfo12 = {
|
|
1836
|
+
name: "remove_file",
|
|
1837
|
+
description: "Request to remove a file at the specified path.",
|
|
1838
|
+
parameters: [
|
|
1839
|
+
{
|
|
1840
|
+
name: "path",
|
|
1841
|
+
description: "The path of the file to remove",
|
|
1842
|
+
required: true,
|
|
1843
|
+
usageValue: "File path here"
|
|
1844
|
+
}
|
|
1845
|
+
],
|
|
1846
|
+
examples: [
|
|
1847
|
+
{
|
|
1848
|
+
description: "Request to remove a file",
|
|
1849
|
+
parameters: [
|
|
1850
|
+
{
|
|
1851
|
+
name: "path",
|
|
1852
|
+
value: "src/main.js"
|
|
1853
|
+
}
|
|
1854
|
+
]
|
|
1855
|
+
}
|
|
1856
|
+
],
|
|
1857
|
+
permissionLevel: 2 /* Write */
|
|
1858
|
+
};
|
|
1859
|
+
var handler12 = async (provider, args) => {
|
|
1860
|
+
if (!provider.removeFile) {
|
|
1861
|
+
return {
|
|
1862
|
+
type: "Error" /* Error */,
|
|
1863
|
+
message: "Not possible to remove file. Abort."
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
const path = getString(args, "path");
|
|
1867
|
+
await provider.removeFile(path);
|
|
1868
|
+
return {
|
|
1869
|
+
type: "Reply" /* Reply */,
|
|
1870
|
+
message: `<remove_file_path>${path}</remove_file_path><status>Success</status>`
|
|
1871
|
+
};
|
|
1872
|
+
};
|
|
1873
|
+
var isAvailable12 = (provider) => {
|
|
1874
|
+
return !!provider.removeFile;
|
|
1875
|
+
};
|
|
1876
|
+
var removeFile_default = {
|
|
1877
|
+
...toolInfo12,
|
|
1878
|
+
handler: handler12,
|
|
1879
|
+
isAvailable: isAvailable12
|
|
1880
|
+
};
|
|
1881
|
+
|
|
1882
|
+
// src/tools/renameFile.ts
|
|
1883
|
+
var toolInfo13 = {
|
|
1884
|
+
name: "rename_file",
|
|
1885
|
+
description: "Request to rename a file from source path to target path.",
|
|
1886
|
+
parameters: [
|
|
1887
|
+
{
|
|
1888
|
+
name: "sourcePath",
|
|
1889
|
+
description: "The current path of the file",
|
|
1890
|
+
required: true,
|
|
1891
|
+
usageValue: "Source file path here"
|
|
1892
|
+
},
|
|
1893
|
+
{
|
|
1894
|
+
name: "targetPath",
|
|
1895
|
+
description: "The new path for the file",
|
|
1896
|
+
required: true,
|
|
1897
|
+
usageValue: "Target file path here"
|
|
1898
|
+
}
|
|
1899
|
+
],
|
|
1900
|
+
examples: [
|
|
1901
|
+
{
|
|
1902
|
+
description: "Request to rename a file",
|
|
1903
|
+
parameters: [
|
|
1904
|
+
{
|
|
1905
|
+
name: "sourcePath",
|
|
1906
|
+
value: "src/old-name.js"
|
|
1907
|
+
},
|
|
1908
|
+
{
|
|
1909
|
+
name: "targetPath",
|
|
1910
|
+
value: "src/new-name.js"
|
|
1911
|
+
}
|
|
1912
|
+
]
|
|
1913
|
+
}
|
|
1914
|
+
],
|
|
1915
|
+
permissionLevel: 2 /* Write */
|
|
1916
|
+
};
|
|
1917
|
+
var handler13 = async (provider, args) => {
|
|
1918
|
+
if (!provider.renameFile) {
|
|
1919
|
+
return {
|
|
1920
|
+
type: "Error" /* Error */,
|
|
1921
|
+
message: "Not possible to rename file. Abort."
|
|
1922
|
+
};
|
|
1923
|
+
}
|
|
1924
|
+
const sourcePath = getString(args, "sourcePath");
|
|
1925
|
+
const targetPath = getString(args, "targetPath");
|
|
1926
|
+
await provider.renameFile(sourcePath, targetPath);
|
|
1927
|
+
return {
|
|
1928
|
+
type: "Reply" /* Reply */,
|
|
1929
|
+
message: `<rename_file_path>${targetPath}</rename_file_path><status>Success</status>`
|
|
1930
|
+
};
|
|
1931
|
+
};
|
|
1932
|
+
var isAvailable13 = (provider) => {
|
|
1933
|
+
return !!provider.renameFile;
|
|
1934
|
+
};
|
|
1935
|
+
var renameFile_default = {
|
|
1936
|
+
...toolInfo13,
|
|
1937
|
+
handler: handler13,
|
|
1938
|
+
isAvailable: isAvailable13
|
|
1939
|
+
};
|
|
1940
|
+
|
|
1941
|
+
// src/getAvailableTools.ts
|
|
1942
|
+
var getAvailableTools = ({
|
|
1943
|
+
provider,
|
|
1944
|
+
allTools,
|
|
1945
|
+
hasAgent,
|
|
1946
|
+
permissionLevel,
|
|
1947
|
+
interactive
|
|
1948
|
+
}) => {
|
|
1949
|
+
const filteredTools = interactive ? allTools : allTools.filter((tool) => tool.name !== askFollowupQuestion_default.name);
|
|
1950
|
+
const tools = [];
|
|
1951
|
+
for (const tool of filteredTools) {
|
|
1952
|
+
if (!hasAgent) {
|
|
1953
|
+
switch (tool.name) {
|
|
1954
|
+
case handOver_default.name:
|
|
1955
|
+
case delegate_default.name:
|
|
1956
|
+
continue;
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
if (tool.isAvailable(provider) && tool.permissionLevel <= permissionLevel) {
|
|
1960
|
+
tools.push(tool);
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
return tools;
|
|
1964
|
+
};
|
|
1965
|
+
|
|
1966
|
+
// src/Agent/parseAssistantMessage.ts
|
|
1967
|
+
function parseAssistantMessage(assistantMessage, tools, toolNamePrefix) {
|
|
1968
|
+
const parameterPrefix = `${toolNamePrefix}parameter_`;
|
|
1969
|
+
const results = [];
|
|
1970
|
+
const toolTags = tools.map((tool) => `${toolNamePrefix}${tool.name}`);
|
|
1971
|
+
const toolPattern = toolTags.join("|");
|
|
1972
|
+
let remainingMessage = assistantMessage;
|
|
1973
|
+
let match;
|
|
1974
|
+
const tagRegex = new RegExp(`<(${toolPattern})>([\\s\\S]*?)<\\/\\1>`, "s");
|
|
1975
|
+
while (true) {
|
|
1976
|
+
match = tagRegex.exec(remainingMessage);
|
|
1977
|
+
if (match === null) break;
|
|
1978
|
+
const beforeTag = remainingMessage.slice(0, match.index).trim();
|
|
1979
|
+
if (beforeTag) {
|
|
1980
|
+
results.push({
|
|
1981
|
+
type: "text",
|
|
1982
|
+
content: beforeTag
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1985
|
+
const tagName = match[1];
|
|
1986
|
+
const toolName = tagName.replace(toolNamePrefix, "");
|
|
1987
|
+
const tool = tools.find((t) => t.name === toolName);
|
|
1988
|
+
const fullTagContent = match[0];
|
|
1989
|
+
if (tool) {
|
|
1990
|
+
const params = {};
|
|
1991
|
+
for (const param of tool.parameters) {
|
|
1992
|
+
const paramName = `${parameterPrefix}${param.name}`;
|
|
1993
|
+
const escapedParamName = paramName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1994
|
+
const paramPattern = `<${escapedParamName}>([\\s\\S]*?)<\\/${escapedParamName}>`;
|
|
1995
|
+
const paramMatch = fullTagContent.match(new RegExp(paramPattern, "s"));
|
|
1996
|
+
if (paramMatch) {
|
|
1997
|
+
params[param.name] = paramMatch[1].trim();
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
results.push({
|
|
2001
|
+
type: "tool_use",
|
|
2002
|
+
name: toolName,
|
|
2003
|
+
params
|
|
2004
|
+
});
|
|
2005
|
+
} else {
|
|
2006
|
+
results.push({
|
|
2007
|
+
type: "text",
|
|
2008
|
+
content: fullTagContent
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
remainingMessage = remainingMessage.slice(match.index + fullTagContent.length);
|
|
2012
|
+
}
|
|
2013
|
+
if (remainingMessage.trim()) {
|
|
2014
|
+
results.push({
|
|
2015
|
+
type: "text",
|
|
2016
|
+
content: remainingMessage.trim()
|
|
2017
|
+
});
|
|
2018
|
+
}
|
|
2019
|
+
if (results.length === 0) {
|
|
2020
|
+
results.push({
|
|
2021
|
+
type: "text",
|
|
2022
|
+
content: assistantMessage
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
2025
|
+
return results;
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
// src/Agent/prompts.ts
|
|
2029
|
+
var toolInfoPrompt = (tool, toolNamePrefix, parameterPrefix) => `
|
|
2030
|
+
## ${toolNamePrefix}${tool.name}
|
|
2031
|
+
|
|
2032
|
+
Description: ${tool.description}
|
|
2033
|
+
|
|
2034
|
+
Parameters:
|
|
2035
|
+
${tool.parameters.map((param) => `- ${parameterPrefix}${param.name}: (${param.required ? "required" : "optional"}) ${param.description}`).join("\n")}
|
|
2036
|
+
|
|
2037
|
+
Usage:
|
|
2038
|
+
<${toolNamePrefix}${tool.name}>
|
|
2039
|
+
${tool.parameters.map((param) => `<${parameterPrefix}${param.name}>${param.usageValue}</${parameterPrefix}${param.name}>`).join("\n")}
|
|
2040
|
+
</${toolNamePrefix}${tool.name}>`;
|
|
2041
|
+
var toolInfoExamplesPrompt = (idx, tool, example, toolNamePrefix, parameterPrefix) => `
|
|
2042
|
+
## Example ${idx + 1}: ${example.description}
|
|
2043
|
+
|
|
2044
|
+
<${toolNamePrefix}${tool.name}>
|
|
2045
|
+
${example.parameters.map((param) => `<${parameterPrefix}${param.name}>${param.value}</${parameterPrefix}${param.name}>`).join("\n")}
|
|
2046
|
+
</${toolNamePrefix}${tool.name}>
|
|
2047
|
+
`;
|
|
2048
|
+
var toolUsePrompt = (tools, toolNamePrefix) => {
|
|
2049
|
+
if (tools.length === 0) {
|
|
2050
|
+
return "";
|
|
2051
|
+
}
|
|
2052
|
+
const parameterPrefix = `${toolNamePrefix}parameter_`;
|
|
2053
|
+
let exampleIndex = 0;
|
|
2054
|
+
return `
|
|
2055
|
+
====
|
|
2056
|
+
|
|
2057
|
+
TOOL USE
|
|
2058
|
+
|
|
2059
|
+
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
|
|
2060
|
+
|
|
2061
|
+
# Tool Use Formatting
|
|
2062
|
+
|
|
2063
|
+
Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
|
|
2064
|
+
|
|
2065
|
+
<${toolNamePrefix}tool_name>
|
|
2066
|
+
<${parameterPrefix}name1>value1</${parameterPrefix}name1>
|
|
2067
|
+
<${parameterPrefix}name2>value2</${parameterPrefix}name2>
|
|
2068
|
+
...
|
|
2069
|
+
</${toolNamePrefix}tool_name>
|
|
2070
|
+
|
|
2071
|
+
For example:
|
|
2072
|
+
|
|
2073
|
+
<${toolNamePrefix}read_file>
|
|
2074
|
+
<${parameterPrefix}path>src/main.js</${parameterPrefix}path>
|
|
2075
|
+
</${toolNamePrefix}read_file>
|
|
2076
|
+
|
|
2077
|
+
Always adhere to this format for the tool use to ensure proper parsing and execution.
|
|
2078
|
+
|
|
2079
|
+
NEVER surround tool use with triple backticks (\`\`\`).
|
|
2080
|
+
|
|
2081
|
+
# Tools
|
|
2082
|
+
${tools.map((tool) => toolInfoPrompt(tool, toolNamePrefix, parameterPrefix)).join("\n")}
|
|
2083
|
+
|
|
2084
|
+
# Tool Use Examples
|
|
2085
|
+
${tools.map((tool) => {
|
|
2086
|
+
let promp = "";
|
|
2087
|
+
for (const example of tool.examples ?? []) {
|
|
2088
|
+
promp += toolInfoExamplesPrompt(exampleIndex++, tool, example, toolNamePrefix, parameterPrefix);
|
|
2089
|
+
}
|
|
2090
|
+
return promp;
|
|
2091
|
+
}).join("")}
|
|
2092
|
+
# Tool Use Guidelines
|
|
2093
|
+
|
|
2094
|
+
1. **Thinking**: Use \`<thinking>\` XCM tag to clearly outline your thought process *before* using any tools. This includes:
|
|
2095
|
+
* Assessing the current situation and available information.
|
|
2096
|
+
* Defining specific goals and a plan to achieve them.
|
|
2097
|
+
* Justifying the selection of a particular tool.
|
|
2098
|
+
* Explaining how you intend to use the tool and what you expect to achieve.
|
|
2099
|
+
2. **Tool Selection**: Choose one tool at a time per message based on the task and its description. Do not assume a tool\u2019s outcome without explicit confirmation.
|
|
2100
|
+
3. **Formatting**: Formulate tool use only in the specified XML format for each tool.
|
|
2101
|
+
4. **User Response**: Wait for the user\u2019s response after each tool use. Do not proceed until you have their confirmation. The user\u2019s response may include:
|
|
2102
|
+
* Tool success or failure details
|
|
2103
|
+
* Linter errors
|
|
2104
|
+
* Terminal output or other relevant feedback
|
|
2105
|
+
5. **Conciseness**: Never repeat or quote the entire tool command in your final user-facing message. Summarize outcomes clearly and avoid echoing commands verbatim.
|
|
2106
|
+
6. **Brevity**: Respond concisely and move the conversation forward. Do not re-issue the same command or re-trigger tool use without necessity.
|
|
2107
|
+
7. **Iteration**: Follow these steps iteratively, confirming success and addressing issues as you go.
|
|
2108
|
+
8. **Error Handling**: If a tool returns an error, analyze the error message and adjust your approach accordingly. Consider alternative tools or strategies to achieve the desired outcome.
|
|
2109
|
+
|
|
2110
|
+
By adhering to these guidelines:
|
|
2111
|
+
- You maintain clarity without accidentally re-invoking tools.
|
|
2112
|
+
- You confirm each step\u2019s results before proceeding.
|
|
2113
|
+
- You provide only the necessary information in user-facing replies to prevent re-interpretation as new commands.`;
|
|
2114
|
+
};
|
|
2115
|
+
var agentsPrompt = (agents, name) => `
|
|
2116
|
+
====
|
|
2117
|
+
|
|
2118
|
+
AVAILABLE AGENTS
|
|
2119
|
+
|
|
2120
|
+
The following agents are available for task handover/delegate:
|
|
2121
|
+
${agents.map(
|
|
2122
|
+
(agent) => `
|
|
2123
|
+
- **${agent.name}**
|
|
2124
|
+
- Responsibilities:
|
|
2125
|
+
${agent.responsibilities.map((resp) => ` - ${resp}`).join("\n")}`
|
|
2126
|
+
).join("\n")}
|
|
2127
|
+
|
|
2128
|
+
- **Current Agent Role**
|
|
2129
|
+
You are currently acting as **${name}**. If you identify the task is beyond your current scope, use the handover or delegate tool to transition to the other agent. Include sufficient context so the new agent can seamlessly continue the work.
|
|
2130
|
+
`;
|
|
2131
|
+
var capabilities = (toolNamePrefix) => `
|
|
2132
|
+
====
|
|
2133
|
+
|
|
2134
|
+
CAPABILITIES
|
|
2135
|
+
|
|
2136
|
+
- You have access to a range of tools to aid you in your work. These tools help you effectively accomplish a wide range of tasks.
|
|
2137
|
+
- When the user initially gives you a task, a recursive list of all filepaths in the current working directory will be included in context. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further.`;
|
|
2138
|
+
var systemInformation = (info) => `
|
|
2139
|
+
====
|
|
2140
|
+
|
|
2141
|
+
SYSTEM INFORMATION
|
|
2142
|
+
|
|
2143
|
+
Operating System: ${info.os}`;
|
|
2144
|
+
var customInstructions = (customInstructions2) => {
|
|
2145
|
+
const joined = customInstructions2.join("\n");
|
|
2146
|
+
if (joined.trim() === "") {
|
|
2147
|
+
return "";
|
|
2148
|
+
}
|
|
2149
|
+
return `
|
|
2150
|
+
====
|
|
2151
|
+
|
|
2152
|
+
USER'S CUSTOM INSTRUCTIONS
|
|
2153
|
+
|
|
2154
|
+
The following additional instructions are provided by the user, and should be followed to the best of your ability without interfering with the TOOL USE guidelines.
|
|
2155
|
+
|
|
2156
|
+
${joined}`;
|
|
2157
|
+
};
|
|
2158
|
+
var customScripts = (commands) => {
|
|
2159
|
+
const joined = Object.entries(commands).map(([name, command]) => {
|
|
2160
|
+
if (typeof command === "string") {
|
|
2161
|
+
return `- ${name}
|
|
2162
|
+
- Command: \`${command}\``;
|
|
2163
|
+
}
|
|
2164
|
+
return `- ${name}
|
|
2165
|
+
- Command: \`${command.command}\`
|
|
2166
|
+
- Description: ${command.description}`;
|
|
2167
|
+
}).join("\n");
|
|
2168
|
+
if (joined.trim() === "") {
|
|
2169
|
+
return "";
|
|
2170
|
+
}
|
|
2171
|
+
return `
|
|
2172
|
+
====
|
|
2173
|
+
|
|
2174
|
+
USER'S CUSTOM COMMANDS
|
|
2175
|
+
|
|
2176
|
+
The following additional commands are provided by the user, and should be followed to the best of your ability without interfering with the TOOL USE guidelines.
|
|
2177
|
+
|
|
2178
|
+
${joined}`;
|
|
2179
|
+
};
|
|
2180
|
+
var responsePrompts = {
|
|
2181
|
+
errorInvokeTool: (tool, error) => `An error occurred while invoking the tool "${tool}": ${error}`,
|
|
2182
|
+
requireUseTool: "Error: You MUST use a tool before proceeding using XCM tags. e.g. <tool_tool_name>tool_name</tool_tool_name>",
|
|
2183
|
+
toolResults: (tool, result) => `<tool_response>
|
|
2184
|
+
<tool_name>${tool}</tool_name>
|
|
2185
|
+
<tool_result>
|
|
2186
|
+
${result}
|
|
2187
|
+
</tool_result>
|
|
2188
|
+
</tool_response>`,
|
|
2189
|
+
commandResult: (command, exitCode, stdout, stderr) => `<command>${command}</command>
|
|
2190
|
+
<command_exit_code>${exitCode}</command_exit_code>
|
|
2191
|
+
<command_stdout>
|
|
2192
|
+
${stdout}
|
|
2193
|
+
</command_stdout>
|
|
2194
|
+
<command_stderr>
|
|
2195
|
+
${stderr}
|
|
2196
|
+
</command_stderr>`
|
|
2197
|
+
};
|
|
2198
|
+
|
|
2199
|
+
// src/Agent/AgentBase.ts
|
|
2200
|
+
var TaskEventKind = /* @__PURE__ */ ((TaskEventKind2) => {
|
|
2201
|
+
TaskEventKind2["StartTask"] = "StartTask";
|
|
2202
|
+
TaskEventKind2["StartRequest"] = "StartRequest";
|
|
2203
|
+
TaskEventKind2["EndRequest"] = "EndRequest";
|
|
2204
|
+
TaskEventKind2["Usage"] = "Usage";
|
|
2205
|
+
TaskEventKind2["Text"] = "Text";
|
|
2206
|
+
TaskEventKind2["Reasoning"] = "Reasoning";
|
|
2207
|
+
TaskEventKind2["ToolUse"] = "ToolUse";
|
|
2208
|
+
TaskEventKind2["ToolReply"] = "ToolReply";
|
|
2209
|
+
TaskEventKind2["ToolInvalid"] = "ToolInvalid";
|
|
2210
|
+
TaskEventKind2["ToolError"] = "ToolError";
|
|
2211
|
+
TaskEventKind2["ToolInterrupted"] = "ToolInterrupted";
|
|
2212
|
+
TaskEventKind2["ToolHandOver"] = "ToolHandOver";
|
|
2213
|
+
TaskEventKind2["ToolDelegate"] = "ToolDelegate";
|
|
2214
|
+
TaskEventKind2["UsageExceeded"] = "UsageExceeded";
|
|
2215
|
+
TaskEventKind2["EndTask"] = "EndTask";
|
|
2216
|
+
return TaskEventKind2;
|
|
2217
|
+
})(TaskEventKind || {});
|
|
2218
|
+
var AgentBase = class {
|
|
2219
|
+
ai;
|
|
2220
|
+
config;
|
|
2221
|
+
handlers;
|
|
2222
|
+
messages = [];
|
|
2223
|
+
constructor(name, ai, config) {
|
|
2224
|
+
this.ai = ai;
|
|
2225
|
+
if (config.agents && config.agents.length > 0) {
|
|
2226
|
+
const agents = agentsPrompt(config.agents, name);
|
|
2227
|
+
config.systemPrompt += `
|
|
2228
|
+
${agents}`;
|
|
2229
|
+
}
|
|
2230
|
+
this.config = config;
|
|
2231
|
+
const handlers = {};
|
|
2232
|
+
for (const tool of config.tools) {
|
|
2233
|
+
handlers[tool.name] = tool;
|
|
2234
|
+
}
|
|
2235
|
+
this.handlers = handlers;
|
|
2236
|
+
}
|
|
2237
|
+
async #callback(event) {
|
|
2238
|
+
await this.config.callback?.(event);
|
|
2239
|
+
}
|
|
2240
|
+
async startTask({ task, context }) {
|
|
2241
|
+
let text = `<task>${task}</task>`;
|
|
2242
|
+
if (context) {
|
|
2243
|
+
text += `
|
|
2244
|
+
<context>${context}</context>`;
|
|
2245
|
+
}
|
|
2246
|
+
this.#callback({ kind: "StartTask" /* StartTask */, agent: this, systemPrompt: this.config.systemPrompt });
|
|
2247
|
+
return await this.#processLoop(text);
|
|
2248
|
+
}
|
|
2249
|
+
async #processLoop(userMessage) {
|
|
2250
|
+
let nextRequest = userMessage;
|
|
2251
|
+
while (true) {
|
|
2252
|
+
if (this.ai.usageMeter.isLimitExceeded().result) {
|
|
2253
|
+
this.#callback({ kind: "UsageExceeded" /* UsageExceeded */, agent: this });
|
|
2254
|
+
return { type: "UsageExceeded" };
|
|
2255
|
+
}
|
|
2256
|
+
const response = await this.#request(nextRequest);
|
|
2257
|
+
const resp = await this.#handleResponse(response);
|
|
2258
|
+
if ("exit" in resp) {
|
|
2259
|
+
this.#callback({ kind: "EndTask" /* EndTask */, agent: this, exitReason: resp.exit });
|
|
2260
|
+
return resp.exit;
|
|
2261
|
+
}
|
|
2262
|
+
nextRequest = resp.replay;
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
async continueTask(userMessage) {
|
|
2266
|
+
return await this.#processLoop(userMessage);
|
|
2267
|
+
}
|
|
2268
|
+
async #request(userMessage) {
|
|
2269
|
+
if (!userMessage) {
|
|
2270
|
+
throw new Error("userMessage is missing");
|
|
2271
|
+
}
|
|
2272
|
+
await this.#callback({ kind: "StartRequest" /* StartRequest */, agent: this, userMessage });
|
|
2273
|
+
this.messages.push({
|
|
2274
|
+
role: "user",
|
|
2275
|
+
content: userMessage
|
|
2276
|
+
});
|
|
2277
|
+
let currentAssistantMessage = "";
|
|
2278
|
+
const retryCount = 5;
|
|
2279
|
+
for (let i = 0; i < retryCount; i++) {
|
|
2280
|
+
currentAssistantMessage = "";
|
|
2281
|
+
const stream = this.ai.send(this.config.systemPrompt, this.messages);
|
|
2282
|
+
for await (const chunk of stream) {
|
|
2283
|
+
switch (chunk.type) {
|
|
2284
|
+
case "usage":
|
|
2285
|
+
await this.#callback({ kind: "Usage" /* Usage */, agent: this });
|
|
2286
|
+
break;
|
|
2287
|
+
case "text":
|
|
2288
|
+
currentAssistantMessage += chunk.text;
|
|
2289
|
+
await this.#callback({ kind: "Text" /* Text */, agent: this, newText: chunk.text });
|
|
2290
|
+
break;
|
|
2291
|
+
case "reasoning":
|
|
2292
|
+
await this.#callback({ kind: "Reasoning" /* Reasoning */, agent: this, newText: chunk.text });
|
|
2293
|
+
break;
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
if (currentAssistantMessage) {
|
|
2297
|
+
break;
|
|
2298
|
+
}
|
|
2299
|
+
console.debug(`Retrying request ${i + 1} of ${retryCount}`);
|
|
2300
|
+
}
|
|
2301
|
+
if (!currentAssistantMessage) {
|
|
2302
|
+
throw new Error("No assistant message received");
|
|
2303
|
+
}
|
|
2304
|
+
this.messages.push({
|
|
2305
|
+
role: "assistant",
|
|
2306
|
+
content: currentAssistantMessage
|
|
2307
|
+
});
|
|
2308
|
+
const ret = parseAssistantMessage(currentAssistantMessage, this.config.tools, this.config.toolNamePrefix);
|
|
2309
|
+
await this.#callback({ kind: "EndRequest" /* EndRequest */, agent: this });
|
|
2310
|
+
return ret;
|
|
2311
|
+
}
|
|
2312
|
+
async #handleResponse(response) {
|
|
2313
|
+
const toolReponses = [];
|
|
2314
|
+
outer: for (const content of response) {
|
|
2315
|
+
switch (content.type) {
|
|
2316
|
+
case "text":
|
|
2317
|
+
break;
|
|
2318
|
+
case "tool_use": {
|
|
2319
|
+
await this.#callback({ kind: "ToolUse" /* ToolUse */, agent: this, tool: content.name });
|
|
2320
|
+
const toolResp = await this.#invokeTool(content.name, content.params);
|
|
2321
|
+
switch (toolResp.type) {
|
|
2322
|
+
case "Reply" /* Reply */:
|
|
2323
|
+
await this.#callback({ kind: "ToolReply" /* ToolReply */, agent: this, tool: content.name });
|
|
2324
|
+
toolReponses.push({ tool: content.name, response: toolResp.message });
|
|
2325
|
+
break;
|
|
2326
|
+
case "Exit" /* Exit */:
|
|
2327
|
+
if (toolReponses.length > 0) {
|
|
2328
|
+
break outer;
|
|
2329
|
+
}
|
|
2330
|
+
return { exit: toolResp };
|
|
2331
|
+
case "Invalid" /* Invalid */:
|
|
2332
|
+
await this.#callback({ kind: "ToolInvalid" /* ToolInvalid */, agent: this, tool: content.name });
|
|
2333
|
+
toolReponses.push({ tool: content.name, response: toolResp.message });
|
|
2334
|
+
break outer;
|
|
2335
|
+
case "Error" /* Error */:
|
|
2336
|
+
await this.#callback({ kind: "ToolError" /* ToolError */, agent: this, tool: content.name });
|
|
2337
|
+
toolReponses.push({ tool: content.name, response: toolResp.message });
|
|
2338
|
+
break outer;
|
|
2339
|
+
case "Interrupted" /* Interrupted */:
|
|
2340
|
+
await this.#callback({ kind: "ToolInterrupted" /* ToolInterrupted */, agent: this, tool: content.name });
|
|
2341
|
+
return { exit: toolResp };
|
|
2342
|
+
case "HandOver" /* HandOver */:
|
|
2343
|
+
if (toolReponses.length > 0) {
|
|
2344
|
+
break outer;
|
|
2345
|
+
}
|
|
2346
|
+
await this.#callback({
|
|
2347
|
+
kind: "ToolHandOver" /* ToolHandOver */,
|
|
2348
|
+
agent: this,
|
|
2349
|
+
tool: content.name,
|
|
2350
|
+
agentName: toolResp.agentName,
|
|
2351
|
+
task: toolResp.task,
|
|
2352
|
+
context: toolResp.context,
|
|
2353
|
+
files: toolResp.files
|
|
2354
|
+
});
|
|
2355
|
+
return { exit: toolResp };
|
|
2356
|
+
case "Delegate" /* Delegate */:
|
|
2357
|
+
if (toolReponses.length > 0) {
|
|
2358
|
+
continue;
|
|
2359
|
+
}
|
|
2360
|
+
await this.#callback({
|
|
2361
|
+
kind: "ToolDelegate" /* ToolDelegate */,
|
|
2362
|
+
agent: this,
|
|
2363
|
+
tool: content.name,
|
|
2364
|
+
agentName: toolResp.agentName,
|
|
2365
|
+
task: toolResp.task,
|
|
2366
|
+
context: toolResp.context,
|
|
2367
|
+
files: toolResp.files
|
|
2368
|
+
});
|
|
2369
|
+
return { exit: toolResp };
|
|
2370
|
+
}
|
|
2371
|
+
break;
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
if (toolReponses.length === 0) {
|
|
2376
|
+
return { replay: responsePrompts.requireUseTool };
|
|
2377
|
+
}
|
|
2378
|
+
const finalResp = toolReponses.map(({ tool, response: response2 }) => responsePrompts.toolResults(tool, response2)).join("\n\n");
|
|
2379
|
+
return { replay: finalResp };
|
|
2380
|
+
}
|
|
2381
|
+
async #invokeTool(name, args) {
|
|
2382
|
+
try {
|
|
2383
|
+
const handler14 = this.handlers[name]?.handler;
|
|
2384
|
+
if (!handler14) {
|
|
2385
|
+
return {
|
|
2386
|
+
type: "Error" /* Error */,
|
|
2387
|
+
message: responsePrompts.errorInvokeTool(name, "Tool not found"),
|
|
2388
|
+
canRetry: false
|
|
2389
|
+
};
|
|
2390
|
+
}
|
|
2391
|
+
const resp = await this.onBeforeInvokeTool(this.handlers[name].name, args);
|
|
2392
|
+
if (resp) {
|
|
2393
|
+
return resp;
|
|
2394
|
+
}
|
|
2395
|
+
return await handler14(this.config.provider, args);
|
|
2396
|
+
} catch (error) {
|
|
2397
|
+
return {
|
|
2398
|
+
type: "Error" /* Error */,
|
|
2399
|
+
message: responsePrompts.errorInvokeTool(name, error),
|
|
2400
|
+
canRetry: false
|
|
2401
|
+
};
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
get model() {
|
|
2405
|
+
return this.ai.model;
|
|
2406
|
+
}
|
|
2407
|
+
get usage() {
|
|
2408
|
+
return this.ai.usageMeter.usage;
|
|
2409
|
+
}
|
|
2410
|
+
};
|
|
2411
|
+
|
|
2412
|
+
// src/Agent/AnalyzerAgent/prompts.ts
|
|
2413
|
+
var fullSystemPrompt = (info, tools, toolNamePrefix, instructions, scripts) => `
|
|
2414
|
+
# Analyzer Agent
|
|
2415
|
+
|
|
2416
|
+
## Role
|
|
2417
|
+
You are the **Analyzer** agent, responsible for:
|
|
2418
|
+
1. **Project Structure Analysis** \u2013 Understand codebase organization and architecture.
|
|
2419
|
+
2. **Code Pattern Analysis** \u2013 Identify common patterns, conventions, and best practices.
|
|
2420
|
+
3. **Dependency Analysis** \u2013 Examine project dependencies and their usage.
|
|
2421
|
+
4. **Workflow Analysis** \u2013 Understand development tools, scripts, and processes.
|
|
2422
|
+
5. **Documentation Review** \u2013 Analyze documentation and code comments.
|
|
2423
|
+
|
|
2424
|
+
> **Note**: The **Analyzer** agent focuses on understanding and analyzing the codebase without making modifications. Your role is to provide insights and understanding that can inform development decisions.
|
|
2425
|
+
|
|
2426
|
+
## Rules
|
|
2427
|
+
1. **Thoroughness**: Conduct comprehensive analysis of relevant project aspects.
|
|
2428
|
+
2. **Pattern Recognition**: Identify recurring patterns, conventions, and architectural decisions.
|
|
2429
|
+
3. **Dependency Mapping**: Track and understand relationships between components.
|
|
2430
|
+
4. **Workflow Understanding**: Analyze build processes, testing approaches, and development tools.
|
|
2431
|
+
5. **Documentation Assessment**: Review documentation quality and completeness.
|
|
2432
|
+
6. **Non-Modification**: Never modify code or files - focus solely on analysis.
|
|
2433
|
+
|
|
2434
|
+
${toolUsePrompt(tools, toolNamePrefix)}
|
|
2435
|
+
${capabilities(toolNamePrefix)}
|
|
2436
|
+
${systemInformation(info)}
|
|
2437
|
+
${customInstructions(instructions)}
|
|
2438
|
+
${customScripts(scripts)}
|
|
2439
|
+
`;
|
|
2440
|
+
|
|
2441
|
+
// src/Agent/AnalyzerAgent/index.ts
|
|
2442
|
+
var AnalyzerAgent = class extends AgentBase {
|
|
2443
|
+
constructor(options) {
|
|
2444
|
+
const combinedTools = [...options.additionalTools ?? [], ...Object.values(allTools_exports)];
|
|
2445
|
+
const tools = getAvailableTools({
|
|
2446
|
+
provider: options.provider,
|
|
2447
|
+
allTools: combinedTools,
|
|
2448
|
+
hasAgent: (options.agents?.length ?? 0) > 0,
|
|
2449
|
+
permissionLevel: 1 /* Read */,
|
|
2450
|
+
interactive: true
|
|
2451
|
+
});
|
|
2452
|
+
const toolNamePrefix = "tool_";
|
|
2453
|
+
const systemPrompt = fullSystemPrompt(
|
|
2454
|
+
{
|
|
2455
|
+
os: options.os
|
|
2456
|
+
},
|
|
2457
|
+
tools,
|
|
2458
|
+
toolNamePrefix,
|
|
2459
|
+
options.customInstructions ?? [],
|
|
2460
|
+
options.scripts ?? {}
|
|
2461
|
+
);
|
|
2462
|
+
super(analyzerAgentInfo.name, options.ai, {
|
|
2463
|
+
systemPrompt,
|
|
2464
|
+
tools,
|
|
2465
|
+
toolNamePrefix,
|
|
2466
|
+
provider: options.provider,
|
|
2467
|
+
interactive: options.interactive,
|
|
2468
|
+
agents: options.agents,
|
|
2469
|
+
scripts: options.scripts,
|
|
2470
|
+
callback: options.callback
|
|
2471
|
+
});
|
|
2472
|
+
}
|
|
2473
|
+
onBeforeInvokeTool() {
|
|
2474
|
+
return Promise.resolve(void 0);
|
|
2475
|
+
}
|
|
2476
|
+
};
|
|
2477
|
+
var analyzerAgentInfo = {
|
|
2478
|
+
name: "analyzer",
|
|
2479
|
+
responsibilities: [
|
|
2480
|
+
"Analyzing project structure and organization",
|
|
2481
|
+
"Identifying key source code files and their relationships",
|
|
2482
|
+
"Understanding common coding patterns and conventions",
|
|
2483
|
+
"Examining development workflow and tooling",
|
|
2484
|
+
"Analyzing dependencies and their usage patterns"
|
|
2485
|
+
]
|
|
2486
|
+
};
|
|
2487
|
+
|
|
2488
|
+
// src/Agent/ArchitectAgent/prompts.ts
|
|
2489
|
+
var fullSystemPrompt2 = (info, tools, toolNamePrefix, instructions, scripts) => `
|
|
2490
|
+
# Architect Agent
|
|
2491
|
+
|
|
2492
|
+
## Role
|
|
2493
|
+
You are the **Architect** agent, responsible for:
|
|
2494
|
+
1. **Task Analysis** \u2013 Understand requirements.
|
|
2495
|
+
2. **File Identification** \u2013 Find and select relevant files.
|
|
2496
|
+
3. **File Reading** \u2013 Use the provided tools to gather information from these files.
|
|
2497
|
+
4. **Implementation Plan** \u2013 Draft a concise plan detailing steps, resources, and dependencies.
|
|
2498
|
+
5. **Review & Improve** \u2013 Evaluate and refine the plan.
|
|
2499
|
+
6. **Handover/Delegate** \u2013 Provide the final plan, context, and files to the **Coder** agent.
|
|
2500
|
+
|
|
2501
|
+
> **Note**: The **Architect** agent must not make any direct modifications. Your role is limited to creating the implementation plan and handing it over to the **Coder** agent, who will perform any actual changes.
|
|
2502
|
+
|
|
2503
|
+
## Rules
|
|
2504
|
+
1. **Consistency**: Maintain alignment with the user\u2019s instructions and the system\u2019s objectives at all times.
|
|
2505
|
+
2. **Relevance**: Only read and use files directly related to the task. Avoid unnecessary or tangential information.
|
|
2506
|
+
3. **Conciseness**: Keep all communications and plans succinct, avoiding superfluous or repetitive details.
|
|
2507
|
+
4. **Accuracy**: Ensure the information you gather and any conclusions you draw are correct and verifiable.
|
|
2508
|
+
5. **Clarity**: Present the final plan and any supporting details in a structured and easily understandable format.
|
|
2509
|
+
6. **Minimal Queries**: Ask clarifying questions only when essential, and avoid repeated questioning that does not add value.
|
|
2510
|
+
|
|
2511
|
+
## Steps
|
|
2512
|
+
1. **Analyze Task**
|
|
2513
|
+
- Gather and understand the user\u2019s requirements.
|
|
2514
|
+
- Note any potential constraints or objectives that may influence the plan.
|
|
2515
|
+
|
|
2516
|
+
2. **Identify Relevant Files**
|
|
2517
|
+
- Determine which files or documents are necessary.
|
|
2518
|
+
- Justify why these files are relevant.
|
|
2519
|
+
|
|
2520
|
+
3. **Read Files via Tools**
|
|
2521
|
+
- Utilize the provided tools to access and extract information from the identified files.
|
|
2522
|
+
- Summarize key insights or data for the solution.
|
|
2523
|
+
|
|
2524
|
+
4. **Create Implementation Plan**
|
|
2525
|
+
- Outline tasks, define milestones, and detail resources or dependencies.
|
|
2526
|
+
- Provide clear, concise instructions for each step.
|
|
2527
|
+
- Each step should be appropriate sized and self-contained.
|
|
2528
|
+
|
|
2529
|
+
5. **Handover/Delegate**
|
|
2530
|
+
- Evaluate the number of steps required.
|
|
2531
|
+
- Handleover to the **Coder** agent if only one step is required.
|
|
2532
|
+
- If multiple steps are required, delegate each step to the **Coder** agent.
|
|
2533
|
+
- Deliver the final implementation plan, context, and relevant files to the **Coder** agent.
|
|
2534
|
+
- Provide any additional instructions or clarifications needed for successful implementation.
|
|
2535
|
+
|
|
2536
|
+
${toolUsePrompt(tools, toolNamePrefix)}
|
|
2537
|
+
${capabilities(toolNamePrefix)}
|
|
2538
|
+
${systemInformation(info)}
|
|
2539
|
+
${customInstructions(instructions)}
|
|
2540
|
+
${customScripts(scripts)}
|
|
2541
|
+
`;
|
|
2542
|
+
|
|
2543
|
+
// src/Agent/ArchitectAgent/index.ts
|
|
2544
|
+
var ArchitectAgent = class extends AgentBase {
|
|
2545
|
+
constructor(options) {
|
|
2546
|
+
const combinedTools = [...options.additionalTools ?? [], ...Object.values(allTools_exports)];
|
|
2547
|
+
const tools = getAvailableTools({
|
|
2548
|
+
provider: options.provider,
|
|
2549
|
+
allTools: combinedTools,
|
|
2550
|
+
hasAgent: (options.agents?.length ?? 0) > 0,
|
|
2551
|
+
permissionLevel: 1 /* Read */,
|
|
2552
|
+
interactive: true
|
|
2553
|
+
});
|
|
2554
|
+
const toolNamePrefix = "tool_";
|
|
2555
|
+
const systemPrompt = fullSystemPrompt2(
|
|
2556
|
+
{
|
|
2557
|
+
os: options.os
|
|
2558
|
+
},
|
|
2559
|
+
tools,
|
|
2560
|
+
toolNamePrefix,
|
|
2561
|
+
options.customInstructions ?? [],
|
|
2562
|
+
options.scripts ?? {}
|
|
2563
|
+
);
|
|
2564
|
+
super(architectAgentInfo.name, options.ai, {
|
|
2565
|
+
systemPrompt,
|
|
2566
|
+
tools,
|
|
2567
|
+
toolNamePrefix,
|
|
2568
|
+
provider: options.provider,
|
|
2569
|
+
interactive: options.interactive,
|
|
2570
|
+
agents: options.agents,
|
|
2571
|
+
scripts: options.scripts,
|
|
2572
|
+
callback: options.callback
|
|
2573
|
+
});
|
|
2574
|
+
}
|
|
2575
|
+
onBeforeInvokeTool() {
|
|
2576
|
+
return Promise.resolve(void 0);
|
|
2577
|
+
}
|
|
2578
|
+
};
|
|
2579
|
+
var architectAgentInfo = {
|
|
2580
|
+
name: "architect",
|
|
2581
|
+
responsibilities: [
|
|
2582
|
+
"Analyzing the user\u2019s overall task and requirements.",
|
|
2583
|
+
"Creating plans and making higher-level decisions about system structure and design.",
|
|
2584
|
+
"Reviewing and analyzing existing code or components for maintainability and scalability.",
|
|
2585
|
+
"Laying out the roadmap for implementation."
|
|
2586
|
+
]
|
|
2587
|
+
};
|
|
2588
|
+
|
|
2589
|
+
// src/Agent/CodeFixerAgent/prompts.ts
|
|
2590
|
+
var basePrompt = `You are a highly skilled software engineer specializing in debugging and fixing code issues. You have extensive experience with:
|
|
2591
|
+
- Type systems and type checking
|
|
2592
|
+
- Test frameworks and debugging test failures
|
|
2593
|
+
- Code quality tools and best practices
|
|
2594
|
+
- Systematic debugging approaches`;
|
|
2595
|
+
var codeFixingStrategies = `
|
|
2596
|
+
====
|
|
2597
|
+
|
|
2598
|
+
CODE FIXING STRATEGIES
|
|
2599
|
+
|
|
2600
|
+
1. Type Errors
|
|
2601
|
+
- Analyze type error messages carefully
|
|
2602
|
+
- Check type definitions and imports
|
|
2603
|
+
- Consider type assertions only as a last resort
|
|
2604
|
+
- Verify type compatibility across function boundaries
|
|
2605
|
+
- Look for null/undefined handling issues
|
|
2606
|
+
|
|
2607
|
+
2. Test Failures
|
|
2608
|
+
- Examine test output and error messages
|
|
2609
|
+
- Check test setup and fixtures
|
|
2610
|
+
- Verify assertions and expectations
|
|
2611
|
+
- Look for async/timing issues
|
|
2612
|
+
- Consider edge cases and input validation
|
|
2613
|
+
|
|
2614
|
+
3. Code Quality Issues
|
|
2615
|
+
- Follow project's coding standards
|
|
2616
|
+
- Address linter warnings systematically
|
|
2617
|
+
- Improve code readability
|
|
2618
|
+
- Fix potential runtime issues
|
|
2619
|
+
- Consider performance implications
|
|
2620
|
+
|
|
2621
|
+
4. General Approach
|
|
2622
|
+
- Start with the most critical issues
|
|
2623
|
+
- Make minimal necessary changes
|
|
2624
|
+
- Verify fixes don't introduce new issues
|
|
2625
|
+
- Document complex fixes with comments
|
|
2626
|
+
- Track attempted solutions for each issue`;
|
|
2627
|
+
var retryGuidelines = `
|
|
2628
|
+
====
|
|
2629
|
+
|
|
2630
|
+
RETRY GUIDELINES
|
|
2631
|
+
|
|
2632
|
+
1. Before Retrying
|
|
2633
|
+
- Analyze previous attempt's failure
|
|
2634
|
+
- Consider alternative approaches
|
|
2635
|
+
- Check if similar issues were fixed
|
|
2636
|
+
- Verify no new issues were introduced
|
|
2637
|
+
|
|
2638
|
+
2. When to Retry
|
|
2639
|
+
- Error message changed but issue persists
|
|
2640
|
+
- New information available about the root cause
|
|
2641
|
+
- Different fixing strategy available
|
|
2642
|
+
- Previous attempt partially successful
|
|
2643
|
+
|
|
2644
|
+
3. When to Stop
|
|
2645
|
+
- Maximum retry limit reached
|
|
2646
|
+
- Same error occurs repeatedly
|
|
2647
|
+
- Fix would require major refactoring
|
|
2648
|
+
- Issue requires human intervention
|
|
2649
|
+
|
|
2650
|
+
4. After Maximum Retries
|
|
2651
|
+
- Document attempted solutions
|
|
2652
|
+
- Explain why the issue remains
|
|
2653
|
+
- Suggest manual intervention steps
|
|
2654
|
+
- Report any partial improvements`;
|
|
2655
|
+
var fullSystemPrompt3 = (info, tools, toolNamePrefix, instructions, scripts, interactive) => `
|
|
2656
|
+
${basePrompt}
|
|
2657
|
+
${toolUsePrompt(tools, toolNamePrefix)}
|
|
2658
|
+
${codeFixingStrategies}
|
|
2659
|
+
${retryGuidelines}
|
|
2660
|
+
${capabilities(toolNamePrefix)}
|
|
2661
|
+
${systemInformation(info)}
|
|
2662
|
+
${customInstructions(instructions)}
|
|
2663
|
+
${customScripts(scripts)}`;
|
|
2664
|
+
|
|
2665
|
+
// src/Agent/CodeFixerAgent/index.ts
|
|
2666
|
+
var CodeFixerAgent = class extends AgentBase {
|
|
2667
|
+
#maxRetries;
|
|
2668
|
+
#retryCount = 0;
|
|
2669
|
+
constructor(options) {
|
|
2670
|
+
const combinedTools = [...options.additionalTools ?? [], ...Object.values(allTools_exports)];
|
|
2671
|
+
const tools = getAvailableTools({
|
|
2672
|
+
provider: options.provider,
|
|
2673
|
+
allTools: combinedTools,
|
|
2674
|
+
hasAgent: (options.agents?.length ?? 0) > 0,
|
|
2675
|
+
permissionLevel: 3 /* Arbitrary */,
|
|
2676
|
+
interactive: true
|
|
2677
|
+
});
|
|
2678
|
+
const toolNamePrefix = "tool_";
|
|
2679
|
+
const systemPrompt = fullSystemPrompt3(
|
|
2680
|
+
{
|
|
2681
|
+
os: options.os
|
|
2682
|
+
},
|
|
2683
|
+
tools,
|
|
2684
|
+
toolNamePrefix,
|
|
2685
|
+
options.customInstructions ?? [],
|
|
2686
|
+
options.scripts ?? {},
|
|
2687
|
+
options.interactive
|
|
2688
|
+
);
|
|
2689
|
+
super(codeFixerAgentInfo.name, options.ai, {
|
|
2690
|
+
systemPrompt,
|
|
2691
|
+
tools,
|
|
2692
|
+
toolNamePrefix,
|
|
2693
|
+
provider: options.provider,
|
|
2694
|
+
interactive: options.interactive,
|
|
2695
|
+
agents: options.agents,
|
|
2696
|
+
scripts: options.scripts,
|
|
2697
|
+
callback: options.callback
|
|
2698
|
+
});
|
|
2699
|
+
this.#maxRetries = options.maxRetries ?? 5;
|
|
2700
|
+
}
|
|
2701
|
+
async onBeforeInvokeTool(name, args) {
|
|
2702
|
+
if (name === attemptCompletion_default.name) {
|
|
2703
|
+
if (this.#retryCount > this.#maxRetries) {
|
|
2704
|
+
return;
|
|
2705
|
+
}
|
|
2706
|
+
this.#retryCount++;
|
|
2707
|
+
const executeCommand = this.config.provider.executeCommand;
|
|
2708
|
+
if (!executeCommand) {
|
|
2709
|
+
return;
|
|
2710
|
+
}
|
|
2711
|
+
const check = this.config.scripts?.check;
|
|
2712
|
+
const checkCommand = typeof check === "string" ? check : check?.command;
|
|
2713
|
+
if (checkCommand) {
|
|
2714
|
+
try {
|
|
2715
|
+
const { exitCode, stdout, stderr } = await executeCommand(checkCommand, false);
|
|
2716
|
+
if (exitCode !== 0) {
|
|
2717
|
+
return {
|
|
2718
|
+
type: "Reply" /* Reply */,
|
|
2719
|
+
message: responsePrompts.commandResult(checkCommand, exitCode, stdout, stderr)
|
|
2720
|
+
};
|
|
2721
|
+
}
|
|
2722
|
+
} catch (error) {
|
|
2723
|
+
console.warn(`Failed to check code using command: ${checkCommand}`, error);
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
const test = this.config.scripts?.test;
|
|
2727
|
+
const testCommand = typeof test === "string" ? test : test?.command;
|
|
2728
|
+
if (testCommand) {
|
|
2729
|
+
try {
|
|
2730
|
+
const { exitCode, stdout, stderr } = await executeCommand(testCommand, false);
|
|
2731
|
+
if (exitCode !== 0) {
|
|
2732
|
+
return {
|
|
2733
|
+
type: "Reply" /* Reply */,
|
|
2734
|
+
message: responsePrompts.commandResult(testCommand, exitCode, stdout, stderr)
|
|
2735
|
+
};
|
|
2736
|
+
}
|
|
2737
|
+
} catch (error) {
|
|
2738
|
+
console.warn(`Failed to test code using command: ${testCommand}`, error);
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
};
|
|
2744
|
+
var codeFixerAgentInfo = {
|
|
2745
|
+
name: "codefixer",
|
|
2746
|
+
responsibilities: [
|
|
2747
|
+
"Fixing type errors and type-related issues",
|
|
2748
|
+
"Resolving failing tests",
|
|
2749
|
+
"Addressing code quality issues",
|
|
2750
|
+
"Tracking and reporting unfixed issues"
|
|
2751
|
+
]
|
|
2752
|
+
};
|
|
2753
|
+
|
|
2754
|
+
// src/Agent/CoderAgent/prompts.ts
|
|
2755
|
+
var basePrompt2 = "You are a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.";
|
|
2756
|
+
var editingFilesPrompt = (toolNamePrefix) => `
|
|
2757
|
+
====
|
|
2758
|
+
|
|
2759
|
+
EDITING FILES
|
|
2760
|
+
|
|
2761
|
+
You have access to two tools for working with files: **${toolNamePrefix}write_to_file** and **${toolNamePrefix}replace_in_file**. Understanding their roles and selecting the right one for the job will help ensure efficient and accurate modifications.
|
|
2762
|
+
|
|
2763
|
+
# ${toolNamePrefix}write_to_file
|
|
2764
|
+
|
|
2765
|
+
## Purpose
|
|
2766
|
+
|
|
2767
|
+
- Create a new file, or overwrite the entire contents of an existing file.
|
|
2768
|
+
|
|
2769
|
+
## When to Use
|
|
2770
|
+
|
|
2771
|
+
- Initial file creation, such as when scaffolding a new project.
|
|
2772
|
+
- Overwriting large boilerplate files where you want to replace the entire content at once.
|
|
2773
|
+
- When the complexity or number of changes would make ${toolNamePrefix}replace_in_file unwieldy or error-prone.
|
|
2774
|
+
- When you need to completely restructure a file's content or change its fundamental organization.
|
|
2775
|
+
|
|
2776
|
+
## Important Considerations
|
|
2777
|
+
|
|
2778
|
+
- Using ${toolNamePrefix}write_to_file requires providing the file\u2019s complete final content.
|
|
2779
|
+
- If you only need to make small changes to an existing file, consider using ${toolNamePrefix}replace_in_file instead to avoid unnecessarily rewriting the entire file.
|
|
2780
|
+
- While ${toolNamePrefix}write_to_file should not be your default choice, don't hesitate to use it when the situation truly calls for it.
|
|
2781
|
+
|
|
2782
|
+
# ${toolNamePrefix}replace_in_file
|
|
2783
|
+
|
|
2784
|
+
## Purpose
|
|
2785
|
+
|
|
2786
|
+
- Make targeted edits to specific parts of an existing file without overwriting the entire file.
|
|
2787
|
+
|
|
2788
|
+
## When to Use
|
|
2789
|
+
|
|
2790
|
+
- Small, localized changes like updating a few lines, function implementations, changing variable names, modifying a section of text, etc.
|
|
2791
|
+
- Targeted improvements where only specific portions of the file\u2019s content needs to be altered.
|
|
2792
|
+
- Especially useful for long files where much of the file will remain unchanged.
|
|
2793
|
+
|
|
2794
|
+
## Advantages
|
|
2795
|
+
|
|
2796
|
+
- More efficient for minor edits, since you don\u2019t need to supply the entire file content.
|
|
2797
|
+
- Reduces the chance of errors that can occur when overwriting large files.
|
|
2798
|
+
|
|
2799
|
+
# Choosing the Appropriate Tool
|
|
2800
|
+
|
|
2801
|
+
- **Default to ${toolNamePrefix}replace_in_file** for most changes. It's the safer, more precise option that minimizes potential issues.
|
|
2802
|
+
- **Use ${toolNamePrefix}write_to_file** when:
|
|
2803
|
+
- Creating new files
|
|
2804
|
+
- The changes are so extensive that using ${toolNamePrefix}replace_in_file would be more complex or risky
|
|
2805
|
+
- You need to completely reorganize or restructure a file
|
|
2806
|
+
- The file is relatively small and the changes affect most of its content
|
|
2807
|
+
- You're generating boilerplate or template files
|
|
2808
|
+
|
|
2809
|
+
# Workflow Tips
|
|
2810
|
+
|
|
2811
|
+
1. Before editing, assess the scope of your changes and decide which tool to use.
|
|
2812
|
+
2. For targeted edits, apply ${toolNamePrefix}replace_in_file with carefully crafted SEARCH/REPLACE blocks. If you need multiple changes, you can stack multiple SEARCH/REPLACE blocks within a single ${toolNamePrefix}replace_in_file call.
|
|
2813
|
+
3. For major overhauls or initial file creation, rely on ${toolNamePrefix}write_to_file.
|
|
2814
|
+
4. Once the file has been edited with either ${toolNamePrefix}write_to_file or ${toolNamePrefix}replace_in_file, the system will provide you with the final state of the modified file. Use this updated content as the reference point for any subsequent SEARCH/REPLACE operations, since it reflects any auto-formatting or user-applied changes.
|
|
2815
|
+
|
|
2816
|
+
By thoughtfully selecting between ${toolNamePrefix}write_to_file and ${toolNamePrefix}replace_in_file, you can make your file editing process smoother, safer, and more efficient.`;
|
|
2817
|
+
var rules = (toolNamePrefix) => `
|
|
2818
|
+
====
|
|
2819
|
+
|
|
2820
|
+
RULES
|
|
2821
|
+
|
|
2822
|
+
- You may use \`cd\` to enter any child directory within the current working directory. For example, \`cd myChildDir\`. But you may never move to a parent directory or any directory outside your current path. For example, do not use \`cd ..\`, \`cd /\`, or any absolute path.
|
|
2823
|
+
- Always work with relative path names, and never use absolute paths.
|
|
2824
|
+
- When generating code or test or any file that support comments, add a comment on top of the file with a description of the file's purpose and a note that this file is generated by "polka.codes".
|
|
2825
|
+
- When generate text file such as README.md, add a footer indicating this file is generated by "polka.codes".
|
|
2826
|
+
- Before using the ${toolNamePrefix}execute_command tool, you must first think about the SYSTEM INFORMATION context provided to understand the user's environment and tailor your commands to ensure they are compatible with their system. You must also consider if the command you need to run should be executed in a specific directory outside of the current working directory, and if so prepend with \`cd\`'ing into that directory && then executing the command (as one command). For example, if you needed to run \`npm install\` in a project that's not in the current working directory, you would need to prepend with a \`cd\` i.e. pseudocode for this would be \`cd (path to project) && (command, in this case npm install)\`. However, you can only cd into child directory, but never parent directory or root directory or home directory.
|
|
2827
|
+
- When using the ${toolNamePrefix}search_files tool, craft your regex patterns carefully to balance specificity and flexibility. Based on the user's task you may use it to find code patterns, TODO comments, function definitions, or any text-based information across the project. The results include context, so analyze the surrounding code to better understand the matches. Leverage the ${toolNamePrefix}search_files tool in combination with other tools for more comprehensive analysis. For example, use it to find specific code patterns, then use ${toolNamePrefix}read_file to examine the full context of interesting matches before using ${toolNamePrefix}replace_in_file to make informed changes.
|
|
2828
|
+
- When creating a new project (such as an app, website, or any software project), organize all new files within a dedicated project directory unless the user specifies otherwise. Use appropriate file paths when creating files, as the ${toolNamePrefix}write_to_file tool will automatically create any necessary directories. Structure the project logically, adhering to best practices for the specific type of project being created. Unless otherwise specified, new projects should be easily run without additional setup, for example most projects can be built in HTML, CSS, and JavaScript - which you can open in a browser.
|
|
2829
|
+
- Be sure to consider the type of project (e.g. Python, JavaScript, web application) when determining the appropriate structure and files to include. Also consider what files may be most relevant to accomplishing the task, for example looking at a project's manifest file would help you understand the project's dependencies, which you could incorporate into any code you write.
|
|
2830
|
+
- When making changes to code, always consider the context in which the code is being used. Ensure that your changes are compatible with the existing codebase and that they follow the project's coding standards and best practices.
|
|
2831
|
+
- **Adhere to any established coding style, linting rules, or naming conventions if they are known or can be inferred from the existing codebase, to maintain consistency.**
|
|
2832
|
+
- When you want to modify a file, use the ${toolNamePrefix}replace_in_file or ${toolNamePrefix}write_to_file tool directly with the desired changes. You do not need to display the changes before using the tool.
|
|
2833
|
+
- **Do not guess or hallucinate file content that has not been explicitly provided or read. Always read an existing file with \`${toolNamePrefix}read_file\` (or rely on content the user directly provided) before modifying it, unless you are creating a brand-new file.**
|
|
2834
|
+
- Do not ask for more information than necessary. Use the tools provided to accomplish the user's request efficiently and effectively. When you've completed your task, you must use the ${toolNamePrefix}attempt_completion tool to present the result to the user.
|
|
2835
|
+
- The user may provide a file's contents directly in their message, in which case you shouldn't use the ${toolNamePrefix}read_file tool to get the file contents again since you already have it.
|
|
2836
|
+
- Your goal is to try to accomplish the user's task, NOT engage in a back and forth conversation.
|
|
2837
|
+
- NEVER end ${toolNamePrefix}attempt_completion result with a question or request to engage in further conversation! Formulate the end of your result in a way that is final and does not require further input from the user.
|
|
2838
|
+
- You are STRICTLY FORBIDDEN from starting your messages with "Great", "Certainly", "Okay", "Sure". You should NOT be conversational in your responses, but rather direct and to the point. For example you should NOT say "Great, I've updated the CSS" but instead something like "I've updated the CSS". It is important you be clear and technical in your messages.
|
|
2839
|
+
- When presented with images, utilize your vision capabilities to thoroughly examine them and extract meaningful information. Incorporate these insights into your thought process as you accomplish the user's task.
|
|
2840
|
+
- When using the ${toolNamePrefix}replace_in_file tool, you must include complete lines in your SEARCH blocks, not partial lines. The system requires exact line matches and cannot match partial lines. For example, if you want to match a line containing "const x = 5;", your SEARCH block must include the entire line, not just "x = 5" or other fragments.
|
|
2841
|
+
- When using the ${toolNamePrefix}replace_in_file tool, if you use multiple SEARCH/REPLACE blocks, list them in the order they appear in the file. For example if you need to make changes to both line 10 and line 50, first include the SEARCH/REPLACE block for line 10, followed by the SEARCH/REPLACE block for line 50.
|
|
2842
|
+
- It is critical you wait for the user's response after each tool use, in order to confirm the success of the tool use. For example, if asked to make a todo app, you would create a file, wait for the user's response it was created successfully, then create another file if needed, wait for the user's response it was created successfully, etc.
|
|
2843
|
+
- Keep the inline docs up to date if needed.
|
|
2844
|
+
`;
|
|
2845
|
+
var objectives = (toolNamePrefix) => `
|
|
2846
|
+
====
|
|
2847
|
+
|
|
2848
|
+
OBJECTIVE
|
|
2849
|
+
|
|
2850
|
+
You accomplish a given task iteratively, breaking it down into clear steps and working through them methodically.
|
|
2851
|
+
|
|
2852
|
+
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
|
|
2853
|
+
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
|
|
2854
|
+
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within <thinking></thinking> tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Then, think about which of the provided tools is the most relevant tool to accomplish the user's task. Next, go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use.
|
|
2855
|
+
4. Once you've completed the user's task, you must use the ${toolNamePrefix}attempt_completion tool to present the result of the task to the user.
|
|
2856
|
+
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.`;
|
|
2857
|
+
var fullSystemPrompt4 = (info, tools, toolNamePrefix, instructions, scripts) => `
|
|
2858
|
+
${basePrompt2}
|
|
2859
|
+
${toolUsePrompt(tools, toolNamePrefix)}
|
|
2860
|
+
${editingFilesPrompt(toolNamePrefix)}
|
|
2861
|
+
${capabilities(toolNamePrefix)}
|
|
2862
|
+
${rules(toolNamePrefix)}
|
|
2863
|
+
${objectives(toolNamePrefix)}
|
|
2864
|
+
${systemInformation(info)}
|
|
2865
|
+
${customInstructions(instructions)}
|
|
2866
|
+
${customScripts(scripts)}
|
|
2867
|
+
`;
|
|
2868
|
+
|
|
2869
|
+
// src/Agent/CoderAgent/index.ts
|
|
2870
|
+
var CoderAgent = class extends AgentBase {
|
|
2871
|
+
constructor(options) {
|
|
2872
|
+
const combinedTools = [...options.additionalTools ?? [], ...Object.values(allTools_exports)];
|
|
2873
|
+
const tools = getAvailableTools({
|
|
2874
|
+
provider: options.provider,
|
|
2875
|
+
allTools: combinedTools,
|
|
2876
|
+
hasAgent: (options.agents?.length ?? 0) > 0,
|
|
2877
|
+
permissionLevel: 3 /* Arbitrary */,
|
|
2878
|
+
interactive: true
|
|
2879
|
+
});
|
|
2880
|
+
const toolNamePrefix = "tool_";
|
|
2881
|
+
const systemPrompt = fullSystemPrompt4(
|
|
2882
|
+
{
|
|
2883
|
+
os: options.os
|
|
2884
|
+
},
|
|
2885
|
+
tools,
|
|
2886
|
+
toolNamePrefix,
|
|
2887
|
+
options.customInstructions ?? [],
|
|
2888
|
+
options.scripts ?? {}
|
|
2889
|
+
);
|
|
2890
|
+
super(coderAgentInfo.name, options.ai, {
|
|
2891
|
+
systemPrompt,
|
|
2892
|
+
tools,
|
|
2893
|
+
toolNamePrefix,
|
|
2894
|
+
provider: options.provider,
|
|
2895
|
+
interactive: options.interactive,
|
|
2896
|
+
agents: options.agents,
|
|
2897
|
+
scripts: options.scripts,
|
|
2898
|
+
callback: options.callback
|
|
2899
|
+
});
|
|
2900
|
+
}
|
|
2901
|
+
async onBeforeInvokeTool(name, args) {
|
|
2902
|
+
if (name !== attemptCompletion_default.name) {
|
|
2903
|
+
return;
|
|
2904
|
+
}
|
|
2905
|
+
const executeCommand = this.config.provider.executeCommand;
|
|
2906
|
+
if (!executeCommand) {
|
|
2907
|
+
return;
|
|
2908
|
+
}
|
|
2909
|
+
const format = this.config.scripts?.format;
|
|
2910
|
+
const formatCommand = typeof format === "string" ? format : format?.command;
|
|
2911
|
+
if (formatCommand) {
|
|
2912
|
+
try {
|
|
2913
|
+
await executeCommand(formatCommand, false);
|
|
2914
|
+
} catch (error) {
|
|
2915
|
+
console.warn(`Failed to format code using command: ${formatCommand}`, error);
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
const check = this.config.scripts?.check;
|
|
2919
|
+
const checkCommand = typeof check === "string" ? check : check?.command;
|
|
2920
|
+
if (checkCommand) {
|
|
2921
|
+
try {
|
|
2922
|
+
const { exitCode, stdout, stderr } = await executeCommand(checkCommand, false);
|
|
2923
|
+
if (exitCode !== 0) {
|
|
2924
|
+
return {
|
|
2925
|
+
type: "Reply" /* Reply */,
|
|
2926
|
+
message: responsePrompts.commandResult(checkCommand, exitCode, stdout, stderr)
|
|
2927
|
+
};
|
|
2928
|
+
}
|
|
2929
|
+
} catch (error) {
|
|
2930
|
+
console.warn(`Failed to check code using command: ${checkCommand}`, error);
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
const test = this.config.scripts?.test;
|
|
2934
|
+
const testCommand = typeof test === "string" ? test : test?.command;
|
|
2935
|
+
if (testCommand) {
|
|
2936
|
+
try {
|
|
2937
|
+
const { exitCode, stdout, stderr } = await executeCommand(testCommand, false);
|
|
2938
|
+
if (exitCode !== 0) {
|
|
2939
|
+
return {
|
|
2940
|
+
type: "Reply" /* Reply */,
|
|
2941
|
+
message: responsePrompts.commandResult(testCommand, exitCode, stdout, stderr)
|
|
2942
|
+
};
|
|
2943
|
+
}
|
|
2944
|
+
} catch (error) {
|
|
2945
|
+
console.warn(`Failed to test code using command: ${testCommand}`, error);
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
};
|
|
2950
|
+
var coderAgentInfo = {
|
|
2951
|
+
name: "coder",
|
|
2952
|
+
responsibilities: [
|
|
2953
|
+
"Editing and refactoring existing code.",
|
|
2954
|
+
"Creating new features or modules.",
|
|
2955
|
+
"Running tests and analyzing test results.",
|
|
2956
|
+
"Maintaining coding standards, lint rules, and general code quality."
|
|
2957
|
+
]
|
|
2958
|
+
};
|
|
2959
|
+
|
|
2960
|
+
// src/Agent/MultiAgent.ts
|
|
2961
|
+
var MultiAgent = class {
|
|
2962
|
+
#config;
|
|
2963
|
+
#agents = [];
|
|
2964
|
+
constructor(config) {
|
|
2965
|
+
this.#config = config;
|
|
2966
|
+
}
|
|
2967
|
+
async #handleTaskResult(exitReason) {
|
|
2968
|
+
switch (exitReason.type) {
|
|
2969
|
+
case "HandOver" /* HandOver */: {
|
|
2970
|
+
this.#agents.pop();
|
|
2971
|
+
const newContext = await this.#config.getContext?.(exitReason.agentName, exitReason.context, exitReason.files);
|
|
2972
|
+
return await this.#startTask(exitReason.agentName, exitReason.task, newContext);
|
|
2973
|
+
}
|
|
2974
|
+
case "Delegate" /* Delegate */: {
|
|
2975
|
+
const newContext = await this.#config.getContext?.(exitReason.agentName, exitReason.context, exitReason.files);
|
|
2976
|
+
const delegateResult = await this.#startTask(exitReason.agentName, exitReason.task, newContext);
|
|
2977
|
+
switch (delegateResult.type) {
|
|
2978
|
+
case "HandOver" /* HandOver */:
|
|
2979
|
+
case "Delegate" /* Delegate */:
|
|
2980
|
+
console.warn("Unexpected exit reason", delegateResult);
|
|
2981
|
+
break;
|
|
2982
|
+
case "Interrupted" /* Interrupted */:
|
|
2983
|
+
return delegateResult;
|
|
2984
|
+
case "Exit" /* Exit */:
|
|
2985
|
+
return this.continueTask(delegateResult.message);
|
|
2986
|
+
}
|
|
2987
|
+
return delegateResult;
|
|
2988
|
+
}
|
|
2989
|
+
case "Interrupted" /* Interrupted */:
|
|
2990
|
+
case "Exit" /* Exit */:
|
|
2991
|
+
this.#agents.pop();
|
|
2992
|
+
return exitReason;
|
|
2993
|
+
default:
|
|
2994
|
+
return exitReason;
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
async #startTask(agentName, task, context) {
|
|
2998
|
+
const newAgent = await this.#config.createAgent(agentName);
|
|
2999
|
+
this.#agents.push(newAgent);
|
|
3000
|
+
const exitReason = await newAgent.startTask({
|
|
3001
|
+
task,
|
|
3002
|
+
context
|
|
3003
|
+
});
|
|
3004
|
+
return await this.#handleTaskResult(exitReason);
|
|
3005
|
+
}
|
|
3006
|
+
async startTask(options) {
|
|
3007
|
+
if (this.#agents.length > 0) {
|
|
3008
|
+
throw new Error("An active agent already exists");
|
|
3009
|
+
}
|
|
3010
|
+
return this.#startTask(options.agentName, options.task, options.context);
|
|
3011
|
+
}
|
|
3012
|
+
async continueTask(userMessage) {
|
|
3013
|
+
if (!this.#agents.length) {
|
|
3014
|
+
throw new Error("No active agent");
|
|
3015
|
+
}
|
|
3016
|
+
const exitReason = await this.#agents[this.#agents.length - 1].continueTask(userMessage);
|
|
3017
|
+
return await this.#handleTaskResult(exitReason);
|
|
3018
|
+
}
|
|
3019
|
+
get hasActiveAgent() {
|
|
3020
|
+
return this.#agents.length > 0;
|
|
3021
|
+
}
|
|
3022
|
+
};
|
|
3023
|
+
|
|
3024
|
+
// src/Agent/index.ts
|
|
3025
|
+
var allAgents = [architectAgentInfo, coderAgentInfo, analyzerAgentInfo, codeFixerAgentInfo];
|
|
3026
|
+
|
|
3027
|
+
// src/AiTool/createNewProject.ts
|
|
3028
|
+
var prompt = `You are an AiTool designed to assist users in creating new projects. Follow these guidelines:
|
|
3029
|
+
|
|
3030
|
+
1. **Gather Information:**
|
|
3031
|
+
- Begin by asking the user for essential project details, including:
|
|
3032
|
+
- Project type (e.g., web, mobile, desktop, etc.)
|
|
3033
|
+
- Desired programming languages
|
|
3034
|
+
- Preferred frameworks or libraries
|
|
3035
|
+
- Build tools and package manager preferences
|
|
3036
|
+
- Testing frameworks and patterns
|
|
3037
|
+
- Code style and linting preferences
|
|
3038
|
+
- Any additional specifications or requirements
|
|
3039
|
+
|
|
3040
|
+
2. **Clarification & Confirmation:**
|
|
3041
|
+
- Do not make any decisions or assumptions on behalf of the user.
|
|
3042
|
+
- Ask clarifying questions if any detail is ambiguous.
|
|
3043
|
+
- Confirm each piece of information with the user before proceeding to the next step.
|
|
3044
|
+
|
|
3045
|
+
3. **Avoid Redundancy:**
|
|
3046
|
+
- Do not repeat questions or details that have already been confirmed.
|
|
3047
|
+
- Keep interactions concise and focused on gathering complete and accurate details.
|
|
3048
|
+
|
|
3049
|
+
4. **Generate Configuration:**
|
|
3050
|
+
- Based on the collected information, generate a .polkacodes.yml configuration file that includes:
|
|
3051
|
+
- scripts section with common development commands (test, format, check, etc.)
|
|
3052
|
+
- rules section reflecting project conventions and tools
|
|
3053
|
+
- excludeFiles section for sensitive files only
|
|
3054
|
+
- Example structure:
|
|
3055
|
+
\`\`\`yaml
|
|
3056
|
+
scripts:
|
|
3057
|
+
test:
|
|
3058
|
+
command: "[test-command]"
|
|
3059
|
+
description: "Run tests"
|
|
3060
|
+
format:
|
|
3061
|
+
command: "[format-command]"
|
|
3062
|
+
description: "Format code"
|
|
3063
|
+
check:
|
|
3064
|
+
command: "[check-command]"
|
|
3065
|
+
description: "Check code"
|
|
3066
|
+
|
|
3067
|
+
rules:
|
|
3068
|
+
- "[package-manager-rule]"
|
|
3069
|
+
- "[testing-framework-rule]"
|
|
3070
|
+
- "[code-style-rule]"
|
|
3071
|
+
- "[other-rule]"
|
|
3072
|
+
|
|
3073
|
+
excludeFiles:
|
|
3074
|
+
- ".env"
|
|
3075
|
+
- ".env.*"
|
|
3076
|
+
\`\`\`
|
|
3077
|
+
|
|
3078
|
+
5. **Generate Essential Project Files:**
|
|
3079
|
+
- Create a .gitattributes file with appropriate configurations:
|
|
3080
|
+
- Mark lock files as generated and exclude them from diffs
|
|
3081
|
+
- Example for different package managers:
|
|
3082
|
+
|
|
3083
|
+
# For Bun
|
|
3084
|
+
bun.lock linguist-generated=true
|
|
3085
|
+
bun.lock -diff
|
|
3086
|
+
|
|
3087
|
+
# For npm
|
|
3088
|
+
package-lock.json linguist-generated=true
|
|
3089
|
+
package-lock.json -diff
|
|
3090
|
+
|
|
3091
|
+
# For Yarn
|
|
3092
|
+
yarn.lock linguist-generated=true
|
|
3093
|
+
yarn.lock -diff
|
|
3094
|
+
|
|
3095
|
+
# For pnpm
|
|
3096
|
+
pnpm-lock.yaml linguist-generated=true
|
|
3097
|
+
pnpm-lock.yaml -diff
|
|
3098
|
+
|
|
3099
|
+
- Include other common configurations as needed based on project type
|
|
3100
|
+
|
|
3101
|
+
6. **Handover to Coder Agent:**
|
|
3102
|
+
- Once all required information is collected and validated by the user, compile:
|
|
3103
|
+
1. The final project specifications
|
|
3104
|
+
2. The .polkacodes.yml configuration content
|
|
3105
|
+
- Clearly hand over these details to the coder agent, instructing them to:
|
|
3106
|
+
1. Create the new project based on the confirmed specifications
|
|
3107
|
+
2. Include the .polkacodes.yml file in the project root
|
|
3108
|
+
3. Include the .gitattributes file with appropriate configurations
|
|
3109
|
+
4. Ensure all specified tools and configurations are properly set up`;
|
|
3110
|
+
var createNewProject_default = {
|
|
3111
|
+
name: "createNewProject",
|
|
3112
|
+
description: "Creates a new project",
|
|
3113
|
+
prompt,
|
|
3114
|
+
formatInput: (params) => {
|
|
3115
|
+
return `<project_name>${params}</project_name>`;
|
|
3116
|
+
},
|
|
3117
|
+
parseOutput: (output) => {
|
|
3118
|
+
return output.trim();
|
|
3119
|
+
},
|
|
3120
|
+
agent: "architect"
|
|
3121
|
+
};
|
|
3122
|
+
|
|
3123
|
+
// src/AiTool/generateGitCommitMessage.ts
|
|
3124
|
+
var prompt2 = `
|
|
3125
|
+
You are an advanced assistant specialized in creating concise and accurate Git commit messages. When you receive:
|
|
3126
|
+
- A Git diff inside the <tool_input> tag.
|
|
3127
|
+
- Additional user-supplied context inside the <tool_input_context> tag (if any).
|
|
3128
|
+
|
|
3129
|
+
You will produce a single commit message enclosed within <tool_output> tags. The commit message must accurately reflect the changes shown in the diff and should be clear, descriptive, and devoid of unnecessary or repeated information. If a context is provided, it MUST be incorporated into the commit message.
|
|
3130
|
+
|
|
3131
|
+
Here\u2019s an example of the input and the expected output format:
|
|
3132
|
+
|
|
3133
|
+
<tool_input>
|
|
3134
|
+
--- a/example_file.py
|
|
3135
|
+
+++ b/example_file.py
|
|
3136
|
+
@@ -10,7 +10,7 @@ def example_function():
|
|
3137
|
+
- print("Old behavior")
|
|
3138
|
+
+ print("New behavior")
|
|
3139
|
+
</tool_input>
|
|
3140
|
+
<tool_input_context>
|
|
3141
|
+
Changing print statement to update the user-facing message.
|
|
3142
|
+
</tool_input_context>
|
|
3143
|
+
|
|
3144
|
+
Example Output:
|
|
3145
|
+
|
|
3146
|
+
<tool_output>
|
|
3147
|
+
Update print statement for revised user-facing message
|
|
3148
|
+
</tool_output>
|
|
3149
|
+
|
|
3150
|
+
Follow the same structure for any new input. Never repeat questions; focus on generating a concise commit message that captures the essence of the changes.
|
|
3151
|
+
`;
|
|
3152
|
+
var generateGitCommitMessage_default = {
|
|
3153
|
+
name: "generateGitCommitMessage",
|
|
3154
|
+
description: "Generates git commit messages from git diff output",
|
|
3155
|
+
prompt: prompt2,
|
|
3156
|
+
formatInput: (params) => {
|
|
3157
|
+
let ret = `<tool_input>
|
|
3158
|
+
${params.diff}
|
|
3159
|
+
</tool_input>`;
|
|
3160
|
+
if (params.context) {
|
|
3161
|
+
ret += `
|
|
3162
|
+
<tool_input_context>
|
|
3163
|
+
${params.context}
|
|
3164
|
+
</tool_input_context>`;
|
|
3165
|
+
}
|
|
3166
|
+
return ret;
|
|
3167
|
+
},
|
|
3168
|
+
parseOutput: (output) => {
|
|
3169
|
+
const regex = /<tool_output>([\s\S]*)<\/tool_output>/gm;
|
|
3170
|
+
const match = regex.exec(output);
|
|
3171
|
+
if (match) {
|
|
3172
|
+
return match[1];
|
|
3173
|
+
}
|
|
3174
|
+
throw new Error(`Could not parse output:
|
|
3175
|
+
${output}`);
|
|
3176
|
+
}
|
|
3177
|
+
};
|
|
3178
|
+
|
|
3179
|
+
// src/AiTool/generateGithubPullRequestDetails.ts
|
|
3180
|
+
var prompt3 = `
|
|
3181
|
+
# Generate Github Pull Request Details
|
|
3182
|
+
|
|
3183
|
+
You are given:
|
|
3184
|
+
- A branch name in <tool_input_branch_name>.
|
|
3185
|
+
- An optional context message in <tool_input_context> (which may or may not be present).
|
|
3186
|
+
- All commit messages combined in <tool_input_commit_messages>.
|
|
3187
|
+
- All diffs combined in <tool_input_commit_diff>.
|
|
3188
|
+
|
|
3189
|
+
Your task:
|
|
3190
|
+
1. Consider the optional context (if provided).
|
|
3191
|
+
- If an issue number is found, add "Closes #xxx" at the beginning of the PR description
|
|
3192
|
+
- IMPORTANT: Use ONLY the exact format "Closes #xxx" at the beginning of the description
|
|
3193
|
+
- DO NOT use variations like "Closes issue #xxx" or other formats
|
|
3194
|
+
2. Analyze the combined commit messages and diffs.
|
|
3195
|
+
3. Produce a single GitHub Pull Request title.
|
|
3196
|
+
4. Produce a Pull Request description that explains the changes.
|
|
3197
|
+
|
|
3198
|
+
Use the following template for the Pull Request description:
|
|
3199
|
+
|
|
3200
|
+
---
|
|
3201
|
+
**Context (if provided)**:
|
|
3202
|
+
- Acknowledge any guiding concerns or instructions.
|
|
3203
|
+
|
|
3204
|
+
**Summary of Changes**:
|
|
3205
|
+
- Provide a concise list or overview of what changed.
|
|
3206
|
+
|
|
3207
|
+
**Highlights of Changed Code**:
|
|
3208
|
+
- Mention only the specific sections or functionalities updated, without showing full surrounding context.
|
|
3209
|
+
|
|
3210
|
+
**Additional Information (if needed)**:
|
|
3211
|
+
- Testing steps (if applicable).
|
|
3212
|
+
- Any notes or caveats.
|
|
3213
|
+
|
|
3214
|
+
---
|
|
3215
|
+
|
|
3216
|
+
Output format:
|
|
3217
|
+
<tool_output>
|
|
3218
|
+
<tool_output_pr_title>YOUR PR TITLE HERE</tool_output_pr_title>
|
|
3219
|
+
<tool_output_pr_description>
|
|
3220
|
+
YOUR PR DESCRIPTION HERE
|
|
3221
|
+
</tool_output_pr_description>
|
|
3222
|
+
</tool_output>
|
|
3223
|
+
|
|
3224
|
+
Below is an **example** of the input and output:
|
|
3225
|
+
|
|
3226
|
+
Example Input:
|
|
3227
|
+
<tool_input>
|
|
3228
|
+
<tool_input_branch_name>feature/refactor-logging</tool_input_branch_name>
|
|
3229
|
+
<tool_input_context>Implementing changes for issue #123 - Focus on clean code and maintainability</tool_input_context>
|
|
3230
|
+
<tool_input_commit_messages>
|
|
3231
|
+
Remove debug logs
|
|
3232
|
+
Refactor order validation logic
|
|
3233
|
+
</tool_input_commit_messages>
|
|
3234
|
+
<tool_input_commit_diff>
|
|
3235
|
+
diff --git a/user_service.py b/user_service.py
|
|
3236
|
+
- print("Debug info")
|
|
3237
|
+
+ # Removed debug print statements
|
|
3238
|
+
|
|
3239
|
+
diff --git a/order_service.py b/order_service.py
|
|
3240
|
+
- if is_valid_order(order):
|
|
3241
|
+
- process_order(order)
|
|
3242
|
+
+ validate_and_process(order)
|
|
3243
|
+
</tool_input_commit_diff>
|
|
3244
|
+
</tool_input>
|
|
3245
|
+
|
|
3246
|
+
Example Output:
|
|
3247
|
+
<tool_output>
|
|
3248
|
+
<tool_output_pr_title>Refactor Order Validation and Remove Debug Logs</tool_output_pr_title>
|
|
3249
|
+
<tool_output_pr_description>
|
|
3250
|
+
closes #123
|
|
3251
|
+
|
|
3252
|
+
This PR removes unnecessary debug print statements and updates order validation
|
|
3253
|
+
to use the new validate_and_process method for improved maintainability.
|
|
3254
|
+
</tool_output_pr_description>
|
|
3255
|
+
</tool_output>
|
|
3256
|
+
|
|
3257
|
+
---
|
|
3258
|
+
|
|
3259
|
+
Use the above format whenever you receive <tool_input> that may include a branch name, an optional context, aggregated commit messages in a single tag, and a combined diff in a single tag. Provide your final output strictly in <tool_output> with <tool_output_pr_title> and <tool_output_pr_description>. Only highlight the changed code and avoid including the context around the changes in the description.
|
|
3260
|
+
`;
|
|
3261
|
+
var generateGithubPullRequestDetails_default = {
|
|
3262
|
+
name: "generateGithubPullRequestDetails",
|
|
3263
|
+
description: "Generates a GitHub pull request title and description from git commits",
|
|
3264
|
+
prompt: prompt3,
|
|
3265
|
+
formatInput: (params) => {
|
|
3266
|
+
return `<tool_input>
|
|
3267
|
+
<tool_input_branch_name>${params.branchName}</tool_input_branch_name>${params.context ? `
|
|
3268
|
+
<tool_input_context>${params.context}</tool_input_context>` : ""}
|
|
3269
|
+
<tool_input_commit_messages>${params.commitMessages}</tool_input_commit_messages>
|
|
3270
|
+
<tool_input_commit_diff>${params.commitDiff}</tool_input_commit_diff>
|
|
3271
|
+
</tool_input>`;
|
|
3272
|
+
},
|
|
3273
|
+
parseOutput: (output) => {
|
|
3274
|
+
const regex = /<tool_output>([\s\S]*)<\/tool_output>/gm;
|
|
3275
|
+
const match = regex.exec(output);
|
|
3276
|
+
if (!match) {
|
|
3277
|
+
throw new Error(`Could not parse output:
|
|
3278
|
+
${output}`);
|
|
3279
|
+
}
|
|
3280
|
+
const [, outputContent] = match;
|
|
3281
|
+
const titleRegex = /<tool_output_pr_title>([\s\S]*)<\/tool_output_pr_title>/gm;
|
|
3282
|
+
const titleMatch = titleRegex.exec(outputContent);
|
|
3283
|
+
const descriptionRegex = /<tool_output_pr_description>([\s\S]*)<\/tool_output_pr_description>/gm;
|
|
3284
|
+
const descriptionMatch = descriptionRegex.exec(outputContent);
|
|
3285
|
+
if (titleMatch && descriptionMatch) {
|
|
3286
|
+
return {
|
|
3287
|
+
title: titleMatch[1],
|
|
3288
|
+
description: descriptionMatch[1]
|
|
3289
|
+
};
|
|
3290
|
+
}
|
|
3291
|
+
throw new Error(`Could not parse output:
|
|
3292
|
+
${output}`);
|
|
3293
|
+
}
|
|
3294
|
+
};
|
|
3295
|
+
|
|
3296
|
+
// src/AiTool/generateProjectConfig.ts
|
|
3297
|
+
var prompt4 = `You are an analyzer agent responsible for examining project files and generating appropriate polkacodes configuration. Your task is to:
|
|
3298
|
+
|
|
3299
|
+
1. Read and analyze the provided files using tool_read_file to understand:
|
|
3300
|
+
- Build tools and package manager (e.g., bun, npm)
|
|
3301
|
+
- Testing frameworks and patterns
|
|
3302
|
+
- Code style tools and rules
|
|
3303
|
+
- Project structure and conventions
|
|
3304
|
+
- Common development workflows
|
|
3305
|
+
|
|
3306
|
+
2. Generate a YAML configuration that captures:
|
|
3307
|
+
- scripts section based on package.json scripts and CI workflows. If applicable, generate following scripts:
|
|
3308
|
+
- format: Format the code using a code formatter tool
|
|
3309
|
+
- check: Check the code for errors using a linter tool
|
|
3310
|
+
- test: Run tests using a test runner tool
|
|
3311
|
+
- include other relevant scripts based on project conventions, tools, and patterns
|
|
3312
|
+
- rules section based on project conventions, tools, and patterns
|
|
3313
|
+
- excludeFiles section for sensitive files
|
|
3314
|
+
|
|
3315
|
+
3. Use tool_attempt_completion to return the final configuration in this format:
|
|
3316
|
+
|
|
3317
|
+
<tool_attempt_completion>
|
|
3318
|
+
<tool_parameter_result>
|
|
3319
|
+
scripts:
|
|
3320
|
+
test:
|
|
3321
|
+
command: "bun test"
|
|
3322
|
+
description: "Run tests with bun:test"
|
|
3323
|
+
lint:
|
|
3324
|
+
command: "biome check ."
|
|
3325
|
+
description: "Check code style with Biome"
|
|
3326
|
+
|
|
3327
|
+
rules:
|
|
3328
|
+
- "Use \`bun\` as package manager"
|
|
3329
|
+
- "Write tests using bun:test with snapshots"
|
|
3330
|
+
- "Follow Biome code style"
|
|
3331
|
+
|
|
3332
|
+
excludeFiles:
|
|
3333
|
+
# Sensitive files
|
|
3334
|
+
- ".env"
|
|
3335
|
+
- ".env.*"
|
|
3336
|
+
- ".npmrc"
|
|
3337
|
+
</tool_parameter_result>
|
|
3338
|
+
</tool_attempt_completion>
|
|
3339
|
+
|
|
3340
|
+
Focus on:
|
|
3341
|
+
- Package manager and dependency management
|
|
3342
|
+
- Testing frameworks and patterns
|
|
3343
|
+
- Code style and linting rules
|
|
3344
|
+
- File organization and naming conventions
|
|
3345
|
+
- Build and development workflows
|
|
3346
|
+
- Sensitive files that should not be committed:
|
|
3347
|
+
- Environment files (.env*)
|
|
3348
|
+
- Configuration files with potential secrets
|
|
3349
|
+
- Generated files to exclude:
|
|
3350
|
+
- Lock files from package managers
|
|
3351
|
+
- Build artifacts and outputs
|
|
3352
|
+
- Generated file that are not ignored by .gitignore
|
|
3353
|
+
|
|
3354
|
+
The configuration should accurately reflect the project's structure, tools, and conventions.
|
|
3355
|
+
`;
|
|
3356
|
+
var generateProjectConfig_default = {
|
|
3357
|
+
name: "generateProjectConfig",
|
|
3358
|
+
description: "Analyzes project files to generate polkacodes config sections",
|
|
3359
|
+
prompt: prompt4,
|
|
3360
|
+
formatInput: () => {
|
|
3361
|
+
return "";
|
|
3362
|
+
},
|
|
3363
|
+
parseOutput: (output) => {
|
|
3364
|
+
return output;
|
|
3365
|
+
},
|
|
3366
|
+
agent: "analyzer"
|
|
3367
|
+
};
|
|
3368
|
+
|
|
3369
|
+
// src/AiTool/index.ts
|
|
3370
|
+
var executeTool = async (definition, ai, params) => {
|
|
3371
|
+
const { response, usage } = await ai.request(definition.prompt, [
|
|
3372
|
+
{ role: "user", content: definition.formatInput(params) }
|
|
3373
|
+
]);
|
|
3374
|
+
return {
|
|
3375
|
+
response: definition.parseOutput(response),
|
|
3376
|
+
usage
|
|
3377
|
+
};
|
|
3378
|
+
};
|
|
3379
|
+
var executeAgentTool = async (definition, agent, params) => {
|
|
3380
|
+
if (!definition.agent) {
|
|
3381
|
+
throw new Error("Agent not specified");
|
|
3382
|
+
}
|
|
3383
|
+
const exitReason = await agent.startTask({
|
|
3384
|
+
agentName: definition.agent,
|
|
3385
|
+
task: definition.prompt,
|
|
3386
|
+
context: definition.formatInput(params)
|
|
3387
|
+
});
|
|
3388
|
+
if (exitReason.type === "Exit" /* Exit */) {
|
|
3389
|
+
return definition.parseOutput(exitReason.message);
|
|
3390
|
+
}
|
|
3391
|
+
throw new Error(`Tool execution failed: ${exitReason.type}`);
|
|
3392
|
+
};
|
|
3393
|
+
var makeTool = (definition) => {
|
|
3394
|
+
return async (ai, params) => {
|
|
3395
|
+
return executeTool(definition, ai, params);
|
|
3396
|
+
};
|
|
3397
|
+
};
|
|
3398
|
+
var makeAgentTool = (definition) => {
|
|
3399
|
+
return async (agent, params) => {
|
|
3400
|
+
return executeAgentTool(definition, agent, params);
|
|
3401
|
+
};
|
|
3402
|
+
};
|
|
3403
|
+
var generateGitCommitMessage = makeTool(generateGitCommitMessage_default);
|
|
3404
|
+
var generateGithubPullRequestDetails = makeTool(generateGithubPullRequestDetails_default);
|
|
3405
|
+
var generateProjectConfig = makeAgentTool(generateProjectConfig_default);
|
|
3406
|
+
var createNewProject = makeAgentTool(createNewProject_default);
|
|
3407
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
3408
|
+
0 && (module.exports = {
|
|
3409
|
+
AgentBase,
|
|
3410
|
+
AiServiceProvider,
|
|
3411
|
+
AnalyzerAgent,
|
|
3412
|
+
ArchitectAgent,
|
|
3413
|
+
CodeFixerAgent,
|
|
3414
|
+
CoderAgent,
|
|
3415
|
+
MockProvider,
|
|
3416
|
+
MultiAgent,
|
|
3417
|
+
PermissionLevel,
|
|
3418
|
+
TaskEventKind,
|
|
3419
|
+
ToolResponseType,
|
|
3420
|
+
UsageMeter,
|
|
3421
|
+
allAgents,
|
|
3422
|
+
allTools,
|
|
3423
|
+
analyzerAgentInfo,
|
|
3424
|
+
anthropicDefaultModelId,
|
|
3425
|
+
anthropicModels,
|
|
3426
|
+
architectAgentInfo,
|
|
3427
|
+
askFollowupQuestion,
|
|
3428
|
+
attemptCompletion,
|
|
3429
|
+
codeFixerAgentInfo,
|
|
3430
|
+
coderAgentInfo,
|
|
3431
|
+
createNewProject,
|
|
3432
|
+
createService,
|
|
3433
|
+
deepSeekDefaultModelId,
|
|
3434
|
+
deepSeekModels,
|
|
3435
|
+
defaultModels,
|
|
3436
|
+
delegate,
|
|
3437
|
+
executeAgentTool,
|
|
3438
|
+
executeCommand,
|
|
3439
|
+
executeTool,
|
|
3440
|
+
generateGitCommitMessage,
|
|
3441
|
+
generateGithubPullRequestDetails,
|
|
3442
|
+
generateProjectConfig,
|
|
3443
|
+
getAvailableTools,
|
|
3444
|
+
handOver,
|
|
3445
|
+
listCodeDefinitionNames,
|
|
3446
|
+
listFiles,
|
|
3447
|
+
makeAgentTool,
|
|
3448
|
+
makeTool,
|
|
3449
|
+
modelInfos,
|
|
3450
|
+
openAiModelInfoSaneDefaults,
|
|
3451
|
+
readFile,
|
|
3452
|
+
removeFile,
|
|
3453
|
+
renameFile,
|
|
3454
|
+
replaceInFile,
|
|
3455
|
+
searchFiles,
|
|
3456
|
+
writeToFile
|
|
3457
|
+
});
|