@polka-codes/core 0.8.28 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_tsup-dts-rollup.d.ts +379 -1640
- package/dist/index.d.ts +9 -30
- package/dist/index.js +824 -1960
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -4,865 +4,142 @@ var __export = (target, all) => {
|
|
|
4
4
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
-
// src/
|
|
8
|
-
var
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
for await (const chunk of stream) {
|
|
25
|
-
switch (chunk.type) {
|
|
26
|
-
case "usage":
|
|
27
|
-
this.usageMeter.addUsage(chunk, this.model);
|
|
28
|
-
break;
|
|
29
|
-
}
|
|
30
|
-
yield chunk;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
async request(systemPrompt, messages) {
|
|
34
|
-
this.usageMeter.checkLimit();
|
|
35
|
-
this.usageMeter.incrementMessageCount();
|
|
36
|
-
this.#abortController = new AbortController();
|
|
37
|
-
const stream = this.sendImpl(systemPrompt, messages, this.#abortController.signal);
|
|
38
|
-
const usage = {
|
|
39
|
-
inputTokens: 0,
|
|
40
|
-
outputTokens: 0,
|
|
41
|
-
cacheWriteTokens: 0,
|
|
42
|
-
cacheReadTokens: 0,
|
|
43
|
-
totalCost: 0
|
|
44
|
-
};
|
|
45
|
-
let resp = "";
|
|
46
|
-
let reasoning = "";
|
|
47
|
-
for await (const chunk of stream) {
|
|
48
|
-
switch (chunk.type) {
|
|
49
|
-
case "usage":
|
|
50
|
-
usage.inputTokens = chunk.inputTokens ?? 0;
|
|
51
|
-
usage.outputTokens = chunk.outputTokens ?? 0;
|
|
52
|
-
usage.cacheWriteTokens = chunk.cacheWriteTokens ?? 0;
|
|
53
|
-
usage.cacheReadTokens = chunk.cacheReadTokens ?? 0;
|
|
54
|
-
usage.totalCost = chunk.totalCost;
|
|
55
|
-
break;
|
|
56
|
-
case "text":
|
|
57
|
-
resp += chunk.text;
|
|
58
|
-
break;
|
|
59
|
-
case "reasoning":
|
|
60
|
-
reasoning += chunk.text;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
this.usageMeter.addUsage(usage, this.model);
|
|
64
|
-
return {
|
|
65
|
-
response: resp,
|
|
66
|
-
reasoning,
|
|
67
|
-
usage
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
// src/AiService/AnthropicService.ts
|
|
73
|
-
import { Anthropic } from "@anthropic-ai/sdk";
|
|
74
|
-
|
|
75
|
-
// src/AiService/ModelInfo.ts
|
|
76
|
-
var anthropicDefaultModelId = "claude-3-7-sonnet-20250219";
|
|
77
|
-
var anthropicModels = {
|
|
78
|
-
"claude-opus-4-20250514": {
|
|
79
|
-
maxTokens: 32e3,
|
|
80
|
-
contextWindow: 2e5,
|
|
81
|
-
supportsImages: true,
|
|
82
|
-
supportsComputerUse: true,
|
|
83
|
-
supportsPromptCache: true,
|
|
84
|
-
inputPrice: 15,
|
|
85
|
-
outputPrice: 75,
|
|
86
|
-
cacheWritesPrice: 18.75,
|
|
87
|
-
cacheReadsPrice: 1.5,
|
|
88
|
-
reasoning: true
|
|
89
|
-
},
|
|
90
|
-
"claude-sonnet-4-20250514": {
|
|
91
|
-
maxTokens: 64e3,
|
|
92
|
-
contextWindow: 2e5,
|
|
93
|
-
supportsImages: true,
|
|
94
|
-
supportsComputerUse: true,
|
|
95
|
-
supportsPromptCache: true,
|
|
96
|
-
inputPrice: 3,
|
|
97
|
-
outputPrice: 15,
|
|
98
|
-
cacheWritesPrice: 3.75,
|
|
99
|
-
cacheReadsPrice: 0.3,
|
|
100
|
-
reasoning: true
|
|
101
|
-
},
|
|
102
|
-
"claude-3-7-sonnet-20250219": {
|
|
103
|
-
maxTokens: 64e3,
|
|
104
|
-
contextWindow: 2e5,
|
|
105
|
-
supportsImages: true,
|
|
106
|
-
supportsComputerUse: true,
|
|
107
|
-
supportsPromptCache: true,
|
|
108
|
-
inputPrice: 3,
|
|
109
|
-
outputPrice: 15,
|
|
110
|
-
cacheWritesPrice: 3.75,
|
|
111
|
-
cacheReadsPrice: 0.3,
|
|
112
|
-
reasoning: true
|
|
113
|
-
},
|
|
114
|
-
"claude-3-5-sonnet-20241022": {
|
|
115
|
-
maxTokens: 8192,
|
|
116
|
-
contextWindow: 2e5,
|
|
117
|
-
supportsImages: true,
|
|
118
|
-
supportsComputerUse: true,
|
|
119
|
-
supportsPromptCache: true,
|
|
120
|
-
inputPrice: 3,
|
|
121
|
-
// $3 per million input tokens
|
|
122
|
-
outputPrice: 15,
|
|
123
|
-
// $15 per million output tokens
|
|
124
|
-
cacheWritesPrice: 3.75,
|
|
125
|
-
// $3.75 per million tokens
|
|
126
|
-
cacheReadsPrice: 0.3
|
|
127
|
-
// $0.30 per million tokens
|
|
128
|
-
},
|
|
129
|
-
"claude-3-5-haiku-20241022": {
|
|
130
|
-
maxTokens: 8192,
|
|
131
|
-
contextWindow: 2e5,
|
|
132
|
-
supportsImages: false,
|
|
133
|
-
supportsPromptCache: true,
|
|
134
|
-
inputPrice: 0.8,
|
|
135
|
-
outputPrice: 4,
|
|
136
|
-
cacheWritesPrice: 1,
|
|
137
|
-
cacheReadsPrice: 0.08
|
|
138
|
-
},
|
|
139
|
-
"claude-3-opus-20240229": {
|
|
140
|
-
maxTokens: 4096,
|
|
141
|
-
contextWindow: 2e5,
|
|
142
|
-
supportsImages: true,
|
|
143
|
-
supportsPromptCache: true,
|
|
144
|
-
inputPrice: 15,
|
|
145
|
-
outputPrice: 75,
|
|
146
|
-
cacheWritesPrice: 18.75,
|
|
147
|
-
cacheReadsPrice: 1.5
|
|
148
|
-
},
|
|
149
|
-
"claude-3-haiku-20240307": {
|
|
150
|
-
maxTokens: 4096,
|
|
151
|
-
contextWindow: 2e5,
|
|
152
|
-
supportsImages: true,
|
|
153
|
-
supportsPromptCache: true,
|
|
154
|
-
inputPrice: 0.25,
|
|
155
|
-
outputPrice: 1.25,
|
|
156
|
-
cacheWritesPrice: 0.3,
|
|
157
|
-
cacheReadsPrice: 0.03
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
var openAiModelInfoSaneDefaults = {
|
|
161
|
-
maxTokens: -1,
|
|
162
|
-
contextWindow: 128e3,
|
|
163
|
-
supportsImages: true,
|
|
164
|
-
supportsPromptCache: false,
|
|
165
|
-
inputPrice: 0,
|
|
166
|
-
outputPrice: 0
|
|
167
|
-
};
|
|
168
|
-
var deepSeekDefaultModelId = "deepseek-chat";
|
|
169
|
-
var deepSeekModels = {
|
|
170
|
-
"deepseek-chat": {
|
|
171
|
-
maxTokens: 8e3,
|
|
172
|
-
contextWindow: 64e3,
|
|
173
|
-
supportsImages: false,
|
|
174
|
-
supportsPromptCache: true,
|
|
175
|
-
// 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
|
|
176
|
-
inputPrice: 0,
|
|
177
|
-
// technically there is no input price, it's all either a cache hit or miss (ApiOptions will not show this)
|
|
178
|
-
outputPrice: 1.1,
|
|
179
|
-
cacheWritesPrice: 0.27,
|
|
180
|
-
cacheReadsPrice: 0.07
|
|
181
|
-
},
|
|
182
|
-
"deepseek-reasoner": {
|
|
183
|
-
maxTokens: 8e3,
|
|
184
|
-
contextWindow: 64e3,
|
|
185
|
-
supportsImages: false,
|
|
186
|
-
supportsPromptCache: true,
|
|
187
|
-
inputPrice: 0,
|
|
188
|
-
outputPrice: 2.19,
|
|
189
|
-
cacheWritesPrice: 0.55,
|
|
190
|
-
cacheReadsPrice: 0.14
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
var modelInfos = {
|
|
194
|
-
anthropic: anthropicModels,
|
|
195
|
-
deepseek: deepSeekModels
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
// src/AiService/AnthropicService.ts
|
|
199
|
-
var AnthropicService = class extends AiServiceBase {
|
|
200
|
-
#options;
|
|
201
|
-
#client;
|
|
202
|
-
model;
|
|
203
|
-
constructor(options) {
|
|
204
|
-
super(options);
|
|
205
|
-
this.#options = options;
|
|
206
|
-
this.#client = new Anthropic({
|
|
207
|
-
apiKey: options.apiKey,
|
|
208
|
-
baseURL: options.baseUrl || void 0
|
|
209
|
-
});
|
|
210
|
-
const id = this.#options.model ?? anthropicDefaultModelId;
|
|
211
|
-
this.model = {
|
|
212
|
-
provider: "anthropic",
|
|
213
|
-
id,
|
|
214
|
-
info: anthropicModels[id] ?? anthropicModels[anthropicDefaultModelId]
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
async *sendImpl(systemPrompt, messages, signal) {
|
|
218
|
-
let stream;
|
|
219
|
-
const modelId = this.model.id;
|
|
220
|
-
const cacheControl = this.#options.enableCache ? { type: "ephemeral" } : void 0;
|
|
221
|
-
let temperature = 0;
|
|
222
|
-
let thinkingBudgetTokens = 0;
|
|
223
|
-
if (this.model.info.reasoning) {
|
|
224
|
-
thinkingBudgetTokens = this.#options.parameters.thinkingBudgetTokens ?? 0;
|
|
225
|
-
}
|
|
226
|
-
if (thinkingBudgetTokens > 0) {
|
|
227
|
-
temperature = void 0;
|
|
228
|
-
}
|
|
229
|
-
switch (modelId) {
|
|
230
|
-
// 'latest' alias does not support cache_control
|
|
231
|
-
case "claude-sonnet-4-20250514":
|
|
232
|
-
case "claude-3-7-sonnet-20250219":
|
|
233
|
-
case "claude-3-5-sonnet-20241022":
|
|
234
|
-
case "claude-3-5-haiku-20241022":
|
|
235
|
-
case "claude-3-opus-20240229":
|
|
236
|
-
case "claude-3-haiku-20240307": {
|
|
237
|
-
const userMsgIndices = messages.reduce((acc, msg, index) => {
|
|
238
|
-
if (msg.role === "user") {
|
|
239
|
-
acc.push(index);
|
|
240
|
-
}
|
|
241
|
-
return acc;
|
|
242
|
-
}, []);
|
|
243
|
-
const lastUserMsgIndex = userMsgIndices[userMsgIndices.length - 1] ?? -1;
|
|
244
|
-
const secondLastMsgUserIndex = userMsgIndices[userMsgIndices.length - 2] ?? -1;
|
|
245
|
-
stream = await this.#client.messages.create(
|
|
246
|
-
{
|
|
247
|
-
model: modelId,
|
|
248
|
-
max_tokens: this.model.info.maxTokens || 8192,
|
|
249
|
-
thinking: thinkingBudgetTokens ? { type: "enabled", budget_tokens: thinkingBudgetTokens } : void 0,
|
|
250
|
-
temperature,
|
|
251
|
-
system: [
|
|
252
|
-
{
|
|
253
|
-
text: systemPrompt,
|
|
254
|
-
type: "text",
|
|
255
|
-
cache_control: cacheControl
|
|
256
|
-
}
|
|
257
|
-
],
|
|
258
|
-
// setting cache breakpoint for system prompt so new tasks can reuse it
|
|
259
|
-
messages: messages.map((message, index) => {
|
|
260
|
-
if (index === lastUserMsgIndex || index === secondLastMsgUserIndex) {
|
|
261
|
-
return {
|
|
262
|
-
...message,
|
|
263
|
-
content: typeof message.content === "string" ? [
|
|
264
|
-
{
|
|
265
|
-
type: "text",
|
|
266
|
-
text: message.content,
|
|
267
|
-
cache_control: cacheControl
|
|
268
|
-
}
|
|
269
|
-
] : message.content.map(
|
|
270
|
-
(content, contentIndex) => contentIndex === message.content.length - 1 ? {
|
|
271
|
-
...content,
|
|
272
|
-
cache_control: cacheControl
|
|
273
|
-
} : content
|
|
274
|
-
)
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
return message;
|
|
278
|
-
}),
|
|
279
|
-
stream: true
|
|
280
|
-
},
|
|
281
|
-
{ signal }
|
|
282
|
-
);
|
|
283
|
-
break;
|
|
284
|
-
}
|
|
285
|
-
default: {
|
|
286
|
-
stream = await this.#client.messages.create(
|
|
287
|
-
{
|
|
288
|
-
model: modelId,
|
|
289
|
-
max_tokens: this.model.info.maxTokens || 8192,
|
|
290
|
-
temperature: 0,
|
|
291
|
-
system: [{ text: systemPrompt, type: "text" }],
|
|
292
|
-
messages,
|
|
293
|
-
stream: true
|
|
294
|
-
},
|
|
295
|
-
{ signal }
|
|
296
|
-
);
|
|
297
|
-
break;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
for await (const chunk of stream) {
|
|
301
|
-
switch (chunk.type) {
|
|
302
|
-
case "message_start": {
|
|
303
|
-
const usage = chunk.message.usage;
|
|
304
|
-
yield {
|
|
305
|
-
type: "usage",
|
|
306
|
-
inputTokens: usage.input_tokens,
|
|
307
|
-
outputTokens: usage.output_tokens,
|
|
308
|
-
cacheWriteTokens: usage.cache_creation_input_tokens || 0,
|
|
309
|
-
cacheReadTokens: usage.cache_read_input_tokens || 0
|
|
310
|
-
};
|
|
311
|
-
break;
|
|
312
|
-
}
|
|
313
|
-
case "message_delta": {
|
|
314
|
-
yield {
|
|
315
|
-
type: "usage",
|
|
316
|
-
inputTokens: 0,
|
|
317
|
-
outputTokens: chunk.usage.output_tokens
|
|
318
|
-
};
|
|
319
|
-
break;
|
|
320
|
-
}
|
|
321
|
-
case "message_stop":
|
|
322
|
-
break;
|
|
323
|
-
case "content_block_start":
|
|
324
|
-
switch (chunk.content_block.type) {
|
|
325
|
-
case "text":
|
|
326
|
-
if (chunk.index > 0) {
|
|
327
|
-
yield {
|
|
328
|
-
type: "text",
|
|
329
|
-
text: "\n"
|
|
330
|
-
};
|
|
331
|
-
}
|
|
332
|
-
yield {
|
|
333
|
-
type: "text",
|
|
334
|
-
text: chunk.content_block.text
|
|
335
|
-
};
|
|
336
|
-
break;
|
|
337
|
-
case "thinking":
|
|
338
|
-
yield {
|
|
339
|
-
type: "reasoning",
|
|
340
|
-
text: chunk.content_block.thinking
|
|
341
|
-
};
|
|
342
|
-
break;
|
|
343
|
-
case "redacted_thinking":
|
|
344
|
-
yield {
|
|
345
|
-
type: "reasoning",
|
|
346
|
-
text: "[Redacted by providered]"
|
|
347
|
-
};
|
|
348
|
-
break;
|
|
349
|
-
}
|
|
350
|
-
break;
|
|
351
|
-
case "content_block_delta":
|
|
352
|
-
switch (chunk.delta.type) {
|
|
353
|
-
case "text_delta":
|
|
354
|
-
yield {
|
|
355
|
-
type: "text",
|
|
356
|
-
text: chunk.delta.text
|
|
357
|
-
};
|
|
358
|
-
break;
|
|
359
|
-
case "thinking_delta":
|
|
360
|
-
yield {
|
|
361
|
-
type: "reasoning",
|
|
362
|
-
text: chunk.delta.thinking
|
|
363
|
-
};
|
|
364
|
-
break;
|
|
365
|
-
}
|
|
366
|
-
break;
|
|
367
|
-
case "content_block_stop":
|
|
368
|
-
break;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
// src/AiService/DeepSeekService.ts
|
|
375
|
-
import OpenAI from "openai";
|
|
376
|
-
|
|
377
|
-
// src/AiService/utils.ts
|
|
378
|
-
function convertToOpenAiMessages(anthropicMessages) {
|
|
379
|
-
const openAiMessages = [];
|
|
380
|
-
for (const anthropicMessage of anthropicMessages) {
|
|
381
|
-
if (typeof anthropicMessage.content === "string") {
|
|
382
|
-
openAiMessages.push({
|
|
383
|
-
role: anthropicMessage.role,
|
|
384
|
-
content: anthropicMessage.content
|
|
385
|
-
});
|
|
386
|
-
} else {
|
|
387
|
-
if (anthropicMessage.role === "user") {
|
|
388
|
-
const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce(
|
|
389
|
-
(acc, part) => {
|
|
390
|
-
if (part.type === "tool_result") {
|
|
391
|
-
acc.toolMessages.push(part);
|
|
392
|
-
} else if (part.type === "text" || part.type === "image") {
|
|
393
|
-
acc.nonToolMessages.push(part);
|
|
394
|
-
}
|
|
395
|
-
return acc;
|
|
396
|
-
},
|
|
397
|
-
{ nonToolMessages: [], toolMessages: [] }
|
|
398
|
-
);
|
|
399
|
-
const toolResultImages = [];
|
|
400
|
-
for (const toolMessage of toolMessages) {
|
|
401
|
-
let content;
|
|
402
|
-
if (typeof toolMessage.content === "string") {
|
|
403
|
-
content = toolMessage.content;
|
|
404
|
-
} else {
|
|
405
|
-
content = toolMessage.content?.map((part) => {
|
|
406
|
-
if (part.type === "image") {
|
|
407
|
-
toolResultImages.push(part);
|
|
408
|
-
return "(see following user message for image)";
|
|
409
|
-
}
|
|
410
|
-
return part.text;
|
|
411
|
-
}).join("\n") ?? "";
|
|
412
|
-
}
|
|
413
|
-
openAiMessages.push({
|
|
414
|
-
role: "tool",
|
|
415
|
-
tool_call_id: toolMessage.tool_use_id,
|
|
416
|
-
content
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
if (nonToolMessages.length > 0) {
|
|
420
|
-
openAiMessages.push({
|
|
421
|
-
role: "user",
|
|
422
|
-
content: nonToolMessages.map((part) => {
|
|
423
|
-
if (part.type === "image") {
|
|
424
|
-
if (part.source.type === "base64") {
|
|
425
|
-
return {
|
|
426
|
-
type: "image_url",
|
|
427
|
-
image_url: {
|
|
428
|
-
url: `data:${part.source.media_type};base64,${part.source.data}`
|
|
429
|
-
}
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
return {
|
|
433
|
-
type: "image_url",
|
|
434
|
-
image_url: {
|
|
435
|
-
url: part.source.url
|
|
436
|
-
}
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
return { type: "text", text: part.text };
|
|
440
|
-
})
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
} else if (anthropicMessage.role === "assistant") {
|
|
444
|
-
const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce(
|
|
445
|
-
(acc, part) => {
|
|
446
|
-
if (part.type === "tool_use") {
|
|
447
|
-
acc.toolMessages.push(part);
|
|
448
|
-
} else if (part.type === "text" || part.type === "image") {
|
|
449
|
-
acc.nonToolMessages.push(part);
|
|
450
|
-
}
|
|
451
|
-
return acc;
|
|
452
|
-
},
|
|
453
|
-
{ nonToolMessages: [], toolMessages: [] }
|
|
454
|
-
);
|
|
455
|
-
let content;
|
|
456
|
-
if (nonToolMessages.length > 0) {
|
|
457
|
-
content = nonToolMessages.map((part) => {
|
|
458
|
-
if (part.type === "image") {
|
|
459
|
-
return "";
|
|
460
|
-
}
|
|
461
|
-
return part.text;
|
|
462
|
-
}).join("\n");
|
|
463
|
-
}
|
|
464
|
-
const tool_calls = toolMessages.map((toolMessage) => ({
|
|
465
|
-
id: toolMessage.id,
|
|
466
|
-
type: "function",
|
|
467
|
-
function: {
|
|
468
|
-
name: toolMessage.name,
|
|
469
|
-
// json string
|
|
470
|
-
arguments: JSON.stringify(toolMessage.input)
|
|
471
|
-
}
|
|
472
|
-
}));
|
|
473
|
-
openAiMessages.push({
|
|
474
|
-
role: "assistant",
|
|
475
|
-
content,
|
|
476
|
-
// Cannot be an empty array. API expects an array with minimum length 1, and will respond with an error if it's empty
|
|
477
|
-
tool_calls: tool_calls.length > 0 ? tool_calls : void 0
|
|
478
|
-
});
|
|
7
|
+
// src/UsageMeter.ts
|
|
8
|
+
var UsageMeter = class {
|
|
9
|
+
#totals = { input: 0, output: 0, cachedRead: 0, cost: 0 };
|
|
10
|
+
#calls = 0;
|
|
11
|
+
#modelInfos;
|
|
12
|
+
#maxMessages;
|
|
13
|
+
#maxCost;
|
|
14
|
+
constructor(modelInfos = {}, opts = {}) {
|
|
15
|
+
const infos = {};
|
|
16
|
+
for (const [provider, providerInfo] of Object.entries(modelInfos)) {
|
|
17
|
+
for (const [model, modelInfo] of Object.entries(providerInfo)) {
|
|
18
|
+
infos[`${provider.split("-")[0]}:${model.replace(/[\.-]/g, "")}`] = {
|
|
19
|
+
inputPrice: modelInfo.inputPrice ?? 0,
|
|
20
|
+
outputPrice: modelInfo.outputPrice ?? 0,
|
|
21
|
+
cacheWritesPrice: modelInfo.cacheWritesPrice ?? 0,
|
|
22
|
+
cacheReadsPrice: modelInfo.cacheReadsPrice ?? 0
|
|
23
|
+
};
|
|
479
24
|
}
|
|
480
25
|
}
|
|
26
|
+
this.#modelInfos = infos;
|
|
27
|
+
this.#maxMessages = opts.maxMessages ?? 1e3;
|
|
28
|
+
this.#maxCost = opts.maxCost ?? 100;
|
|
481
29
|
}
|
|
482
|
-
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
baseURL: "https://api.deepseek.com/v1",
|
|
493
|
-
apiKey: options.apiKey
|
|
494
|
-
});
|
|
495
|
-
const id = options.model || deepSeekDefaultModelId;
|
|
496
|
-
this.model = {
|
|
497
|
-
provider: "deepseek",
|
|
498
|
-
id,
|
|
499
|
-
info: deepSeekModels[id] ?? deepSeekModels[deepSeekDefaultModelId]
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
async *sendImpl(systemPrompt, messages, signal) {
|
|
503
|
-
const openAiMessages = [
|
|
504
|
-
{ role: "system", content: systemPrompt },
|
|
505
|
-
...convertToOpenAiMessages(messages)
|
|
506
|
-
];
|
|
507
|
-
const stream = await this.#client.chat.completions.create(
|
|
508
|
-
{
|
|
509
|
-
model: this.model.id,
|
|
510
|
-
max_completion_tokens: this.model.info.maxTokens,
|
|
511
|
-
messages: openAiMessages,
|
|
512
|
-
temperature: 0,
|
|
513
|
-
stream: true,
|
|
514
|
-
stream_options: { include_usage: true }
|
|
515
|
-
},
|
|
516
|
-
{ signal }
|
|
517
|
-
);
|
|
518
|
-
for await (const chunk of stream) {
|
|
519
|
-
const delta = chunk.choices[0]?.delta;
|
|
520
|
-
if (delta?.reasoning_content) {
|
|
521
|
-
yield {
|
|
522
|
-
type: "reasoning",
|
|
523
|
-
text: delta.reasoning_content
|
|
30
|
+
#calculageUsage(usage, providerMetadata, modelInfo) {
|
|
31
|
+
const providerMetadataKey = Object.keys(providerMetadata ?? {})[0];
|
|
32
|
+
const metadata = providerMetadata?.[providerMetadataKey] ?? {};
|
|
33
|
+
switch (providerMetadataKey) {
|
|
34
|
+
case "openrouter":
|
|
35
|
+
return {
|
|
36
|
+
input: usage.inputTokens ?? 0,
|
|
37
|
+
output: usage.outputTokens ?? 0,
|
|
38
|
+
cachedRead: usage.cachedInputTokens ?? 0,
|
|
39
|
+
cost: metadata.usage?.cost ?? 0
|
|
524
40
|
};
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
41
|
+
case "anthropic": {
|
|
42
|
+
const cachedRead = usage.cachedInputTokens ?? 0;
|
|
43
|
+
const cacheWrite = metadata?.promptCacheMissTokens ?? 0;
|
|
44
|
+
const input = usage.inputTokens ?? 0;
|
|
45
|
+
const output = usage.outputTokens ?? 0;
|
|
46
|
+
return {
|
|
47
|
+
input: input + cacheWrite + cachedRead,
|
|
48
|
+
output,
|
|
49
|
+
cachedRead,
|
|
50
|
+
cost: (input * modelInfo.inputPrice + output * modelInfo.outputPrice + cacheWrite * modelInfo.cacheWritesPrice + cachedRead * modelInfo.cacheReadsPrice) / 1e6
|
|
530
51
|
};
|
|
531
52
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
cacheWriteTokens: chunk.usage.prompt_cache_hit_tokens || 0,
|
|
543
|
-
cacheReadTokens: chunk.usage.prompt_cache_miss_tokens || 0
|
|
53
|
+
case "deepseek": {
|
|
54
|
+
const cachedRead = usage.cachedInputTokens ?? 0;
|
|
55
|
+
const cacheWrite = metadata.promptCacheMissTokens ?? 0;
|
|
56
|
+
const input = usage.inputTokens ?? 0;
|
|
57
|
+
const output = usage.outputTokens ?? 0;
|
|
58
|
+
return {
|
|
59
|
+
input,
|
|
60
|
+
output,
|
|
61
|
+
cachedRead,
|
|
62
|
+
cost: (output * modelInfo.outputPrice + cacheWrite * modelInfo.inputPrice + cachedRead * modelInfo.cacheReadsPrice) / 1e6
|
|
544
63
|
};
|
|
545
64
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
constructor(options) {
|
|
556
|
-
super(options);
|
|
557
|
-
this.#client = new OpenAI2({
|
|
558
|
-
baseURL: `${options.baseUrl || "http://localhost:11434"}/v1`,
|
|
559
|
-
apiKey: "ollama"
|
|
560
|
-
});
|
|
561
|
-
this.model = {
|
|
562
|
-
provider: "ollama",
|
|
563
|
-
id: options.model || "maryasov/qwen2.5-coder-cline:7b",
|
|
564
|
-
info: openAiModelInfoSaneDefaults
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
async *sendImpl(systemPrompt, messages, signal) {
|
|
568
|
-
const openAiMessages = [
|
|
569
|
-
{ role: "system", content: systemPrompt },
|
|
570
|
-
...convertToOpenAiMessages(messages)
|
|
571
|
-
];
|
|
572
|
-
const stream = await this.#client.chat.completions.create(
|
|
573
|
-
{
|
|
574
|
-
model: this.model.id,
|
|
575
|
-
messages: openAiMessages,
|
|
576
|
-
temperature: 0,
|
|
577
|
-
stream: true
|
|
578
|
-
},
|
|
579
|
-
{ signal }
|
|
580
|
-
);
|
|
581
|
-
for await (const chunk of stream) {
|
|
582
|
-
const delta = chunk.choices[0]?.delta;
|
|
583
|
-
if (delta?.content) {
|
|
584
|
-
yield {
|
|
585
|
-
type: "text",
|
|
586
|
-
text: delta.content
|
|
65
|
+
default: {
|
|
66
|
+
const cachedRead = usage.cachedInputTokens ?? 0;
|
|
67
|
+
const input = usage.inputTokens ?? 0;
|
|
68
|
+
const output = usage.outputTokens ?? 0;
|
|
69
|
+
return {
|
|
70
|
+
input,
|
|
71
|
+
output,
|
|
72
|
+
cachedRead,
|
|
73
|
+
cost: (input * modelInfo.inputPrice + output * modelInfo.outputPrice) / 1e6
|
|
587
74
|
};
|
|
588
75
|
}
|
|
589
76
|
}
|
|
590
77
|
}
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
//
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
#modelProviderInfo;
|
|
600
|
-
model;
|
|
601
|
-
constructor(options) {
|
|
602
|
-
super(options);
|
|
603
|
-
if (!options.model) {
|
|
604
|
-
throw new Error("OpenRouter requires a model");
|
|
605
|
-
}
|
|
606
|
-
if (!options.apiKey) {
|
|
607
|
-
throw new Error("OpenRouter requires an API key");
|
|
608
|
-
}
|
|
609
|
-
this.#apiKey = options.apiKey;
|
|
610
|
-
this.#client = new OpenAI3({
|
|
611
|
-
baseURL: "https://openrouter.ai/api/v1",
|
|
612
|
-
apiKey: options.apiKey,
|
|
613
|
-
defaultHeaders: {
|
|
614
|
-
"HTTP-Referer": "https://polka.codes",
|
|
615
|
-
// Optional, for including your app on openrouter.ai rankings.
|
|
616
|
-
"X-Title": "Polka Codes"
|
|
617
|
-
// Optional. Shows in rankings on openrouter.ai.
|
|
618
|
-
}
|
|
619
|
-
});
|
|
620
|
-
this.#options = options;
|
|
621
|
-
this.model = {
|
|
622
|
-
provider: "openrouter",
|
|
623
|
-
id: options.model,
|
|
624
|
-
info: {}
|
|
78
|
+
addUsage(llm, resp, options = {}) {
|
|
79
|
+
const modelInfo = options.modelInfo ?? // make google.vertex.chat to google
|
|
80
|
+
// and anthropic.messages to anthropic
|
|
81
|
+
this.#modelInfos[`${llm.provider.split(".")[0]}:${llm.modelId.replace(/[\.-]/g, "")}`] ?? {
|
|
82
|
+
inputPrice: 0,
|
|
83
|
+
outputPrice: 0,
|
|
84
|
+
cacheWritesPrice: 0,
|
|
85
|
+
cacheReadsPrice: 0
|
|
625
86
|
};
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
if (this.
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
};
|
|
648
|
-
const lastTwoUserMessages = openAiMessages.filter((msg) => msg.role === "user").slice(-2);
|
|
649
|
-
for (const msg of lastTwoUserMessages) {
|
|
650
|
-
if (typeof msg.content === "string") {
|
|
651
|
-
msg.content = [{ type: "text", text: msg.content }];
|
|
652
|
-
}
|
|
653
|
-
if (Array.isArray(msg.content)) {
|
|
654
|
-
let lastTextPart = msg.content.filter((part) => part.type === "text").pop();
|
|
655
|
-
if (!lastTextPart) {
|
|
656
|
-
lastTextPart = { type: "text", text: "..." };
|
|
657
|
-
msg.content.push(lastTextPart);
|
|
658
|
-
}
|
|
659
|
-
lastTextPart.cache_control = cacheControl;
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
let reasoning = {};
|
|
664
|
-
switch (this.model.id) {
|
|
665
|
-
case "anthropic/claude-3.7-sonnet":
|
|
666
|
-
case "anthropic/claude-3.7-sonnet:beta":
|
|
667
|
-
case "anthropic/claude-3.7-sonnet:thinking":
|
|
668
|
-
case "anthropic/claude-3-7-sonnet":
|
|
669
|
-
case "anthropic/claude-3-7-sonnet:beta":
|
|
670
|
-
case "anthropic/claude-opus-4":
|
|
671
|
-
case "anthropic/claude-sonnet-4": {
|
|
672
|
-
const budget_tokens = this.#options.parameters.thinkingBudgetTokens || 0;
|
|
673
|
-
if (budget_tokens > 0) {
|
|
674
|
-
reasoning = { max_tokens: budget_tokens };
|
|
675
|
-
}
|
|
676
|
-
break;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
let shouldApplyMiddleOutTransform = !this.model.info.supportsPromptCache;
|
|
680
|
-
if (this.model.id === "deepseek/deepseek-chat") {
|
|
681
|
-
shouldApplyMiddleOutTransform = true;
|
|
682
|
-
}
|
|
683
|
-
const stream = await this.#client.chat.completions.create(
|
|
684
|
-
{
|
|
685
|
-
model: this.model.id,
|
|
686
|
-
messages: openAiMessages,
|
|
687
|
-
temperature: 0,
|
|
688
|
-
stream: true,
|
|
689
|
-
transforms: shouldApplyMiddleOutTransform ? ["middle-out"] : void 0,
|
|
690
|
-
include_reasoning: true,
|
|
691
|
-
...reasoning
|
|
692
|
-
},
|
|
693
|
-
{ signal }
|
|
694
|
-
);
|
|
695
|
-
let genId;
|
|
696
|
-
for await (const chunk of stream) {
|
|
697
|
-
if ("error" in chunk) {
|
|
698
|
-
const error = chunk.error;
|
|
699
|
-
console.error(`OpenRouter API Error: ${error?.code} - ${error?.message}`);
|
|
700
|
-
throw new Error(`OpenRouter API Error ${error?.code}: ${error?.message}`);
|
|
701
|
-
}
|
|
702
|
-
if (!genId && chunk.id) {
|
|
703
|
-
genId = chunk.id;
|
|
704
|
-
}
|
|
705
|
-
const delta = chunk.choices[0]?.delta;
|
|
706
|
-
if (delta?.reasoning) {
|
|
707
|
-
yield {
|
|
708
|
-
type: "reasoning",
|
|
709
|
-
text: delta.reasoning
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
if (delta?.content) {
|
|
713
|
-
yield {
|
|
714
|
-
type: "text",
|
|
715
|
-
text: delta.content
|
|
716
|
-
};
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
720
|
-
const controller = new AbortController();
|
|
721
|
-
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
722
|
-
try {
|
|
723
|
-
const response = await fetch(`https://openrouter.ai/api/v1/generation?id=${genId}`, {
|
|
724
|
-
headers: {
|
|
725
|
-
Authorization: `Bearer ${this.#apiKey}`
|
|
726
|
-
},
|
|
727
|
-
signal: controller.signal
|
|
728
|
-
// this request hangs sometimes
|
|
729
|
-
});
|
|
730
|
-
const responseBody = await response.json();
|
|
731
|
-
const generation = responseBody.data ?? {};
|
|
732
|
-
let totalCost = generation.total_cost || 0;
|
|
733
|
-
if (generation.is_byok && this.#modelProviderInfo) {
|
|
734
|
-
const price = this.#modelProviderInfo.endpoints.find((e) => e.provider_name === generation.provider_name)?.pricing;
|
|
735
|
-
if (price) {
|
|
736
|
-
totalCost += (generation.native_tokens_prompt || 0) * price.request;
|
|
737
|
-
totalCost += (generation.native_tokens_completion || 0) * price.completion;
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
yield {
|
|
741
|
-
type: "usage",
|
|
742
|
-
// cacheWriteTokens: 0,
|
|
743
|
-
// cacheReadTokens: 0,
|
|
744
|
-
// openrouter generation endpoint fails often
|
|
745
|
-
inputTokens: generation.native_tokens_prompt || 0,
|
|
746
|
-
outputTokens: generation.native_tokens_completion || 0,
|
|
747
|
-
totalCost
|
|
748
|
-
};
|
|
749
|
-
} catch (error) {
|
|
750
|
-
console.error("Error fetching OpenRouter generation details:", error);
|
|
751
|
-
} finally {
|
|
752
|
-
clearTimeout(timeout);
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
};
|
|
756
|
-
|
|
757
|
-
// src/AiService/UsageMeter.ts
|
|
758
|
-
import { merge } from "lodash";
|
|
759
|
-
var UsageMeter = class {
|
|
760
|
-
#usage = {
|
|
761
|
-
inputTokens: 0,
|
|
762
|
-
outputTokens: 0,
|
|
763
|
-
cacheWriteTokens: 0,
|
|
764
|
-
cacheReadTokens: 0,
|
|
765
|
-
totalCost: 0
|
|
766
|
-
};
|
|
767
|
-
#messageCount = 0;
|
|
768
|
-
#prices = {};
|
|
769
|
-
maxCost;
|
|
770
|
-
maxMessageCount;
|
|
771
|
-
constructor(options = {}) {
|
|
772
|
-
this.maxCost = options.maxCost || 1e3;
|
|
773
|
-
this.maxMessageCount = options.maxMessageCount || 1e3;
|
|
774
|
-
this.#prices = merge({}, modelInfos, options.prices ?? {});
|
|
775
|
-
}
|
|
776
|
-
/**
|
|
777
|
-
* Add usage metrics to the current totals
|
|
778
|
-
*/
|
|
779
|
-
addUsage(usage, model) {
|
|
780
|
-
this.#usage.inputTokens += usage.inputTokens ?? 0;
|
|
781
|
-
this.#usage.outputTokens += usage.outputTokens ?? 0;
|
|
782
|
-
this.#usage.cacheWriteTokens += usage.cacheWriteTokens ?? 0;
|
|
783
|
-
this.#usage.cacheReadTokens += usage.cacheReadTokens ?? 0;
|
|
784
|
-
if (!usage.totalCost && model) {
|
|
785
|
-
const modelInfo = this.#prices[model.provider]?.[model.id] ?? {};
|
|
786
|
-
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;
|
|
787
|
-
}
|
|
788
|
-
this.#usage.totalCost += usage.totalCost ?? 0;
|
|
789
|
-
}
|
|
790
|
-
setUsage(usage, messageCount) {
|
|
791
|
-
this.#usage.inputTokens = usage.inputTokens ?? this.#usage.inputTokens;
|
|
792
|
-
this.#usage.outputTokens = usage.outputTokens ?? this.#usage.outputTokens;
|
|
793
|
-
this.#usage.cacheWriteTokens = usage.cacheWriteTokens ?? this.#usage.cacheWriteTokens;
|
|
794
|
-
this.#usage.cacheReadTokens = usage.cacheReadTokens ?? this.#usage.cacheReadTokens;
|
|
795
|
-
this.#usage.totalCost = usage.totalCost ?? this.#usage.totalCost;
|
|
796
|
-
if (messageCount !== void 0) {
|
|
797
|
-
this.#messageCount = messageCount;
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
incrementMessageCount(count = 1) {
|
|
801
|
-
this.#messageCount += count;
|
|
802
|
-
}
|
|
87
|
+
const usage = "totalUsage" in resp ? resp.totalUsage : resp.usage;
|
|
88
|
+
const result = this.#calculageUsage(usage, resp.providerMetadata, modelInfo);
|
|
89
|
+
this.#totals.input += result.input;
|
|
90
|
+
this.#totals.output += result.output;
|
|
91
|
+
this.#totals.cachedRead += result.cachedRead;
|
|
92
|
+
this.#totals.cost += result.cost;
|
|
93
|
+
this.#calls++;
|
|
94
|
+
}
|
|
95
|
+
/** Override the running totals (e.g., restore from saved state). */
|
|
96
|
+
setUsage(newUsage) {
|
|
97
|
+
if (newUsage.input != null) this.#totals.input = newUsage.input;
|
|
98
|
+
if (newUsage.output != null) this.#totals.output = newUsage.output;
|
|
99
|
+
if (newUsage.cachedRead != null) this.#totals.cachedRead = newUsage.cachedRead;
|
|
100
|
+
if (newUsage.cost != null) this.#totals.cost = newUsage.cost;
|
|
101
|
+
if (newUsage.calls != null) this.#calls = newUsage.calls;
|
|
102
|
+
}
|
|
103
|
+
/** Manually bump the message count (useful if you record some calls without token info). */
|
|
104
|
+
incrementMessageCount(n = 1) {
|
|
105
|
+
this.#calls += n;
|
|
106
|
+
}
|
|
107
|
+
/** Return true once either messages or cost exceed the configured caps. */
|
|
803
108
|
isLimitExceeded() {
|
|
804
|
-
const messageCount = this.#
|
|
805
|
-
const cost = this.#
|
|
109
|
+
const messageCount = this.#maxMessages !== void 0 && this.#calls >= this.#maxMessages;
|
|
110
|
+
const cost = this.#maxCost !== void 0 && this.#totals.cost >= this.#maxCost;
|
|
806
111
|
return {
|
|
807
112
|
messageCount,
|
|
808
|
-
|
|
113
|
+
maxMessages: this.#maxMessages,
|
|
809
114
|
cost,
|
|
810
|
-
maxCost: this
|
|
115
|
+
maxCost: this.#maxCost,
|
|
811
116
|
result: messageCount || cost
|
|
812
117
|
};
|
|
813
118
|
}
|
|
119
|
+
/** Same as isLimitExceeded but throws an error if a limit is hit. */
|
|
814
120
|
checkLimit() {
|
|
815
121
|
const result = this.isLimitExceeded();
|
|
816
122
|
if (result.result) {
|
|
817
123
|
throw new Error(
|
|
818
|
-
`Usage limit exceeded. Message count: ${result.messageCount}/${result.
|
|
124
|
+
`Usage limit exceeded. Message count: ${result.messageCount}/${result.maxMessages}, cost: ${result.cost}/${result.maxCost}`
|
|
819
125
|
);
|
|
820
126
|
}
|
|
821
127
|
}
|
|
822
|
-
/**
|
|
823
|
-
* Get current usage totals
|
|
824
|
-
*/
|
|
128
|
+
/** Getter for the aggregated totals (immutable copy). */
|
|
825
129
|
get usage() {
|
|
826
|
-
return { ...this.#
|
|
130
|
+
return { ...this.#totals, messageCount: this.#calls };
|
|
827
131
|
}
|
|
132
|
+
/** Print a concise usage summary to console. */
|
|
828
133
|
printUsage() {
|
|
829
|
-
const
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
console.log(`Input tokens: ${this.#usage.inputTokens}`);
|
|
834
|
-
console.log(`Output tokens: ${this.#usage.outputTokens}`);
|
|
835
|
-
console.log(`Cache read tokens: ${this.#usage.cacheReadTokens}`);
|
|
836
|
-
console.log(`Cache write tokens: ${this.#usage.cacheWriteTokens}`);
|
|
837
|
-
}
|
|
838
|
-
console.log(`Total cost: ${this.#usage.totalCost}`);
|
|
134
|
+
const u = this.usage;
|
|
135
|
+
console.log(
|
|
136
|
+
`Usage - messages: ${u.messageCount}, input: ${u.input}, cached: ${u.cachedRead}, output: ${u.output}, cost: $${u.cost.toFixed(4)}`
|
|
137
|
+
);
|
|
839
138
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
AiServiceProvider2["Anthropic"] = "anthropic";
|
|
845
|
-
AiServiceProvider2["Ollama"] = "ollama";
|
|
846
|
-
AiServiceProvider2["DeepSeek"] = "deepseek";
|
|
847
|
-
AiServiceProvider2["OpenRouter"] = "openrouter";
|
|
848
|
-
return AiServiceProvider2;
|
|
849
|
-
})(AiServiceProvider || {});
|
|
850
|
-
var defaultModels = {
|
|
851
|
-
["anthropic" /* Anthropic */]: "claude-3-7-sonnet-20250219",
|
|
852
|
-
["ollama" /* Ollama */]: "maryasov/qwen2.5-coder-cline:7b",
|
|
853
|
-
["deepseek" /* DeepSeek */]: "deepseek-chat",
|
|
854
|
-
["openrouter" /* OpenRouter */]: "anthropic/claude-3.7-sonnet"
|
|
855
|
-
};
|
|
856
|
-
var createService = (provider, options) => {
|
|
857
|
-
switch (provider) {
|
|
858
|
-
case "anthropic" /* Anthropic */:
|
|
859
|
-
return new AnthropicService(options);
|
|
860
|
-
case "ollama" /* Ollama */:
|
|
861
|
-
return new OllamaService(options);
|
|
862
|
-
case "deepseek" /* DeepSeek */:
|
|
863
|
-
return new DeepSeekService(options);
|
|
864
|
-
case "openrouter" /* OpenRouter */:
|
|
865
|
-
return new OpenRouterService(options);
|
|
139
|
+
onFinishHandler(llm) {
|
|
140
|
+
return (evt) => {
|
|
141
|
+
this.addUsage(llm, evt);
|
|
142
|
+
};
|
|
866
143
|
}
|
|
867
144
|
};
|
|
868
145
|
|
|
@@ -912,10 +189,12 @@ __export(allTools_exports, {
|
|
|
912
189
|
renameFile: () => renameFile_default,
|
|
913
190
|
replaceInFile: () => replaceInFile_default,
|
|
914
191
|
searchFiles: () => searchFiles_default,
|
|
915
|
-
updateKnowledge: () => updateKnowledge_default,
|
|
916
192
|
writeToFile: () => writeToFile_default
|
|
917
193
|
});
|
|
918
194
|
|
|
195
|
+
// src/tools/askFollowupQuestion.ts
|
|
196
|
+
import { z } from "zod";
|
|
197
|
+
|
|
919
198
|
// src/tool.ts
|
|
920
199
|
var PermissionLevel = /* @__PURE__ */ ((PermissionLevel2) => {
|
|
921
200
|
PermissionLevel2[PermissionLevel2["None"] = 0] = "None";
|
|
@@ -936,200 +215,17 @@ var ToolResponseType = /* @__PURE__ */ ((ToolResponseType2) => {
|
|
|
936
215
|
return ToolResponseType2;
|
|
937
216
|
})(ToolResponseType || {});
|
|
938
217
|
|
|
939
|
-
// src/tools/utils/getArg.ts
|
|
940
|
-
var getString = (args, name, defaultValue) => {
|
|
941
|
-
if (typeof args !== "object" || Array.isArray(args)) {
|
|
942
|
-
throw new Error(`Invalid argument type: ${name} ${args}`);
|
|
943
|
-
}
|
|
944
|
-
const ret = args[name] ?? defaultValue;
|
|
945
|
-
if (ret === void 0) {
|
|
946
|
-
throw new Error(`Missing required argument: ${name}`);
|
|
947
|
-
}
|
|
948
|
-
if (typeof ret !== "string") {
|
|
949
|
-
throw new Error(`Invalid argument type: ${name} ${ret}`);
|
|
950
|
-
}
|
|
951
|
-
return ret;
|
|
952
|
-
};
|
|
953
|
-
var getStringArray = (args, name, defaultValue) => {
|
|
954
|
-
const ret = args[name];
|
|
955
|
-
if (ret === void 0) {
|
|
956
|
-
if (defaultValue === void 0) {
|
|
957
|
-
throw new Error(`Missing required argument: ${name}`);
|
|
958
|
-
}
|
|
959
|
-
return defaultValue;
|
|
960
|
-
}
|
|
961
|
-
if (ret === "") {
|
|
962
|
-
return [];
|
|
963
|
-
}
|
|
964
|
-
if (Array.isArray(ret)) {
|
|
965
|
-
for (const item of ret) {
|
|
966
|
-
if (typeof item !== "string") {
|
|
967
|
-
throw new Error(`Invalid argument type: ${name} ${item}`);
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
return ret;
|
|
971
|
-
}
|
|
972
|
-
if (typeof ret !== "string") {
|
|
973
|
-
throw new Error(`Invalid argument type: ${name} ${ret}`);
|
|
974
|
-
}
|
|
975
|
-
return ret.split(",").map((s) => s.trim());
|
|
976
|
-
};
|
|
977
|
-
var getBoolean = (args, name, defaultValue) => {
|
|
978
|
-
const ret = args[name];
|
|
979
|
-
if (ret === void 0) {
|
|
980
|
-
if (defaultValue === void 0) {
|
|
981
|
-
throw new Error(`Missing required argument: ${name}`);
|
|
982
|
-
}
|
|
983
|
-
return defaultValue;
|
|
984
|
-
}
|
|
985
|
-
if (typeof ret !== "string") {
|
|
986
|
-
throw new Error(`Invalid argument type: ${name} ${ret}`);
|
|
987
|
-
}
|
|
988
|
-
switch (ret.toLowerCase()) {
|
|
989
|
-
case "true":
|
|
990
|
-
return true;
|
|
991
|
-
case "false":
|
|
992
|
-
return false;
|
|
993
|
-
default:
|
|
994
|
-
throw new Error(`Invalid argument value: ${name} ${ret}`);
|
|
995
|
-
}
|
|
996
|
-
};
|
|
997
|
-
var getInt = (args, name, defaultValue) => {
|
|
998
|
-
const ret = args[name];
|
|
999
|
-
if (ret === void 0) {
|
|
1000
|
-
if (defaultValue === void 0) {
|
|
1001
|
-
throw new Error(`Missing required argument: ${name}`);
|
|
1002
|
-
}
|
|
1003
|
-
return defaultValue;
|
|
1004
|
-
}
|
|
1005
|
-
if (typeof ret !== "string") {
|
|
1006
|
-
throw new Error(`Invalid argument type: ${name} ${ret}`);
|
|
1007
|
-
}
|
|
1008
|
-
const parsed = Number.parseInt(ret);
|
|
1009
|
-
if (Number.isNaN(parsed)) {
|
|
1010
|
-
throw new Error(`Invalid argument value: ${name} ${ret}`);
|
|
1011
|
-
}
|
|
1012
|
-
return parsed;
|
|
1013
|
-
};
|
|
1014
|
-
var getArray = (args, name, defaultValue) => {
|
|
1015
|
-
if (typeof args !== "object" || Array.isArray(args)) {
|
|
1016
|
-
throw new Error(`Invalid argument type: ${name} ${args}`);
|
|
1017
|
-
}
|
|
1018
|
-
const ret = args[name];
|
|
1019
|
-
if (ret === void 0) {
|
|
1020
|
-
if (defaultValue === void 0) {
|
|
1021
|
-
throw new Error(`Missing required argument: ${name}`);
|
|
1022
|
-
}
|
|
1023
|
-
return defaultValue;
|
|
1024
|
-
}
|
|
1025
|
-
if (Array.isArray(ret)) {
|
|
1026
|
-
return ret;
|
|
1027
|
-
}
|
|
1028
|
-
return [ret];
|
|
1029
|
-
};
|
|
1030
|
-
|
|
1031
|
-
// src/tools/utils/replaceInFile.ts
|
|
1032
|
-
var replaceInFile = (fileContent, diff) => {
|
|
1033
|
-
const blockPattern = /<<<<<+ SEARCH>?\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
|
|
1034
|
-
const blocks = [];
|
|
1035
|
-
for (let match = blockPattern.exec(diff); match !== null; match = blockPattern.exec(diff)) {
|
|
1036
|
-
blocks.push({ search: match[1], replace: match[2] });
|
|
1037
|
-
}
|
|
1038
|
-
if (blocks.length === 0) {
|
|
1039
|
-
throw new Error("No valid diff blocks found.");
|
|
1040
|
-
}
|
|
1041
|
-
const findAndReplace = (content, search, replace) => {
|
|
1042
|
-
let index = content.indexOf(search);
|
|
1043
|
-
if (index !== -1) {
|
|
1044
|
-
return content.slice(0, index) + replace + content.slice(index + search.length);
|
|
1045
|
-
}
|
|
1046
|
-
const trimmedSearch = search.trim();
|
|
1047
|
-
const trimmedContent = content.trim();
|
|
1048
|
-
const offset = content.indexOf(trimmedContent);
|
|
1049
|
-
index = trimmedContent.indexOf(trimmedSearch);
|
|
1050
|
-
if (index !== -1) {
|
|
1051
|
-
const absoluteIndex = offset + index;
|
|
1052
|
-
return content.slice(0, absoluteIndex) + replace + content.slice(absoluteIndex + trimmedSearch.length);
|
|
1053
|
-
}
|
|
1054
|
-
const normalizedSearch = trimmedSearch.replace(/\s+/g, " ");
|
|
1055
|
-
const normalizedContent = trimmedContent.replace(/\s+/g, " ");
|
|
1056
|
-
index = normalizedContent.indexOf(normalizedSearch);
|
|
1057
|
-
if (index !== -1) {
|
|
1058
|
-
let runningIndex = 0;
|
|
1059
|
-
let actualPos = offset;
|
|
1060
|
-
for (const segment of trimmedSearch.replace(/\s+/g, " ").split(" ")) {
|
|
1061
|
-
const segIndex = content.indexOf(segment, actualPos);
|
|
1062
|
-
if (segIndex === -1) {
|
|
1063
|
-
break;
|
|
1064
|
-
}
|
|
1065
|
-
if (runningIndex === 0) {
|
|
1066
|
-
actualPos = segIndex;
|
|
1067
|
-
} else {
|
|
1068
|
-
actualPos = segIndex + segment.length;
|
|
1069
|
-
}
|
|
1070
|
-
runningIndex++;
|
|
1071
|
-
}
|
|
1072
|
-
const strippedSearch = trimmedSearch.replace(/\s+/g, "");
|
|
1073
|
-
const endPos = actualPos;
|
|
1074
|
-
const startPos = endPos - strippedSearch.length;
|
|
1075
|
-
return content.slice(0, startPos) + replace + content.slice(endPos);
|
|
1076
|
-
}
|
|
1077
|
-
return null;
|
|
1078
|
-
};
|
|
1079
|
-
let updatedFile = fileContent;
|
|
1080
|
-
let appliedCount = 0;
|
|
1081
|
-
const totalCount = blocks.length;
|
|
1082
|
-
for (const { search, replace } of blocks) {
|
|
1083
|
-
const result = findAndReplace(updatedFile, search, replace);
|
|
1084
|
-
if (result !== null) {
|
|
1085
|
-
updatedFile = result;
|
|
1086
|
-
appliedCount++;
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
let status;
|
|
1090
|
-
if (appliedCount === 0) {
|
|
1091
|
-
status = "no_diff_applied";
|
|
1092
|
-
} else if (appliedCount < totalCount) {
|
|
1093
|
-
status = "some_diff_applied";
|
|
1094
|
-
} else {
|
|
1095
|
-
status = "all_diff_applied";
|
|
1096
|
-
}
|
|
1097
|
-
return {
|
|
1098
|
-
content: updatedFile,
|
|
1099
|
-
status,
|
|
1100
|
-
appliedCount,
|
|
1101
|
-
totalCount
|
|
1102
|
-
};
|
|
1103
|
-
};
|
|
1104
|
-
|
|
1105
218
|
// src/tools/askFollowupQuestion.ts
|
|
219
|
+
var questionObject = z.object({
|
|
220
|
+
prompt: z.string().describe("The text of the question.").meta({ usageValue: "question text here" }),
|
|
221
|
+
options: z.array(z.string()).default([]).describe("Ordered list of suggested answers (omit if none).").meta({ usageValue: "suggested answer here" })
|
|
222
|
+
});
|
|
1106
223
|
var toolInfo = {
|
|
1107
224
|
name: "ask_followup_question",
|
|
1108
225
|
description: "Call this when vital details are missing. Pose each follow-up as one direct, unambiguous question. If it speeds the reply, add up to five short, mutually-exclusive answer options. Group any related questions in the same call to avoid a back-and-forth chain.",
|
|
1109
|
-
parameters:
|
|
1110
|
-
{
|
|
1111
|
-
|
|
1112
|
-
description: "One or more follow-up questions you need answered before you can continue.",
|
|
1113
|
-
required: true,
|
|
1114
|
-
allowMultiple: true,
|
|
1115
|
-
usageValue: "questions here",
|
|
1116
|
-
children: [
|
|
1117
|
-
{
|
|
1118
|
-
name: "prompt",
|
|
1119
|
-
description: "The text of the question.",
|
|
1120
|
-
required: true,
|
|
1121
|
-
usageValue: "question text here"
|
|
1122
|
-
},
|
|
1123
|
-
{
|
|
1124
|
-
name: "options",
|
|
1125
|
-
description: "Ordered list of suggested answers (omit if none).",
|
|
1126
|
-
required: false,
|
|
1127
|
-
allowMultiple: true,
|
|
1128
|
-
usageValue: "suggested answer here"
|
|
1129
|
-
}
|
|
1130
|
-
]
|
|
1131
|
-
}
|
|
1132
|
-
],
|
|
226
|
+
parameters: z.object({
|
|
227
|
+
questions: z.array(questionObject).describe("One or more follow-up questions you need answered before you can continue.").meta({ usageValue: "questions here" })
|
|
228
|
+
}),
|
|
1133
229
|
examples: [
|
|
1134
230
|
{
|
|
1135
231
|
description: "Single clarifying question (no options)",
|
|
@@ -1189,19 +285,18 @@ var handler = async (provider, args) => {
|
|
|
1189
285
|
message: "Not possible to ask followup question. Abort."
|
|
1190
286
|
};
|
|
1191
287
|
}
|
|
1192
|
-
const questions =
|
|
1193
|
-
if (
|
|
288
|
+
const { questions } = toolInfo.parameters.parse(args);
|
|
289
|
+
if (questions.length === 0) {
|
|
1194
290
|
return {
|
|
1195
|
-
type: "
|
|
291
|
+
type: "Invalid" /* Invalid */,
|
|
1196
292
|
message: "No questions provided"
|
|
1197
293
|
};
|
|
1198
294
|
}
|
|
1199
295
|
const answers = [];
|
|
1200
296
|
for (const question of questions) {
|
|
1201
|
-
const
|
|
1202
|
-
const
|
|
1203
|
-
|
|
1204
|
-
answers.push(`<ask_followup_question_answer question="${prompt6}">
|
|
297
|
+
const { prompt: prompt5, options } = question;
|
|
298
|
+
const answer = await provider.askFollowupQuestion(prompt5, options);
|
|
299
|
+
answers.push(`<ask_followup_question_answer question="${prompt5}">
|
|
1205
300
|
${answer}
|
|
1206
301
|
</ask_followup_question_answer>`);
|
|
1207
302
|
}
|
|
@@ -1220,17 +315,15 @@ var askFollowupQuestion_default = {
|
|
|
1220
315
|
};
|
|
1221
316
|
|
|
1222
317
|
// src/tools/attemptCompletion.ts
|
|
318
|
+
import { z as z2 } from "zod";
|
|
1223
319
|
var toolInfo2 = {
|
|
1224
320
|
name: "attempt_completion",
|
|
1225
321
|
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.",
|
|
1226
|
-
parameters:
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
usageValue: "Your final result description here"
|
|
1232
|
-
}
|
|
1233
|
-
],
|
|
322
|
+
parameters: z2.object({
|
|
323
|
+
result: z2.string().describe(
|
|
324
|
+
"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."
|
|
325
|
+
).meta({ usageValue: "Your final result description here" })
|
|
326
|
+
}),
|
|
1234
327
|
examples: [
|
|
1235
328
|
{
|
|
1236
329
|
description: "Request to present the result of the task",
|
|
@@ -1245,7 +338,14 @@ var toolInfo2 = {
|
|
|
1245
338
|
permissionLevel: 0 /* None */
|
|
1246
339
|
};
|
|
1247
340
|
var handler2 = async (provider, args) => {
|
|
1248
|
-
const
|
|
341
|
+
const parsed = toolInfo2.parameters.safeParse(args);
|
|
342
|
+
if (!parsed.success) {
|
|
343
|
+
return {
|
|
344
|
+
type: "Invalid" /* Invalid */,
|
|
345
|
+
message: `Invalid arguments for attempt_completion: ${parsed.error.message}`
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
const { result } = parsed.data;
|
|
1249
349
|
const moreMessage = await provider.attemptCompletion?.(result);
|
|
1250
350
|
if (!moreMessage) {
|
|
1251
351
|
return {
|
|
@@ -1268,41 +368,26 @@ var attemptCompletion_default = {
|
|
|
1268
368
|
};
|
|
1269
369
|
|
|
1270
370
|
// src/tools/delegate.ts
|
|
371
|
+
import { z as z3 } from "zod";
|
|
1271
372
|
var toolInfo3 = {
|
|
1272
373
|
name: "delegate",
|
|
1273
374
|
description: "Temporarily delegate a task to another agent and receive the result back. This tool MUST NOT to be used with any other tool.",
|
|
1274
|
-
parameters:
|
|
1275
|
-
{
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
required: true,
|
|
1285
|
-
usageValue: "Task description"
|
|
1286
|
-
},
|
|
1287
|
-
{
|
|
1288
|
-
name: "context",
|
|
1289
|
-
description: "The context information for the task",
|
|
1290
|
-
required: true,
|
|
1291
|
-
usageValue: "Context information"
|
|
1292
|
-
},
|
|
1293
|
-
{
|
|
1294
|
-
name: "files",
|
|
1295
|
-
description: "The files relevant to the task. Comma separated paths",
|
|
1296
|
-
required: false,
|
|
1297
|
-
usageValue: "Relevant files"
|
|
1298
|
-
}
|
|
1299
|
-
],
|
|
375
|
+
parameters: z3.object({
|
|
376
|
+
agentName: z3.string().describe("The name of the agent to delegate the task to").meta({ usageValue: "Name of the target agent" }),
|
|
377
|
+
task: z3.string().describe("The task to be completed by the target agent").meta({ usageValue: "Task description" }),
|
|
378
|
+
context: z3.string().describe("The context information for the task").meta({ usageValue: "Context information" }),
|
|
379
|
+
files: z3.preprocess((val) => {
|
|
380
|
+
if (!val) return [];
|
|
381
|
+
const values = Array.isArray(val) ? val : [val];
|
|
382
|
+
return values.flatMap((i) => typeof i === "string" ? i.split(",") : []).filter((s) => s.length > 0);
|
|
383
|
+
}, z3.array(z3.string())).optional().describe("The files relevant to the task. Comma separated paths").meta({ usageValue: "Relevant files" })
|
|
384
|
+
}),
|
|
1300
385
|
examples: [
|
|
1301
386
|
{
|
|
1302
387
|
description: "Delegate a code analysis task to the analyzer agent",
|
|
1303
388
|
parameters: [
|
|
1304
389
|
{
|
|
1305
|
-
name: "
|
|
390
|
+
name: "agentName",
|
|
1306
391
|
value: "analyzer"
|
|
1307
392
|
},
|
|
1308
393
|
{
|
|
@@ -1323,16 +408,20 @@ var toolInfo3 = {
|
|
|
1323
408
|
permissionLevel: 0 /* None */
|
|
1324
409
|
};
|
|
1325
410
|
var handler3 = async (_provider, args) => {
|
|
1326
|
-
const
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
411
|
+
const parsed = toolInfo3.parameters.safeParse(args);
|
|
412
|
+
if (!parsed.success) {
|
|
413
|
+
return {
|
|
414
|
+
type: "Invalid" /* Invalid */,
|
|
415
|
+
message: `Invalid arguments for delegate: ${parsed.error.message}`
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
const { agentName, task, context, files } = parsed.data;
|
|
1330
419
|
return {
|
|
1331
420
|
type: "Delegate" /* Delegate */,
|
|
1332
421
|
agentName,
|
|
1333
422
|
task,
|
|
1334
423
|
context,
|
|
1335
|
-
files
|
|
424
|
+
files: files ?? []
|
|
1336
425
|
};
|
|
1337
426
|
};
|
|
1338
427
|
var isAvailable3 = (_provider) => {
|
|
@@ -1345,29 +434,29 @@ var delegate_default = {
|
|
|
1345
434
|
};
|
|
1346
435
|
|
|
1347
436
|
// src/tools/executeCommand.ts
|
|
437
|
+
import { z as z4 } from "zod";
|
|
1348
438
|
var toolInfo4 = {
|
|
1349
439
|
name: "execute_command",
|
|
1350
440
|
description: "Run a single CLI command. The command is always executed in the project-root working directory (regardless of earlier commands). Prefer one-off shell commands over wrapper scripts for flexibility. **IMPORTANT**: After an `execute_command` call, you MUST stop and NOT allowed to make further tool calls in the same message.",
|
|
1351
|
-
parameters:
|
|
1352
|
-
{
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
],
|
|
441
|
+
parameters: z4.object({
|
|
442
|
+
command: z4.string().describe("The exact command to run (valid for the current OS). It must be correctly formatted and free of harmful instructions.").meta({ usageValue: "your-command-here" }),
|
|
443
|
+
requiresApproval: z4.preprocess((val) => {
|
|
444
|
+
if (typeof val === "string") {
|
|
445
|
+
const lower = val.toLowerCase();
|
|
446
|
+
if (lower === "false") return false;
|
|
447
|
+
if (lower === "true") return true;
|
|
448
|
+
}
|
|
449
|
+
return val;
|
|
450
|
+
}, z4.boolean().optional().default(false)).describe(
|
|
451
|
+
"Set to `true` for commands that install/uninstall software, modify or delete files, change system settings, perform network operations, or have other side effects. Use `false` for safe, read-only, or purely local development actions (e.g., listing files, make a build, running tests)."
|
|
452
|
+
).meta({ usageValue: "true | false" })
|
|
453
|
+
}),
|
|
1365
454
|
examples: [
|
|
1366
455
|
{
|
|
1367
456
|
description: "Make a build",
|
|
1368
457
|
parameters: [
|
|
1369
458
|
{ name: "command", value: "npm run build" },
|
|
1370
|
-
{ name: "
|
|
459
|
+
{ name: "requiresApproval", value: "false" }
|
|
1371
460
|
]
|
|
1372
461
|
}
|
|
1373
462
|
],
|
|
@@ -1380,10 +469,11 @@ var handler4 = async (provider, args) => {
|
|
|
1380
469
|
message: "Not possible to execute command. Abort."
|
|
1381
470
|
};
|
|
1382
471
|
}
|
|
1383
|
-
const command =
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
472
|
+
const { command, requiresApproval } = toolInfo4.parameters.parse(args);
|
|
473
|
+
try {
|
|
474
|
+
console.log("Executing command:", command, "Requires approval:", requiresApproval);
|
|
475
|
+
const result = await provider.executeCommand(command, requiresApproval);
|
|
476
|
+
const message = `<command>${command}</command>
|
|
1387
477
|
<command_exit_code>${result.exitCode}</command_exit_code>
|
|
1388
478
|
<command_stdout>
|
|
1389
479
|
${result.stdout}
|
|
@@ -1391,16 +481,22 @@ ${result.stdout}
|
|
|
1391
481
|
<command_stderr>
|
|
1392
482
|
${result.stderr}
|
|
1393
483
|
</command_stderr>`;
|
|
1394
|
-
|
|
484
|
+
if (result.exitCode === 0) {
|
|
485
|
+
return {
|
|
486
|
+
type: "Reply" /* Reply */,
|
|
487
|
+
message
|
|
488
|
+
};
|
|
489
|
+
}
|
|
1395
490
|
return {
|
|
1396
|
-
type: "
|
|
491
|
+
type: "Error" /* Error */,
|
|
1397
492
|
message
|
|
1398
493
|
};
|
|
494
|
+
} catch (error) {
|
|
495
|
+
return {
|
|
496
|
+
type: "Error" /* Error */,
|
|
497
|
+
message: error instanceof Error ? error.message : String(error)
|
|
498
|
+
};
|
|
1399
499
|
}
|
|
1400
|
-
return {
|
|
1401
|
-
type: "Error" /* Error */,
|
|
1402
|
-
message
|
|
1403
|
-
};
|
|
1404
500
|
};
|
|
1405
501
|
var isAvailable4 = (provider) => {
|
|
1406
502
|
return !!provider.executeCommand;
|
|
@@ -1412,16 +508,17 @@ var executeCommand_default = {
|
|
|
1412
508
|
};
|
|
1413
509
|
|
|
1414
510
|
// src/tools/fetchUrl.ts
|
|
511
|
+
import { z as z5 } from "zod";
|
|
1415
512
|
var toolInfo5 = {
|
|
1416
513
|
name: "fetch_url",
|
|
1417
514
|
description: "Fetch the content located at one or more HTTP(S) URLs and return it in Markdown format. This works for standard web pages as well as raw files (e.g. README.md, source code) hosted on platforms like GitHub.",
|
|
1418
|
-
parameters:
|
|
1419
|
-
{
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
}
|
|
1424
|
-
|
|
515
|
+
parameters: z5.object({
|
|
516
|
+
url: z5.preprocess((val) => {
|
|
517
|
+
if (!val) return [];
|
|
518
|
+
const values = Array.isArray(val) ? val : [val];
|
|
519
|
+
return values.flatMap((i) => typeof i === "string" ? i.split(",") : []).filter((s) => s.length > 0);
|
|
520
|
+
}, z5.array(z5.string())).describe("One or more URLs to fetch, separated by commas if multiple.").meta({ usageValue: "url" })
|
|
521
|
+
}),
|
|
1425
522
|
examples: [
|
|
1426
523
|
{
|
|
1427
524
|
description: "Fetch a single webpage",
|
|
@@ -1460,7 +557,7 @@ var handler5 = async (provider, args) => {
|
|
|
1460
557
|
message: "Not possible to fetch url. Abort."
|
|
1461
558
|
};
|
|
1462
559
|
}
|
|
1463
|
-
const urls =
|
|
560
|
+
const { url: urls } = toolInfo5.parameters.parse(args);
|
|
1464
561
|
if (urls.length === 0) {
|
|
1465
562
|
return {
|
|
1466
563
|
type: "Error" /* Error */,
|
|
@@ -1491,31 +588,24 @@ var fetchUrl_default = {
|
|
|
1491
588
|
handler: handler5,
|
|
1492
589
|
isAvailable: isAvailable5
|
|
1493
590
|
};
|
|
1494
|
-
|
|
1495
|
-
// src/tools/listFiles.ts
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
{
|
|
1513
|
-
name: "recursive",
|
|
1514
|
-
description: "Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.",
|
|
1515
|
-
required: false,
|
|
1516
|
-
usageValue: "true or false (optional)"
|
|
1517
|
-
}
|
|
1518
|
-
],
|
|
591
|
+
|
|
592
|
+
// src/tools/listFiles.ts
|
|
593
|
+
import { z as z6 } from "zod";
|
|
594
|
+
var toolInfo6 = {
|
|
595
|
+
name: "list_files",
|
|
596
|
+
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.",
|
|
597
|
+
parameters: z6.object({
|
|
598
|
+
path: z6.string().describe("The path of the directory to list contents for (relative to the current working directory)").meta({ usageValue: "Directory path here" }),
|
|
599
|
+
maxCount: z6.coerce.number().optional().default(2e3).describe("The maximum number of files to list. Default to 2000").meta({ usageValue: "Maximum number of files to list (optional)" }),
|
|
600
|
+
recursive: z6.preprocess((val) => {
|
|
601
|
+
if (typeof val === "string") {
|
|
602
|
+
const lower = val.toLowerCase();
|
|
603
|
+
if (lower === "false") return false;
|
|
604
|
+
if (lower === "true") return true;
|
|
605
|
+
}
|
|
606
|
+
return val;
|
|
607
|
+
}, z6.boolean().optional().default(true)).describe("Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.").meta({ usageValue: "true or false (optional)" })
|
|
608
|
+
}),
|
|
1519
609
|
examples: [
|
|
1520
610
|
{
|
|
1521
611
|
description: "Request to list files",
|
|
@@ -1525,7 +615,7 @@ var toolInfo6 = {
|
|
|
1525
615
|
value: "src"
|
|
1526
616
|
},
|
|
1527
617
|
{
|
|
1528
|
-
name: "
|
|
618
|
+
name: "maxCount",
|
|
1529
619
|
value: "100"
|
|
1530
620
|
}
|
|
1531
621
|
]
|
|
@@ -1540,9 +630,7 @@ var handler6 = async (provider, args) => {
|
|
|
1540
630
|
message: "Not possible to list files. Abort."
|
|
1541
631
|
};
|
|
1542
632
|
}
|
|
1543
|
-
const path =
|
|
1544
|
-
const maxCount = getInt(args, "max_count", 2e3);
|
|
1545
|
-
const recursive = getBoolean(args, "recursive", true);
|
|
633
|
+
const { path, maxCount, recursive } = toolInfo6.parameters.parse(args);
|
|
1546
634
|
const [files, limitReached] = await provider.listFiles(path, recursive, maxCount);
|
|
1547
635
|
return {
|
|
1548
636
|
type: "Reply" /* Reply */,
|
|
@@ -1563,17 +651,17 @@ var listFiles_default = {
|
|
|
1563
651
|
};
|
|
1564
652
|
|
|
1565
653
|
// src/tools/readFile.ts
|
|
654
|
+
import { z as z7 } from "zod";
|
|
1566
655
|
var toolInfo7 = {
|
|
1567
656
|
name: "read_file",
|
|
1568
657
|
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.",
|
|
1569
|
-
parameters:
|
|
1570
|
-
{
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
],
|
|
658
|
+
parameters: z7.object({
|
|
659
|
+
path: z7.preprocess((val) => {
|
|
660
|
+
if (!val) return [];
|
|
661
|
+
const values = Array.isArray(val) ? val : [val];
|
|
662
|
+
return values.flatMap((i) => typeof i === "string" ? i.split(",") : []).filter((s) => s.length > 0);
|
|
663
|
+
}, z7.array(z7.string())).describe("The path of the file to read").meta({ usageValue: "Comma separated paths here" })
|
|
664
|
+
}),
|
|
1577
665
|
examples: [
|
|
1578
666
|
{
|
|
1579
667
|
description: "Request to read the contents of a file",
|
|
@@ -1603,7 +691,7 @@ var handler7 = async (provider, args) => {
|
|
|
1603
691
|
message: "Not possible to read file. Abort."
|
|
1604
692
|
};
|
|
1605
693
|
}
|
|
1606
|
-
const paths =
|
|
694
|
+
const { path: paths } = toolInfo7.parameters.parse(args);
|
|
1607
695
|
const resp = [];
|
|
1608
696
|
for (const path of paths) {
|
|
1609
697
|
const fileContent = await provider.readFile(path);
|
|
@@ -1632,20 +720,91 @@ var readFile_default = {
|
|
|
1632
720
|
isAvailable: isAvailable7
|
|
1633
721
|
};
|
|
1634
722
|
|
|
723
|
+
// src/tools/replaceInFile.ts
|
|
724
|
+
import { z as z8 } from "zod";
|
|
725
|
+
|
|
726
|
+
// src/tools/utils/replaceInFile.ts
|
|
727
|
+
var replaceInFile = (fileContent, diff) => {
|
|
728
|
+
const blockPattern = /<<<<<+ SEARCH>?\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
|
|
729
|
+
const blocks = [];
|
|
730
|
+
for (let match = blockPattern.exec(diff); match !== null; match = blockPattern.exec(diff)) {
|
|
731
|
+
blocks.push({ search: match[1], replace: match[2] });
|
|
732
|
+
}
|
|
733
|
+
if (blocks.length === 0) {
|
|
734
|
+
throw new Error("No valid diff blocks found.");
|
|
735
|
+
}
|
|
736
|
+
const findAndReplace = (content, search, replace) => {
|
|
737
|
+
let index = content.indexOf(search);
|
|
738
|
+
if (index !== -1) {
|
|
739
|
+
return content.slice(0, index) + replace + content.slice(index + search.length);
|
|
740
|
+
}
|
|
741
|
+
const trimmedSearch = search.trim();
|
|
742
|
+
const trimmedContent = content.trim();
|
|
743
|
+
const offset = content.indexOf(trimmedContent);
|
|
744
|
+
index = trimmedContent.indexOf(trimmedSearch);
|
|
745
|
+
if (index !== -1) {
|
|
746
|
+
const absoluteIndex = offset + index;
|
|
747
|
+
return content.slice(0, absoluteIndex) + replace + content.slice(absoluteIndex + trimmedSearch.length);
|
|
748
|
+
}
|
|
749
|
+
const normalizedSearch = trimmedSearch.replace(/\s+/g, " ");
|
|
750
|
+
const normalizedContent = trimmedContent.replace(/\s+/g, " ");
|
|
751
|
+
index = normalizedContent.indexOf(normalizedSearch);
|
|
752
|
+
if (index !== -1) {
|
|
753
|
+
let runningIndex = 0;
|
|
754
|
+
let actualPos = offset;
|
|
755
|
+
for (const segment of trimmedSearch.replace(/\s+/g, " ").split(" ")) {
|
|
756
|
+
const segIndex = content.indexOf(segment, actualPos);
|
|
757
|
+
if (segIndex === -1) {
|
|
758
|
+
break;
|
|
759
|
+
}
|
|
760
|
+
if (runningIndex === 0) {
|
|
761
|
+
actualPos = segIndex;
|
|
762
|
+
} else {
|
|
763
|
+
actualPos = segIndex + segment.length;
|
|
764
|
+
}
|
|
765
|
+
runningIndex++;
|
|
766
|
+
}
|
|
767
|
+
const strippedSearch = trimmedSearch.replace(/\s+/g, "");
|
|
768
|
+
const endPos = actualPos;
|
|
769
|
+
const startPos = endPos - strippedSearch.length;
|
|
770
|
+
return content.slice(0, startPos) + replace + content.slice(endPos);
|
|
771
|
+
}
|
|
772
|
+
return null;
|
|
773
|
+
};
|
|
774
|
+
let updatedFile = fileContent;
|
|
775
|
+
let appliedCount = 0;
|
|
776
|
+
const totalCount = blocks.length;
|
|
777
|
+
for (const { search, replace } of blocks) {
|
|
778
|
+
const result = findAndReplace(updatedFile, search, replace);
|
|
779
|
+
if (result !== null) {
|
|
780
|
+
updatedFile = result;
|
|
781
|
+
appliedCount++;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
let status;
|
|
785
|
+
if (appliedCount === 0) {
|
|
786
|
+
status = "no_diff_applied";
|
|
787
|
+
} else if (appliedCount < totalCount) {
|
|
788
|
+
status = "some_diff_applied";
|
|
789
|
+
} else {
|
|
790
|
+
status = "all_diff_applied";
|
|
791
|
+
}
|
|
792
|
+
return {
|
|
793
|
+
content: updatedFile,
|
|
794
|
+
status,
|
|
795
|
+
appliedCount,
|
|
796
|
+
totalCount
|
|
797
|
+
};
|
|
798
|
+
};
|
|
799
|
+
|
|
1635
800
|
// src/tools/replaceInFile.ts
|
|
1636
801
|
var toolInfo8 = {
|
|
1637
802
|
name: "replace_in_file",
|
|
1638
803
|
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.",
|
|
1639
|
-
parameters:
|
|
1640
|
-
{
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
required: true,
|
|
1644
|
-
usageValue: "File path here"
|
|
1645
|
-
},
|
|
1646
|
-
{
|
|
1647
|
-
name: "diff",
|
|
1648
|
-
description: `One or more SEARCH/REPLACE blocks following this exact format:
|
|
804
|
+
parameters: z8.object({
|
|
805
|
+
path: z8.string().describe("The path of the file to modify").meta({ usageValue: "File path here" }),
|
|
806
|
+
diff: z8.string().describe(
|
|
807
|
+
`One or more SEARCH/REPLACE blocks following this exact format:
|
|
1649
808
|
\`\`\`
|
|
1650
809
|
<<<<<<< SEARCH
|
|
1651
810
|
[exact content to find]
|
|
@@ -1668,11 +827,9 @@ Critical rules:
|
|
|
1668
827
|
* Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.
|
|
1669
828
|
4. Special operations:
|
|
1670
829
|
* To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
|
|
1671
|
-
* To delete code: Use empty REPLACE section
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
}
|
|
1675
|
-
],
|
|
830
|
+
* To delete code: Use empty REPLACE section`
|
|
831
|
+
).meta({ usageValue: "Search and replace blocks here" })
|
|
832
|
+
}),
|
|
1676
833
|
examples: [
|
|
1677
834
|
{
|
|
1678
835
|
description: "Request to replace sections of content in a file",
|
|
@@ -1683,8 +840,7 @@ Critical rules:
|
|
|
1683
840
|
},
|
|
1684
841
|
{
|
|
1685
842
|
name: "diff",
|
|
1686
|
-
value:
|
|
1687
|
-
<<<<<<< SEARCH
|
|
843
|
+
value: `<<<<<<< SEARCH
|
|
1688
844
|
import React from 'react';
|
|
1689
845
|
=======
|
|
1690
846
|
import React, { useState } from 'react';
|
|
@@ -1710,8 +866,7 @@ function handleSubmit() {
|
|
|
1710
866
|
|
|
1711
867
|
return (
|
|
1712
868
|
<div>
|
|
1713
|
-
>>>>>>> REPLACE
|
|
1714
|
-
`
|
|
869
|
+
>>>>>>> REPLACE`
|
|
1715
870
|
}
|
|
1716
871
|
]
|
|
1717
872
|
},
|
|
@@ -1724,13 +879,11 @@ return (
|
|
|
1724
879
|
},
|
|
1725
880
|
{
|
|
1726
881
|
name: "diff",
|
|
1727
|
-
value:
|
|
1728
|
-
<<<<<<< SEARCH
|
|
882
|
+
value: `<<<<<<< SEARCH
|
|
1729
883
|
const API_URL = 'https://api.example.com';
|
|
1730
884
|
=======
|
|
1731
885
|
const API_URL = 'https://api.staging.example.com';
|
|
1732
|
-
>>>>>>> REPLACE
|
|
1733
|
-
`
|
|
886
|
+
>>>>>>> REPLACE`
|
|
1734
887
|
}
|
|
1735
888
|
]
|
|
1736
889
|
},
|
|
@@ -1743,8 +896,7 @@ const API_URL = 'https://api.staging.example.com';
|
|
|
1743
896
|
},
|
|
1744
897
|
{
|
|
1745
898
|
name: "diff",
|
|
1746
|
-
value:
|
|
1747
|
-
<<<<<<< SEARCH
|
|
899
|
+
value: `<<<<<<< SEARCH
|
|
1748
900
|
function helperA() {
|
|
1749
901
|
// ...
|
|
1750
902
|
}
|
|
@@ -1756,8 +908,7 @@ function helperA() {
|
|
|
1756
908
|
function newHelper() {
|
|
1757
909
|
// implementation
|
|
1758
910
|
}
|
|
1759
|
-
>>>>>>> REPLACE
|
|
1760
|
-
`
|
|
911
|
+
>>>>>>> REPLACE`
|
|
1761
912
|
}
|
|
1762
913
|
]
|
|
1763
914
|
},
|
|
@@ -1770,15 +921,13 @@ function newHelper() {
|
|
|
1770
921
|
},
|
|
1771
922
|
{
|
|
1772
923
|
name: "diff",
|
|
1773
|
-
value:
|
|
1774
|
-
<<<<<<< SEARCH
|
|
924
|
+
value: `<<<<<<< SEARCH
|
|
1775
925
|
function oldFeature() {
|
|
1776
926
|
// This is no longer needed
|
|
1777
927
|
}
|
|
1778
928
|
|
|
1779
929
|
=======
|
|
1780
|
-
>>>>>>> REPLACE
|
|
1781
|
-
`
|
|
930
|
+
>>>>>>> REPLACE`
|
|
1782
931
|
}
|
|
1783
932
|
]
|
|
1784
933
|
}
|
|
@@ -1792,37 +941,43 @@ var handler8 = async (provider, args) => {
|
|
|
1792
941
|
message: "Not possible to replace in file. Abort."
|
|
1793
942
|
};
|
|
1794
943
|
}
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
944
|
+
try {
|
|
945
|
+
const { path, diff } = toolInfo8.parameters.parse(args);
|
|
946
|
+
const fileContent = await provider.readFile(path);
|
|
947
|
+
if (fileContent == null) {
|
|
948
|
+
return {
|
|
949
|
+
type: "Error" /* Error */,
|
|
950
|
+
message: `<replace_in_file_result path="${path}" status="failed" message="File not found" />`
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
const result = replaceInFile(fileContent, diff);
|
|
954
|
+
if (result.status === "no_diff_applied") {
|
|
955
|
+
return {
|
|
956
|
+
type: "Error" /* Error */,
|
|
957
|
+
message: `<replace_in_file_result path="${path}" status="failed" message="Unable to apply changes">
|
|
1809
958
|
<file_content path="${path}">${fileContent}</file_content>
|
|
1810
959
|
</replace_in_file_result>`
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
await provider.writeFile(path, result.content);
|
|
963
|
+
if (result.status === "some_diff_applied") {
|
|
964
|
+
return {
|
|
965
|
+
type: "Reply" /* Reply */,
|
|
966
|
+
message: `<replace_in_file_result path="${path}" status="some_diff_applied" applied_count="${result.appliedCount}" total_count="${result.totalCount}">
|
|
1818
967
|
<file_content path="${path}">${result.content}</file_content>
|
|
1819
968
|
</replace_in_file_result>`
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
return {
|
|
972
|
+
type: "Reply" /* Reply */,
|
|
973
|
+
message: `<replace_in_file_result path="${path}" status="all_diff_applied" />`
|
|
974
|
+
};
|
|
975
|
+
} catch (error) {
|
|
976
|
+
return {
|
|
977
|
+
type: "Invalid" /* Invalid */,
|
|
978
|
+
message: `Invalid arguments for replace_in_file: ${error}`
|
|
1820
979
|
};
|
|
1821
980
|
}
|
|
1822
|
-
return {
|
|
1823
|
-
type: "Reply" /* Reply */,
|
|
1824
|
-
message: `<replace_in_file_result path="${path}" status="all_diff_applied" />`
|
|
1825
|
-
};
|
|
1826
981
|
};
|
|
1827
982
|
var isAvailable8 = (provider) => {
|
|
1828
983
|
return !!provider.readFile && !!provider.writeFile;
|
|
@@ -1834,29 +989,23 @@ var replaceInFile_default = {
|
|
|
1834
989
|
};
|
|
1835
990
|
|
|
1836
991
|
// src/tools/searchFiles.ts
|
|
992
|
+
import { z as z9 } from "zod";
|
|
1837
993
|
var toolInfo9 = {
|
|
1838
994
|
name: "search_files",
|
|
1839
995
|
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.",
|
|
1840
|
-
parameters:
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
usageValue: "Directory path here"
|
|
1846
|
-
},
|
|
1847
|
-
{
|
|
1848
|
-
name: "regex",
|
|
1849
|
-
description: "The regular expression pattern to search for. Uses Rust regex syntax.",
|
|
1850
|
-
required: true,
|
|
996
|
+
parameters: z9.object({
|
|
997
|
+
path: z9.string().describe(
|
|
998
|
+
"The path of the directory to search in (relative to the current working directory). This directory will be recursively searched."
|
|
999
|
+
).meta({ usageValue: "Directory path here" }),
|
|
1000
|
+
regex: z9.string().describe("The regular expression pattern to search for. Uses Rust regex syntax.").meta({
|
|
1851
1001
|
usageValue: "Your regex pattern here"
|
|
1852
|
-
},
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
required: false,
|
|
1002
|
+
}),
|
|
1003
|
+
filePattern: z9.string().optional().describe(
|
|
1004
|
+
'Comma-separated glob pattern to filter files (e.g., "*.ts" for TypeScript files or "*.ts,*.js" for both TypeScript and JavaScript files). If not provided, it will search all files (*).'
|
|
1005
|
+
).meta({
|
|
1857
1006
|
usageValue: "file pattern here (optional)"
|
|
1858
|
-
}
|
|
1859
|
-
|
|
1007
|
+
})
|
|
1008
|
+
}),
|
|
1860
1009
|
examples: [
|
|
1861
1010
|
{
|
|
1862
1011
|
description: "Request to perform a regex search across files",
|
|
@@ -1868,374 +1017,63 @@ var toolInfo9 = {
|
|
|
1868
1017
|
{
|
|
1869
1018
|
name: "regex",
|
|
1870
1019
|
value: "^components/"
|
|
1871
|
-
},
|
|
1872
|
-
{
|
|
1873
|
-
name: "
|
|
1874
|
-
value: "*.ts,*.tsx"
|
|
1875
|
-
}
|
|
1876
|
-
]
|
|
1877
|
-
}
|
|
1878
|
-
],
|
|
1879
|
-
permissionLevel: 1 /* Read */
|
|
1880
|
-
};
|
|
1881
|
-
var handler9 = async (provider, args) => {
|
|
1882
|
-
if (!provider.searchFiles) {
|
|
1883
|
-
return {
|
|
1884
|
-
type: "Error" /* Error */,
|
|
1885
|
-
message: "Not possible to search files. Abort."
|
|
1886
|
-
};
|
|
1887
|
-
}
|
|
1888
|
-
const path = getString(args, "path");
|
|
1889
|
-
const regex = getString(args, "regex");
|
|
1890
|
-
const filePattern = getString(args, "file_pattern", "*");
|
|
1891
|
-
const files = await provider.searchFiles(path, regex, filePattern);
|
|
1892
|
-
return {
|
|
1893
|
-
type: "Reply" /* Reply */,
|
|
1894
|
-
message: `<search_files_path>${path}</search_files_path>
|
|
1895
|
-
<search_files_regex>${regex}</search_files_regex>
|
|
1896
|
-
<search_files_file_pattern>${filePattern}</search_files_file_pattern>
|
|
1897
|
-
<search_files_files>
|
|
1898
|
-
${files.join("\n")}
|
|
1899
|
-
</search_files_files>
|
|
1900
|
-
`
|
|
1901
|
-
};
|
|
1902
|
-
};
|
|
1903
|
-
var isAvailable9 = (provider) => {
|
|
1904
|
-
return !!provider.searchFiles;
|
|
1905
|
-
};
|
|
1906
|
-
var searchFiles_default = {
|
|
1907
|
-
...toolInfo9,
|
|
1908
|
-
handler: handler9,
|
|
1909
|
-
isAvailable: isAvailable9
|
|
1910
|
-
};
|
|
1911
|
-
|
|
1912
|
-
// src/tools/updateKnowledge.ts
|
|
1913
|
-
import YAML from "yaml";
|
|
1914
|
-
|
|
1915
|
-
// src/path.ts
|
|
1916
|
-
function dirname(path) {
|
|
1917
|
-
if (path.length === 0) return ".";
|
|
1918
|
-
const isRooted = path[0] === "/";
|
|
1919
|
-
let end = path.length - 1;
|
|
1920
|
-
while (end > 0 && path[end] === "/") end--;
|
|
1921
|
-
const idx = path.lastIndexOf("/", end);
|
|
1922
|
-
if (idx < 0) {
|
|
1923
|
-
return isRooted ? "/" : ".";
|
|
1924
|
-
}
|
|
1925
|
-
if (isRooted && idx === 0) {
|
|
1926
|
-
return "/";
|
|
1927
|
-
}
|
|
1928
|
-
return path.slice(0, idx);
|
|
1929
|
-
}
|
|
1930
|
-
function normalize(path) {
|
|
1931
|
-
const isAbsolute = path.startsWith("/");
|
|
1932
|
-
const segments = path.split("/").filter(Boolean);
|
|
1933
|
-
const stack = [];
|
|
1934
|
-
for (const seg of segments) {
|
|
1935
|
-
if (seg === ".") continue;
|
|
1936
|
-
if (seg === "..") {
|
|
1937
|
-
if (stack.length && stack[stack.length - 1] !== "..") {
|
|
1938
|
-
stack.pop();
|
|
1939
|
-
} else if (!isAbsolute) {
|
|
1940
|
-
stack.push("..");
|
|
1941
|
-
}
|
|
1942
|
-
} else {
|
|
1943
|
-
stack.push(seg);
|
|
1944
|
-
}
|
|
1945
|
-
}
|
|
1946
|
-
let result = stack.join("/");
|
|
1947
|
-
if (!result && !isAbsolute) return ".";
|
|
1948
|
-
if (result && path.endsWith("/")) result += "/";
|
|
1949
|
-
return (isAbsolute ? "/" : "") + result;
|
|
1950
|
-
}
|
|
1951
|
-
function join(...parts) {
|
|
1952
|
-
if (parts.length === 0) return ".";
|
|
1953
|
-
let combined = "";
|
|
1954
|
-
for (const p of parts) {
|
|
1955
|
-
if (typeof p !== "string") {
|
|
1956
|
-
throw new TypeError("Arguments to join must be strings");
|
|
1957
|
-
}
|
|
1958
|
-
if (p) {
|
|
1959
|
-
combined = combined ? `${combined}/${p}` : p;
|
|
1960
|
-
}
|
|
1961
|
-
}
|
|
1962
|
-
return normalize(combined);
|
|
1963
|
-
}
|
|
1964
|
-
|
|
1965
|
-
// src/tools/updateKnowledge.ts
|
|
1966
|
-
var toolInfo10 = {
|
|
1967
|
-
name: "update_knowledge",
|
|
1968
|
-
description: "Update knowledge in a knowledge.ai.yml file with smart merging capabilities. This tool lets you add, update, or remove information using path-based updates and special directives.",
|
|
1969
|
-
parameters: [
|
|
1970
|
-
{
|
|
1971
|
-
name: "path",
|
|
1972
|
-
description: "Directory containing (or where to create) the knowledge.ai.yml file",
|
|
1973
|
-
required: true,
|
|
1974
|
-
usageValue: "Directory path here"
|
|
1975
|
-
},
|
|
1976
|
-
{
|
|
1977
|
-
name: "knowledge",
|
|
1978
|
-
description: "YAML content to merge into the knowledge file",
|
|
1979
|
-
required: true,
|
|
1980
|
-
usageValue: "YAML content with knowledge to update"
|
|
1981
|
-
}
|
|
1982
|
-
],
|
|
1983
|
-
examples: [
|
|
1984
|
-
{
|
|
1985
|
-
description: "Add a new file entry",
|
|
1986
|
-
parameters: [
|
|
1987
|
-
{ name: "path", value: "src/utils" },
|
|
1988
|
-
{
|
|
1989
|
-
name: "knowledge",
|
|
1990
|
-
value: `files:
|
|
1991
|
-
"newFile.ts":
|
|
1992
|
-
description: "A new utility file"
|
|
1993
|
-
api:
|
|
1994
|
-
functions:
|
|
1995
|
-
1:
|
|
1996
|
-
name: "processData"
|
|
1997
|
-
params:
|
|
1998
|
-
1: { name: "data", type: "object" }
|
|
1999
|
-
returns: "object"`
|
|
2000
|
-
}
|
|
2001
|
-
]
|
|
2002
|
-
},
|
|
2003
|
-
{
|
|
2004
|
-
description: "Update an existing file description",
|
|
2005
|
-
parameters: [
|
|
2006
|
-
{ name: "path", value: "src/utils" },
|
|
2007
|
-
{
|
|
2008
|
-
name: "knowledge",
|
|
2009
|
-
value: `files:
|
|
2010
|
-
"existingFile.ts":
|
|
2011
|
-
description: "Updated description for the file"`
|
|
2012
|
-
}
|
|
2013
|
-
]
|
|
2014
|
-
},
|
|
2015
|
-
{
|
|
2016
|
-
description: "Add a new rule",
|
|
2017
|
-
parameters: [
|
|
2018
|
-
{ name: "path", value: "src" },
|
|
2019
|
-
{
|
|
2020
|
-
name: "knowledge",
|
|
2021
|
-
value: `rules:
|
|
2022
|
-
10: "New rule to follow"`
|
|
2023
|
-
}
|
|
2024
|
-
]
|
|
2025
|
-
},
|
|
2026
|
-
{
|
|
2027
|
-
description: "Remove a rule",
|
|
2028
|
-
parameters: [
|
|
2029
|
-
{ name: "path", value: "src" },
|
|
2030
|
-
{
|
|
2031
|
-
name: "knowledge",
|
|
2032
|
-
value: `rules:
|
|
2033
|
-
5: null`
|
|
2034
|
-
}
|
|
2035
|
-
]
|
|
2036
|
-
},
|
|
2037
|
-
{
|
|
2038
|
-
description: "Update nested properties using dot notation",
|
|
2039
|
-
parameters: [
|
|
2040
|
-
{ name: "path", value: "src/components" },
|
|
2041
|
-
{
|
|
2042
|
-
name: "knowledge",
|
|
2043
|
-
value: `files.Button.tsx.api.functions.1.description: "Updated function description"`
|
|
2044
|
-
}
|
|
2045
|
-
]
|
|
2046
|
-
}
|
|
2047
|
-
],
|
|
2048
|
-
permissionLevel: 2 /* Write */
|
|
2049
|
-
};
|
|
2050
|
-
function getNextKey(obj) {
|
|
2051
|
-
if (!obj || typeof obj !== "object") return 1;
|
|
2052
|
-
const numericKeys = Object.keys(obj).filter((key) => !Number.isNaN(Number(key))).map((key) => Number(key));
|
|
2053
|
-
if (numericKeys.length === 0) return 1;
|
|
2054
|
-
return Math.max(...numericKeys) + 1;
|
|
2055
|
-
}
|
|
2056
|
-
function arrayToNumberedDict(arr) {
|
|
2057
|
-
const result = {};
|
|
2058
|
-
arr.forEach((item, index) => {
|
|
2059
|
-
result[(index + 1).toString()] = item;
|
|
2060
|
-
});
|
|
2061
|
-
return result;
|
|
2062
|
-
}
|
|
2063
|
-
function deepMerge(target, source) {
|
|
2064
|
-
if (source && typeof source === "object") {
|
|
2065
|
-
if (Array.isArray(target)) {
|
|
2066
|
-
target = arrayToNumberedDict(target);
|
|
2067
|
-
}
|
|
2068
|
-
if (Array.isArray(source)) {
|
|
2069
|
-
source = arrayToNumberedDict(source);
|
|
2070
|
-
}
|
|
2071
|
-
if (typeof target === "object" && !Array.isArray(target) && "$merge" in source) {
|
|
2072
|
-
const result = { ...target };
|
|
2073
|
-
const itemsToMerge = Array.isArray(source.$merge) ? source.$merge : [source.$merge];
|
|
2074
|
-
for (const item of itemsToMerge) {
|
|
2075
|
-
if (typeof item === "object" && item !== null && "path" in item) {
|
|
2076
|
-
let found = false;
|
|
2077
|
-
for (const key in result) {
|
|
2078
|
-
if (typeof result[key] === "object" && result[key] !== null && "path" in result[key] && result[key].path === item.path) {
|
|
2079
|
-
result[key] = deepMerge(result[key], item);
|
|
2080
|
-
found = true;
|
|
2081
|
-
break;
|
|
2082
|
-
}
|
|
2083
|
-
}
|
|
2084
|
-
if (!found) {
|
|
2085
|
-
const nextKey = getNextKey(result).toString();
|
|
2086
|
-
result[nextKey] = item;
|
|
2087
|
-
}
|
|
2088
|
-
} else {
|
|
2089
|
-
const nextKey = getNextKey(result).toString();
|
|
2090
|
-
result[nextKey] = item;
|
|
2091
|
-
}
|
|
2092
|
-
}
|
|
2093
|
-
return result;
|
|
2094
|
-
}
|
|
2095
|
-
if (typeof target === "object" && !Array.isArray(target) && "$remove" in source) {
|
|
2096
|
-
const result = { ...target };
|
|
2097
|
-
const itemsToRemove = Array.isArray(source.$remove) ? source.$remove : [source.$remove];
|
|
2098
|
-
for (const item of itemsToRemove) {
|
|
2099
|
-
if (typeof item === "string" && !Number.isNaN(Number(item))) {
|
|
2100
|
-
delete result[item];
|
|
2101
|
-
} else if (typeof item === "object" && item !== null && "path" in item) {
|
|
2102
|
-
for (const key in result) {
|
|
2103
|
-
if (typeof result[key] === "object" && result[key] !== null && "path" in result[key] && result[key].path === item.path) {
|
|
2104
|
-
delete result[key];
|
|
2105
|
-
break;
|
|
2106
|
-
}
|
|
2107
|
-
}
|
|
2108
|
-
} else {
|
|
2109
|
-
for (const key in result) {
|
|
2110
|
-
if (result[key] === item) {
|
|
2111
|
-
delete result[key];
|
|
2112
|
-
break;
|
|
2113
|
-
}
|
|
2114
|
-
}
|
|
2115
|
-
}
|
|
2116
|
-
}
|
|
2117
|
-
return result;
|
|
2118
|
-
}
|
|
2119
|
-
if (typeof target === "object" && !Array.isArray(target) && "$replace" in source) {
|
|
2120
|
-
const replacements = Array.isArray(source.$replace) ? source.$replace : [source.$replace];
|
|
2121
|
-
return arrayToNumberedDict(replacements);
|
|
2122
|
-
}
|
|
2123
|
-
}
|
|
2124
|
-
if (!source || typeof source !== "object") {
|
|
2125
|
-
return source;
|
|
2126
|
-
}
|
|
2127
|
-
if (!target || typeof target !== "object") {
|
|
2128
|
-
if (Array.isArray(source)) {
|
|
2129
|
-
return arrayToNumberedDict(source);
|
|
1020
|
+
},
|
|
1021
|
+
{
|
|
1022
|
+
name: "filePattern",
|
|
1023
|
+
value: "*.ts,*.tsx"
|
|
1024
|
+
}
|
|
1025
|
+
]
|
|
2130
1026
|
}
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
output[key] = deepMerge(target[key], source[key]);
|
|
2137
|
-
}
|
|
2138
|
-
return output;
|
|
2139
|
-
}
|
|
2140
|
-
var handler10 = async (provider, args) => {
|
|
2141
|
-
if (!provider.readFile || !provider.writeFile) {
|
|
1027
|
+
],
|
|
1028
|
+
permissionLevel: 1 /* Read */
|
|
1029
|
+
};
|
|
1030
|
+
var handler9 = async (provider, args) => {
|
|
1031
|
+
if (!provider.searchFiles) {
|
|
2142
1032
|
return {
|
|
2143
1033
|
type: "Error" /* Error */,
|
|
2144
|
-
message: "
|
|
1034
|
+
message: "Not possible to search files. Abort."
|
|
2145
1035
|
};
|
|
2146
1036
|
}
|
|
2147
|
-
const dirPath = getString(args, "path");
|
|
2148
|
-
const knowledgeContent = getString(args, "knowledge");
|
|
2149
|
-
const filePath = join(dirPath, "knowledge.ai.yml");
|
|
2150
1037
|
try {
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
newKnowledge = YAML.parse(knowledgeContent);
|
|
2154
|
-
} catch (error) {
|
|
2155
|
-
return {
|
|
2156
|
-
type: "Error" /* Error */,
|
|
2157
|
-
message: `Invalid YAML content: ${error.message}`
|
|
2158
|
-
};
|
|
2159
|
-
}
|
|
2160
|
-
const dotNotationUpdates = {};
|
|
2161
|
-
const regularUpdates = {};
|
|
2162
|
-
for (const key in newKnowledge) {
|
|
2163
|
-
if (key.includes(".")) {
|
|
2164
|
-
dotNotationUpdates[key] = newKnowledge[key];
|
|
2165
|
-
} else {
|
|
2166
|
-
regularUpdates[key] = newKnowledge[key];
|
|
2167
|
-
}
|
|
2168
|
-
}
|
|
2169
|
-
const existingContent = await provider.readFile(filePath);
|
|
2170
|
-
let existingKnowledge = {};
|
|
2171
|
-
if (existingContent) {
|
|
2172
|
-
try {
|
|
2173
|
-
existingKnowledge = YAML.parse(existingContent);
|
|
2174
|
-
} catch (error) {
|
|
2175
|
-
return {
|
|
2176
|
-
type: "Error" /* Error */,
|
|
2177
|
-
message: `Error parsing existing knowledge file: ${error.message}`
|
|
2178
|
-
};
|
|
2179
|
-
}
|
|
2180
|
-
}
|
|
2181
|
-
let updatedKnowledge = existingKnowledge;
|
|
2182
|
-
updatedKnowledge = deepMerge(updatedKnowledge, regularUpdates);
|
|
2183
|
-
if (Object.keys(dotNotationUpdates).length > 0) {
|
|
2184
|
-
const nestedUpdates = {};
|
|
2185
|
-
for (const path in dotNotationUpdates) {
|
|
2186
|
-
const parts = path.split(".");
|
|
2187
|
-
let current = nestedUpdates;
|
|
2188
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
2189
|
-
const part = parts[i];
|
|
2190
|
-
if (!(part in current)) {
|
|
2191
|
-
current[part] = {};
|
|
2192
|
-
}
|
|
2193
|
-
current = current[part];
|
|
2194
|
-
}
|
|
2195
|
-
current[parts[parts.length - 1]] = dotNotationUpdates[path];
|
|
2196
|
-
}
|
|
2197
|
-
updatedKnowledge = deepMerge(updatedKnowledge, nestedUpdates);
|
|
2198
|
-
}
|
|
2199
|
-
const updatedContent = YAML.stringify(updatedKnowledge);
|
|
2200
|
-
await provider.writeFile(filePath, updatedContent);
|
|
1038
|
+
const { path, regex, filePattern } = toolInfo9.parameters.parse(args);
|
|
1039
|
+
const files = await provider.searchFiles(path, regex, filePattern ?? "*");
|
|
2201
1040
|
return {
|
|
2202
1041
|
type: "Reply" /* Reply */,
|
|
2203
|
-
message: `<
|
|
1042
|
+
message: `<search_files_path>${path}</search_files_path>
|
|
1043
|
+
<search_files_regex>${regex}</search_files_regex>
|
|
1044
|
+
<search_files_file_pattern>${filePattern}</search_files_file_pattern>
|
|
1045
|
+
<search_files_files>
|
|
1046
|
+
${files.join("\n")}
|
|
1047
|
+
</search_files_files>
|
|
1048
|
+
`
|
|
2204
1049
|
};
|
|
2205
1050
|
} catch (error) {
|
|
2206
1051
|
return {
|
|
2207
|
-
type: "
|
|
2208
|
-
message: `
|
|
1052
|
+
type: "Invalid" /* Invalid */,
|
|
1053
|
+
message: `Invalid arguments for search_files: ${error}`
|
|
2209
1054
|
};
|
|
2210
1055
|
}
|
|
2211
1056
|
};
|
|
2212
|
-
var
|
|
2213
|
-
return !!provider.
|
|
1057
|
+
var isAvailable9 = (provider) => {
|
|
1058
|
+
return !!provider.searchFiles;
|
|
2214
1059
|
};
|
|
2215
|
-
var
|
|
2216
|
-
...
|
|
2217
|
-
handler:
|
|
2218
|
-
isAvailable:
|
|
1060
|
+
var searchFiles_default = {
|
|
1061
|
+
...toolInfo9,
|
|
1062
|
+
handler: handler9,
|
|
1063
|
+
isAvailable: isAvailable9
|
|
2219
1064
|
};
|
|
2220
1065
|
|
|
2221
1066
|
// src/tools/writeToFile.ts
|
|
2222
|
-
|
|
1067
|
+
import { z as z10 } from "zod";
|
|
1068
|
+
var toolInfo10 = {
|
|
2223
1069
|
name: "write_to_file",
|
|
2224
1070
|
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. Ensure that the output content does not include incorrect escaped character patterns such as `<`, `>`, or `&`. Also ensure there is no unwanted CDATA tags in the content.",
|
|
2225
|
-
parameters:
|
|
2226
|
-
{
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
},
|
|
2232
|
-
{
|
|
2233
|
-
name: "content",
|
|
2234
|
-
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.",
|
|
2235
|
-
required: true,
|
|
2236
|
-
usageValue: "Your file content here"
|
|
2237
|
-
}
|
|
2238
|
-
],
|
|
1071
|
+
parameters: z10.object({
|
|
1072
|
+
path: z10.string().describe("The path of the file to write to").meta({ usageValue: "File path here" }),
|
|
1073
|
+
content: z10.string().describe(
|
|
1074
|
+
"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."
|
|
1075
|
+
).meta({ usageValue: "Your file content here" })
|
|
1076
|
+
}),
|
|
2239
1077
|
examples: [
|
|
2240
1078
|
{
|
|
2241
1079
|
description: "Request to write content to a file",
|
|
@@ -2264,15 +1102,21 @@ export default App;
|
|
|
2264
1102
|
],
|
|
2265
1103
|
permissionLevel: 2 /* Write */
|
|
2266
1104
|
};
|
|
2267
|
-
var
|
|
1105
|
+
var handler10 = async (provider, args) => {
|
|
2268
1106
|
if (!provider.writeFile) {
|
|
2269
1107
|
return {
|
|
2270
1108
|
type: "Error" /* Error */,
|
|
2271
1109
|
message: "Not possible to write file. Abort."
|
|
2272
1110
|
};
|
|
2273
1111
|
}
|
|
2274
|
-
const
|
|
2275
|
-
|
|
1112
|
+
const parsed = toolInfo10.parameters.safeParse(args);
|
|
1113
|
+
if (!parsed.success) {
|
|
1114
|
+
return {
|
|
1115
|
+
type: "Invalid" /* Invalid */,
|
|
1116
|
+
message: `Invalid arguments for write_to_file: ${parsed.error.message}`
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
let { path, content } = parsed.data;
|
|
2276
1120
|
const trimmedContent = content.trim();
|
|
2277
1121
|
if (trimmedContent.startsWith("<![CDATA[") && content.endsWith("]]>")) content = trimmedContent.slice(9, -3);
|
|
2278
1122
|
await provider.writeFile(path, content);
|
|
@@ -2281,51 +1125,36 @@ var handler11 = async (provider, args) => {
|
|
|
2281
1125
|
message: `<write_to_file_path>${path}</write_to_file_path><status>Success</status>`
|
|
2282
1126
|
};
|
|
2283
1127
|
};
|
|
2284
|
-
var
|
|
1128
|
+
var isAvailable10 = (provider) => {
|
|
2285
1129
|
return !!provider.writeFile;
|
|
2286
1130
|
};
|
|
2287
1131
|
var writeToFile_default = {
|
|
2288
|
-
...
|
|
2289
|
-
handler:
|
|
2290
|
-
isAvailable:
|
|
1132
|
+
...toolInfo10,
|
|
1133
|
+
handler: handler10,
|
|
1134
|
+
isAvailable: isAvailable10
|
|
2291
1135
|
};
|
|
2292
1136
|
|
|
2293
1137
|
// src/tools/handOver.ts
|
|
2294
|
-
|
|
1138
|
+
import { z as z11 } from "zod";
|
|
1139
|
+
var toolInfo11 = {
|
|
2295
1140
|
name: "hand_over",
|
|
2296
1141
|
description: "Hand over the current task to another agent to complete. This tool MUST NOT to be used with any other tool.",
|
|
2297
|
-
parameters:
|
|
2298
|
-
{
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
required: true,
|
|
2308
|
-
usageValue: "Task description"
|
|
2309
|
-
},
|
|
2310
|
-
{
|
|
2311
|
-
name: "context",
|
|
2312
|
-
description: "The context information for the task",
|
|
2313
|
-
required: true,
|
|
2314
|
-
usageValue: "Context information"
|
|
2315
|
-
},
|
|
2316
|
-
{
|
|
2317
|
-
name: "files",
|
|
2318
|
-
description: "The files relevant to the task. Comma separated paths",
|
|
2319
|
-
required: false,
|
|
2320
|
-
usageValue: "Relevant files"
|
|
2321
|
-
}
|
|
2322
|
-
],
|
|
1142
|
+
parameters: z11.object({
|
|
1143
|
+
agentName: z11.string().describe("The name of the agent to hand over the task to").meta({ usageValue: "Name of the target agent" }),
|
|
1144
|
+
task: z11.string().describe("The task to be completed by the target agent").meta({ usageValue: "Task description" }),
|
|
1145
|
+
context: z11.string().describe("The context information for the task").meta({ usageValue: "Context information" }),
|
|
1146
|
+
files: z11.preprocess((val) => {
|
|
1147
|
+
if (!val) return [];
|
|
1148
|
+
const values = Array.isArray(val) ? val : [val];
|
|
1149
|
+
return values.flatMap((i) => typeof i === "string" ? i.split(",") : []).filter((s) => s.length > 0);
|
|
1150
|
+
}, z11.array(z11.string())).optional().describe("The files relevant to the task. Comma separated paths").meta({ usageValue: "Relevant files" })
|
|
1151
|
+
}),
|
|
2323
1152
|
examples: [
|
|
2324
1153
|
{
|
|
2325
1154
|
description: "Hand over a coding task to the coder agent",
|
|
2326
1155
|
parameters: [
|
|
2327
1156
|
{
|
|
2328
|
-
name: "
|
|
1157
|
+
name: "agentName",
|
|
2329
1158
|
value: "coder"
|
|
2330
1159
|
},
|
|
2331
1160
|
{
|
|
@@ -2345,40 +1174,40 @@ var toolInfo12 = {
|
|
|
2345
1174
|
],
|
|
2346
1175
|
permissionLevel: 0 /* None */
|
|
2347
1176
|
};
|
|
2348
|
-
var
|
|
2349
|
-
const
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
1177
|
+
var handler11 = async (_provider, args) => {
|
|
1178
|
+
const parsed = toolInfo11.parameters.safeParse(args);
|
|
1179
|
+
if (!parsed.success) {
|
|
1180
|
+
return {
|
|
1181
|
+
type: "Invalid" /* Invalid */,
|
|
1182
|
+
message: `Invalid arguments for hand_over: ${parsed.error.message}`
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
const { agentName, task, context, files } = parsed.data;
|
|
2353
1186
|
return {
|
|
2354
1187
|
type: "HandOver" /* HandOver */,
|
|
2355
1188
|
agentName,
|
|
2356
1189
|
task,
|
|
2357
1190
|
context,
|
|
2358
|
-
files
|
|
1191
|
+
files: files ?? []
|
|
2359
1192
|
};
|
|
2360
1193
|
};
|
|
2361
|
-
var
|
|
1194
|
+
var isAvailable11 = (_provider) => {
|
|
2362
1195
|
return true;
|
|
2363
1196
|
};
|
|
2364
1197
|
var handOver_default = {
|
|
2365
|
-
...
|
|
2366
|
-
handler:
|
|
2367
|
-
isAvailable:
|
|
1198
|
+
...toolInfo11,
|
|
1199
|
+
handler: handler11,
|
|
1200
|
+
isAvailable: isAvailable11
|
|
2368
1201
|
};
|
|
2369
1202
|
|
|
2370
1203
|
// src/tools/removeFile.ts
|
|
2371
|
-
|
|
1204
|
+
import { z as z12 } from "zod";
|
|
1205
|
+
var toolInfo12 = {
|
|
2372
1206
|
name: "remove_file",
|
|
2373
1207
|
description: "Request to remove a file at the specified path.",
|
|
2374
|
-
parameters:
|
|
2375
|
-
{
|
|
2376
|
-
|
|
2377
|
-
description: "The path of the file to remove",
|
|
2378
|
-
required: true,
|
|
2379
|
-
usageValue: "File path here"
|
|
2380
|
-
}
|
|
2381
|
-
],
|
|
1208
|
+
parameters: z12.object({
|
|
1209
|
+
path: z12.string().describe("The path of the file to remove").meta({ usageValue: "File path here" })
|
|
1210
|
+
}),
|
|
2382
1211
|
examples: [
|
|
2383
1212
|
{
|
|
2384
1213
|
description: "Request to remove a file",
|
|
@@ -2392,47 +1221,45 @@ var toolInfo13 = {
|
|
|
2392
1221
|
],
|
|
2393
1222
|
permissionLevel: 2 /* Write */
|
|
2394
1223
|
};
|
|
2395
|
-
var
|
|
1224
|
+
var handler12 = async (provider, args) => {
|
|
2396
1225
|
if (!provider.removeFile) {
|
|
2397
1226
|
return {
|
|
2398
1227
|
type: "Error" /* Error */,
|
|
2399
1228
|
message: "Not possible to remove file. Abort."
|
|
2400
1229
|
};
|
|
2401
1230
|
}
|
|
2402
|
-
const
|
|
1231
|
+
const parsed = toolInfo12.parameters.safeParse(args);
|
|
1232
|
+
if (!parsed.success) {
|
|
1233
|
+
return {
|
|
1234
|
+
type: "Invalid" /* Invalid */,
|
|
1235
|
+
message: `Invalid arguments for remove_file: ${parsed.error.message}`
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
const { path } = parsed.data;
|
|
2403
1239
|
await provider.removeFile(path);
|
|
2404
1240
|
return {
|
|
2405
1241
|
type: "Reply" /* Reply */,
|
|
2406
1242
|
message: `<remove_file_path>${path}</remove_file_path><status>Success</status>`
|
|
2407
1243
|
};
|
|
2408
1244
|
};
|
|
2409
|
-
var
|
|
1245
|
+
var isAvailable12 = (provider) => {
|
|
2410
1246
|
return !!provider.removeFile;
|
|
2411
1247
|
};
|
|
2412
1248
|
var removeFile_default = {
|
|
2413
|
-
...
|
|
2414
|
-
handler:
|
|
2415
|
-
isAvailable:
|
|
1249
|
+
...toolInfo12,
|
|
1250
|
+
handler: handler12,
|
|
1251
|
+
isAvailable: isAvailable12
|
|
2416
1252
|
};
|
|
2417
1253
|
|
|
2418
1254
|
// src/tools/renameFile.ts
|
|
2419
|
-
|
|
1255
|
+
import { z as z13 } from "zod";
|
|
1256
|
+
var toolInfo13 = {
|
|
2420
1257
|
name: "rename_file",
|
|
2421
1258
|
description: "Request to rename a file from source path to target path.",
|
|
2422
|
-
parameters:
|
|
2423
|
-
{
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
required: true,
|
|
2427
|
-
usageValue: "Source file path here"
|
|
2428
|
-
},
|
|
2429
|
-
{
|
|
2430
|
-
name: "target_path",
|
|
2431
|
-
description: "The new path for the file",
|
|
2432
|
-
required: true,
|
|
2433
|
-
usageValue: "Target file path here"
|
|
2434
|
-
}
|
|
2435
|
-
],
|
|
1259
|
+
parameters: z13.object({
|
|
1260
|
+
source_path: z13.string().describe("The current path of the file").meta({ usageValue: "Source file path here" }),
|
|
1261
|
+
target_path: z13.string().describe("The new path for the file").meta({ usageValue: "Target file path here" })
|
|
1262
|
+
}),
|
|
2436
1263
|
examples: [
|
|
2437
1264
|
{
|
|
2438
1265
|
description: "Request to rename a file",
|
|
@@ -2450,28 +1277,27 @@ var toolInfo14 = {
|
|
|
2450
1277
|
],
|
|
2451
1278
|
permissionLevel: 2 /* Write */
|
|
2452
1279
|
};
|
|
2453
|
-
var
|
|
1280
|
+
var handler13 = async (provider, args) => {
|
|
2454
1281
|
if (!provider.renameFile) {
|
|
2455
1282
|
return {
|
|
2456
1283
|
type: "Error" /* Error */,
|
|
2457
1284
|
message: "Not possible to rename file. Abort."
|
|
2458
1285
|
};
|
|
2459
1286
|
}
|
|
2460
|
-
const
|
|
2461
|
-
|
|
2462
|
-
await provider.renameFile(sourcePath, targetPath);
|
|
1287
|
+
const { source_path, target_path } = toolInfo13.parameters.parse(args);
|
|
1288
|
+
await provider.renameFile(source_path, target_path);
|
|
2463
1289
|
return {
|
|
2464
1290
|
type: "Reply" /* Reply */,
|
|
2465
|
-
message: `<rename_file_path>${
|
|
1291
|
+
message: `<rename_file_path>${target_path}</rename_file_path><status>Success</status>`
|
|
2466
1292
|
};
|
|
2467
1293
|
};
|
|
2468
|
-
var
|
|
1294
|
+
var isAvailable13 = (provider) => {
|
|
2469
1295
|
return !!provider.renameFile;
|
|
2470
1296
|
};
|
|
2471
1297
|
var renameFile_default = {
|
|
2472
|
-
...
|
|
2473
|
-
handler:
|
|
2474
|
-
isAvailable:
|
|
1298
|
+
...toolInfo13,
|
|
1299
|
+
handler: handler13,
|
|
1300
|
+
isAvailable: isAvailable13
|
|
2475
1301
|
};
|
|
2476
1302
|
|
|
2477
1303
|
// src/getAvailableTools.ts
|
|
@@ -2499,6 +1325,49 @@ var getAvailableTools = ({
|
|
|
2499
1325
|
return tools;
|
|
2500
1326
|
};
|
|
2501
1327
|
|
|
1328
|
+
// src/tool-v1-compat.ts
|
|
1329
|
+
import { z as z14 } from "zod";
|
|
1330
|
+
function zodSchemaToParameters(schema) {
|
|
1331
|
+
const parameters = [];
|
|
1332
|
+
const { shape } = schema;
|
|
1333
|
+
for (const name in shape) {
|
|
1334
|
+
const def = shape[name];
|
|
1335
|
+
const isOptional = def.safeParse(void 0).success;
|
|
1336
|
+
const description = def.description || "";
|
|
1337
|
+
const param = {
|
|
1338
|
+
name,
|
|
1339
|
+
description,
|
|
1340
|
+
required: !isOptional
|
|
1341
|
+
};
|
|
1342
|
+
const usageValue = def.meta()?.usageValue;
|
|
1343
|
+
if (usageValue) {
|
|
1344
|
+
param.usageValue = usageValue;
|
|
1345
|
+
}
|
|
1346
|
+
if (def instanceof z14.ZodObject) {
|
|
1347
|
+
param.children = zodSchemaToParameters(def);
|
|
1348
|
+
} else if (def instanceof z14.ZodArray) {
|
|
1349
|
+
param.allowMultiple = true;
|
|
1350
|
+
const element = def.element;
|
|
1351
|
+
if (element instanceof z14.ZodObject) {
|
|
1352
|
+
param.children = zodSchemaToParameters(element);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
parameters.push(param);
|
|
1356
|
+
}
|
|
1357
|
+
return parameters;
|
|
1358
|
+
}
|
|
1359
|
+
function toToolInfoV1(tool) {
|
|
1360
|
+
const { parameters: zodSchema, ...rest } = tool;
|
|
1361
|
+
const v1Parameters = zodSchemaToParameters(zodSchema);
|
|
1362
|
+
return {
|
|
1363
|
+
...rest,
|
|
1364
|
+
parameters: v1Parameters
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
// src/Agent/AgentBase.ts
|
|
1369
|
+
import { streamText } from "ai";
|
|
1370
|
+
|
|
2502
1371
|
// src/Agent/parseAssistantMessage.ts
|
|
2503
1372
|
function parseNestedParameters(content, parameterPrefix, childrenParams) {
|
|
2504
1373
|
const result = {};
|
|
@@ -2885,9 +1754,10 @@ var AgentBase = class {
|
|
|
2885
1754
|
ai;
|
|
2886
1755
|
config;
|
|
2887
1756
|
handlers;
|
|
2888
|
-
#messages = [];
|
|
2889
1757
|
#policies;
|
|
1758
|
+
#messages = [];
|
|
2890
1759
|
#aborted = false;
|
|
1760
|
+
#abortController;
|
|
2891
1761
|
constructor(name, ai, config) {
|
|
2892
1762
|
this.ai = ai;
|
|
2893
1763
|
if (config.agents && config.agents.length > 0) {
|
|
@@ -2901,7 +1771,7 @@ ${agents}`;
|
|
|
2901
1771
|
}
|
|
2902
1772
|
const policies = [];
|
|
2903
1773
|
for (const policy of config.policies) {
|
|
2904
|
-
const instance = policy(handlers);
|
|
1774
|
+
const instance = policy(handlers, config.parameters);
|
|
2905
1775
|
if (instance) {
|
|
2906
1776
|
policies.push(instance);
|
|
2907
1777
|
if (instance.prompt) {
|
|
@@ -2918,13 +1788,19 @@ ${instance.prompt}`;
|
|
|
2918
1788
|
this.handlers = handlers;
|
|
2919
1789
|
this.config = config;
|
|
2920
1790
|
this.#policies = policies;
|
|
1791
|
+
this.#messages.push({
|
|
1792
|
+
role: "system",
|
|
1793
|
+
content: this.config.systemPrompt
|
|
1794
|
+
});
|
|
2921
1795
|
}
|
|
2922
1796
|
abort() {
|
|
2923
1797
|
this.#aborted = true;
|
|
2924
|
-
this
|
|
1798
|
+
if (this.#abortController) {
|
|
1799
|
+
this.#abortController.abort();
|
|
1800
|
+
}
|
|
2925
1801
|
}
|
|
2926
1802
|
get parameters() {
|
|
2927
|
-
return this.
|
|
1803
|
+
return this.config.parameters;
|
|
2928
1804
|
}
|
|
2929
1805
|
get messages() {
|
|
2930
1806
|
return this.#messages;
|
|
@@ -2935,15 +1811,15 @@ ${instance.prompt}`;
|
|
|
2935
1811
|
async #callback(event) {
|
|
2936
1812
|
await this.config.callback?.(event);
|
|
2937
1813
|
}
|
|
2938
|
-
async start(
|
|
1814
|
+
async start(prompt5) {
|
|
2939
1815
|
this.#callback({ kind: "StartTask" /* StartTask */, agent: this, systemPrompt: this.config.systemPrompt });
|
|
2940
|
-
return await this.#processLoop(
|
|
1816
|
+
return await this.#processLoop(prompt5);
|
|
2941
1817
|
}
|
|
2942
|
-
async step(
|
|
1818
|
+
async step(prompt5) {
|
|
2943
1819
|
if (this.#messages.length === 0) {
|
|
2944
1820
|
this.#callback({ kind: "StartTask" /* StartTask */, agent: this, systemPrompt: this.config.systemPrompt });
|
|
2945
1821
|
}
|
|
2946
|
-
return await this.#request(
|
|
1822
|
+
return await this.#request(prompt5);
|
|
2947
1823
|
}
|
|
2948
1824
|
async handleStepResponse(response) {
|
|
2949
1825
|
return this.#handleResponse(response);
|
|
@@ -2954,7 +1830,7 @@ ${instance.prompt}`;
|
|
|
2954
1830
|
if (this.#aborted) {
|
|
2955
1831
|
return { type: "Aborted" };
|
|
2956
1832
|
}
|
|
2957
|
-
if (this.
|
|
1833
|
+
if (this.config.usageMeter.isLimitExceeded().result) {
|
|
2958
1834
|
this.#callback({ kind: "UsageExceeded" /* UsageExceeded */, agent: this });
|
|
2959
1835
|
return { type: "UsageExceeded" };
|
|
2960
1836
|
}
|
|
@@ -2987,6 +1863,12 @@ ${instance.prompt}`;
|
|
|
2987
1863
|
await instance.onBeforeRequest(this);
|
|
2988
1864
|
}
|
|
2989
1865
|
}
|
|
1866
|
+
let messages = this.#messages;
|
|
1867
|
+
for (const instance of this.#policies) {
|
|
1868
|
+
if (instance.prepareMessages) {
|
|
1869
|
+
messages = await instance.prepareMessages(this, messages);
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
2990
1872
|
let currentAssistantMessage = "";
|
|
2991
1873
|
const retryCount = this.config.retryCount ?? 5;
|
|
2992
1874
|
const requestTimeoutSeconds = this.config.requestTimeoutSeconds ?? 10;
|
|
@@ -3000,28 +1882,54 @@ ${instance.prompt}`;
|
|
|
3000
1882
|
if (requestTimeoutSeconds > 0) {
|
|
3001
1883
|
timeout = setTimeout(() => {
|
|
3002
1884
|
console.debug(`No data received for ${requestTimeoutSeconds} seconds. Aborting request.`);
|
|
3003
|
-
this.
|
|
1885
|
+
this.abort();
|
|
3004
1886
|
}, requestTimeoutSeconds * 1e3);
|
|
3005
1887
|
}
|
|
3006
1888
|
};
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
await this.#callback({ kind: "Text" /* Text */, agent: this, newText: chunk.text });
|
|
3019
|
-
break;
|
|
3020
|
-
case "reasoning":
|
|
3021
|
-
await this.#callback({ kind: "Reasoning" /* Reasoning */, agent: this, newText: chunk.text });
|
|
3022
|
-
break;
|
|
1889
|
+
this.#abortController = new AbortController();
|
|
1890
|
+
const providerOptions = {};
|
|
1891
|
+
const thinkingBudgetTokens = this.config.parameters?.thinkingBudgetTokens;
|
|
1892
|
+
const enableThinking = thinkingBudgetTokens > 0;
|
|
1893
|
+
if (enableThinking) {
|
|
1894
|
+
providerOptions.anthropic = {
|
|
1895
|
+
thinking: { type: "enabled", budgetTokens: thinkingBudgetTokens }
|
|
1896
|
+
};
|
|
1897
|
+
providerOptions.openrouter = {
|
|
1898
|
+
reasoning: {
|
|
1899
|
+
max_tokens: thinkingBudgetTokens
|
|
3023
1900
|
}
|
|
3024
|
-
}
|
|
1901
|
+
};
|
|
1902
|
+
providerOptions.google = {
|
|
1903
|
+
thinkingConfig: {
|
|
1904
|
+
includeThoughts: true,
|
|
1905
|
+
thinkingBudget: thinkingBudgetTokens
|
|
1906
|
+
}
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
try {
|
|
1910
|
+
const stream = streamText({
|
|
1911
|
+
model: this.ai,
|
|
1912
|
+
messages,
|
|
1913
|
+
providerOptions,
|
|
1914
|
+
onChunk: async ({ chunk }) => {
|
|
1915
|
+
resetTimeout();
|
|
1916
|
+
switch (chunk.type) {
|
|
1917
|
+
case "text":
|
|
1918
|
+
currentAssistantMessage += chunk.text;
|
|
1919
|
+
await this.#callback({ kind: "Text" /* Text */, agent: this, newText: chunk.text });
|
|
1920
|
+
break;
|
|
1921
|
+
case "reasoning":
|
|
1922
|
+
await this.#callback({ kind: "Reasoning" /* Reasoning */, agent: this, newText: chunk.text });
|
|
1923
|
+
break;
|
|
1924
|
+
}
|
|
1925
|
+
},
|
|
1926
|
+
onFinish: this.config.usageMeter.onFinishHandler(this.ai),
|
|
1927
|
+
onError: async (error) => {
|
|
1928
|
+
console.error("Error in stream:", error);
|
|
1929
|
+
},
|
|
1930
|
+
abortSignal: this.#abortController.signal
|
|
1931
|
+
});
|
|
1932
|
+
await stream.consumeStream();
|
|
3025
1933
|
} catch (error) {
|
|
3026
1934
|
if (error instanceof Error && error.name === "AbortError") {
|
|
3027
1935
|
break;
|
|
@@ -3046,24 +1954,19 @@ ${instance.prompt}`;
|
|
|
3046
1954
|
}
|
|
3047
1955
|
throw new Error("No assistant message received");
|
|
3048
1956
|
}
|
|
1957
|
+
console.log("Assistant message:", currentAssistantMessage);
|
|
3049
1958
|
this.#messages.push({
|
|
3050
1959
|
role: "assistant",
|
|
3051
1960
|
content: currentAssistantMessage
|
|
3052
1961
|
});
|
|
3053
|
-
const ret = parseAssistantMessage(currentAssistantMessage, this.config.tools, this.config.toolNamePrefix);
|
|
1962
|
+
const ret = parseAssistantMessage(currentAssistantMessage, this.config.tools.map(toToolInfoV1), this.config.toolNamePrefix);
|
|
3054
1963
|
await this.#callback({ kind: "EndRequest" /* EndRequest */, agent: this, message: currentAssistantMessage });
|
|
3055
1964
|
return ret;
|
|
3056
1965
|
}
|
|
3057
1966
|
async #handleResponse(response) {
|
|
3058
1967
|
const toolResponses = [];
|
|
3059
1968
|
let hasPause = false;
|
|
3060
|
-
|
|
3061
|
-
for (const hook of this.#policies) {
|
|
3062
|
-
if (hook.updateResponse) {
|
|
3063
|
-
updatedResponse = await hook.updateResponse(updatedResponse);
|
|
3064
|
-
}
|
|
3065
|
-
}
|
|
3066
|
-
outer: for (const content of updatedResponse) {
|
|
1969
|
+
outer: for (const content of response) {
|
|
3067
1970
|
switch (content.type) {
|
|
3068
1971
|
case "text":
|
|
3069
1972
|
break;
|
|
@@ -3145,8 +2048,8 @@ ${instance.prompt}`;
|
|
|
3145
2048
|
}
|
|
3146
2049
|
async #invokeTool(name, args) {
|
|
3147
2050
|
try {
|
|
3148
|
-
const
|
|
3149
|
-
if (!
|
|
2051
|
+
const handler14 = this.handlers[name]?.handler;
|
|
2052
|
+
if (!handler14) {
|
|
3150
2053
|
return {
|
|
3151
2054
|
type: "Error" /* Error */,
|
|
3152
2055
|
message: responsePrompts.errorInvokeTool(name, "Tool not found"),
|
|
@@ -3165,7 +2068,7 @@ ${instance.prompt}`;
|
|
|
3165
2068
|
if (resp) {
|
|
3166
2069
|
return resp;
|
|
3167
2070
|
}
|
|
3168
|
-
return await
|
|
2071
|
+
return await handler14(this.config.provider, args);
|
|
3169
2072
|
} catch (error) {
|
|
3170
2073
|
return {
|
|
3171
2074
|
type: "Error" /* Error */,
|
|
@@ -3175,15 +2078,15 @@ ${instance.prompt}`;
|
|
|
3175
2078
|
}
|
|
3176
2079
|
}
|
|
3177
2080
|
get model() {
|
|
3178
|
-
return this.ai.
|
|
2081
|
+
return `${this.ai.provider}:${this.ai.modelId}`;
|
|
3179
2082
|
}
|
|
3180
2083
|
get usage() {
|
|
3181
|
-
return this.
|
|
2084
|
+
return this.config.usageMeter.usage;
|
|
3182
2085
|
}
|
|
3183
2086
|
};
|
|
3184
2087
|
|
|
3185
2088
|
// src/Agent/AnalyzerAgent/prompts.ts
|
|
3186
|
-
var fullSystemPrompt = (info, tools, toolNamePrefix, instructions, scripts) => `
|
|
2089
|
+
var fullSystemPrompt = (info, tools, toolNamePrefix, instructions, scripts, useNativeTool) => `
|
|
3187
2090
|
# Analyzer Agent
|
|
3188
2091
|
|
|
3189
2092
|
## Role
|
|
@@ -3204,7 +2107,7 @@ You are the **Analyzer** agent, responsible for:
|
|
|
3204
2107
|
5. **Documentation Assessment**: Review documentation quality and completeness.
|
|
3205
2108
|
6. **Non-Modification**: Never modify code or files - focus solely on analysis.
|
|
3206
2109
|
|
|
3207
|
-
${toolUsePrompt(tools, toolNamePrefix)}
|
|
2110
|
+
${useNativeTool ? "" : toolUsePrompt(tools, toolNamePrefix)}
|
|
3208
2111
|
${capabilities(toolNamePrefix)}
|
|
3209
2112
|
${systemInformation(info)}
|
|
3210
2113
|
${customInstructions(instructions)}
|
|
@@ -3227,10 +2130,11 @@ var AnalyzerAgent = class extends AgentBase {
|
|
|
3227
2130
|
{
|
|
3228
2131
|
os: options.os
|
|
3229
2132
|
},
|
|
3230
|
-
tools,
|
|
2133
|
+
tools.map(toToolInfoV1),
|
|
3231
2134
|
toolNamePrefix,
|
|
3232
2135
|
options.customInstructions ?? [],
|
|
3233
|
-
options.scripts ?? {}
|
|
2136
|
+
options.scripts ?? {},
|
|
2137
|
+
options.toolFormat === "native"
|
|
3234
2138
|
);
|
|
3235
2139
|
super(analyzerAgentInfo.name, options.ai, {
|
|
3236
2140
|
systemPrompt,
|
|
@@ -3241,7 +2145,10 @@ var AnalyzerAgent = class extends AgentBase {
|
|
|
3241
2145
|
agents: options.agents,
|
|
3242
2146
|
scripts: options.scripts,
|
|
3243
2147
|
callback: options.callback,
|
|
3244
|
-
policies: options.policies
|
|
2148
|
+
policies: options.policies,
|
|
2149
|
+
toolFormat: options.toolFormat,
|
|
2150
|
+
parameters: options.parameters ?? {},
|
|
2151
|
+
usageMeter: options.usageMeter ?? new UsageMeter()
|
|
3245
2152
|
});
|
|
3246
2153
|
}
|
|
3247
2154
|
onBeforeInvokeTool() {
|
|
@@ -3260,7 +2167,7 @@ var analyzerAgentInfo = {
|
|
|
3260
2167
|
};
|
|
3261
2168
|
|
|
3262
2169
|
// src/Agent/ArchitectAgent/prompts.ts
|
|
3263
|
-
var fullSystemPrompt2 = (info, tools, toolNamePrefix, instructions, scripts) => `
|
|
2170
|
+
var fullSystemPrompt2 = (info, tools, toolNamePrefix, instructions, scripts, useNativeTool) => `
|
|
3264
2171
|
# Architect Agent
|
|
3265
2172
|
|
|
3266
2173
|
## Role
|
|
@@ -3296,7 +2203,7 @@ You are the **Architect** agent, responsible for:
|
|
|
3296
2203
|
- If multiple steps are required, break them into numbered tasks to delegate to the **Coder** agent.
|
|
3297
2204
|
- Provide all necessary context, implementation plan, file references, and clarifications for successful execution.
|
|
3298
2205
|
|
|
3299
|
-
${toolUsePrompt(tools, toolNamePrefix)}
|
|
2206
|
+
${useNativeTool ? "" : toolUsePrompt(tools, toolNamePrefix)}
|
|
3300
2207
|
${capabilities(toolNamePrefix)}
|
|
3301
2208
|
${systemInformation(info)}
|
|
3302
2209
|
${customInstructions(instructions)}
|
|
@@ -3319,10 +2226,11 @@ var ArchitectAgent = class extends AgentBase {
|
|
|
3319
2226
|
{
|
|
3320
2227
|
os: options.os
|
|
3321
2228
|
},
|
|
3322
|
-
tools,
|
|
2229
|
+
tools.map(toToolInfoV1),
|
|
3323
2230
|
toolNamePrefix,
|
|
3324
2231
|
options.customInstructions ?? [],
|
|
3325
|
-
options.scripts ?? {}
|
|
2232
|
+
options.scripts ?? {},
|
|
2233
|
+
options.toolFormat === "native"
|
|
3326
2234
|
);
|
|
3327
2235
|
super(architectAgentInfo.name, options.ai, {
|
|
3328
2236
|
systemPrompt,
|
|
@@ -3333,7 +2241,10 @@ var ArchitectAgent = class extends AgentBase {
|
|
|
3333
2241
|
agents: options.agents,
|
|
3334
2242
|
scripts: options.scripts,
|
|
3335
2243
|
callback: options.callback,
|
|
3336
|
-
policies: options.policies
|
|
2244
|
+
policies: options.policies,
|
|
2245
|
+
toolFormat: options.toolFormat,
|
|
2246
|
+
parameters: options.parameters ?? {},
|
|
2247
|
+
usageMeter: options.usageMeter ?? new UsageMeter()
|
|
3337
2248
|
});
|
|
3338
2249
|
}
|
|
3339
2250
|
onBeforeInvokeTool() {
|
|
@@ -3416,9 +2327,9 @@ RETRY GUIDELINES
|
|
|
3416
2327
|
- Explain why the issue remains
|
|
3417
2328
|
- Suggest manual intervention steps
|
|
3418
2329
|
- Report any partial improvements`;
|
|
3419
|
-
var fullSystemPrompt3 = (info, tools, toolNamePrefix, instructions, scripts, interactive) => `
|
|
2330
|
+
var fullSystemPrompt3 = (info, tools, toolNamePrefix, instructions, scripts, interactive, useNativeTool) => `
|
|
3420
2331
|
${basePrompt}
|
|
3421
|
-
${toolUsePrompt(tools, toolNamePrefix)}
|
|
2332
|
+
${useNativeTool ? "" : toolUsePrompt(tools, toolNamePrefix)}
|
|
3422
2333
|
${codeFixingStrategies}
|
|
3423
2334
|
${retryGuidelines}
|
|
3424
2335
|
${capabilities(toolNamePrefix)}
|
|
@@ -3444,11 +2355,12 @@ var CodeFixerAgent = class extends AgentBase {
|
|
|
3444
2355
|
{
|
|
3445
2356
|
os: options.os
|
|
3446
2357
|
},
|
|
3447
|
-
tools,
|
|
2358
|
+
tools.map(toToolInfoV1),
|
|
3448
2359
|
toolNamePrefix,
|
|
3449
2360
|
options.customInstructions ?? [],
|
|
3450
2361
|
options.scripts ?? {},
|
|
3451
|
-
options.interactive
|
|
2362
|
+
options.interactive,
|
|
2363
|
+
options.toolFormat === "native"
|
|
3452
2364
|
);
|
|
3453
2365
|
super(codeFixerAgentInfo.name, options.ai, {
|
|
3454
2366
|
systemPrompt,
|
|
@@ -3459,7 +2371,10 @@ var CodeFixerAgent = class extends AgentBase {
|
|
|
3459
2371
|
agents: options.agents,
|
|
3460
2372
|
scripts: options.scripts,
|
|
3461
2373
|
callback: options.callback,
|
|
3462
|
-
policies: options.policies
|
|
2374
|
+
policies: options.policies,
|
|
2375
|
+
toolFormat: options.toolFormat,
|
|
2376
|
+
parameters: options.parameters ?? {},
|
|
2377
|
+
usageMeter: options.usageMeter ?? new UsageMeter()
|
|
3463
2378
|
});
|
|
3464
2379
|
this.#maxRetries = options.maxRetries ?? 5;
|
|
3465
2380
|
}
|
|
@@ -3618,9 +2533,9 @@ You solve the user's task by working in small, verifiable steps.
|
|
|
3618
2533
|
4. **Iterate** - Repeat Plan \u2192 Think \u2192 Act until all goals are complete.
|
|
3619
2534
|
5. **Complete** - Use ${toolNamePrefix}attempt_completion to deliver the final result. Do not invite further discussion unless the user explicitly requests changes.
|
|
3620
2535
|
`;
|
|
3621
|
-
var fullSystemPrompt4 = (info, tools, toolNamePrefix, instructions, scripts) => `
|
|
2536
|
+
var fullSystemPrompt4 = (info, tools, toolNamePrefix, instructions, scripts, useNativeTool) => `
|
|
3622
2537
|
${basePrompt2}
|
|
3623
|
-
${toolUsePrompt(tools, toolNamePrefix)}
|
|
2538
|
+
${useNativeTool ? "" : toolUsePrompt(tools, toolNamePrefix)}
|
|
3624
2539
|
${editingFilesPrompt(toolNamePrefix)}
|
|
3625
2540
|
${capabilities(toolNamePrefix)}
|
|
3626
2541
|
${rules(toolNamePrefix)}
|
|
@@ -3646,10 +2561,11 @@ var CoderAgent = class extends AgentBase {
|
|
|
3646
2561
|
{
|
|
3647
2562
|
os: options.os
|
|
3648
2563
|
},
|
|
3649
|
-
tools,
|
|
2564
|
+
tools.map(toToolInfoV1),
|
|
3650
2565
|
toolNamePrefix,
|
|
3651
2566
|
options.customInstructions ?? [],
|
|
3652
|
-
options.scripts ?? {}
|
|
2567
|
+
options.scripts ?? {},
|
|
2568
|
+
options.toolFormat === "native"
|
|
3653
2569
|
);
|
|
3654
2570
|
super(coderAgentInfo.name, options.ai, {
|
|
3655
2571
|
systemPrompt,
|
|
@@ -3660,7 +2576,10 @@ var CoderAgent = class extends AgentBase {
|
|
|
3660
2576
|
agents: options.agents,
|
|
3661
2577
|
scripts: options.scripts,
|
|
3662
2578
|
callback: options.callback,
|
|
3663
|
-
policies: options.policies
|
|
2579
|
+
policies: options.policies,
|
|
2580
|
+
toolFormat: options.toolFormat,
|
|
2581
|
+
parameters: options.parameters ?? {},
|
|
2582
|
+
usageMeter: options.usageMeter ?? new UsageMeter()
|
|
3664
2583
|
});
|
|
3665
2584
|
}
|
|
3666
2585
|
async onBeforeInvokeTool(name, args) {
|
|
@@ -3734,24 +2653,24 @@ var MultiAgent = class {
|
|
|
3734
2653
|
switch (exitReason.type) {
|
|
3735
2654
|
case "HandOver" /* HandOver */: {
|
|
3736
2655
|
this.#agents.pop();
|
|
3737
|
-
const
|
|
2656
|
+
const prompt5 = await this.#config.getPrompt?.(
|
|
3738
2657
|
exitReason.agentName,
|
|
3739
2658
|
exitReason.task,
|
|
3740
2659
|
exitReason.context,
|
|
3741
2660
|
exitReason.files,
|
|
3742
2661
|
this.#originalTask
|
|
3743
2662
|
) ?? exitReason.task;
|
|
3744
|
-
return await this.#startTask(exitReason.agentName,
|
|
2663
|
+
return await this.#startTask(exitReason.agentName, prompt5);
|
|
3745
2664
|
}
|
|
3746
2665
|
case "Delegate" /* Delegate */: {
|
|
3747
|
-
const
|
|
2666
|
+
const prompt5 = await this.#config.getPrompt?.(
|
|
3748
2667
|
exitReason.agentName,
|
|
3749
2668
|
exitReason.task,
|
|
3750
2669
|
exitReason.context,
|
|
3751
2670
|
exitReason.files,
|
|
3752
2671
|
this.#originalTask
|
|
3753
2672
|
) ?? exitReason.task;
|
|
3754
|
-
const delegateResult = await this.#startTask(exitReason.agentName,
|
|
2673
|
+
const delegateResult = await this.#startTask(exitReason.agentName, prompt5);
|
|
3755
2674
|
switch (delegateResult.type) {
|
|
3756
2675
|
case "HandOver" /* HandOver */:
|
|
3757
2676
|
case "Delegate" /* Delegate */:
|
|
@@ -3806,214 +2725,79 @@ var MultiAgent = class {
|
|
|
3806
2725
|
};
|
|
3807
2726
|
|
|
3808
2727
|
// src/config.ts
|
|
3809
|
-
import { z } from "zod";
|
|
3810
|
-
var
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
2728
|
+
import { z as z15 } from "zod";
|
|
2729
|
+
var toolFormatSchema = z15.enum(["native", "polka-codes"]).optional();
|
|
2730
|
+
var providerModelSchema = z15.object({
|
|
2731
|
+
provider: z15.string().optional(),
|
|
2732
|
+
model: z15.string().optional(),
|
|
2733
|
+
parameters: z15.record(z15.string(), z15.any()).optional(),
|
|
2734
|
+
toolFormat: toolFormatSchema
|
|
3814
2735
|
});
|
|
3815
2736
|
var agentSchema = providerModelSchema.extend({
|
|
3816
|
-
initialContext:
|
|
3817
|
-
maxFileCount:
|
|
3818
|
-
excludes:
|
|
2737
|
+
initialContext: z15.object({
|
|
2738
|
+
maxFileCount: z15.number().int().positive().optional(),
|
|
2739
|
+
excludes: z15.array(z15.string()).optional()
|
|
3819
2740
|
}).optional(),
|
|
3820
|
-
retryCount:
|
|
3821
|
-
requestTimeoutSeconds:
|
|
2741
|
+
retryCount: z15.number().int().min(0).optional(),
|
|
2742
|
+
requestTimeoutSeconds: z15.number().int().positive().optional()
|
|
3822
2743
|
});
|
|
3823
|
-
var configSchema =
|
|
3824
|
-
agent:
|
|
3825
|
-
prices:
|
|
3826
|
-
|
|
2744
|
+
var configSchema = z15.object({
|
|
2745
|
+
agent: z15.string().optional(),
|
|
2746
|
+
prices: z15.record(
|
|
2747
|
+
z15.string(),
|
|
3827
2748
|
// provider
|
|
3828
|
-
|
|
3829
|
-
|
|
2749
|
+
z15.record(
|
|
2750
|
+
z15.string(),
|
|
3830
2751
|
// model
|
|
3831
|
-
|
|
3832
|
-
inputPrice:
|
|
3833
|
-
outputPrice:
|
|
3834
|
-
cacheWritesPrice:
|
|
3835
|
-
cacheReadsPrice:
|
|
2752
|
+
z15.object({
|
|
2753
|
+
inputPrice: z15.number().optional(),
|
|
2754
|
+
outputPrice: z15.number().optional(),
|
|
2755
|
+
cacheWritesPrice: z15.number().optional(),
|
|
2756
|
+
cacheReadsPrice: z15.number().optional()
|
|
3836
2757
|
})
|
|
3837
2758
|
)
|
|
3838
2759
|
).optional(),
|
|
3839
|
-
providers:
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
apiKey:
|
|
3843
|
-
defaultModel:
|
|
3844
|
-
defaultParameters:
|
|
2760
|
+
providers: z15.record(
|
|
2761
|
+
z15.string(),
|
|
2762
|
+
z15.object({
|
|
2763
|
+
apiKey: z15.string().optional(),
|
|
2764
|
+
defaultModel: z15.string().optional(),
|
|
2765
|
+
defaultParameters: z15.record(z15.string(), z15.any()).optional()
|
|
3845
2766
|
})
|
|
3846
2767
|
).optional(),
|
|
3847
|
-
defaultProvider:
|
|
3848
|
-
defaultModel:
|
|
3849
|
-
defaultParameters:
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
2768
|
+
defaultProvider: z15.string().optional(),
|
|
2769
|
+
defaultModel: z15.string().optional(),
|
|
2770
|
+
defaultParameters: z15.record(z15.string(), z15.any()).optional(),
|
|
2771
|
+
toolFormat: toolFormatSchema,
|
|
2772
|
+
maxMessageCount: z15.number().int().positive().optional(),
|
|
2773
|
+
budget: z15.number().positive().optional(),
|
|
2774
|
+
retryCount: z15.number().int().min(0).optional(),
|
|
2775
|
+
requestTimeoutSeconds: z15.number().int().positive().optional(),
|
|
2776
|
+
scripts: z15.record(
|
|
2777
|
+
z15.string(),
|
|
2778
|
+
z15.string().or(
|
|
2779
|
+
z15.object({
|
|
2780
|
+
command: z15.string(),
|
|
2781
|
+
description: z15.string()
|
|
3860
2782
|
})
|
|
3861
2783
|
)
|
|
3862
2784
|
).optional(),
|
|
3863
|
-
agents:
|
|
3864
|
-
commands:
|
|
2785
|
+
agents: z15.record(z15.string(), agentSchema).optional(),
|
|
2786
|
+
commands: z15.object({
|
|
3865
2787
|
default: providerModelSchema.optional()
|
|
3866
2788
|
}).catchall(providerModelSchema).optional(),
|
|
3867
|
-
rules:
|
|
3868
|
-
excludeFiles:
|
|
3869
|
-
policies:
|
|
2789
|
+
rules: z15.array(z15.string()).optional().or(z15.string()).optional(),
|
|
2790
|
+
excludeFiles: z15.array(z15.string()).optional(),
|
|
2791
|
+
policies: z15.array(z15.string()).optional()
|
|
3870
2792
|
}).strict();
|
|
3871
2793
|
var Policies = /* @__PURE__ */ ((Policies2) => {
|
|
3872
|
-
Policies2["KnowledgeManagement"] = "knowledgemanagement";
|
|
3873
2794
|
Policies2["TruncateContext"] = "truncatecontext";
|
|
2795
|
+
Policies2["EnableCache"] = "enablecache";
|
|
3874
2796
|
return Policies2;
|
|
3875
2797
|
})(Policies || {});
|
|
3876
2798
|
|
|
3877
|
-
// src/Agent/policies/
|
|
3878
|
-
var
|
|
3879
|
-
====
|
|
3880
|
-
|
|
3881
|
-
# Knowledge Extraction & Maintenance
|
|
3882
|
-
|
|
3883
|
-
You are equipped with **Knowledge Management** capabilities:
|
|
3884
|
-
|
|
3885
|
-
1. **What to capture**
|
|
3886
|
-
- Public API of each file (public classes, functions, methods, parameters, return types).
|
|
3887
|
-
- High-level description of each file's purpose.
|
|
3888
|
-
- Invariants and assumptions that must always hold.
|
|
3889
|
-
- Project or directory-specific coding patterns, styles, and architectural conventions.
|
|
3890
|
-
- Any other insight that a future contributor would find crucial.
|
|
3891
|
-
|
|
3892
|
-
2. **Where to store it**
|
|
3893
|
-
- Save knowledge in a YAML file named \`knowledge.ai.yml\`.
|
|
3894
|
-
- **Create the file in the repository root if it does not yet exist.**
|
|
3895
|
-
- One file per directory.
|
|
3896
|
-
- The repository root file records knowledge that applies project-wide (e.g., service responsibilities, global patterns).
|
|
3897
|
-
- Each sub-directory keeps only the knowledge relevant to that directory or package.
|
|
3898
|
-
- Use clear top-level keys such as \`description\`, \`files\`, \`rules\`.
|
|
3899
|
-
|
|
3900
|
-
3. **When to update**
|
|
3901
|
-
- **Default behaviour:** only create / update knowledge for the files you actively read, create, or modify during the current task.
|
|
3902
|
-
- Operate on other files **only if the user explicitly requests it**.
|
|
3903
|
-
- **While working**: after reading, analysing, creating, or modifying code, immediately record any new or changed knowledge.
|
|
3904
|
-
- **On refactor / deletion**: locate and delete or amend obsolete entries so that knowledge never drifts from the codebase.
|
|
3905
|
-
- **Granularity**: update only the affected directory's \`knowledge.ai.yml\`, except when the change has global impact.
|
|
3906
|
-
|
|
3907
|
-
4. **How to format (illustrative)**
|
|
3908
|
-
\`\`\`yaml
|
|
3909
|
-
description: "description of the directory"
|
|
3910
|
-
files:
|
|
3911
|
-
"math.ts":
|
|
3912
|
-
description: "Numeric helpers for currency calculations"
|
|
3913
|
-
api:
|
|
3914
|
-
functions:
|
|
3915
|
-
1: add(a: number, b: number): number
|
|
3916
|
-
rules:
|
|
3917
|
-
1: "rules that apply to all files in this directory"
|
|
3918
|
-
\`\`\`
|
|
3919
|
-
|
|
3920
|
-
5. **Source of truth**
|
|
3921
|
-
- **Never invent knowledge.** Everything you record must be *directly derived* from existing code, comments, commit messages, or explicit user instructions.
|
|
3922
|
-
- If a section has no confirmed content, omit it rather than guessing.
|
|
3923
|
-
|
|
3924
|
-
6. **Automatic context**
|
|
3925
|
-
When you are asked to read or modify a file, the orchestration layer will supply any existing knowledge for that path automatically. Use it, refine it, and keep it accurate.
|
|
3926
|
-
|
|
3927
|
-
7. **Using the updateKnowledge tool**
|
|
3928
|
-
You can use the \`updateKnowledge\` tool to efficiently update knowledge files with smart merging capabilities.
|
|
3929
|
-
|
|
3930
|
-
8. **Dictionary-First Format**
|
|
3931
|
-
- **Always prefer dictionaries** for structured data.
|
|
3932
|
-
- The **\`files\` section must be a dictionary keyed by file path** (e.g., \`"math.ts": {...}\`).
|
|
3933
|
-
- For other lists (rules, functions, etc.), use numbered dictionaries.
|
|
3934
|
-
- Arrays are allowed only when strict ordering is essential and dictionaries cannot express it.
|
|
3935
|
-
- When removing items, refer to them by their numeric key or index; gaps are fine.
|
|
3936
|
-
|
|
3937
|
-
Your workflow **must**:
|
|
3938
|
-
1. Detect knowledge deltas.
|
|
3939
|
-
2. Create \`knowledge.ai.yml\` if missing and write edits to the correct file.
|
|
3940
|
-
3. Remove stale facts.
|
|
3941
|
-
4. Use provided tools to update the knowledge files.
|
|
3942
|
-
5. Record only evidence-based information; do not hallucinate.
|
|
3943
|
-
6. Use dictionaries throughout, with numbered dictionaries for ordered data and path-keyed dictionaries for the \`files\` section.
|
|
3944
|
-
`;
|
|
3945
|
-
var KnowledgeManagementPolicy = (tools) => {
|
|
3946
|
-
if (!tools[readFile_default.name]) {
|
|
3947
|
-
return void 0;
|
|
3948
|
-
}
|
|
3949
|
-
const readFiles = /* @__PURE__ */ new Set();
|
|
3950
|
-
return {
|
|
3951
|
-
name: "knowledgemanagement" /* KnowledgeManagement */,
|
|
3952
|
-
tools: tools[writeToFile_default.name] ? [updateKnowledge_default] : [],
|
|
3953
|
-
prompt: tools[writeToFile_default.name] || tools[updateKnowledge_default.name] ? prompt : void 0,
|
|
3954
|
-
async getKnowledgeFilePaths(inputFiles) {
|
|
3955
|
-
const paths = /* @__PURE__ */ new Set();
|
|
3956
|
-
for (const file of inputFiles) {
|
|
3957
|
-
let dir = dirname(file);
|
|
3958
|
-
paths.add(dir);
|
|
3959
|
-
while (dir !== ".") {
|
|
3960
|
-
paths.add(dir);
|
|
3961
|
-
dir = dirname(dir);
|
|
3962
|
-
}
|
|
3963
|
-
}
|
|
3964
|
-
const allFullPaths = [];
|
|
3965
|
-
for (const path of paths) {
|
|
3966
|
-
if (path === ".") {
|
|
3967
|
-
continue;
|
|
3968
|
-
}
|
|
3969
|
-
const fullpath = join(path, "knowledge.ai.yml");
|
|
3970
|
-
if (!readFiles.has(fullpath)) {
|
|
3971
|
-
allFullPaths.push(fullpath);
|
|
3972
|
-
readFiles.add(fullpath);
|
|
3973
|
-
}
|
|
3974
|
-
}
|
|
3975
|
-
return allFullPaths;
|
|
3976
|
-
},
|
|
3977
|
-
async updateResponse(response) {
|
|
3978
|
-
const files = /* @__PURE__ */ new Set();
|
|
3979
|
-
for (const content of response) {
|
|
3980
|
-
if (content.type === "tool_use") {
|
|
3981
|
-
switch (content.name) {
|
|
3982
|
-
case readFile_default.name: {
|
|
3983
|
-
const paths = getStringArray(content.params, "path");
|
|
3984
|
-
for (const path of paths) {
|
|
3985
|
-
files.add(path);
|
|
3986
|
-
}
|
|
3987
|
-
break;
|
|
3988
|
-
}
|
|
3989
|
-
case listFiles_default.name: {
|
|
3990
|
-
const path = getString(content.params, "path");
|
|
3991
|
-
files.add(path);
|
|
3992
|
-
break;
|
|
3993
|
-
}
|
|
3994
|
-
}
|
|
3995
|
-
}
|
|
3996
|
-
}
|
|
3997
|
-
const allFullPaths = await this.getKnowledgeFilePaths(Array.from(files));
|
|
3998
|
-
if (allFullPaths.length === 0) {
|
|
3999
|
-
return response;
|
|
4000
|
-
}
|
|
4001
|
-
return [
|
|
4002
|
-
...response,
|
|
4003
|
-
{
|
|
4004
|
-
type: "tool_use",
|
|
4005
|
-
name: readFile_default.name,
|
|
4006
|
-
params: {
|
|
4007
|
-
path: allFullPaths.join(",")
|
|
4008
|
-
}
|
|
4009
|
-
}
|
|
4010
|
-
];
|
|
4011
|
-
}
|
|
4012
|
-
};
|
|
4013
|
-
};
|
|
4014
|
-
|
|
4015
|
-
// src/Agent/policies/TruncateContext.ts
|
|
4016
|
-
var DEFAULT_MAX_TOKENS_ESTIMATE = 8e3;
|
|
2799
|
+
// src/Agent/policies/TruncateContextPolicy.ts
|
|
2800
|
+
var DEFAULT_MAX_TOKENS_ESTIMATE = 32e3;
|
|
4017
2801
|
function getMaxTokens(agent) {
|
|
4018
2802
|
const params = agent.parameters || {};
|
|
4019
2803
|
if (params.maxTokens && typeof params.maxTokens === "number" && params.maxTokens > 0) {
|
|
@@ -4024,7 +2808,22 @@ function getMaxTokens(agent) {
|
|
|
4024
2808
|
function estimateTokens(text) {
|
|
4025
2809
|
return Math.ceil(text.length / 4);
|
|
4026
2810
|
}
|
|
4027
|
-
|
|
2811
|
+
function estimateMessageTokens(msg) {
|
|
2812
|
+
if (typeof msg.content === "string") {
|
|
2813
|
+
return estimateTokens(msg.content);
|
|
2814
|
+
}
|
|
2815
|
+
if (Array.isArray(msg.content)) {
|
|
2816
|
+
let messageTokens = 0;
|
|
2817
|
+
for (const block of msg.content) {
|
|
2818
|
+
if (typeof block === "object" && "text" in block && typeof block.text === "string") {
|
|
2819
|
+
messageTokens += estimateTokens(block.text);
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
return messageTokens;
|
|
2823
|
+
}
|
|
2824
|
+
return 0;
|
|
2825
|
+
}
|
|
2826
|
+
var TruncateContextPolicy = () => {
|
|
4028
2827
|
return {
|
|
4029
2828
|
name: "truncatecontext" /* TruncateContext */,
|
|
4030
2829
|
async onBeforeRequest(agent) {
|
|
@@ -4032,52 +2831,128 @@ var TruncateContextPolicy = (tools) => {
|
|
|
4032
2831
|
if (messages.length < 3) {
|
|
4033
2832
|
return;
|
|
4034
2833
|
}
|
|
4035
|
-
let totalTokens = 0;
|
|
4036
|
-
for (const msg of messages) {
|
|
4037
|
-
if (typeof msg.content === "string") {
|
|
4038
|
-
totalTokens += estimateTokens(msg.content);
|
|
4039
|
-
} else if (Array.isArray(msg.content)) {
|
|
4040
|
-
for (const block of msg.content) {
|
|
4041
|
-
if (typeof block === "object" && "text" in block && typeof block.text === "string") {
|
|
4042
|
-
totalTokens += estimateTokens(block.text);
|
|
4043
|
-
}
|
|
4044
|
-
}
|
|
4045
|
-
}
|
|
4046
|
-
}
|
|
2834
|
+
let totalTokens = messages.reduce((acc, msg) => acc + estimateMessageTokens(msg), 0);
|
|
4047
2835
|
const maxTokens = getMaxTokens(agent);
|
|
4048
2836
|
if (totalTokens <= maxTokens) {
|
|
4049
2837
|
return;
|
|
4050
2838
|
}
|
|
4051
|
-
const
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
2839
|
+
const protectedIndices = /* @__PURE__ */ new Set();
|
|
2840
|
+
let userMessagesFound = 0;
|
|
2841
|
+
messages.forEach((msg, index) => {
|
|
2842
|
+
if (msg.role === "system") {
|
|
2843
|
+
protectedIndices.add(index);
|
|
2844
|
+
}
|
|
2845
|
+
if (msg.role === "user") {
|
|
2846
|
+
if (userMessagesFound < 2) {
|
|
2847
|
+
protectedIndices.add(index);
|
|
2848
|
+
}
|
|
2849
|
+
userMessagesFound++;
|
|
2850
|
+
}
|
|
2851
|
+
});
|
|
2852
|
+
if (messages.length > 0) {
|
|
2853
|
+
protectedIndices.add(messages.length - 1);
|
|
2854
|
+
}
|
|
2855
|
+
const truncatableIndices = [];
|
|
2856
|
+
for (let i = 0; i < messages.length; i++) {
|
|
2857
|
+
if (!protectedIndices.has(i)) {
|
|
2858
|
+
truncatableIndices.push(i);
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
const removedIndices = /* @__PURE__ */ new Set();
|
|
2862
|
+
const initialTotalTokens = totalTokens;
|
|
2863
|
+
while (totalTokens > maxTokens && truncatableIndices.length > 0) {
|
|
2864
|
+
const middleIndex = Math.floor(truncatableIndices.length / 2);
|
|
2865
|
+
const indexToRemove = truncatableIndices.splice(middleIndex, 1)[0];
|
|
2866
|
+
removedIndices.add(indexToRemove);
|
|
2867
|
+
totalTokens -= estimateMessageTokens(messages[indexToRemove]);
|
|
2868
|
+
}
|
|
2869
|
+
if (removedIndices.size === 0) {
|
|
2870
|
+
if (initialTotalTokens > maxTokens) {
|
|
2871
|
+
console.warn("Warning: Protected messages exceed token limit. Cannot truncate further.");
|
|
2872
|
+
}
|
|
4055
2873
|
return;
|
|
4056
2874
|
}
|
|
4057
|
-
const
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
}
|
|
4069
|
-
|
|
4070
|
-
|
|
2875
|
+
const truncatedMessages = [];
|
|
2876
|
+
let truncationNoticeAdded = false;
|
|
2877
|
+
for (let i = 0; i < messages.length; i++) {
|
|
2878
|
+
if (removedIndices.has(i)) {
|
|
2879
|
+
if (!truncationNoticeAdded) {
|
|
2880
|
+
truncatedMessages.push({
|
|
2881
|
+
role: "user",
|
|
2882
|
+
content: `Note: ${removedIndices.size} messages were truncated from the conversation to prevent context overflow.`
|
|
2883
|
+
});
|
|
2884
|
+
truncationNoticeAdded = true;
|
|
2885
|
+
}
|
|
2886
|
+
} else {
|
|
2887
|
+
truncatedMessages.push(messages[i]);
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
console.log(`Truncated context: removed ${removedIndices.size} messages.`);
|
|
4071
2891
|
agent.setMessages(truncatedMessages);
|
|
4072
2892
|
}
|
|
4073
2893
|
};
|
|
4074
2894
|
};
|
|
4075
2895
|
|
|
2896
|
+
// src/Agent/policies/EnableCachePolicy.ts
|
|
2897
|
+
var CACHEABLE_MODELS = ["sonnet", "opus", "haiku", "gemini"];
|
|
2898
|
+
function isCacheableModel(modelId) {
|
|
2899
|
+
return CACHEABLE_MODELS.some((model) => modelId.includes(model));
|
|
2900
|
+
}
|
|
2901
|
+
function getProviderKey(provider) {
|
|
2902
|
+
if (provider === "openrouter") {
|
|
2903
|
+
return "openrouter";
|
|
2904
|
+
}
|
|
2905
|
+
if (provider.includes("anthropic")) {
|
|
2906
|
+
return "anthropic";
|
|
2907
|
+
}
|
|
2908
|
+
return void 0;
|
|
2909
|
+
}
|
|
2910
|
+
var EnableCachePolicy = () => {
|
|
2911
|
+
return {
|
|
2912
|
+
name: "enablecache" /* EnableCache */,
|
|
2913
|
+
async prepareMessages(agent, messages) {
|
|
2914
|
+
const providerKey = getProviderKey(agent.ai.provider);
|
|
2915
|
+
if (!providerKey || !isCacheableModel(agent.ai.modelId)) {
|
|
2916
|
+
return messages;
|
|
2917
|
+
}
|
|
2918
|
+
const providerOptions = { [providerKey]: { cacheControl: { type: "ephemeral" } } };
|
|
2919
|
+
const newMessages = messages.slice();
|
|
2920
|
+
let userMessagesToUpdate = 2;
|
|
2921
|
+
for (let i = newMessages.length - 1; i >= 0; i--) {
|
|
2922
|
+
const message = newMessages[i];
|
|
2923
|
+
if (message.role === "user" && userMessagesToUpdate > 0) {
|
|
2924
|
+
newMessages[i] = {
|
|
2925
|
+
...message,
|
|
2926
|
+
providerOptions: {
|
|
2927
|
+
...providerOptions,
|
|
2928
|
+
...message.providerOptions ?? {}
|
|
2929
|
+
}
|
|
2930
|
+
};
|
|
2931
|
+
userMessagesToUpdate--;
|
|
2932
|
+
} else if (message.role === "system") {
|
|
2933
|
+
newMessages[i] = {
|
|
2934
|
+
...message,
|
|
2935
|
+
providerOptions: {
|
|
2936
|
+
...providerOptions,
|
|
2937
|
+
...message.providerOptions ?? {}
|
|
2938
|
+
}
|
|
2939
|
+
};
|
|
2940
|
+
break;
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
return newMessages;
|
|
2944
|
+
}
|
|
2945
|
+
};
|
|
2946
|
+
};
|
|
2947
|
+
|
|
4076
2948
|
// src/Agent/index.ts
|
|
4077
2949
|
var allAgents = [architectAgentInfo, coderAgentInfo, analyzerAgentInfo, codeFixerAgentInfo];
|
|
4078
2950
|
|
|
2951
|
+
// src/AiTool/index.ts
|
|
2952
|
+
import { generateText } from "ai";
|
|
2953
|
+
|
|
4079
2954
|
// src/AiTool/createNewProject.ts
|
|
4080
|
-
var
|
|
2955
|
+
var prompt = `You are an AiTool designed to assist users in creating new projects. Follow these guidelines:
|
|
4081
2956
|
|
|
4082
2957
|
1. **Gather Information:**
|
|
4083
2958
|
- Begin by asking the user for essential project details, including:
|
|
@@ -4162,7 +3037,7 @@ var prompt2 = `You are an AiTool designed to assist users in creating new projec
|
|
|
4162
3037
|
var createNewProject_default = {
|
|
4163
3038
|
name: "createNewProject",
|
|
4164
3039
|
description: "Creates a new project",
|
|
4165
|
-
prompt
|
|
3040
|
+
prompt,
|
|
4166
3041
|
formatInput: (params) => {
|
|
4167
3042
|
return `<project_name>${params}</project_name>`;
|
|
4168
3043
|
},
|
|
@@ -4173,7 +3048,7 @@ var createNewProject_default = {
|
|
|
4173
3048
|
};
|
|
4174
3049
|
|
|
4175
3050
|
// src/AiTool/generateGitCommitMessage.ts
|
|
4176
|
-
var
|
|
3051
|
+
var prompt2 = `
|
|
4177
3052
|
You are an advanced assistant specialized in creating concise and accurate Git commit messages. When you receive:
|
|
4178
3053
|
- A Git diff inside the <tool_input> tag.
|
|
4179
3054
|
- Additional user-supplied context inside the <tool_input_context> tag (if any).
|
|
@@ -4204,7 +3079,7 @@ Follow the same structure for any new input. Never repeat questions; focus on ge
|
|
|
4204
3079
|
var generateGitCommitMessage_default = {
|
|
4205
3080
|
name: "generateGitCommitMessage",
|
|
4206
3081
|
description: "Generates git commit messages from git diff output",
|
|
4207
|
-
prompt:
|
|
3082
|
+
prompt: prompt2,
|
|
4208
3083
|
formatInput: (params) => {
|
|
4209
3084
|
let ret = `<tool_input>
|
|
4210
3085
|
${params.diff}
|
|
@@ -4229,7 +3104,7 @@ ${output}`);
|
|
|
4229
3104
|
};
|
|
4230
3105
|
|
|
4231
3106
|
// src/AiTool/generateGithubPullRequestDetails.ts
|
|
4232
|
-
var
|
|
3107
|
+
var prompt3 = `
|
|
4233
3108
|
# Generate Github Pull Request Details
|
|
4234
3109
|
|
|
4235
3110
|
You are given:
|
|
@@ -4313,7 +3188,7 @@ Use the above format whenever you receive <tool_input> that may include a branch
|
|
|
4313
3188
|
var generateGithubPullRequestDetails_default = {
|
|
4314
3189
|
name: "generateGithubPullRequestDetails",
|
|
4315
3190
|
description: "Generates a GitHub pull request title and description from git commits",
|
|
4316
|
-
prompt:
|
|
3191
|
+
prompt: prompt3,
|
|
4317
3192
|
formatInput: (params) => {
|
|
4318
3193
|
return `<tool_input>
|
|
4319
3194
|
<tool_input_branch_name>${params.branchName}</tool_input_branch_name>${params.context ? `
|
|
@@ -4346,7 +3221,7 @@ ${output}`);
|
|
|
4346
3221
|
};
|
|
4347
3222
|
|
|
4348
3223
|
// src/AiTool/generateProjectConfig.ts
|
|
4349
|
-
var
|
|
3224
|
+
var prompt4 = `
|
|
4350
3225
|
Role: Analyzer agent
|
|
4351
3226
|
Goal: Produce a valid polkacodes YAML configuration for the project.
|
|
4352
3227
|
|
|
@@ -4393,7 +3268,7 @@ excludeFiles: # only files likely to hold secrets
|
|
|
4393
3268
|
var generateProjectConfig_default = {
|
|
4394
3269
|
name: "generateProjectConfig",
|
|
4395
3270
|
description: "Analyzes project files to generate polkacodes config sections",
|
|
4396
|
-
prompt:
|
|
3271
|
+
prompt: prompt4,
|
|
4397
3272
|
formatInput: () => {
|
|
4398
3273
|
return "";
|
|
4399
3274
|
},
|
|
@@ -4404,14 +3279,19 @@ var generateProjectConfig_default = {
|
|
|
4404
3279
|
};
|
|
4405
3280
|
|
|
4406
3281
|
// src/AiTool/index.ts
|
|
4407
|
-
var executeTool = async (definition, ai, params) => {
|
|
4408
|
-
const
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
3282
|
+
var executeTool = async (definition, ai, params, usageMeter) => {
|
|
3283
|
+
const resp = await generateText({
|
|
3284
|
+
model: ai,
|
|
3285
|
+
system: definition.prompt,
|
|
3286
|
+
messages: [
|
|
3287
|
+
{
|
|
3288
|
+
role: "user",
|
|
3289
|
+
content: definition.formatInput(params)
|
|
3290
|
+
}
|
|
3291
|
+
]
|
|
3292
|
+
});
|
|
3293
|
+
usageMeter.addUsage(ai, resp);
|
|
3294
|
+
return definition.parseOutput(resp.text);
|
|
4415
3295
|
};
|
|
4416
3296
|
var executeAgentTool = async (definition, agent, params) => {
|
|
4417
3297
|
if (!definition.agent) {
|
|
@@ -4428,8 +3308,8 @@ var executeAgentTool = async (definition, agent, params) => {
|
|
|
4428
3308
|
throw new Error(`Tool execution failed: ${exitReason.type}`);
|
|
4429
3309
|
};
|
|
4430
3310
|
var makeTool = (definition) => {
|
|
4431
|
-
return async (ai, params) => {
|
|
4432
|
-
return executeTool(definition, ai, params);
|
|
3311
|
+
return async (ai, params, usageMeter) => {
|
|
3312
|
+
return executeTool(definition, ai, params, usageMeter);
|
|
4433
3313
|
};
|
|
4434
3314
|
};
|
|
4435
3315
|
var makeAgentTool = (definition) => {
|
|
@@ -4443,13 +3323,11 @@ var generateProjectConfig = makeAgentTool(generateProjectConfig_default);
|
|
|
4443
3323
|
var createNewProject = makeAgentTool(createNewProject_default);
|
|
4444
3324
|
export {
|
|
4445
3325
|
AgentBase,
|
|
4446
|
-
AiServiceBase,
|
|
4447
|
-
AiServiceProvider,
|
|
4448
3326
|
AnalyzerAgent,
|
|
4449
3327
|
ArchitectAgent,
|
|
4450
3328
|
CodeFixerAgent,
|
|
4451
3329
|
CoderAgent,
|
|
4452
|
-
|
|
3330
|
+
EnableCachePolicy,
|
|
4453
3331
|
MockProvider,
|
|
4454
3332
|
MultiAgent,
|
|
4455
3333
|
PermissionLevel,
|
|
@@ -4462,8 +3340,6 @@ export {
|
|
|
4462
3340
|
allAgents,
|
|
4463
3341
|
allTools_exports as allTools,
|
|
4464
3342
|
analyzerAgentInfo,
|
|
4465
|
-
anthropicDefaultModelId,
|
|
4466
|
-
anthropicModels,
|
|
4467
3343
|
architectAgentInfo,
|
|
4468
3344
|
askFollowupQuestion_default as askFollowupQuestion,
|
|
4469
3345
|
attemptCompletion_default as attemptCompletion,
|
|
@@ -4472,12 +3348,8 @@ export {
|
|
|
4472
3348
|
coderAgentInfo,
|
|
4473
3349
|
configSchema,
|
|
4474
3350
|
createNewProject,
|
|
4475
|
-
createService,
|
|
4476
3351
|
customInstructions,
|
|
4477
3352
|
customScripts,
|
|
4478
|
-
deepSeekDefaultModelId,
|
|
4479
|
-
deepSeekModels,
|
|
4480
|
-
defaultModels,
|
|
4481
3353
|
delegate_default as delegate,
|
|
4482
3354
|
executeAgentTool,
|
|
4483
3355
|
executeCommand_default as executeCommand,
|
|
@@ -4486,18 +3358,11 @@ export {
|
|
|
4486
3358
|
generateGitCommitMessage,
|
|
4487
3359
|
generateGithubPullRequestDetails,
|
|
4488
3360
|
generateProjectConfig,
|
|
4489
|
-
getArray,
|
|
4490
3361
|
getAvailableTools,
|
|
4491
|
-
getBoolean,
|
|
4492
|
-
getInt,
|
|
4493
|
-
getString,
|
|
4494
|
-
getStringArray,
|
|
4495
3362
|
handOver_default as handOver,
|
|
4496
3363
|
listFiles_default as listFiles,
|
|
4497
3364
|
makeAgentTool,
|
|
4498
3365
|
makeTool,
|
|
4499
|
-
modelInfos,
|
|
4500
|
-
openAiModelInfoSaneDefaults,
|
|
4501
3366
|
parseAssistantMessage,
|
|
4502
3367
|
readFile_default as readFile,
|
|
4503
3368
|
removeFile_default as removeFile,
|
|
@@ -4508,6 +3373,5 @@ export {
|
|
|
4508
3373
|
searchFiles_default as searchFiles,
|
|
4509
3374
|
systemInformation,
|
|
4510
3375
|
toolUsePrompt,
|
|
4511
|
-
updateKnowledge_default as updateKnowledge,
|
|
4512
3376
|
writeToFile_default as writeToFile
|
|
4513
3377
|
};
|