@polka-codes/core 0.9.1 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,176 +4,6 @@ var __export = (target, all) => {
4
4
  __defProp(target, name, { get: all[name], enumerable: true });
5
5
  };
6
6
 
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
- };
24
- }
25
- }
26
- this.#modelInfos = infos;
27
- this.#maxMessages = opts.maxMessages ?? 1e3;
28
- this.#maxCost = opts.maxCost ?? 100;
29
- }
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
40
- };
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
51
- };
52
- }
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
63
- };
64
- }
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
74
- };
75
- }
76
- }
77
- }
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
86
- };
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. */
108
- isLimitExceeded() {
109
- const messageCount = this.#maxMessages !== void 0 && this.#calls >= this.#maxMessages;
110
- const cost = this.#maxCost !== void 0 && this.#totals.cost >= this.#maxCost;
111
- return {
112
- messageCount,
113
- maxMessages: this.#maxMessages,
114
- cost,
115
- maxCost: this.#maxCost,
116
- result: messageCount || cost
117
- };
118
- }
119
- /** Same as isLimitExceeded but throws an error if a limit is hit. */
120
- checkLimit() {
121
- const result = this.isLimitExceeded();
122
- if (result.result) {
123
- throw new Error(
124
- `Usage limit exceeded. Message count: ${result.messageCount}/${result.maxMessages}, cost: ${result.cost}/${result.maxCost}`
125
- );
126
- }
127
- }
128
- /** Getter for the aggregated totals (immutable copy). */
129
- get usage() {
130
- return { ...this.#totals, messageCount: this.#calls };
131
- }
132
- /** Print a concise usage summary to console. */
133
- printUsage() {
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
- );
138
- }
139
- onFinishHandler(llm) {
140
- return (evt) => {
141
- this.addUsage(llm, evt);
142
- };
143
- }
144
- };
145
-
146
- // src/tools/provider.ts
147
- var MockProvider = class {
148
- async readFile(path) {
149
- return "mock content";
150
- }
151
- async writeFile(path, content) {
152
- return;
153
- }
154
- async removeFile(path) {
155
- return;
156
- }
157
- async renameFile(sourcePath, targetPath) {
158
- return;
159
- }
160
- async listFiles(path, recursive, maxCount) {
161
- return [["mock-file.txt"], false];
162
- }
163
- async searchFiles(path, regex, filePattern) {
164
- return ["mock-file.txt"];
165
- }
166
- async executeCommand(command, needApprove) {
167
- return { stdout: "mock output", stderr: "", exitCode: 0 };
168
- }
169
- async askFollowupQuestion(question, options) {
170
- return "mock answer";
171
- }
172
- async attemptCompletion(result) {
173
- return "mock completion";
174
- }
175
- };
176
-
177
7
  // src/tools/allTools.ts
178
8
  var allTools_exports = {};
179
9
  __export(allTools_exports, {
@@ -225,35 +55,27 @@ var toolInfo = {
225
55
  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.",
226
56
  parameters: z.object({
227
57
  questions: z.array(questionObject).describe("One or more follow-up questions you need answered before you can continue.").meta({ usageValue: "questions here" })
228
- }),
229
- examples: [
230
- {
231
- description: "Single clarifying question (no options)",
232
- parameters: [
233
- {
234
- name: "questions",
235
- value: { prompt: "What is the target deployment environment?" }
58
+ }).meta({
59
+ examples: [
60
+ {
61
+ description: "Single clarifying question (no options)",
62
+ input: {
63
+ questions: { prompt: "What is the target deployment environment?" }
236
64
  }
237
- ]
238
- },
239
- {
240
- description: "Single question with multiple-choice options",
241
- parameters: [
242
- {
243
- name: "questions",
244
- value: {
65
+ },
66
+ {
67
+ description: "Single question with multiple-choice options",
68
+ input: {
69
+ questions: {
245
70
  prompt: "Which frontend framework are you using?",
246
71
  options: ["React", "Angular", "Vue", "Svelte"]
247
72
  }
248
73
  }
249
- ]
250
- },
251
- {
252
- description: "Two related questions in one call",
253
- parameters: [
254
- {
255
- name: "questions",
256
- value: [
74
+ },
75
+ {
76
+ description: "Two related questions in one call",
77
+ input: {
78
+ questions: [
257
79
  { prompt: "What type of application are you building?" },
258
80
  {
259
81
  prompt: "Preferred programming language?",
@@ -261,21 +83,18 @@ var toolInfo = {
261
83
  }
262
84
  ]
263
85
  }
264
- ]
265
- },
266
- {
267
- description: "Binary (yes/no) confirmation",
268
- parameters: [
269
- {
270
- name: "questions",
271
- value: {
86
+ },
87
+ {
88
+ description: "Binary (yes/no) confirmation",
89
+ input: {
90
+ questions: {
272
91
  prompt: "Is it acceptable to refactor existing tests to improve performance?",
273
92
  options: ["Yes", "No"]
274
93
  }
275
94
  }
276
- ]
277
- }
278
- ],
95
+ }
96
+ ]
97
+ }),
279
98
  permissionLevel: 0 /* None */
280
99
  };
281
100
  var handler = async (provider, args) => {
@@ -294,9 +113,9 @@ var handler = async (provider, args) => {
294
113
  }
295
114
  const answers = [];
296
115
  for (const question of questions) {
297
- const { prompt: prompt5, options } = question;
298
- const answer = await provider.askFollowupQuestion(prompt5, options);
299
- answers.push(`<ask_followup_question_answer question="${prompt5}">
116
+ const { prompt: prompt6, options } = question;
117
+ const answer = await provider.askFollowupQuestion(prompt6, options);
118
+ answers.push(`<ask_followup_question_answer question="${prompt6}">
300
119
  ${answer}
301
120
  </ask_followup_question_answer>`);
302
121
  }
@@ -323,18 +142,16 @@ var toolInfo2 = {
323
142
  result: z2.string().describe(
324
143
  "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
144
  ).meta({ usageValue: "Your final result description here" })
326
- }),
327
- examples: [
328
- {
329
- description: "Request to present the result of the task",
330
- parameters: [
331
- {
332
- name: "result",
333
- value: "Your final result description here"
145
+ }).meta({
146
+ examples: [
147
+ {
148
+ description: "Request to present the result of the task",
149
+ input: {
150
+ result: "Your final result description here"
334
151
  }
335
- ]
336
- }
337
- ],
152
+ }
153
+ ]
154
+ }),
338
155
  permissionLevel: 0 /* None */
339
156
  };
340
157
  var handler2 = async (provider, args) => {
@@ -358,7 +175,7 @@ var handler2 = async (provider, args) => {
358
175
  message: `<user_message>${moreMessage}</user_message>`
359
176
  };
360
177
  };
361
- var isAvailable2 = (provider) => {
178
+ var isAvailable2 = (_provider) => {
362
179
  return true;
363
180
  };
364
181
  var attemptCompletion_default = {
@@ -381,30 +198,19 @@ var toolInfo3 = {
381
198
  const values = Array.isArray(val) ? val : [val];
382
199
  return values.flatMap((i) => typeof i === "string" ? i.split(",") : []).filter((s) => s.length > 0);
383
200
  }, z3.array(z3.string())).optional().describe("The files relevant to the task. Comma separated paths").meta({ usageValue: "Relevant files" })
384
- }),
385
- examples: [
386
- {
387
- description: "Delegate a code analysis task to the analyzer agent",
388
- parameters: [
389
- {
390
- name: "agentName",
391
- value: "analyzer"
392
- },
393
- {
394
- name: "task",
395
- value: "Analyze the authentication implementation"
396
- },
397
- {
398
- name: "context",
399
- value: "Need to understand the security implications of the current auth system"
400
- },
401
- {
402
- name: "files",
403
- value: "src/auth/login.ts,src/auth/types.ts"
201
+ }).meta({
202
+ examples: [
203
+ {
204
+ description: "Delegate a code analysis task to the analyzer agent",
205
+ input: {
206
+ agentName: "analyzer",
207
+ task: "Analyze the authentication implementation",
208
+ context: "Need to understand the security implications of the current auth system",
209
+ files: "src/auth/login.ts,src/auth/types.ts"
404
210
  }
405
- ]
406
- }
407
- ],
211
+ }
212
+ ]
213
+ }),
408
214
  permissionLevel: 0 /* None */
409
215
  };
410
216
  var handler3 = async (_provider, args) => {
@@ -450,16 +256,17 @@ var toolInfo4 = {
450
256
  }, z4.boolean().optional().default(false)).describe(
451
257
  "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
258
  ).meta({ usageValue: "true | false" })
259
+ }).meta({
260
+ examples: [
261
+ {
262
+ description: "Make a build",
263
+ input: {
264
+ command: "npm run build",
265
+ requiresApproval: "false"
266
+ }
267
+ }
268
+ ]
453
269
  }),
454
- examples: [
455
- {
456
- description: "Make a build",
457
- parameters: [
458
- { name: "command", value: "npm run build" },
459
- { name: "requiresApproval", value: "false" }
460
- ]
461
- }
462
- ],
463
270
  permissionLevel: 3 /* Arbitrary */
464
271
  };
465
272
  var handler4 = async (provider, args) => {
@@ -518,36 +325,28 @@ var toolInfo5 = {
518
325
  const values = Array.isArray(val) ? val : [val];
519
326
  return values.flatMap((i) => typeof i === "string" ? i.split(",") : []).filter((s) => s.length > 0);
520
327
  }, z5.array(z5.string())).describe("One or more URLs to fetch, separated by commas if multiple.").meta({ usageValue: "url" })
521
- }),
522
- examples: [
523
- {
524
- description: "Fetch a single webpage",
525
- parameters: [
526
- {
527
- name: "url",
528
- value: "https://example.com"
328
+ }).meta({
329
+ examples: [
330
+ {
331
+ description: "Fetch a single webpage",
332
+ input: {
333
+ url: "https://example.com"
529
334
  }
530
- ]
531
- },
532
- {
533
- description: "Fetch multiple webpages",
534
- parameters: [
535
- {
536
- name: "url",
537
- value: "https://example.com,https://developer.mozilla.org/en-US/docs/Web/HTTP"
335
+ },
336
+ {
337
+ description: "Fetch multiple webpages",
338
+ input: {
339
+ url: "https://example.com,https://developer.mozilla.org/en-US/docs/Web/HTTP"
538
340
  }
539
- ]
540
- },
541
- {
542
- description: "Fetch a raw file from GitHub",
543
- parameters: [
544
- {
545
- name: "url",
546
- value: "https://raw.githubusercontent.com/user/repo/main/README.md"
341
+ },
342
+ {
343
+ description: "Fetch a raw file from GitHub",
344
+ input: {
345
+ url: "https://raw.githubusercontent.com/user/repo/main/README.md"
547
346
  }
548
- ]
549
- }
550
- ],
347
+ }
348
+ ]
349
+ }),
551
350
  permissionLevel: 1 /* Read */
552
351
  };
553
352
  var handler5 = async (provider, args) => {
@@ -589,109 +388,154 @@ var fetchUrl_default = {
589
388
  isAvailable: isAvailable5
590
389
  };
591
390
 
592
- // src/tools/listFiles.ts
391
+ // src/tools/handOver.ts
593
392
  import { z as z6 } from "zod";
594
393
  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.",
394
+ name: "hand_over",
395
+ description: "Hand over the current task to another agent to complete. This tool MUST NOT to be used with any other tool.",
597
396
  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;
397
+ agentName: z6.string().describe("The name of the agent to hand over the task to").meta({ usageValue: "Name of the target agent" }),
398
+ task: z6.string().describe("The task to be completed by the target agent").meta({ usageValue: "Task description" }),
399
+ context: z6.string().describe("The context information for the task").meta({ usageValue: "Context information" }),
400
+ files: z6.preprocess((val) => {
401
+ if (!val) return [];
402
+ const values = Array.isArray(val) ? val : [val];
403
+ return values.flatMap((i) => typeof i === "string" ? i.split(",") : []).filter((s) => s.length > 0);
404
+ }, z6.array(z6.string())).optional().describe("The files relevant to the task. Comma separated paths").meta({ usageValue: "Relevant files" })
405
+ }).meta({
406
+ examples: [
407
+ {
408
+ description: "Hand over a coding task to the coder agent",
409
+ input: {
410
+ agentName: "coder",
411
+ task: "Implement the login feature",
412
+ context: "We need a secure login system with email and password",
413
+ files: "src/auth/login.ts,src/auth/types.ts"
414
+ }
605
415
  }
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)" })
416
+ ]
608
417
  }),
609
- examples: [
610
- {
611
- description: "Request to list files",
612
- parameters: [
613
- {
614
- name: "path",
615
- value: "src"
616
- },
617
- {
618
- name: "maxCount",
619
- value: "100"
620
- }
621
- ]
622
- }
623
- ],
624
- permissionLevel: 1 /* Read */
418
+ permissionLevel: 0 /* None */
625
419
  };
626
- var handler6 = async (provider, args) => {
627
- if (!provider.listFiles) {
420
+ var handler6 = async (_provider, args) => {
421
+ const parsed = toolInfo6.parameters.safeParse(args);
422
+ if (!parsed.success) {
628
423
  return {
629
- type: "Error" /* Error */,
630
- message: "Not possible to list files. Abort."
424
+ type: "Invalid" /* Invalid */,
425
+ message: `Invalid arguments for hand_over: ${parsed.error.message}`
631
426
  };
632
427
  }
633
- const { path, maxCount, recursive } = toolInfo6.parameters.parse(args);
634
- const [files, limitReached] = await provider.listFiles(path, recursive, maxCount);
428
+ const { agentName, task, context, files } = parsed.data;
635
429
  return {
636
- type: "Reply" /* Reply */,
637
- message: `<list_files_path>${path}</list_files_path>
638
- <list_files_files>
639
- ${files.join("\n")}
640
- </list_files_files>
641
- <list_files_truncated>${limitReached}</list_files_truncated>`
430
+ type: "HandOver" /* HandOver */,
431
+ agentName,
432
+ task,
433
+ context,
434
+ files: files ?? []
642
435
  };
643
436
  };
644
- var isAvailable6 = (provider) => {
645
- return !!provider.listFiles;
437
+ var isAvailable6 = (_provider) => {
438
+ return true;
646
439
  };
647
- var listFiles_default = {
440
+ var handOver_default = {
648
441
  ...toolInfo6,
649
442
  handler: handler6,
650
443
  isAvailable: isAvailable6
651
444
  };
652
445
 
653
- // src/tools/readFile.ts
446
+ // src/tools/listFiles.ts
654
447
  import { z as z7 } from "zod";
655
448
  var toolInfo7 = {
449
+ name: "list_files",
450
+ 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.",
451
+ parameters: z7.object({
452
+ path: z7.string().describe("The path of the directory to list contents for (relative to the current working directory)").meta({ usageValue: "Directory path here" }),
453
+ maxCount: z7.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)" }),
454
+ recursive: z7.preprocess((val) => {
455
+ if (typeof val === "string") {
456
+ const lower = val.toLowerCase();
457
+ if (lower === "false") return false;
458
+ if (lower === "true") return true;
459
+ }
460
+ return val;
461
+ }, z7.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)" })
462
+ }).meta({
463
+ examples: [
464
+ {
465
+ description: "Request to list files",
466
+ input: {
467
+ path: "src",
468
+ maxCount: "100"
469
+ }
470
+ }
471
+ ]
472
+ }),
473
+ permissionLevel: 1 /* Read */
474
+ };
475
+ var handler7 = async (provider, args) => {
476
+ if (!provider.listFiles) {
477
+ return {
478
+ type: "Error" /* Error */,
479
+ message: "Not possible to list files. Abort."
480
+ };
481
+ }
482
+ const { path, maxCount, recursive } = toolInfo7.parameters.parse(args);
483
+ const [files, limitReached] = await provider.listFiles(path, recursive, maxCount);
484
+ return {
485
+ type: "Reply" /* Reply */,
486
+ message: `<list_files_path>${path}</list_files_path>
487
+ <list_files_files>
488
+ ${files.join("\n")}
489
+ </list_files_files>
490
+ <list_files_truncated>${limitReached}</list_files_truncated>`
491
+ };
492
+ };
493
+ var isAvailable7 = (provider) => {
494
+ return !!provider.listFiles;
495
+ };
496
+ var listFiles_default = {
497
+ ...toolInfo7,
498
+ handler: handler7,
499
+ isAvailable: isAvailable7
500
+ };
501
+
502
+ // src/tools/readFile.ts
503
+ import { z as z8 } from "zod";
504
+ var toolInfo8 = {
656
505
  name: "read_file",
657
506
  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.",
658
- parameters: z7.object({
659
- path: z7.preprocess((val) => {
507
+ parameters: z8.object({
508
+ path: z8.preprocess((val) => {
660
509
  if (!val) return [];
661
510
  const values = Array.isArray(val) ? val : [val];
662
511
  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
- }),
665
- examples: [
666
- {
667
- description: "Request to read the contents of a file",
668
- parameters: [
669
- {
670
- name: "path",
671
- value: "src/main.js"
512
+ }, z8.array(z8.string())).describe("The path of the file to read").meta({ usageValue: "Comma separated paths here" })
513
+ }).meta({
514
+ examples: [
515
+ {
516
+ description: "Request to read the contents of a file",
517
+ input: {
518
+ path: "src/main.js"
672
519
  }
673
- ]
674
- },
675
- {
676
- description: "Request to read multiple files",
677
- parameters: [
678
- {
679
- name: "path",
680
- value: "src/main.js,src/index.js"
520
+ },
521
+ {
522
+ description: "Request to read multiple files",
523
+ input: {
524
+ path: "src/main.js,src/index.js"
681
525
  }
682
- ]
683
- }
684
- ],
526
+ }
527
+ ]
528
+ }),
685
529
  permissionLevel: 1 /* Read */
686
530
  };
687
- var handler7 = async (provider, args) => {
531
+ var handler8 = async (provider, args) => {
688
532
  if (!provider.readFile) {
689
533
  return {
690
534
  type: "Error" /* Error */,
691
535
  message: "Not possible to read file. Abort."
692
536
  };
693
537
  }
694
- const { path: paths } = toolInfo7.parameters.parse(args);
538
+ const { path: paths } = toolInfo8.parameters.parse(args);
695
539
  const resp = [];
696
540
  for (const path of paths) {
697
541
  const fileContent = await provider.readFile(path);
@@ -711,17 +555,110 @@ var handler7 = async (provider, args) => {
711
555
  message: resp.join("\n")
712
556
  };
713
557
  };
714
- var isAvailable7 = (provider) => {
558
+ var isAvailable8 = (provider) => {
715
559
  return !!provider.readFile;
716
560
  };
717
561
  var readFile_default = {
718
- ...toolInfo7,
719
- handler: handler7,
720
- isAvailable: isAvailable7
562
+ ...toolInfo8,
563
+ handler: handler8,
564
+ isAvailable: isAvailable8
565
+ };
566
+
567
+ // src/tools/removeFile.ts
568
+ import { z as z9 } from "zod";
569
+ var toolInfo9 = {
570
+ name: "remove_file",
571
+ description: "Request to remove a file at the specified path.",
572
+ parameters: z9.object({
573
+ path: z9.string().describe("The path of the file to remove").meta({ usageValue: "File path here" })
574
+ }).meta({
575
+ examples: [
576
+ {
577
+ description: "Request to remove a file",
578
+ input: {
579
+ path: "src/main.js"
580
+ }
581
+ }
582
+ ]
583
+ }),
584
+ permissionLevel: 2 /* Write */
585
+ };
586
+ var handler9 = async (provider, args) => {
587
+ if (!provider.removeFile) {
588
+ return {
589
+ type: "Error" /* Error */,
590
+ message: "Not possible to remove file. Abort."
591
+ };
592
+ }
593
+ const parsed = toolInfo9.parameters.safeParse(args);
594
+ if (!parsed.success) {
595
+ return {
596
+ type: "Invalid" /* Invalid */,
597
+ message: `Invalid arguments for remove_file: ${parsed.error.message}`
598
+ };
599
+ }
600
+ const { path } = parsed.data;
601
+ await provider.removeFile(path);
602
+ return {
603
+ type: "Reply" /* Reply */,
604
+ message: `<remove_file_path>${path}</remove_file_path><status>Success</status>`
605
+ };
606
+ };
607
+ var isAvailable9 = (provider) => {
608
+ return !!provider.removeFile;
609
+ };
610
+ var removeFile_default = {
611
+ ...toolInfo9,
612
+ handler: handler9,
613
+ isAvailable: isAvailable9
614
+ };
615
+
616
+ // src/tools/renameFile.ts
617
+ import { z as z10 } from "zod";
618
+ var toolInfo10 = {
619
+ name: "rename_file",
620
+ description: "Request to rename a file from source path to target path.",
621
+ parameters: z10.object({
622
+ source_path: z10.string().describe("The current path of the file").meta({ usageValue: "Source file path here" }),
623
+ target_path: z10.string().describe("The new path for the file").meta({ usageValue: "Target file path here" })
624
+ }).meta({
625
+ examples: [
626
+ {
627
+ description: "Request to rename a file",
628
+ input: {
629
+ source_path: "src/old-name.js",
630
+ target_path: "src/new-name.js"
631
+ }
632
+ }
633
+ ]
634
+ }),
635
+ permissionLevel: 2 /* Write */
636
+ };
637
+ var handler10 = async (provider, args) => {
638
+ if (!provider.renameFile) {
639
+ return {
640
+ type: "Error" /* Error */,
641
+ message: "Not possible to rename file. Abort."
642
+ };
643
+ }
644
+ const { source_path, target_path } = toolInfo10.parameters.parse(args);
645
+ await provider.renameFile(source_path, target_path);
646
+ return {
647
+ type: "Reply" /* Reply */,
648
+ message: `<rename_file_path>${target_path}</rename_file_path><status>Success</status>`
649
+ };
650
+ };
651
+ var isAvailable10 = (provider) => {
652
+ return !!provider.renameFile;
653
+ };
654
+ var renameFile_default = {
655
+ ...toolInfo10,
656
+ handler: handler10,
657
+ isAvailable: isAvailable10
721
658
  };
722
659
 
723
660
  // src/tools/replaceInFile.ts
724
- import { z as z8 } from "zod";
661
+ import { z as z11 } from "zod";
725
662
 
726
663
  // src/tools/utils/replaceInFile.ts
727
664
  var replaceInFile = (fileContent, diff) => {
@@ -798,12 +735,12 @@ var replaceInFile = (fileContent, diff) => {
798
735
  };
799
736
 
800
737
  // src/tools/replaceInFile.ts
801
- var toolInfo8 = {
738
+ var toolInfo11 = {
802
739
  name: "replace_in_file",
803
740
  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.",
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(
741
+ parameters: z11.object({
742
+ path: z11.string().describe("The path of the file to modify").meta({ usageValue: "File path here" }),
743
+ diff: z11.string().describe(
807
744
  `One or more SEARCH/REPLACE blocks following this exact format:
808
745
  \`\`\`
809
746
  <<<<<<< SEARCH
@@ -829,18 +766,13 @@ Critical rules:
829
766
  * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
830
767
  * To delete code: Use empty REPLACE section`
831
768
  ).meta({ usageValue: "Search and replace blocks here" })
832
- }),
833
- examples: [
834
- {
835
- description: "Request to replace sections of content in a file",
836
- parameters: [
837
- {
838
- name: "path",
839
- value: "src/main.js"
840
- },
841
- {
842
- name: "diff",
843
- value: `<<<<<<< SEARCH
769
+ }).meta({
770
+ examples: [
771
+ {
772
+ description: "Request to replace sections of content in a file",
773
+ input: {
774
+ path: "src/main.js",
775
+ diff: `<<<<<<< SEARCH
844
776
  import React from 'react';
845
777
  =======
846
778
  import React, { useState } from 'react';
@@ -868,35 +800,23 @@ return (
868
800
  <div>
869
801
  >>>>>>> REPLACE`
870
802
  }
871
- ]
872
- },
873
- {
874
- description: "Request to perform a simple, single-line replacement",
875
- parameters: [
876
- {
877
- name: "path",
878
- value: "src/config.js"
879
- },
880
- {
881
- name: "diff",
882
- value: `<<<<<<< SEARCH
803
+ },
804
+ {
805
+ description: "Request to perform a simple, single-line replacement",
806
+ input: {
807
+ path: "src/config.js",
808
+ diff: `<<<<<<< SEARCH
883
809
  const API_URL = 'https://api.example.com';
884
810
  =======
885
811
  const API_URL = 'https://api.staging.example.com';
886
812
  >>>>>>> REPLACE`
887
813
  }
888
- ]
889
- },
890
- {
891
- description: "Request to add a new function to a file",
892
- parameters: [
893
- {
894
- name: "path",
895
- value: "src/utils.js"
896
- },
897
- {
898
- name: "diff",
899
- value: `<<<<<<< SEARCH
814
+ },
815
+ {
816
+ description: "Request to add a new function to a file",
817
+ input: {
818
+ path: "src/utils.js",
819
+ diff: `<<<<<<< SEARCH
900
820
  function helperA() {
901
821
  // ...
902
822
  }
@@ -910,18 +830,12 @@ function newHelper() {
910
830
  }
911
831
  >>>>>>> REPLACE`
912
832
  }
913
- ]
914
- },
915
- {
916
- description: "Request to delete a block of code from a file",
917
- parameters: [
918
- {
919
- name: "path",
920
- value: "src/app.js"
921
- },
922
- {
923
- name: "diff",
924
- value: `<<<<<<< SEARCH
833
+ },
834
+ {
835
+ description: "Request to delete a block of code from a file",
836
+ input: {
837
+ path: "src/app.js",
838
+ diff: `<<<<<<< SEARCH
925
839
  function oldFeature() {
926
840
  // This is no longer needed
927
841
  }
@@ -929,12 +843,12 @@ function oldFeature() {
929
843
  =======
930
844
  >>>>>>> REPLACE`
931
845
  }
932
- ]
933
- }
934
- ],
846
+ }
847
+ ]
848
+ }),
935
849
  permissionLevel: 2 /* Write */
936
850
  };
937
- var handler8 = async (provider, args) => {
851
+ var handler11 = async (provider, args) => {
938
852
  if (!provider.readFile || !provider.writeFile) {
939
853
  return {
940
854
  type: "Error" /* Error */,
@@ -942,7 +856,7 @@ var handler8 = async (provider, args) => {
942
856
  };
943
857
  }
944
858
  try {
945
- const { path, diff } = toolInfo8.parameters.parse(args);
859
+ const { path, diff } = toolInfo11.parameters.parse(args);
946
860
  const fileContent = await provider.readFile(path);
947
861
  if (fileContent == null) {
948
862
  return {
@@ -979,55 +893,47 @@ var handler8 = async (provider, args) => {
979
893
  };
980
894
  }
981
895
  };
982
- var isAvailable8 = (provider) => {
896
+ var isAvailable11 = (provider) => {
983
897
  return !!provider.readFile && !!provider.writeFile;
984
898
  };
985
899
  var replaceInFile_default = {
986
- ...toolInfo8,
987
- handler: handler8,
988
- isAvailable: isAvailable8
900
+ ...toolInfo11,
901
+ handler: handler11,
902
+ isAvailable: isAvailable11
989
903
  };
990
904
 
991
905
  // src/tools/searchFiles.ts
992
- import { z as z9 } from "zod";
993
- var toolInfo9 = {
906
+ import { z as z12 } from "zod";
907
+ var toolInfo12 = {
994
908
  name: "search_files",
995
909
  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.",
996
- parameters: z9.object({
997
- path: z9.string().describe(
910
+ parameters: z12.object({
911
+ path: z12.string().describe(
998
912
  "The path of the directory to search in (relative to the current working directory). This directory will be recursively searched."
999
913
  ).meta({ usageValue: "Directory path here" }),
1000
- regex: z9.string().describe("The regular expression pattern to search for. Uses Rust regex syntax.").meta({
914
+ regex: z12.string().describe("The regular expression pattern to search for. Uses Rust regex syntax.").meta({
1001
915
  usageValue: "Your regex pattern here"
1002
916
  }),
1003
- filePattern: z9.string().optional().describe(
917
+ filePattern: z12.string().optional().describe(
1004
918
  '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
919
  ).meta({
1006
920
  usageValue: "file pattern here (optional)"
1007
921
  })
1008
- }),
1009
- examples: [
1010
- {
1011
- description: "Request to perform a regex search across files",
1012
- parameters: [
1013
- {
1014
- name: "path",
1015
- value: "src"
1016
- },
1017
- {
1018
- name: "regex",
1019
- value: "^components/"
1020
- },
1021
- {
1022
- name: "filePattern",
1023
- value: "*.ts,*.tsx"
922
+ }).meta({
923
+ examples: [
924
+ {
925
+ description: "Request to perform a regex search across files",
926
+ input: {
927
+ path: "src",
928
+ regex: "^components/",
929
+ filePattern: "*.ts,*.tsx"
1024
930
  }
1025
- ]
1026
- }
1027
- ],
931
+ }
932
+ ]
933
+ }),
1028
934
  permissionLevel: 1 /* Read */
1029
935
  };
1030
- var handler9 = async (provider, args) => {
936
+ var handler12 = async (provider, args) => {
1031
937
  if (!provider.searchFiles) {
1032
938
  return {
1033
939
  type: "Error" /* Error */,
@@ -1035,7 +941,7 @@ var handler9 = async (provider, args) => {
1035
941
  };
1036
942
  }
1037
943
  try {
1038
- const { path, regex, filePattern } = toolInfo9.parameters.parse(args);
944
+ const { path, regex, filePattern } = toolInfo12.parameters.parse(args);
1039
945
  const files = await provider.searchFiles(path, regex, filePattern ?? "*");
1040
946
  return {
1041
947
  type: "Reply" /* Reply */,
@@ -1054,37 +960,32 @@ ${files.join("\n")}
1054
960
  };
1055
961
  }
1056
962
  };
1057
- var isAvailable9 = (provider) => {
963
+ var isAvailable12 = (provider) => {
1058
964
  return !!provider.searchFiles;
1059
965
  };
1060
966
  var searchFiles_default = {
1061
- ...toolInfo9,
1062
- handler: handler9,
1063
- isAvailable: isAvailable9
967
+ ...toolInfo12,
968
+ handler: handler12,
969
+ isAvailable: isAvailable12
1064
970
  };
1065
971
 
1066
972
  // src/tools/writeToFile.ts
1067
- import { z as z10 } from "zod";
1068
- var toolInfo10 = {
973
+ import { z as z13 } from "zod";
974
+ var toolInfo13 = {
1069
975
  name: "write_to_file",
1070
976
  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.",
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(
977
+ parameters: z13.object({
978
+ path: z13.string().describe("The path of the file to write to").meta({ usageValue: "File path here" }),
979
+ content: z13.string().describe(
1074
980
  "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
981
  ).meta({ usageValue: "Your file content here" })
1076
- }),
1077
- examples: [
1078
- {
1079
- description: "Request to write content to a file",
1080
- parameters: [
1081
- {
1082
- name: "path",
1083
- value: "src/main.js"
1084
- },
1085
- {
1086
- name: "content",
1087
- value: `import React from 'react';
982
+ }).meta({
983
+ examples: [
984
+ {
985
+ description: "Request to write content to a file",
986
+ input: {
987
+ path: "src/main.js",
988
+ content: `import React from 'react';
1088
989
 
1089
990
  function App() {
1090
991
  return (
@@ -1097,19 +998,19 @@ function App() {
1097
998
  export default App;
1098
999
  `
1099
1000
  }
1100
- ]
1101
- }
1102
- ],
1001
+ }
1002
+ ]
1003
+ }),
1103
1004
  permissionLevel: 2 /* Write */
1104
1005
  };
1105
- var handler10 = async (provider, args) => {
1006
+ var handler13 = async (provider, args) => {
1106
1007
  if (!provider.writeFile) {
1107
1008
  return {
1108
1009
  type: "Error" /* Error */,
1109
1010
  message: "Not possible to write file. Abort."
1110
1011
  };
1111
1012
  }
1112
- const parsed = toolInfo10.parameters.safeParse(args);
1013
+ const parsed = toolInfo13.parameters.safeParse(args);
1113
1014
  if (!parsed.success) {
1114
1015
  return {
1115
1016
  type: "Invalid" /* Invalid */,
@@ -1125,179 +1026,44 @@ var handler10 = async (provider, args) => {
1125
1026
  message: `<write_to_file_path>${path}</write_to_file_path><status>Success</status>`
1126
1027
  };
1127
1028
  };
1128
- var isAvailable10 = (provider) => {
1029
+ var isAvailable13 = (provider) => {
1129
1030
  return !!provider.writeFile;
1130
1031
  };
1131
1032
  var writeToFile_default = {
1132
- ...toolInfo10,
1133
- handler: handler10,
1134
- isAvailable: isAvailable10
1033
+ ...toolInfo13,
1034
+ handler: handler13,
1035
+ isAvailable: isAvailable13
1135
1036
  };
1136
1037
 
1137
- // src/tools/handOver.ts
1138
- import { z as z11 } from "zod";
1139
- var toolInfo11 = {
1140
- name: "hand_over",
1141
- description: "Hand over the current task to another agent to complete. This tool MUST NOT to be used with any other tool.",
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
- }),
1152
- examples: [
1153
- {
1154
- description: "Hand over a coding task to the coder agent",
1155
- parameters: [
1156
- {
1157
- name: "agentName",
1158
- value: "coder"
1159
- },
1160
- {
1161
- name: "task",
1162
- value: "Implement the login feature"
1163
- },
1164
- {
1165
- name: "context",
1166
- value: "We need a secure login system with email and password"
1167
- },
1168
- {
1169
- name: "files",
1170
- value: "src/auth/login.ts,src/auth/types.ts"
1171
- }
1172
- ]
1173
- }
1174
- ],
1175
- permissionLevel: 0 /* None */
1176
- };
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
- };
1038
+ // src/tools/provider.ts
1039
+ var MockProvider = class {
1040
+ async readFile(_path) {
1041
+ return "mock content";
1184
1042
  }
1185
- const { agentName, task, context, files } = parsed.data;
1186
- return {
1187
- type: "HandOver" /* HandOver */,
1188
- agentName,
1189
- task,
1190
- context,
1191
- files: files ?? []
1192
- };
1193
- };
1194
- var isAvailable11 = (_provider) => {
1195
- return true;
1196
- };
1197
- var handOver_default = {
1198
- ...toolInfo11,
1199
- handler: handler11,
1200
- isAvailable: isAvailable11
1201
- };
1202
-
1203
- // src/tools/removeFile.ts
1204
- import { z as z12 } from "zod";
1205
- var toolInfo12 = {
1206
- name: "remove_file",
1207
- description: "Request to remove a file at the specified path.",
1208
- parameters: z12.object({
1209
- path: z12.string().describe("The path of the file to remove").meta({ usageValue: "File path here" })
1210
- }),
1211
- examples: [
1212
- {
1213
- description: "Request to remove a file",
1214
- parameters: [
1215
- {
1216
- name: "path",
1217
- value: "src/main.js"
1218
- }
1219
- ]
1220
- }
1221
- ],
1222
- permissionLevel: 2 /* Write */
1223
- };
1224
- var handler12 = async (provider, args) => {
1225
- if (!provider.removeFile) {
1226
- return {
1227
- type: "Error" /* Error */,
1228
- message: "Not possible to remove file. Abort."
1229
- };
1043
+ async writeFile(_path, _content) {
1044
+ return;
1230
1045
  }
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
- };
1046
+ async removeFile(_path) {
1047
+ return;
1237
1048
  }
1238
- const { path } = parsed.data;
1239
- await provider.removeFile(path);
1240
- return {
1241
- type: "Reply" /* Reply */,
1242
- message: `<remove_file_path>${path}</remove_file_path><status>Success</status>`
1243
- };
1244
- };
1245
- var isAvailable12 = (provider) => {
1246
- return !!provider.removeFile;
1247
- };
1248
- var removeFile_default = {
1249
- ...toolInfo12,
1250
- handler: handler12,
1251
- isAvailable: isAvailable12
1252
- };
1253
-
1254
- // src/tools/renameFile.ts
1255
- import { z as z13 } from "zod";
1256
- var toolInfo13 = {
1257
- name: "rename_file",
1258
- description: "Request to rename a file from source path to target path.",
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
- }),
1263
- examples: [
1264
- {
1265
- description: "Request to rename a file",
1266
- parameters: [
1267
- {
1268
- name: "source_path",
1269
- value: "src/old-name.js"
1270
- },
1271
- {
1272
- name: "target_path",
1273
- value: "src/new-name.js"
1274
- }
1275
- ]
1276
- }
1277
- ],
1278
- permissionLevel: 2 /* Write */
1279
- };
1280
- var handler13 = async (provider, args) => {
1281
- if (!provider.renameFile) {
1282
- return {
1283
- type: "Error" /* Error */,
1284
- message: "Not possible to rename file. Abort."
1285
- };
1049
+ async renameFile(_sourcePath, _targetPath) {
1050
+ return;
1051
+ }
1052
+ async listFiles(_path, _recursive, _maxCount) {
1053
+ return [["mock-file.txt"], false];
1054
+ }
1055
+ async searchFiles(_path, _regex, _filePattern) {
1056
+ return ["mock-file.txt"];
1057
+ }
1058
+ async executeCommand(_command, _needApprove) {
1059
+ return { stdout: "mock output", stderr: "", exitCode: 0 };
1060
+ }
1061
+ async askFollowupQuestion(_question, _options) {
1062
+ return "mock answer";
1063
+ }
1064
+ async attemptCompletion(_result) {
1065
+ return "mock completion";
1286
1066
  }
1287
- const { source_path, target_path } = toolInfo13.parameters.parse(args);
1288
- await provider.renameFile(source_path, target_path);
1289
- return {
1290
- type: "Reply" /* Reply */,
1291
- message: `<rename_file_path>${target_path}</rename_file_path><status>Success</status>`
1292
- };
1293
- };
1294
- var isAvailable13 = (provider) => {
1295
- return !!provider.renameFile;
1296
- };
1297
- var renameFile_default = {
1298
- ...toolInfo13,
1299
- handler: handler13,
1300
- isAvailable: isAvailable13
1301
1067
  };
1302
1068
 
1303
1069
  // src/getAvailableTools.ts
@@ -1325,6 +1091,155 @@ var getAvailableTools = ({
1325
1091
  return tools;
1326
1092
  };
1327
1093
 
1094
+ // src/UsageMeter.ts
1095
+ var UsageMeter = class {
1096
+ #totals = { input: 0, output: 0, cachedRead: 0, cost: 0 };
1097
+ #calls = 0;
1098
+ #modelInfos;
1099
+ #maxMessages;
1100
+ #maxCost;
1101
+ constructor(modelInfos = {}, opts = {}) {
1102
+ const infos = {};
1103
+ for (const [provider, providerInfo] of Object.entries(modelInfos)) {
1104
+ for (const [model, modelInfo] of Object.entries(providerInfo)) {
1105
+ infos[`${provider.split("-")[0]}:${model.replace(/[.-]/g, "")}`] = {
1106
+ inputPrice: modelInfo.inputPrice ?? 0,
1107
+ outputPrice: modelInfo.outputPrice ?? 0,
1108
+ cacheWritesPrice: modelInfo.cacheWritesPrice ?? 0,
1109
+ cacheReadsPrice: modelInfo.cacheReadsPrice ?? 0
1110
+ };
1111
+ }
1112
+ }
1113
+ this.#modelInfos = infos;
1114
+ this.#maxMessages = opts.maxMessages ?? 1e3;
1115
+ this.#maxCost = opts.maxCost ?? 100;
1116
+ }
1117
+ #calculageUsage(usage, providerMetadata, modelInfo) {
1118
+ const providerMetadataKey = Object.keys(providerMetadata ?? {})[0];
1119
+ const metadata = providerMetadata?.[providerMetadataKey] ?? {};
1120
+ switch (providerMetadataKey) {
1121
+ case "openrouter":
1122
+ return {
1123
+ input: usage.inputTokens ?? 0,
1124
+ output: usage.outputTokens ?? 0,
1125
+ cachedRead: usage.cachedInputTokens ?? 0,
1126
+ cost: metadata.usage?.cost ?? 0
1127
+ };
1128
+ case "anthropic": {
1129
+ const cachedRead = usage.cachedInputTokens ?? 0;
1130
+ const cacheWrite = metadata?.promptCacheMissTokens ?? 0;
1131
+ const input = usage.inputTokens ?? 0;
1132
+ const output = usage.outputTokens ?? 0;
1133
+ return {
1134
+ input: input + cacheWrite + cachedRead,
1135
+ output,
1136
+ cachedRead,
1137
+ cost: (input * modelInfo.inputPrice + output * modelInfo.outputPrice + cacheWrite * modelInfo.cacheWritesPrice + cachedRead * modelInfo.cacheReadsPrice) / 1e6
1138
+ };
1139
+ }
1140
+ case "deepseek": {
1141
+ const cachedRead = usage.cachedInputTokens ?? 0;
1142
+ const cacheWrite = metadata.promptCacheMissTokens ?? 0;
1143
+ const input = usage.inputTokens ?? 0;
1144
+ const output = usage.outputTokens ?? 0;
1145
+ return {
1146
+ input,
1147
+ output,
1148
+ cachedRead,
1149
+ cost: (output * modelInfo.outputPrice + cacheWrite * modelInfo.inputPrice + cachedRead * modelInfo.cacheReadsPrice) / 1e6
1150
+ };
1151
+ }
1152
+ default: {
1153
+ const cachedRead = usage.cachedInputTokens ?? 0;
1154
+ const input = usage.inputTokens ?? 0;
1155
+ const output = usage.outputTokens ?? 0;
1156
+ return {
1157
+ input,
1158
+ output,
1159
+ cachedRead,
1160
+ cost: (input * modelInfo.inputPrice + output * modelInfo.outputPrice) / 1e6
1161
+ };
1162
+ }
1163
+ }
1164
+ }
1165
+ addUsage(llm, resp, options = {}) {
1166
+ const modelInfo = options.modelInfo ?? // make google.vertex.chat to google
1167
+ // and anthropic.messages to anthropic
1168
+ this.#modelInfos[`${llm.provider.split(".")[0]}:${llm.modelId.replace(/[.-]/g, "")}`] ?? {
1169
+ inputPrice: 0,
1170
+ outputPrice: 0,
1171
+ cacheWritesPrice: 0,
1172
+ cacheReadsPrice: 0
1173
+ };
1174
+ const usage = "totalUsage" in resp ? resp.totalUsage : resp.usage;
1175
+ const result = this.#calculageUsage(usage, resp.providerMetadata, modelInfo);
1176
+ this.#totals.input += result.input;
1177
+ this.#totals.output += result.output;
1178
+ this.#totals.cachedRead += result.cachedRead;
1179
+ this.#totals.cost += result.cost;
1180
+ this.#calls++;
1181
+ }
1182
+ /** Override the running totals (e.g., restore from saved state). */
1183
+ setUsage(newUsage) {
1184
+ if (newUsage.input != null) this.#totals.input = newUsage.input;
1185
+ if (newUsage.output != null) this.#totals.output = newUsage.output;
1186
+ if (newUsage.cachedRead != null) this.#totals.cachedRead = newUsage.cachedRead;
1187
+ if (newUsage.cost != null) this.#totals.cost = newUsage.cost;
1188
+ if (newUsage.calls != null) this.#calls = newUsage.calls;
1189
+ }
1190
+ /** Manually bump the message count (useful if you record some calls without token info). */
1191
+ incrementMessageCount(n = 1) {
1192
+ this.#calls += n;
1193
+ }
1194
+ /** Reset the running totals. */
1195
+ resetUsage() {
1196
+ this.#totals = { input: 0, output: 0, cachedRead: 0, cost: 0 };
1197
+ this.#calls = 0;
1198
+ }
1199
+ /** Return true once either messages or cost exceed the configured caps. */
1200
+ isLimitExceeded() {
1201
+ const messageCount = this.#maxMessages !== void 0 && this.#calls >= this.#maxMessages;
1202
+ const cost = this.#maxCost !== void 0 && this.#totals.cost >= this.#maxCost;
1203
+ return {
1204
+ messageCount,
1205
+ maxMessages: this.#maxMessages,
1206
+ cost,
1207
+ maxCost: this.#maxCost,
1208
+ result: messageCount || cost
1209
+ };
1210
+ }
1211
+ /** Same as isLimitExceeded but throws an error if a limit is hit. */
1212
+ checkLimit() {
1213
+ const result = this.isLimitExceeded();
1214
+ if (result.result) {
1215
+ throw new Error(
1216
+ `Usage limit exceeded. Message count: ${result.messageCount}/${result.maxMessages}, cost: ${result.cost}/${result.maxCost}`
1217
+ );
1218
+ }
1219
+ }
1220
+ /** Getter for the aggregated totals (immutable copy). */
1221
+ get usage() {
1222
+ return { ...this.#totals, messageCount: this.#calls };
1223
+ }
1224
+ /** Print a concise usage summary to console. */
1225
+ printUsage() {
1226
+ const u = this.usage;
1227
+ console.log(
1228
+ `Usage - messages: ${u.messageCount}, input: ${u.input}, cached: ${u.cachedRead}, output: ${u.output}, cost: $${u.cost.toFixed(4)}`
1229
+ );
1230
+ }
1231
+ onFinishHandler(llm) {
1232
+ return (evt) => {
1233
+ this.addUsage(llm, evt);
1234
+ };
1235
+ }
1236
+ };
1237
+
1238
+ // src/Agent/AgentBase.ts
1239
+ import { jsonSchema, streamText } from "ai";
1240
+ import { camelCase } from "lodash";
1241
+ import { toJSONSchema } from "zod";
1242
+
1328
1243
  // src/tool-v1-compat.ts
1329
1244
  import { z as z14 } from "zod";
1330
1245
  function zodSchemaToParameters(schema) {
@@ -1359,15 +1274,17 @@ function zodSchemaToParameters(schema) {
1359
1274
  function toToolInfoV1(tool) {
1360
1275
  const { parameters: zodSchema, ...rest } = tool;
1361
1276
  const v1Parameters = zodSchemaToParameters(zodSchema);
1362
- return {
1277
+ const examples = zodSchema.meta()?.examples;
1278
+ const v1Tool = {
1363
1279
  ...rest,
1364
1280
  parameters: v1Parameters
1365
1281
  };
1282
+ if (examples) {
1283
+ v1Tool.examples = examples;
1284
+ }
1285
+ return v1Tool;
1366
1286
  }
1367
1287
 
1368
- // src/Agent/AgentBase.ts
1369
- import { streamText } from "ai";
1370
-
1371
1288
  // src/Agent/parseAssistantMessage.ts
1372
1289
  function parseNestedParameters(content, parameterPrefix, childrenParams) {
1373
1290
  const result = {};
@@ -1538,7 +1455,7 @@ var toolInfoExamplesPrompt = (tool, example, toolNamePrefix, parameterPrefix) =>
1538
1455
  ## Example: ${example.description}
1539
1456
 
1540
1457
  <${toolNamePrefix}${tool.name}>
1541
- ${example.parameters.map((param) => `${renderParameterValue(param.name, param.value, parameterPrefix)}`).join("\n")}
1458
+ ${Object.entries(example.input).map(([name, value]) => renderParameterValue(name, value, parameterPrefix)).join("\n")}
1542
1459
  </${toolNamePrefix}${tool.name}>
1543
1460
  `;
1544
1461
  var toolUsePrompt = (tools, toolNamePrefix) => {
@@ -1546,6 +1463,7 @@ var toolUsePrompt = (tools, toolNamePrefix) => {
1546
1463
  return "";
1547
1464
  }
1548
1465
  const parameterPrefix = `${toolNamePrefix}parameter_`;
1466
+ const v1Tools = tools.map(toToolInfoV1);
1549
1467
  return `
1550
1468
  ====
1551
1469
 
@@ -1604,10 +1522,10 @@ Always adhere to this format, ensuring every opening tag has a matching closing
1604
1522
  NEVER surround tool use with triple backticks (\`\`\`).
1605
1523
 
1606
1524
  # Tools
1607
- ${tools.map((tool) => toolInfoPrompt(tool, toolNamePrefix, parameterPrefix)).join("\n")}
1525
+ ${v1Tools.map((tool) => toolInfoPrompt(tool, toolNamePrefix, parameterPrefix)).join("\n")}
1608
1526
 
1609
1527
  # Tool Use Examples
1610
- ${tools.map((tool) => {
1528
+ ${v1Tools.map((tool) => {
1611
1529
  let promp = "";
1612
1530
  for (const example of tool.examples ?? []) {
1613
1531
  promp += toolInfoExamplesPrompt(tool, example, toolNamePrefix, parameterPrefix);
@@ -1641,7 +1559,7 @@ ${agent.responsibilities.map((resp) => ` - ${resp}`).join("\n")}`
1641
1559
  - **Current Agent Role**
1642
1560
  You are currently acting as **${name}**. If you identify the task is beyond your current scope, use the handover or delegate tool to transition to the other agent. Include sufficient context so the new agent can seamlessly continue the work.
1643
1561
  `;
1644
- var capabilities = (toolNamePrefix) => `
1562
+ var capabilities = (_toolNamePrefix) => `
1645
1563
  ====
1646
1564
 
1647
1565
  CAPABILITIES
@@ -1698,6 +1616,8 @@ e.g. <tool_tool_name>tool_name</tool_tool_name>
1698
1616
  Ensure the opening and closing tags are correctly nested and closed, and that you are using the correct tool name.
1699
1617
  Avoid unnecessary text or symbols before or after the tool use.
1700
1618
  Avoid unnecessary escape characters or special characters.
1619
+ `,
1620
+ requireUseToolNative: `Error: No tool use detected. You MUST use a tool before proceeding.
1701
1621
  `,
1702
1622
  toolResults: (tool, result) => {
1703
1623
  if (typeof result === "string") {
@@ -1755,6 +1675,7 @@ var AgentBase = class {
1755
1675
  config;
1756
1676
  handlers;
1757
1677
  #policies;
1678
+ #toolSet;
1758
1679
  #messages = [];
1759
1680
  #aborted = false;
1760
1681
  #abortController;
@@ -1792,6 +1713,20 @@ ${instance.prompt}`;
1792
1713
  role: "system",
1793
1714
  content: this.config.systemPrompt
1794
1715
  });
1716
+ if (this.config.toolFormat === "native") {
1717
+ const tools = {};
1718
+ for (const tool of Object.values(this.handlers)) {
1719
+ const toolName = camelCase(tool.name);
1720
+ tools[toolName] = {
1721
+ description: tool.description,
1722
+ inputSchema: jsonSchema(toJSONSchema(tool.parameters))
1723
+ };
1724
+ this.handlers[toolName] = tool;
1725
+ }
1726
+ this.#toolSet = tools;
1727
+ } else {
1728
+ this.#toolSet = {};
1729
+ }
1795
1730
  }
1796
1731
  abort() {
1797
1732
  this.#aborted = true;
@@ -1811,21 +1746,27 @@ ${instance.prompt}`;
1811
1746
  async #callback(event) {
1812
1747
  await this.config.callback?.(event);
1813
1748
  }
1814
- async start(prompt5) {
1749
+ async start(prompt6) {
1815
1750
  this.#callback({ kind: "StartTask" /* StartTask */, agent: this, systemPrompt: this.config.systemPrompt });
1816
- return await this.#processLoop(prompt5);
1751
+ return await this.#processLoop(prompt6);
1817
1752
  }
1818
- async step(prompt5) {
1753
+ async step(prompt6) {
1819
1754
  if (this.#messages.length === 0) {
1820
1755
  this.#callback({ kind: "StartTask" /* StartTask */, agent: this, systemPrompt: this.config.systemPrompt });
1821
1756
  }
1822
- return await this.#request(prompt5);
1757
+ return await this.#request({
1758
+ role: "user",
1759
+ content: prompt6
1760
+ });
1823
1761
  }
1824
1762
  async handleStepResponse(response) {
1825
1763
  return this.#handleResponse(response);
1826
1764
  }
1827
1765
  async #processLoop(userMessage) {
1828
- let nextRequest = userMessage;
1766
+ let nextRequest = {
1767
+ role: "user",
1768
+ content: userMessage
1769
+ };
1829
1770
  while (true) {
1830
1771
  if (this.#aborted) {
1831
1772
  return { type: "Aborted" };
@@ -1854,10 +1795,7 @@ ${instance.prompt}`;
1854
1795
  throw new Error("userMessage is missing");
1855
1796
  }
1856
1797
  await this.#callback({ kind: "StartRequest" /* StartRequest */, agent: this, userMessage });
1857
- this.#messages.push({
1858
- role: "user",
1859
- content: userMessage
1860
- });
1798
+ this.#messages.push(userMessage);
1861
1799
  for (const instance of this.#policies) {
1862
1800
  if (instance.onBeforeRequest) {
1863
1801
  await instance.onBeforeRequest(this);
@@ -1869,11 +1807,11 @@ ${instance.prompt}`;
1869
1807
  messages = await instance.prepareMessages(this, messages);
1870
1808
  }
1871
1809
  }
1872
- let currentAssistantMessage = "";
1873
1810
  const retryCount = this.config.retryCount ?? 5;
1874
- const requestTimeoutSeconds = this.config.requestTimeoutSeconds ?? 10;
1811
+ const requestTimeoutSeconds = this.config.requestTimeoutSeconds ?? 90;
1812
+ let respMessages = [];
1875
1813
  for (let i = 0; i < retryCount; i++) {
1876
- currentAssistantMessage = "";
1814
+ respMessages = [];
1877
1815
  let timeout;
1878
1816
  const resetTimeout = () => {
1879
1817
  if (timeout) {
@@ -1887,40 +1825,22 @@ ${instance.prompt}`;
1887
1825
  }
1888
1826
  };
1889
1827
  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
1900
- }
1901
- };
1902
- providerOptions.google = {
1903
- thinkingConfig: {
1904
- includeThoughts: true,
1905
- thinkingBudget: thinkingBudgetTokens
1906
- }
1907
- };
1908
- }
1909
1828
  try {
1910
- const stream = streamText({
1829
+ const streamTextOptions = {
1911
1830
  model: this.ai,
1912
1831
  messages,
1913
- providerOptions,
1832
+ providerOptions: this.config.parameters?.providerOptions,
1914
1833
  onChunk: async ({ chunk }) => {
1915
1834
  resetTimeout();
1916
1835
  switch (chunk.type) {
1917
1836
  case "text":
1918
- currentAssistantMessage += chunk.text;
1919
1837
  await this.#callback({ kind: "Text" /* Text */, agent: this, newText: chunk.text });
1920
1838
  break;
1921
1839
  case "reasoning":
1922
1840
  await this.#callback({ kind: "Reasoning" /* Reasoning */, agent: this, newText: chunk.text });
1923
1841
  break;
1842
+ case "tool-call":
1843
+ break;
1924
1844
  }
1925
1845
  },
1926
1846
  onFinish: this.config.usageMeter.onFinishHandler(this.ai),
@@ -1928,8 +1848,18 @@ ${instance.prompt}`;
1928
1848
  console.error("Error in stream:", error);
1929
1849
  },
1930
1850
  abortSignal: this.#abortController.signal
1851
+ };
1852
+ if (this.config.toolFormat === "native") {
1853
+ streamTextOptions.tools = this.#toolSet;
1854
+ }
1855
+ const stream = streamText(streamTextOptions);
1856
+ await stream.consumeStream({
1857
+ onError: (error) => {
1858
+ console.error("Error in stream:", error);
1859
+ }
1931
1860
  });
1932
- await stream.consumeStream();
1861
+ const resp = await stream.response;
1862
+ respMessages = resp.messages;
1933
1863
  } catch (error) {
1934
1864
  if (error instanceof Error && error.name === "AbortError") {
1935
1865
  break;
@@ -1940,7 +1870,7 @@ ${instance.prompt}`;
1940
1870
  clearTimeout(timeout);
1941
1871
  }
1942
1872
  }
1943
- if (currentAssistantMessage) {
1873
+ if (respMessages.length > 0) {
1944
1874
  break;
1945
1875
  }
1946
1876
  if (this.#aborted) {
@@ -1948,17 +1878,44 @@ ${instance.prompt}`;
1948
1878
  }
1949
1879
  console.debug(`Retrying request ${i + 1} of ${retryCount}`);
1950
1880
  }
1951
- if (!currentAssistantMessage) {
1881
+ if (respMessages.length === 0) {
1952
1882
  if (this.#aborted) {
1953
1883
  return [];
1954
1884
  }
1955
1885
  throw new Error("No assistant message received");
1956
1886
  }
1957
- console.log("Assistant message:", currentAssistantMessage);
1958
- this.#messages.push({
1959
- role: "assistant",
1960
- content: currentAssistantMessage
1961
- });
1887
+ this.#messages.push(...respMessages);
1888
+ if (this.config.toolFormat === "native") {
1889
+ return respMessages.flatMap((msg) => {
1890
+ if (msg.role === "assistant") {
1891
+ const content = msg.content;
1892
+ if (typeof content === "string") {
1893
+ return [{ type: "text", content }];
1894
+ }
1895
+ return content.flatMap((part) => {
1896
+ if (part.type === "text") {
1897
+ return [{ type: "text", content: part.text }];
1898
+ }
1899
+ if (part.type === "tool-call") {
1900
+ return [{ type: "tool_use", id: part.toolCallId, name: part.toolName, params: part.input }];
1901
+ }
1902
+ return [];
1903
+ });
1904
+ }
1905
+ return [];
1906
+ });
1907
+ }
1908
+ const currentAssistantMessage = respMessages.map((msg) => {
1909
+ if (typeof msg.content === "string") {
1910
+ return msg.content;
1911
+ }
1912
+ return msg.content.map((part) => {
1913
+ if (part.type === "text") {
1914
+ return part.text;
1915
+ }
1916
+ return "";
1917
+ });
1918
+ }).join("\n");
1962
1919
  const ret = parseAssistantMessage(currentAssistantMessage, this.config.tools.map(toToolInfoV1), this.config.toolNamePrefix);
1963
1920
  await this.#callback({ kind: "EndRequest" /* EndRequest */, agent: this, message: currentAssistantMessage });
1964
1921
  return ret;
@@ -1971,12 +1928,12 @@ ${instance.prompt}`;
1971
1928
  case "text":
1972
1929
  break;
1973
1930
  case "tool_use": {
1974
- await this.#callback({ kind: "ToolUse" /* ToolUse */, agent: this, tool: content.name });
1931
+ await this.#callback({ kind: "ToolUse" /* ToolUse */, agent: this, tool: content.name, content: content.params });
1975
1932
  const toolResp = await this.#invokeTool(content.name, content.params);
1976
1933
  switch (toolResp.type) {
1977
1934
  case "Reply" /* Reply */: {
1978
- await this.#callback({ kind: "ToolReply" /* ToolReply */, agent: this, tool: content.name });
1979
- toolResponses.push({ type: "response", tool: content.name, response: toolResp.message });
1935
+ await this.#callback({ kind: "ToolReply" /* ToolReply */, agent: this, tool: content.name, content: toolResp.message });
1936
+ toolResponses.push({ type: "response", tool: content.name, response: toolResp.message, id: content.id });
1980
1937
  break;
1981
1938
  }
1982
1939
  case "Exit" /* Exit */:
@@ -1985,17 +1942,17 @@ ${instance.prompt}`;
1985
1942
  }
1986
1943
  return { type: "exit", reason: toolResp };
1987
1944
  case "Invalid" /* Invalid */: {
1988
- await this.#callback({ kind: "ToolInvalid" /* ToolInvalid */, agent: this, tool: content.name });
1989
- toolResponses.push({ type: "response", tool: content.name, response: toolResp.message });
1945
+ await this.#callback({ kind: "ToolInvalid" /* ToolInvalid */, agent: this, tool: content.name, content: toolResp.message });
1946
+ toolResponses.push({ type: "response", tool: content.name, response: toolResp.message, id: content.id });
1990
1947
  break outer;
1991
1948
  }
1992
1949
  case "Error" /* Error */: {
1993
- await this.#callback({ kind: "ToolError" /* ToolError */, agent: this, tool: content.name });
1994
- toolResponses.push({ type: "response", tool: content.name, response: toolResp.message });
1950
+ await this.#callback({ kind: "ToolError" /* ToolError */, agent: this, tool: content.name, content: toolResp.message });
1951
+ toolResponses.push({ type: "response", tool: content.name, response: toolResp.message, id: content.id });
1995
1952
  break outer;
1996
1953
  }
1997
1954
  case "Interrupted" /* Interrupted */:
1998
- await this.#callback({ kind: "ToolInterrupted" /* ToolInterrupted */, agent: this, tool: content.name });
1955
+ await this.#callback({ kind: "ToolInterrupted" /* ToolInterrupted */, agent: this, tool: content.name, content: toolResp.message });
1999
1956
  return { type: "exit", reason: toolResp };
2000
1957
  case "HandOver" /* HandOver */: {
2001
1958
  if (toolResponses.length > 0) {
@@ -2029,7 +1986,7 @@ ${instance.prompt}`;
2029
1986
  }
2030
1987
  case "Pause" /* Pause */: {
2031
1988
  await this.#callback({ kind: "ToolPause" /* ToolPause */, agent: this, tool: content.name, object: toolResp.object });
2032
- toolResponses.push({ type: "pause", tool: content.name, object: toolResp.object });
1989
+ toolResponses.push({ type: "pause", tool: content.name, object: toolResp.object, id: content.id });
2033
1990
  hasPause = true;
2034
1991
  }
2035
1992
  }
@@ -2041,15 +1998,56 @@ ${instance.prompt}`;
2041
1998
  return { type: "exit", reason: { type: "Pause", responses: toolResponses } };
2042
1999
  }
2043
2000
  if (toolResponses.length === 0) {
2044
- return { type: "reply", message: responsePrompts.requireUseTool };
2001
+ return {
2002
+ type: "reply",
2003
+ message: {
2004
+ role: "user",
2005
+ content: responsePrompts.requireUseToolNative
2006
+ }
2007
+ };
2008
+ }
2009
+ if (this.config.toolFormat === "native") {
2010
+ const toolResults = toolResponses.filter((resp) => resp.type === "response").map(
2011
+ (resp) => ({
2012
+ type: "tool-result",
2013
+ toolCallId: resp.id,
2014
+ toolName: resp.tool,
2015
+ output: {
2016
+ type: "text",
2017
+ value: resp.response
2018
+ }
2019
+ })
2020
+ );
2021
+ return {
2022
+ type: "reply",
2023
+ message: {
2024
+ role: "tool",
2025
+ content: toolResults
2026
+ }
2027
+ };
2028
+ }
2029
+ if (toolResponses.length === 0) {
2030
+ return {
2031
+ type: "reply",
2032
+ message: {
2033
+ role: "user",
2034
+ content: responsePrompts.requireUseTool
2035
+ }
2036
+ };
2045
2037
  }
2046
2038
  const finalResp = toolResponses.filter((resp) => resp.type === "response").flatMap(({ tool, response: response2 }) => responsePrompts.toolResults(tool, response2));
2047
- return { type: "reply", message: finalResp };
2039
+ return {
2040
+ type: "reply",
2041
+ message: {
2042
+ role: "user",
2043
+ content: finalResp
2044
+ }
2045
+ };
2048
2046
  }
2049
2047
  async #invokeTool(name, args) {
2050
2048
  try {
2051
- const handler14 = this.handlers[name]?.handler;
2052
- if (!handler14) {
2049
+ const handler15 = this.handlers[name]?.handler;
2050
+ if (!handler15) {
2053
2051
  return {
2054
2052
  type: "Error" /* Error */,
2055
2053
  message: responsePrompts.errorInvokeTool(name, "Tool not found"),
@@ -2068,7 +2066,7 @@ ${instance.prompt}`;
2068
2066
  if (resp) {
2069
2067
  return resp;
2070
2068
  }
2071
- return await handler14(this.config.provider, args);
2069
+ return await handler15(this.config.provider, args);
2072
2070
  } catch (error) {
2073
2071
  return {
2074
2072
  type: "Error" /* Error */,
@@ -2125,12 +2123,12 @@ var AnalyzerAgent = class extends AgentBase {
2125
2123
  permissionLevel: 1 /* Read */,
2126
2124
  interactive: true
2127
2125
  });
2128
- const toolNamePrefix = "tool_";
2126
+ const toolNamePrefix = options.toolFormat === "native" ? "" : "tool_";
2129
2127
  const systemPrompt = fullSystemPrompt(
2130
2128
  {
2131
2129
  os: options.os
2132
2130
  },
2133
- tools.map(toToolInfoV1),
2131
+ tools,
2134
2132
  toolNamePrefix,
2135
2133
  options.customInstructions ?? [],
2136
2134
  options.scripts ?? {},
@@ -2221,12 +2219,12 @@ var ArchitectAgent = class extends AgentBase {
2221
2219
  permissionLevel: 1 /* Read */,
2222
2220
  interactive: true
2223
2221
  });
2224
- const toolNamePrefix = "tool_";
2222
+ const toolNamePrefix = options.toolFormat === "native" ? "" : "tool_";
2225
2223
  const systemPrompt = fullSystemPrompt2(
2226
2224
  {
2227
2225
  os: options.os
2228
2226
  },
2229
- tools.map(toToolInfoV1),
2227
+ tools,
2230
2228
  toolNamePrefix,
2231
2229
  options.customInstructions ?? [],
2232
2230
  options.scripts ?? {},
@@ -2327,7 +2325,7 @@ RETRY GUIDELINES
2327
2325
  - Explain why the issue remains
2328
2326
  - Suggest manual intervention steps
2329
2327
  - Report any partial improvements`;
2330
- var fullSystemPrompt3 = (info, tools, toolNamePrefix, instructions, scripts, interactive, useNativeTool) => `
2328
+ var fullSystemPrompt3 = (info, tools, toolNamePrefix, instructions, scripts, _interactive, useNativeTool) => `
2331
2329
  ${basePrompt}
2332
2330
  ${useNativeTool ? "" : toolUsePrompt(tools, toolNamePrefix)}
2333
2331
  ${codeFixingStrategies}
@@ -2350,12 +2348,12 @@ var CodeFixerAgent = class extends AgentBase {
2350
2348
  permissionLevel: 3 /* Arbitrary */,
2351
2349
  interactive: true
2352
2350
  });
2353
- const toolNamePrefix = "tool_";
2351
+ const toolNamePrefix = options.toolFormat === "native" ? "" : "tool_";
2354
2352
  const systemPrompt = fullSystemPrompt3(
2355
2353
  {
2356
2354
  os: options.os
2357
2355
  },
2358
- tools.map(toToolInfoV1),
2356
+ tools,
2359
2357
  toolNamePrefix,
2360
2358
  options.customInstructions ?? [],
2361
2359
  options.scripts ?? {},
@@ -2378,7 +2376,7 @@ var CodeFixerAgent = class extends AgentBase {
2378
2376
  });
2379
2377
  this.#maxRetries = options.maxRetries ?? 5;
2380
2378
  }
2381
- async onBeforeInvokeTool(name, args) {
2379
+ async onBeforeInvokeTool(name, _args) {
2382
2380
  if (name === attemptCompletion_default.name) {
2383
2381
  if (this.#retryCount > this.#maxRetries) {
2384
2382
  return;
@@ -2556,12 +2554,12 @@ var CoderAgent = class extends AgentBase {
2556
2554
  permissionLevel: 3 /* Arbitrary */,
2557
2555
  interactive: true
2558
2556
  });
2559
- const toolNamePrefix = "tool_";
2557
+ const toolNamePrefix = options.toolFormat === "native" ? "" : "tool_";
2560
2558
  const systemPrompt = fullSystemPrompt4(
2561
2559
  {
2562
2560
  os: options.os
2563
2561
  },
2564
- tools.map(toToolInfoV1),
2562
+ tools,
2565
2563
  toolNamePrefix,
2566
2564
  options.customInstructions ?? [],
2567
2565
  options.scripts ?? {},
@@ -2582,7 +2580,7 @@ var CoderAgent = class extends AgentBase {
2582
2580
  usageMeter: options.usageMeter ?? new UsageMeter()
2583
2581
  });
2584
2582
  }
2585
- async onBeforeInvokeTool(name, args) {
2583
+ async onBeforeInvokeTool(name, _args) {
2586
2584
  if (name !== attemptCompletion_default.name) {
2587
2585
  return;
2588
2586
  }
@@ -2653,24 +2651,24 @@ var MultiAgent = class {
2653
2651
  switch (exitReason.type) {
2654
2652
  case "HandOver" /* HandOver */: {
2655
2653
  this.#agents.pop();
2656
- const prompt5 = await this.#config.getPrompt?.(
2654
+ const prompt6 = await this.#config.getPrompt?.(
2657
2655
  exitReason.agentName,
2658
2656
  exitReason.task,
2659
2657
  exitReason.context,
2660
2658
  exitReason.files,
2661
2659
  this.#originalTask
2662
2660
  ) ?? exitReason.task;
2663
- return await this.#startTask(exitReason.agentName, prompt5);
2661
+ return await this.#startTask(exitReason.agentName, prompt6);
2664
2662
  }
2665
2663
  case "Delegate" /* Delegate */: {
2666
- const prompt5 = await this.#config.getPrompt?.(
2664
+ const prompt6 = await this.#config.getPrompt?.(
2667
2665
  exitReason.agentName,
2668
2666
  exitReason.task,
2669
2667
  exitReason.context,
2670
2668
  exitReason.files,
2671
2669
  this.#originalTask
2672
2670
  ) ?? exitReason.task;
2673
- const delegateResult = await this.#startTask(exitReason.agentName, prompt5);
2671
+ const delegateResult = await this.#startTask(exitReason.agentName, prompt6);
2674
2672
  switch (delegateResult.type) {
2675
2673
  case "HandOver" /* HandOver */:
2676
2674
  case "Delegate" /* Delegate */:
@@ -2799,6 +2797,58 @@ var Policies = /* @__PURE__ */ ((Policies2) => {
2799
2797
  return Policies2;
2800
2798
  })(Policies || {});
2801
2799
 
2800
+ // src/Agent/policies/EnableCachePolicy.ts
2801
+ var CACHEABLE_MODELS = ["sonnet", "opus", "haiku", "gemini"];
2802
+ function isCacheableModel(modelId) {
2803
+ return CACHEABLE_MODELS.some((model) => modelId.includes(model));
2804
+ }
2805
+ function getProviderKey(provider) {
2806
+ if (provider === "openrouter") {
2807
+ return "openrouter";
2808
+ }
2809
+ if (provider.includes("anthropic")) {
2810
+ return "anthropic";
2811
+ }
2812
+ return void 0;
2813
+ }
2814
+ var EnableCachePolicy = () => {
2815
+ return {
2816
+ name: "enablecache" /* EnableCache */,
2817
+ async prepareMessages(agent, messages) {
2818
+ const providerKey = getProviderKey(agent.ai.provider);
2819
+ if (!providerKey || !isCacheableModel(agent.ai.modelId)) {
2820
+ return messages;
2821
+ }
2822
+ const providerOptions = { [providerKey]: { cacheControl: { type: "ephemeral" } } };
2823
+ const newMessages = messages.slice();
2824
+ let userMessagesToUpdate = 2;
2825
+ for (let i = newMessages.length - 1; i >= 0; i--) {
2826
+ const message = newMessages[i];
2827
+ if (message.role === "user" && userMessagesToUpdate > 0) {
2828
+ newMessages[i] = {
2829
+ ...message,
2830
+ providerOptions: {
2831
+ ...providerOptions,
2832
+ ...message.providerOptions ?? {}
2833
+ }
2834
+ };
2835
+ userMessagesToUpdate--;
2836
+ } else if (message.role === "system") {
2837
+ newMessages[i] = {
2838
+ ...message,
2839
+ providerOptions: {
2840
+ ...providerOptions,
2841
+ ...message.providerOptions ?? {}
2842
+ }
2843
+ };
2844
+ break;
2845
+ }
2846
+ }
2847
+ return newMessages;
2848
+ }
2849
+ };
2850
+ };
2851
+
2802
2852
  // src/Agent/policies/TruncateContextPolicy.ts
2803
2853
  var DEFAULT_MAX_TOKENS_ESTIMATE = 32e3;
2804
2854
  function getMaxTokens(agent) {
@@ -2896,58 +2946,6 @@ var TruncateContextPolicy = () => {
2896
2946
  };
2897
2947
  };
2898
2948
 
2899
- // src/Agent/policies/EnableCachePolicy.ts
2900
- var CACHEABLE_MODELS = ["sonnet", "opus", "haiku", "gemini"];
2901
- function isCacheableModel(modelId) {
2902
- return CACHEABLE_MODELS.some((model) => modelId.includes(model));
2903
- }
2904
- function getProviderKey(provider) {
2905
- if (provider === "openrouter") {
2906
- return "openrouter";
2907
- }
2908
- if (provider.includes("anthropic")) {
2909
- return "anthropic";
2910
- }
2911
- return void 0;
2912
- }
2913
- var EnableCachePolicy = () => {
2914
- return {
2915
- name: "enablecache" /* EnableCache */,
2916
- async prepareMessages(agent, messages) {
2917
- const providerKey = getProviderKey(agent.ai.provider);
2918
- if (!providerKey || !isCacheableModel(agent.ai.modelId)) {
2919
- return messages;
2920
- }
2921
- const providerOptions = { [providerKey]: { cacheControl: { type: "ephemeral" } } };
2922
- const newMessages = messages.slice();
2923
- let userMessagesToUpdate = 2;
2924
- for (let i = newMessages.length - 1; i >= 0; i--) {
2925
- const message = newMessages[i];
2926
- if (message.role === "user" && userMessagesToUpdate > 0) {
2927
- newMessages[i] = {
2928
- ...message,
2929
- providerOptions: {
2930
- ...providerOptions,
2931
- ...message.providerOptions ?? {}
2932
- }
2933
- };
2934
- userMessagesToUpdate--;
2935
- } else if (message.role === "system") {
2936
- newMessages[i] = {
2937
- ...message,
2938
- providerOptions: {
2939
- ...providerOptions,
2940
- ...message.providerOptions ?? {}
2941
- }
2942
- };
2943
- break;
2944
- }
2945
- }
2946
- return newMessages;
2947
- }
2948
- };
2949
- };
2950
-
2951
2949
  // src/Agent/index.ts
2952
2950
  var allAgents = [architectAgentInfo, coderAgentInfo, analyzerAgentInfo, codeFixerAgentInfo];
2953
2951
 
@@ -3009,23 +3007,23 @@ var prompt = `You are an AiTool designed to assist users in creating new project
3009
3007
  - Create a .gitattributes file with appropriate configurations:
3010
3008
  - Mark lock files as generated and exclude them from diffs
3011
3009
  - Example for different package managers:
3012
-
3010
+
3013
3011
  # For Bun
3014
3012
  bun.lock linguist-generated=true
3015
3013
  bun.lock -diff
3016
-
3014
+
3017
3015
  # For npm
3018
3016
  package-lock.json linguist-generated=true
3019
3017
  package-lock.json -diff
3020
-
3018
+
3021
3019
  # For Yarn
3022
3020
  yarn.lock linguist-generated=true
3023
3021
  yarn.lock -diff
3024
-
3022
+
3025
3023
  # For pnpm
3026
3024
  pnpm-lock.yaml linguist-generated=true
3027
3025
  pnpm-lock.yaml -diff
3028
-
3026
+
3029
3027
  - Include other common configurations as needed based on project type
3030
3028
 
3031
3029
  6. **Handover to Coder Agent:**
@@ -3281,6 +3279,182 @@ var generateProjectConfig_default = {
3281
3279
  agent: "analyzer"
3282
3280
  };
3283
3281
 
3282
+ // src/AiTool/tools/gitDiff.ts
3283
+ import { z as z16 } from "zod";
3284
+ var toolInfo14 = {
3285
+ name: "git_diff",
3286
+ description: "Get the git diff for the current repository. Can be used to get staged changes, unstaged changes, or changes between commits. By default, it returns unstaged changes.",
3287
+ parameters: z16.object({
3288
+ staged: z16.preprocess((val) => {
3289
+ if (typeof val === "string") {
3290
+ const lower = val.toLowerCase();
3291
+ if (lower === "false") return false;
3292
+ if (lower === "true") return true;
3293
+ }
3294
+ return val;
3295
+ }, z16.boolean().optional().default(false)).describe("Get staged changes instead of unstaged changes."),
3296
+ commitRange: z16.string().optional().describe('The commit range to get the diff for (e.g., "main...HEAD").'),
3297
+ file: z16.string().optional().describe("Get the diff for a specific file.")
3298
+ }),
3299
+ permissionLevel: 1 /* Read */
3300
+ };
3301
+ var handler14 = async (provider, args) => {
3302
+ if (!provider.executeCommand) {
3303
+ return {
3304
+ type: "Error" /* Error */,
3305
+ message: "Not possible to execute command. Abort."
3306
+ };
3307
+ }
3308
+ const { staged, file, commitRange } = toolInfo14.parameters.parse(args);
3309
+ const commandParts = ["git", "diff", "--no-color"];
3310
+ if (staged) {
3311
+ commandParts.push("--staged");
3312
+ }
3313
+ if (commitRange) {
3314
+ commandParts.push(commitRange);
3315
+ }
3316
+ if (file) {
3317
+ commandParts.push("--", file);
3318
+ }
3319
+ const command = commandParts.join(" ");
3320
+ try {
3321
+ const result = await provider.executeCommand(command, false);
3322
+ if (result.exitCode === 0) {
3323
+ if (!result.stdout.trim()) {
3324
+ return {
3325
+ type: "Reply" /* Reply */,
3326
+ message: "No diff found."
3327
+ };
3328
+ }
3329
+ return {
3330
+ type: "Reply" /* Reply */,
3331
+ message: `<diff file="${file ?? "all"}">
3332
+ ${result.stdout}
3333
+ </diff>`
3334
+ };
3335
+ }
3336
+ return {
3337
+ type: "Error" /* Error */,
3338
+ message: `\`${command}\` exited with code ${result.exitCode}:
3339
+ ${result.stderr}`
3340
+ };
3341
+ } catch (error) {
3342
+ return {
3343
+ type: "Error" /* Error */,
3344
+ message: error instanceof Error ? error.message : String(error)
3345
+ };
3346
+ }
3347
+ };
3348
+ var isAvailable14 = (provider) => {
3349
+ return !!provider.executeCommand;
3350
+ };
3351
+ var gitDiff_default = {
3352
+ ...toolInfo14,
3353
+ handler: handler14,
3354
+ isAvailable: isAvailable14
3355
+ };
3356
+
3357
+ // src/AiTool/reviewDiff.ts
3358
+ var prompt5 = `
3359
+ # Code Review Prompt
3360
+
3361
+ You are a senior software engineer reviewing code changes.
3362
+
3363
+ ## Viewing Changes
3364
+ - Use **git_diff** to inspect code.
3365
+ - **Pull request**: use the provided commit range.
3366
+ - **Local changes**: diff staged or unstaged files.
3367
+ - If a pull request is present you may receive:
3368
+ - <pr_title>
3369
+ - <pr_description>
3370
+ - <commit_messages>
3371
+ - A <review_instructions> tag tells you the focus of the review.
3372
+
3373
+ ## Focus Areas
3374
+ - Readability and maintainability
3375
+ - Correctness, edge cases, potential bugs
3376
+ - Performance implications
3377
+ - Clarity of intent
3378
+ - Best-practice adherence
3379
+
3380
+ ## Output Format
3381
+ Do **not** include praise or positive feedback. Ignore generated files such as lock files.
3382
+
3383
+ Return your review as a JSON object inside a \`\`\`json block, wrapped like:
3384
+ <tool_attempt_completion>
3385
+ <tool_parameter_result>
3386
+ \`\`\`json
3387
+ {
3388
+ "overview": "Summary of overall concerns.",
3389
+ "specificReviews": [
3390
+ {
3391
+ "file": "path/filename.ext",
3392
+ "lines": "N or N-M",
3393
+ "review": "Describe the issue and actionable fix or improvement."
3394
+ }
3395
+ ]
3396
+ }
3397
+ \`\`\`
3398
+ </tool_parameter_result>
3399
+ </tool_attempt_completion>
3400
+ `;
3401
+ var reviewDiff_default = {
3402
+ name: "reviewDiff",
3403
+ description: "Reviews a git diff",
3404
+ prompt: prompt5,
3405
+ formatInput: (params) => {
3406
+ const parts = [];
3407
+ if (params.pullRequestTitle) {
3408
+ parts.push(`<pr_title>
3409
+ ${params.pullRequestTitle}
3410
+ </pr_title>`);
3411
+ }
3412
+ if (params.pullRequestDescription) {
3413
+ parts.push(`<pr_description>
3414
+ ${params.pullRequestDescription}
3415
+ </pr_description>`);
3416
+ }
3417
+ if (params.commitMessages) {
3418
+ parts.push(`<commit_messages>
3419
+ ${params.commitMessages}
3420
+ </commit_messages>`);
3421
+ }
3422
+ let instructions = "";
3423
+ if (params.commitRange) {
3424
+ instructions = `Review the pull request. Get the diff using the git_diff tool with the commit range '${params.commitRange}'.`;
3425
+ } else if (params.staged) {
3426
+ instructions = "Review the staged changes. Get the diff using the git_diff tool with staged: true.";
3427
+ } else {
3428
+ instructions = "Review the unstaged changes. Get the diff using the git_diff tool.";
3429
+ }
3430
+ parts.push(`<review_instructions>
3431
+ ${instructions}
3432
+ </review_instructions>`);
3433
+ return parts.join("\n");
3434
+ },
3435
+ parseOutput: (output) => {
3436
+ const jsonBlockRegex = /```json\n([\s\S]*?)\n```/;
3437
+ const match = output.match(jsonBlockRegex);
3438
+ const content = match ? match[1] : output;
3439
+ try {
3440
+ return JSON.parse(content);
3441
+ } catch (error) {
3442
+ console.error("Error parsing JSON output:", error);
3443
+ return {
3444
+ overview: `Could not parse review output. Raw output:
3445
+ ${output}`,
3446
+ specificReviews: []
3447
+ };
3448
+ }
3449
+ },
3450
+ agent: (options) => {
3451
+ return new AnalyzerAgent({
3452
+ ...options,
3453
+ additionalTools: [gitDiff_default]
3454
+ });
3455
+ }
3456
+ };
3457
+
3284
3458
  // src/AiTool/index.ts
3285
3459
  var executeTool = async (definition, ai, params, usageMeter) => {
3286
3460
  const resp = await generateText({
@@ -3296,10 +3470,7 @@ var executeTool = async (definition, ai, params, usageMeter) => {
3296
3470
  usageMeter.addUsage(ai, resp);
3297
3471
  return definition.parseOutput(resp.text);
3298
3472
  };
3299
- var executeAgentTool = async (definition, agent, params) => {
3300
- if (!definition.agent) {
3301
- throw new Error("Agent not specified");
3302
- }
3473
+ var executeMultiAgentTool = async (definition, agent, params) => {
3303
3474
  const exitReason = await agent.startTask({
3304
3475
  agentName: definition.agent,
3305
3476
  task: definition.prompt,
@@ -3310,20 +3481,36 @@ var executeAgentTool = async (definition, agent, params) => {
3310
3481
  }
3311
3482
  throw new Error(`Tool execution failed: ${exitReason.type}`);
3312
3483
  };
3484
+ var executeAgentTool = async (definition, options, params) => {
3485
+ const agent = definition.agent(options);
3486
+ const exitReason = await agent.start(`${definition.prompt}
3487
+
3488
+ ${definition.formatInput(params)}`);
3489
+ if (exitReason.type === "Exit" /* Exit */) {
3490
+ return definition.parseOutput(exitReason.message);
3491
+ }
3492
+ throw new Error(`Tool execution failed: ${exitReason.type}`);
3493
+ };
3313
3494
  var makeTool = (definition) => {
3314
3495
  return async (ai, params, usageMeter) => {
3315
3496
  return executeTool(definition, ai, params, usageMeter);
3316
3497
  };
3317
3498
  };
3318
- var makeAgentTool = (definition) => {
3499
+ var makeMultiAgentTool = (definition) => {
3319
3500
  return async (agent, params) => {
3320
- return executeAgentTool(definition, agent, params);
3501
+ return executeMultiAgentTool(definition, agent, params);
3502
+ };
3503
+ };
3504
+ var makeAgentTool = (definition) => {
3505
+ return async (options, params) => {
3506
+ return executeAgentTool(definition, options, params);
3321
3507
  };
3322
3508
  };
3323
3509
  var generateGitCommitMessage = makeTool(generateGitCommitMessage_default);
3324
3510
  var generateGithubPullRequestDetails = makeTool(generateGithubPullRequestDetails_default);
3325
- var generateProjectConfig = makeAgentTool(generateProjectConfig_default);
3326
- var createNewProject = makeAgentTool(createNewProject_default);
3511
+ var reviewDiff = makeAgentTool(reviewDiff_default);
3512
+ var generateProjectConfig = makeMultiAgentTool(generateProjectConfig_default);
3513
+ var createNewProject = makeMultiAgentTool(createNewProject_default);
3327
3514
  export {
3328
3515
  AgentBase,
3329
3516
  AnalyzerAgent,
@@ -3356,6 +3543,7 @@ export {
3356
3543
  delegate_default as delegate,
3357
3544
  executeAgentTool,
3358
3545
  executeCommand_default as executeCommand,
3546
+ executeMultiAgentTool,
3359
3547
  executeTool,
3360
3548
  fetchUrl_default as fetchUrl,
3361
3549
  generateGitCommitMessage,
@@ -3365,6 +3553,7 @@ export {
3365
3553
  handOver_default as handOver,
3366
3554
  listFiles_default as listFiles,
3367
3555
  makeAgentTool,
3556
+ makeMultiAgentTool,
3368
3557
  makeTool,
3369
3558
  parseAssistantMessage,
3370
3559
  readFile_default as readFile,
@@ -3373,6 +3562,7 @@ export {
3373
3562
  replaceInFile_default as replaceInFile,
3374
3563
  replaceInFile as replaceInFileHelper,
3375
3564
  responsePrompts,
3565
+ reviewDiff,
3376
3566
  searchFiles_default as searchFiles,
3377
3567
  systemInformation,
3378
3568
  toolUsePrompt,