@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/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/AiService/AiServiceBase.ts
8
- var AiServiceBase = class {
9
- usageMeter;
10
- options;
11
- #abortController;
12
- constructor(options) {
13
- this.options = options;
14
- this.usageMeter = options.usageMeter;
15
- }
16
- abort() {
17
- this.#abortController?.abort();
18
- }
19
- async *send(systemPrompt, messages) {
20
- this.usageMeter.checkLimit();
21
- this.usageMeter.incrementMessageCount();
22
- this.#abortController = new AbortController();
23
- const stream = this.sendImpl(systemPrompt, messages, this.#abortController.signal);
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
- return openAiMessages;
483
- }
484
-
485
- // src/AiService/DeepSeekService.ts
486
- var DeepSeekService = class extends AiServiceBase {
487
- #client;
488
- model;
489
- constructor(options) {
490
- super(options);
491
- this.#client = new OpenAI({
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
- if (delta?.content) {
527
- yield {
528
- type: "text",
529
- text: delta.content
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
- if (chunk.usage) {
533
- yield {
534
- type: "usage",
535
- // deepseek reports total input AND cache reads/writes, see context caching: https://api-docs.deepseek.com/guides/kv_cache
536
- // where the input tokens is the sum of the cache hits/misses, while anthropic reports them as separate tokens.
537
- // This is important to know for
538
- // 1) context management truncation algorithm, and
539
- // 2) cost calculation (NOTE: we report both input and cache stats but for now set input price to 0 since all the cost calculation will be done using cache hits/misses)
540
- inputTokens: chunk.usage.prompt_tokens,
541
- outputTokens: chunk.usage.completion_tokens,
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
- // src/AiService/OllamaService.ts
551
- import OpenAI2 from "openai";
552
- var OllamaService = class extends AiServiceBase {
553
- #client;
554
- model;
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
- // src/AiService/OpenRouterService.ts
594
- import OpenAI3 from "openai";
595
- var OpenRouterService = class extends AiServiceBase {
596
- #client;
597
- #apiKey;
598
- #options;
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
- fetch(`https://openrouter.ai/api/v1/models/${this.model.id}/endpoints`).then((res) => res.json()).then((data) => {
627
- this.#modelProviderInfo = data.data;
628
- });
629
- }
630
- async *sendImpl(systemPrompt, messages, signal) {
631
- const openAiMessages = [
632
- { role: "system", content: systemPrompt },
633
- ...convertToOpenAiMessages(messages)
634
- ];
635
- const cacheControl = this.#options.enableCache ? { type: "ephemeral" } : void 0;
636
- if (this.model.id.startsWith("anthropic/claude")) {
637
- openAiMessages[0] = {
638
- role: "system",
639
- content: [
640
- {
641
- type: "text",
642
- text: systemPrompt,
643
- // @ts-ignore-next-line
644
- cache_control: cacheControl
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.#messageCount >= this.maxMessageCount;
805
- const cost = this.#usage.totalCost >= this.maxCost;
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
- maxMessageCount: this.maxMessageCount,
113
+ maxMessages: this.#maxMessages,
809
114
  cost,
810
- maxCost: this.maxCost,
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.maxMessageCount}, cost: ${result.cost}/${result.maxCost}`
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.#usage, messageCount: this.#messageCount };
130
+ return { ...this.#totals, messageCount: this.#calls };
827
131
  }
132
+ /** Print a concise usage summary to console. */
828
133
  printUsage() {
829
- const { inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens } = this.#usage;
830
- const allTokensZero = inputTokens === 0 && outputTokens === 0 && cacheReadTokens === 0 && cacheWriteTokens === 0;
831
- console.log("Usages:");
832
- if (!allTokensZero) {
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
- // src/AiService/index.ts
843
- var AiServiceProvider = /* @__PURE__ */ ((AiServiceProvider2) => {
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
- name: "questions",
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 = getArray(args, "questions");
1193
- if (!questions || questions.length === 0) {
288
+ const { questions } = toolInfo.parameters.parse(args);
289
+ if (questions.length === 0) {
1194
290
  return {
1195
- type: "Error" /* Error */,
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 prompt6 = getString(question, "prompt");
1202
- const options = getArray(question, "options", []);
1203
- const answer = await provider.askFollowupQuestion(prompt6, options);
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
- name: "result",
1229
- description: "The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.",
1230
- required: true,
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 result = getString(args, "result");
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
- name: "agent_name",
1277
- description: "The name of the agent to delegate the task to",
1278
- required: true,
1279
- usageValue: "Name of the target agent"
1280
- },
1281
- {
1282
- name: "task",
1283
- description: "The task to be completed by the target agent",
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: "agent_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 agentName = getString(args, "agent_name");
1327
- const task = getString(args, "task");
1328
- const context = getString(args, "context", void 0);
1329
- const files = getStringArray(args, "files", []);
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
- name: "command",
1354
- description: "The exact command to run (valid for the current OS). It must be correctly formatted and free of harmful instructions.",
1355
- required: true,
1356
- usageValue: "your-command-here"
1357
- },
1358
- {
1359
- name: "requires_approval",
1360
- description: "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).",
1361
- required: false,
1362
- usageValue: "true | false"
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: "requires_approval", value: "false" }
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 = getString(args, "command");
1384
- const requiresApproval = getBoolean(args, "requires_approval", false);
1385
- const result = await provider.executeCommand?.(command, requiresApproval);
1386
- const message = `<command>${command}</command>
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
- if (result.exitCode === 0) {
484
+ if (result.exitCode === 0) {
485
+ return {
486
+ type: "Reply" /* Reply */,
487
+ message
488
+ };
489
+ }
1395
490
  return {
1396
- type: "Reply" /* Reply */,
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
- name: "url",
1421
- description: "One or more URLs to fetch, separated by commas if multiple.",
1422
- required: true
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 = getStringArray(args, "url");
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
- var toolInfo6 = {
1497
- name: "list_files",
1498
- 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.",
1499
- parameters: [
1500
- {
1501
- name: "path",
1502
- description: "The path of the directory to list contents for (relative to the current working directory)",
1503
- required: true,
1504
- usageValue: "Directory path here"
1505
- },
1506
- {
1507
- name: "max_count",
1508
- description: "The maximum number of files to list. Default to 2000",
1509
- required: false,
1510
- usageValue: "Maximum number of files to list (optional)"
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: "max_count",
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 = getString(args, "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
- name: "path",
1572
- description: "The path of the file to read",
1573
- required: true,
1574
- usageValue: "Comma separated paths here"
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 = getStringArray(args, "path");
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
- name: "path",
1642
- description: "The path of the file to modify",
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
- required: true,
1673
- usageValue: "Search and replace blocks here"
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
- const path = getString(args, "path");
1796
- const diff = getString(args, "diff");
1797
- const fileContent = await provider.readFile(path);
1798
- if (fileContent == null) {
1799
- return {
1800
- type: "Error" /* Error */,
1801
- message: `<replace_in_file_result path="${path}" status="failed" message="File not found" />`
1802
- };
1803
- }
1804
- const result = replaceInFile(fileContent, diff);
1805
- if (result.status === "no_diff_applied") {
1806
- return {
1807
- type: "Error" /* Error */,
1808
- message: `<replace_in_file_result path="${path}" status="failed" message="Unable to apply changes">
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
- await provider.writeFile(path, result.content);
1814
- if (result.status === "some_diff_applied") {
1815
- return {
1816
- type: "Reply" /* Reply */,
1817
- message: `<replace_in_file_result path="${path}" status="some_diff_applied" applied_count="${result.appliedCount}" total_count="${result.totalCount}">
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
- name: "path",
1843
- description: "The path of the directory to search in (relative to the current working directory). This directory will be recursively searched.",
1844
- required: true,
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
- name: "file_pattern",
1855
- description: '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 (*).',
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: "file_pattern",
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
- return { ...source };
2132
- }
2133
- const output = { ...target };
2134
- for (const key in source) {
2135
- if (key.startsWith("$")) continue;
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: "File operations not available. Cannot update knowledge file."
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
- let newKnowledge;
2152
- try {
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: `<update_knowledge_path>${filePath}</update_knowledge_path><status>Success</status>`
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: "Error" /* Error */,
2208
- message: `Error updating knowledge file: ${error.message}`
1052
+ type: "Invalid" /* Invalid */,
1053
+ message: `Invalid arguments for search_files: ${error}`
2209
1054
  };
2210
1055
  }
2211
1056
  };
2212
- var isAvailable10 = (provider) => {
2213
- return !!provider.readFile && !!provider.writeFile;
1057
+ var isAvailable9 = (provider) => {
1058
+ return !!provider.searchFiles;
2214
1059
  };
2215
- var updateKnowledge_default = {
2216
- ...toolInfo10,
2217
- handler: handler10,
2218
- isAvailable: isAvailable10
1060
+ var searchFiles_default = {
1061
+ ...toolInfo9,
1062
+ handler: handler9,
1063
+ isAvailable: isAvailable9
2219
1064
  };
2220
1065
 
2221
1066
  // src/tools/writeToFile.ts
2222
- var toolInfo11 = {
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 `&lt;`, `&gt;`, or `&amp;`. Also ensure there is no unwanted CDATA tags in the content.",
2225
- parameters: [
2226
- {
2227
- name: "path",
2228
- description: "The path of the file to write to",
2229
- required: true,
2230
- usageValue: "File path here"
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 handler11 = async (provider, args) => {
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 path = getString(args, "path");
2275
- let content = getString(args, "content");
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 isAvailable11 = (provider) => {
1128
+ var isAvailable10 = (provider) => {
2285
1129
  return !!provider.writeFile;
2286
1130
  };
2287
1131
  var writeToFile_default = {
2288
- ...toolInfo11,
2289
- handler: handler11,
2290
- isAvailable: isAvailable11
1132
+ ...toolInfo10,
1133
+ handler: handler10,
1134
+ isAvailable: isAvailable10
2291
1135
  };
2292
1136
 
2293
1137
  // src/tools/handOver.ts
2294
- var toolInfo12 = {
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
- name: "agent_name",
2300
- description: "The name of the agent to hand over the task to",
2301
- required: true,
2302
- usageValue: "Name of the target agent"
2303
- },
2304
- {
2305
- name: "task",
2306
- description: "The task to be completed by the target agent",
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: "agent_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 handler12 = async (_provider, args) => {
2349
- const agentName = getString(args, "agent_name");
2350
- const task = getString(args, "task");
2351
- const context = getString(args, "context", void 0);
2352
- const files = getStringArray(args, "files", []);
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 isAvailable12 = (_provider) => {
1194
+ var isAvailable11 = (_provider) => {
2362
1195
  return true;
2363
1196
  };
2364
1197
  var handOver_default = {
2365
- ...toolInfo12,
2366
- handler: handler12,
2367
- isAvailable: isAvailable12
1198
+ ...toolInfo11,
1199
+ handler: handler11,
1200
+ isAvailable: isAvailable11
2368
1201
  };
2369
1202
 
2370
1203
  // src/tools/removeFile.ts
2371
- var toolInfo13 = {
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
- name: "path",
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 handler13 = async (provider, args) => {
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 path = getString(args, "path");
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 isAvailable13 = (provider) => {
1245
+ var isAvailable12 = (provider) => {
2410
1246
  return !!provider.removeFile;
2411
1247
  };
2412
1248
  var removeFile_default = {
2413
- ...toolInfo13,
2414
- handler: handler13,
2415
- isAvailable: isAvailable13
1249
+ ...toolInfo12,
1250
+ handler: handler12,
1251
+ isAvailable: isAvailable12
2416
1252
  };
2417
1253
 
2418
1254
  // src/tools/renameFile.ts
2419
- var toolInfo14 = {
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
- name: "source_path",
2425
- description: "The current path of the file",
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 handler14 = async (provider, args) => {
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 sourcePath = getString(args, "source_path");
2461
- const targetPath = getString(args, "target_path");
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>${targetPath}</rename_file_path><status>Success</status>`
1291
+ message: `<rename_file_path>${target_path}</rename_file_path><status>Success</status>`
2466
1292
  };
2467
1293
  };
2468
- var isAvailable14 = (provider) => {
1294
+ var isAvailable13 = (provider) => {
2469
1295
  return !!provider.renameFile;
2470
1296
  };
2471
1297
  var renameFile_default = {
2472
- ...toolInfo14,
2473
- handler: handler14,
2474
- isAvailable: isAvailable14
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.ai.abort();
1798
+ if (this.#abortController) {
1799
+ this.#abortController.abort();
1800
+ }
2925
1801
  }
2926
1802
  get parameters() {
2927
- return this.ai.options.parameters;
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(prompt6) {
1814
+ async start(prompt5) {
2939
1815
  this.#callback({ kind: "StartTask" /* StartTask */, agent: this, systemPrompt: this.config.systemPrompt });
2940
- return await this.#processLoop(prompt6);
1816
+ return await this.#processLoop(prompt5);
2941
1817
  }
2942
- async step(prompt6) {
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(prompt6);
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.ai.usageMeter.isLimitExceeded().result) {
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.ai.abort();
1885
+ this.abort();
3004
1886
  }, requestTimeoutSeconds * 1e3);
3005
1887
  }
3006
1888
  };
3007
- const stream = this.ai.send(this.config.systemPrompt, this.#messages);
3008
- try {
3009
- resetTimeout();
3010
- for await (const chunk of stream) {
3011
- resetTimeout();
3012
- switch (chunk.type) {
3013
- case "usage":
3014
- await this.#callback({ kind: "Usage" /* Usage */, agent: this });
3015
- break;
3016
- case "text":
3017
- currentAssistantMessage += chunk.text;
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
- let updatedResponse = response;
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 handler15 = this.handlers[name]?.handler;
3149
- if (!handler15) {
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 handler15(this.config.provider, args);
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.model;
2081
+ return `${this.ai.provider}:${this.ai.modelId}`;
3179
2082
  }
3180
2083
  get usage() {
3181
- return this.ai.usageMeter.usage;
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 prompt6 = await this.#config.getPrompt?.(
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, prompt6);
2663
+ return await this.#startTask(exitReason.agentName, prompt5);
3745
2664
  }
3746
2665
  case "Delegate" /* Delegate */: {
3747
- const prompt6 = await this.#config.getPrompt?.(
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, prompt6);
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 providerModelSchema = z.object({
3811
- provider: z.string().optional(),
3812
- model: z.string().optional(),
3813
- parameters: z.record(z.string(), z.any()).optional()
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: z.object({
3817
- maxFileCount: z.number().int().positive().optional(),
3818
- excludes: z.array(z.string()).optional()
2737
+ initialContext: z15.object({
2738
+ maxFileCount: z15.number().int().positive().optional(),
2739
+ excludes: z15.array(z15.string()).optional()
3819
2740
  }).optional(),
3820
- retryCount: z.number().int().min(0).optional(),
3821
- requestTimeoutSeconds: z.number().int().positive().optional()
2741
+ retryCount: z15.number().int().min(0).optional(),
2742
+ requestTimeoutSeconds: z15.number().int().positive().optional()
3822
2743
  });
3823
- var configSchema = z.object({
3824
- agent: z.string().optional(),
3825
- prices: z.record(
3826
- z.string(),
2744
+ var configSchema = z15.object({
2745
+ agent: z15.string().optional(),
2746
+ prices: z15.record(
2747
+ z15.string(),
3827
2748
  // provider
3828
- z.record(
3829
- z.string(),
2749
+ z15.record(
2750
+ z15.string(),
3830
2751
  // model
3831
- z.object({
3832
- inputPrice: z.number().optional(),
3833
- outputPrice: z.number().optional(),
3834
- cacheWritesPrice: z.number().optional(),
3835
- cacheReadsPrice: z.number().optional()
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: z.record(
3840
- z.string(),
3841
- z.object({
3842
- apiKey: z.string().optional(),
3843
- defaultModel: z.string().optional(),
3844
- defaultParameters: z.record(z.string(), z.any()).optional()
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: z.string().optional(),
3848
- defaultModel: z.string().optional(),
3849
- defaultParameters: z.record(z.string(), z.any()).optional(),
3850
- maxMessageCount: z.number().int().positive().optional(),
3851
- budget: z.number().positive().optional(),
3852
- retryCount: z.number().int().min(0).optional(),
3853
- requestTimeoutSeconds: z.number().int().positive().optional(),
3854
- scripts: z.record(
3855
- z.string(),
3856
- z.string().or(
3857
- z.object({
3858
- command: z.string(),
3859
- description: z.string()
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: z.record(z.string(), agentSchema).optional(),
3864
- commands: z.object({
2785
+ agents: z15.record(z15.string(), agentSchema).optional(),
2786
+ commands: z15.object({
3865
2787
  default: providerModelSchema.optional()
3866
2788
  }).catchall(providerModelSchema).optional(),
3867
- rules: z.array(z.string()).optional().or(z.string()).optional(),
3868
- excludeFiles: z.array(z.string()).optional(),
3869
- policies: z.array(z.string()).optional()
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/KnowledgeManagement.ts
3878
- var prompt = `
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
- var TruncateContextPolicy = (tools) => {
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 totalMessages = messages.length;
4052
- const messagesToKeep = Math.ceil(totalMessages / 2);
4053
- const minKeep = Math.max(2, messagesToKeep);
4054
- if (minKeep >= totalMessages) {
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 keepFromStart = Math.floor(minKeep / 2);
4058
- const keepFromEnd = minKeep - keepFromStart;
4059
- const startMessages = messages.slice(0, keepFromStart);
4060
- const endMessages = messages.slice(-keepFromEnd);
4061
- const truncatedCount = totalMessages - minKeep;
4062
- const truncatedMessages = [
4063
- ...startMessages,
4064
- // Add a message explaining truncation
4065
- {
4066
- role: "user",
4067
- content: `Note: ${truncatedCount} messages were truncated from the middle to prevent context overflow.`
4068
- },
4069
- ...endMessages
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 prompt2 = `You are an AiTool designed to assist users in creating new projects. Follow these guidelines:
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: prompt2,
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 prompt3 = `
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: prompt3,
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 prompt4 = `
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: prompt4,
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 prompt5 = `
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: prompt5,
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 { response, usage } = await ai.request(definition.prompt, [
4409
- { role: "user", content: definition.formatInput(params) }
4410
- ]);
4411
- return {
4412
- response: definition.parseOutput(response),
4413
- usage
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
- KnowledgeManagementPolicy,
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
  };