@polka-codes/cli 0.4.7 → 0.4.9

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.
Files changed (3) hide show
  1. package/README.md +4 -0
  2. package/dist/index.js +1494 -1189
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -24611,7 +24611,7 @@ var require_emoji_regex2 = __commonJS((exports, module) => {
24611
24611
  });
24612
24612
 
24613
24613
  // src/index.ts
24614
- var import_config5 = __toESM(require_config(), 1);
24614
+ var import_config7 = __toESM(require_config(), 1);
24615
24615
 
24616
24616
  // ../../node_modules/commander/esm.mjs
24617
24617
  var import__ = __toESM(require_commander(), 1);
@@ -24629,7 +24629,7 @@ var {
24629
24629
  Help
24630
24630
  } = import__.default;
24631
24631
  // package.json
24632
- var version = "0.4.7";
24632
+ var version = "0.4.9";
24633
24633
 
24634
24634
  // ../../node_modules/@anthropic-ai/sdk/version.mjs
24635
24635
  var VERSION = "0.36.2";
@@ -27807,10 +27807,78 @@ Anthropic.Models = Models2;
27807
27807
  Anthropic.ModelInfosPage = ModelInfosPage;
27808
27808
  Anthropic.Beta = Beta;
27809
27809
 
27810
+ // ../core/src/AiService/UsageMeter.ts
27811
+ class UsageMeter {
27812
+ #usage = {
27813
+ inputTokens: 0,
27814
+ outputTokens: 0,
27815
+ cacheWriteTokens: 0,
27816
+ cacheReadTokens: 0,
27817
+ totalCost: 0
27818
+ };
27819
+ #messageCount = 0;
27820
+ maxCost;
27821
+ maxMessageCount;
27822
+ constructor(options = {}) {
27823
+ this.maxCost = options.maxCost || 1000;
27824
+ this.maxMessageCount = options.maxMessageCount || 1000;
27825
+ }
27826
+ addUsage(usage, model) {
27827
+ this.#usage.inputTokens += usage.inputTokens ?? 0;
27828
+ this.#usage.outputTokens += usage.outputTokens ?? 0;
27829
+ this.#usage.cacheWriteTokens += usage.cacheWriteTokens ?? 0;
27830
+ this.#usage.cacheReadTokens += usage.cacheReadTokens ?? 0;
27831
+ if (!usage.totalCost && model) {
27832
+ usage.totalCost = ((model.inputPrice ?? 0) * (usage.inputTokens ?? 0) + (model.outputPrice ?? 0) * (usage.outputTokens ?? 0) + (model.cacheWritesPrice ?? 0) * (usage.cacheWriteTokens ?? 0) + (model.cacheReadsPrice ?? 0) * (usage.cacheReadTokens ?? 0)) / 1e6;
27833
+ }
27834
+ this.#usage.totalCost += usage.totalCost ?? 0;
27835
+ }
27836
+ incrementMessageCount(count = 1) {
27837
+ this.#messageCount += count;
27838
+ }
27839
+ isLimitExceeded() {
27840
+ const messageCount = this.#messageCount >= this.maxMessageCount;
27841
+ const cost = this.#usage.totalCost >= this.maxCost;
27842
+ return {
27843
+ messageCount,
27844
+ cost,
27845
+ result: messageCount || cost
27846
+ };
27847
+ }
27848
+ get usage() {
27849
+ return { ...this.#usage };
27850
+ }
27851
+ printUsage() {
27852
+ console.log("Usages:");
27853
+ console.log(`Input tokens: ${this.#usage.inputTokens}`);
27854
+ console.log(`Output tokens: ${this.#usage.outputTokens}`);
27855
+ console.log(`Cache read tokens: ${this.#usage.cacheReadTokens}`);
27856
+ console.log(`Cache write tokens: ${this.#usage.cacheWriteTokens}`);
27857
+ console.log(`Total cost: ${this.#usage.totalCost}`);
27858
+ }
27859
+ }
27860
+
27810
27861
  // ../core/src/AiService/AiServiceBase.ts
27811
27862
  class AiServiceBase {
27863
+ usageMeter;
27864
+ constructor(usageMeter) {
27865
+ this.usageMeter = usageMeter ?? new UsageMeter;
27866
+ }
27867
+ async* send(systemPrompt, messages) {
27868
+ this.usageMeter.incrementMessageCount();
27869
+ const stream = this.sendImpl(systemPrompt, messages);
27870
+ for await (const chunk of stream) {
27871
+ switch (chunk.type) {
27872
+ case "usage":
27873
+ this.usageMeter.addUsage(chunk, this.model.info);
27874
+ break;
27875
+ }
27876
+ yield chunk;
27877
+ }
27878
+ }
27812
27879
  async request(systemPrompt, messages) {
27813
- const stream = this.send(systemPrompt, messages);
27880
+ this.usageMeter.incrementMessageCount();
27881
+ const stream = this.sendImpl(systemPrompt, messages);
27814
27882
  const usage = {
27815
27883
  inputTokens: 0,
27816
27884
  outputTokens: 0,
@@ -27836,6 +27904,7 @@ class AiServiceBase {
27836
27904
  reasoning += chunk.text;
27837
27905
  }
27838
27906
  }
27907
+ this.usageMeter.addUsage(usage, this.model.info);
27839
27908
  return {
27840
27909
  response: resp,
27841
27910
  reasoning,
@@ -27927,7 +27996,7 @@ class AnthropicService extends AiServiceBase {
27927
27996
  #client;
27928
27997
  model;
27929
27998
  constructor(options) {
27930
- super();
27999
+ super(options.usageMeter);
27931
28000
  this.#options = options;
27932
28001
  this.#client = new Anthropic({
27933
28002
  apiKey: options.apiKey,
@@ -27939,7 +28008,7 @@ class AnthropicService extends AiServiceBase {
27939
28008
  info: anthropicModels[id] ?? anthropicModels[anthropicDefaultModelId]
27940
28009
  };
27941
28010
  }
27942
- async* send(systemPrompt, messages) {
28011
+ async* sendImpl(systemPrompt, messages) {
27943
28012
  let stream;
27944
28013
  const modelId = this.model.id;
27945
28014
  switch (modelId) {
@@ -32801,7 +32870,7 @@ class DeepSeekService extends AiServiceBase {
32801
32870
  #client;
32802
32871
  model;
32803
32872
  constructor(options) {
32804
- super();
32873
+ super(options.usageMeter);
32805
32874
  this.#client = new openai_default({
32806
32875
  baseURL: "https://api.deepseek.com/v1",
32807
32876
  apiKey: options.apiKey
@@ -32812,7 +32881,7 @@ class DeepSeekService extends AiServiceBase {
32812
32881
  info: deepSeekModels[id] ?? deepSeekModels[deepSeekDefaultModelId]
32813
32882
  };
32814
32883
  }
32815
- async* send(systemPrompt, messages) {
32884
+ async* sendImpl(systemPrompt, messages) {
32816
32885
  const openAiMessages = [
32817
32886
  { role: "system", content: systemPrompt },
32818
32887
  ...convertToOpenAiMessages(messages)
@@ -32857,7 +32926,7 @@ class OllamaService extends AiServiceBase {
32857
32926
  #client;
32858
32927
  model;
32859
32928
  constructor(options) {
32860
- super();
32929
+ super(options.usageMeter);
32861
32930
  this.#client = new openai_default({
32862
32931
  baseURL: `${options.baseUrl || "http://localhost:11434"}/v1`,
32863
32932
  apiKey: "ollama"
@@ -32867,7 +32936,7 @@ class OllamaService extends AiServiceBase {
32867
32936
  info: openAiModelInfoSaneDefaults
32868
32937
  };
32869
32938
  }
32870
- async* send(systemPrompt, messages) {
32939
+ async* sendImpl(systemPrompt, messages) {
32871
32940
  const openAiMessages = [
32872
32941
  { role: "system", content: systemPrompt },
32873
32942
  ...convertToOpenAiMessages(messages)
@@ -32896,7 +32965,7 @@ class OpenRouterService extends AiServiceBase {
32896
32965
  #apiKey;
32897
32966
  model;
32898
32967
  constructor(options) {
32899
- super();
32968
+ super(options.usageMeter);
32900
32969
  if (!options.model) {
32901
32970
  throw new Error("OpenRouter requires a model");
32902
32971
  }
@@ -32917,7 +32986,7 @@ class OpenRouterService extends AiServiceBase {
32917
32986
  info: {}
32918
32987
  };
32919
32988
  }
32920
- async* send(systemPrompt, messages) {
32989
+ async* sendImpl(systemPrompt, messages) {
32921
32990
  const openAiMessages = [
32922
32991
  { role: "system", content: systemPrompt },
32923
32992
  ...convertToOpenAiMessages(messages)
@@ -33070,1099 +33139,671 @@ var createService = (provider, options) => {
33070
33139
  var getAvailableTools = (provider, allTools) => {
33071
33140
  return allTools.filter((tool) => tool.isAvailable(provider));
33072
33141
  };
33142
+ // ../core/src/tools/allTools.ts
33143
+ var exports_allTools = {};
33144
+ __export(exports_allTools, {
33145
+ writeToFile: () => writeToFile_default,
33146
+ searchFiles: () => searchFiles_default,
33147
+ replaceInFile: () => replaceInFile_default,
33148
+ renameFile: () => renameFile_default,
33149
+ removeFile: () => removeFile_default,
33150
+ readFile: () => readFile_default,
33151
+ listFiles: () => listFiles_default,
33152
+ listCodeDefinitionNames: () => listCodeDefinitionNames_default,
33153
+ handOver: () => handOver_default,
33154
+ executeCommand: () => executeCommand_default,
33155
+ attemptCompletion: () => attemptCompletion_default,
33156
+ askFollowupQuestion: () => askFollowupQuestion_default
33157
+ });
33073
33158
 
33074
- // ../core/src/Agent/parseAssistantMessage.ts
33075
- function parseAssistantMessage(assistantMessage, tools, toolNamePrefix) {
33076
- const parameterPrefix = `${toolNamePrefix}parameter_`;
33077
- const results = [];
33078
- const toolTags = tools.map((tool) => `${toolNamePrefix}${tool.name}`);
33079
- const toolPattern = toolTags.join("|");
33080
- let remainingMessage = assistantMessage;
33081
- let match;
33082
- const tagRegex = new RegExp(`<(${toolPattern})>([\\s\\S]*?)<\\/\\1>`, "s");
33083
- while (true) {
33084
- match = tagRegex.exec(remainingMessage);
33085
- if (match === null)
33086
- break;
33087
- const beforeTag = remainingMessage.slice(0, match.index).trim();
33088
- if (beforeTag) {
33089
- results.push({
33090
- type: "text",
33091
- content: beforeTag
33092
- });
33159
+ // ../core/src/tools/utils/replaceInFile.ts
33160
+ var replaceInFile = async (fileContent, diff) => {
33161
+ const blockPattern = /<<<<<+ SEARCH\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
33162
+ const blocks = [];
33163
+ for (let match = blockPattern.exec(diff);match !== null; match = blockPattern.exec(diff)) {
33164
+ blocks.push({ search: match[1], replace: match[2] });
33165
+ }
33166
+ if (blocks.length === 0) {
33167
+ throw new Error("No valid diff blocks found.");
33168
+ }
33169
+ const findAndReplace = (content, search, replace) => {
33170
+ let index = content.indexOf(search);
33171
+ if (index !== -1) {
33172
+ return content.slice(0, index) + replace + content.slice(index + search.length);
33093
33173
  }
33094
- const tagName = match[1];
33095
- const toolName = tagName.replace(toolNamePrefix, "");
33096
- const tool = tools.find((t2) => t2.name === toolName);
33097
- const fullTagContent = match[0];
33098
- if (tool) {
33099
- const params = {};
33100
- for (const param of tool.parameters) {
33101
- const paramName = `${parameterPrefix}${param.name}`;
33102
- const escapedParamName = paramName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
33103
- const paramPattern = `<${escapedParamName}>([\\s\\S]*?)<\\/${escapedParamName}>`;
33104
- const paramMatch = fullTagContent.match(new RegExp(paramPattern, "s"));
33105
- if (paramMatch) {
33106
- params[param.name] = paramMatch[1].trim();
33174
+ const trimmedSearch = search.trim();
33175
+ const trimmedContent = content.trim();
33176
+ const offset = content.indexOf(trimmedContent);
33177
+ index = trimmedContent.indexOf(trimmedSearch);
33178
+ if (index !== -1) {
33179
+ const absoluteIndex = offset + index;
33180
+ return content.slice(0, absoluteIndex) + replace + content.slice(absoluteIndex + trimmedSearch.length);
33181
+ }
33182
+ const normalizedSearch = trimmedSearch.replace(/\s+/g, " ");
33183
+ const normalizedContent = trimmedContent.replace(/\s+/g, " ");
33184
+ index = normalizedContent.indexOf(normalizedSearch);
33185
+ if (index !== -1) {
33186
+ let runningIndex = 0;
33187
+ let actualPos = offset;
33188
+ for (const segment of trimmedSearch.replace(/\s+/g, " ").split(" ")) {
33189
+ const segIndex = content.indexOf(segment, actualPos);
33190
+ if (segIndex === -1) {
33191
+ break;
33107
33192
  }
33193
+ if (runningIndex === 0) {
33194
+ actualPos = segIndex;
33195
+ } else {
33196
+ actualPos = segIndex + segment.length;
33197
+ }
33198
+ runningIndex++;
33108
33199
  }
33109
- results.push({
33110
- type: "tool_use",
33111
- name: toolName,
33112
- params
33113
- });
33114
- } else {
33115
- results.push({
33116
- type: "text",
33117
- content: fullTagContent
33118
- });
33200
+ const strippedSearch = trimmedSearch.replace(/\s+/g, "");
33201
+ const endPos = actualPos;
33202
+ const startPos = endPos - strippedSearch.length;
33203
+ return content.slice(0, startPos) + replace + content.slice(endPos);
33119
33204
  }
33120
- remainingMessage = remainingMessage.slice(match.index + fullTagContent.length);
33205
+ throw new Error(`Could not find the following text in file:
33206
+ ${search}`);
33207
+ };
33208
+ let updatedFile = fileContent;
33209
+ for (const { search, replace } of blocks) {
33210
+ updatedFile = findAndReplace(updatedFile, search, replace);
33121
33211
  }
33122
- if (remainingMessage.trim()) {
33123
- results.push({
33124
- type: "text",
33125
- content: remainingMessage.trim()
33126
- });
33212
+ return updatedFile;
33213
+ };
33214
+ // ../core/src/tools/utils/getArg.ts
33215
+ var getString = (args, name, defaultValue) => {
33216
+ const ret = args[name] ?? defaultValue;
33217
+ if (ret === undefined) {
33218
+ throw new Error(`Missing required argument: ${name}`);
33127
33219
  }
33128
- if (results.length === 0) {
33129
- results.push({
33130
- type: "text",
33131
- content: assistantMessage
33132
- });
33220
+ return ret;
33221
+ };
33222
+ var getStringArray = (args, name, defaultValue) => {
33223
+ const ret = args[name];
33224
+ if (ret === undefined) {
33225
+ if (defaultValue === undefined) {
33226
+ throw new Error(`Missing required argument: ${name}`);
33227
+ }
33228
+ return defaultValue;
33133
33229
  }
33134
- return results;
33135
- }
33136
-
33137
- // ../core/src/Agent/prompts.ts
33138
- var toolInfoPrompt = (tool, toolNamePrefix, parameterPrefix) => `
33139
- ## ${toolNamePrefix}${tool.name}
33140
-
33141
- Description: ${tool.description}
33142
-
33143
- Parameters:
33144
- ${tool.parameters.map((param) => `- ${parameterPrefix}${param.name}: (${param.required ? "required" : "optional"}) ${param.description}`).join(`
33145
- `)}
33146
-
33147
- Usage:
33148
- <${toolNamePrefix}${tool.name}>
33149
- ${tool.parameters.map((param) => `<${parameterPrefix}${param.name}>${param.usageValue}</${parameterPrefix}${param.name}>`).join(`
33150
- `)}
33151
- </${toolNamePrefix}${tool.name}>`;
33152
- var toolInfoExamplesPrompt = (idx, tool, example, toolNamePrefix, parameterPrefix) => `
33153
- ## Example ${idx + 1}: ${example.description}
33154
-
33155
- <${toolNamePrefix}${tool.name}>
33156
- ${example.parameters.map((param) => `<${parameterPrefix}${param.name}>${param.value}</${parameterPrefix}${param.name}>`).join(`
33157
- `)}
33158
- </${toolNamePrefix}${tool.name}>
33159
- `;
33160
- var toolUsePrompt = (tools, toolNamePrefix) => {
33161
- if (tools.length === 0) {
33162
- return "";
33230
+ if (ret === "") {
33231
+ return [];
33163
33232
  }
33164
- const parameterPrefix = `${toolNamePrefix}parameter_`;
33165
- let exampleIndex = 0;
33166
- return `
33167
- ====
33168
-
33169
- TOOL USE
33170
-
33171
- You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
33172
-
33173
- # Tool Use Formatting
33174
-
33175
- Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
33176
-
33177
- <${toolNamePrefix}tool_name>
33178
- <${parameterPrefix}name1>value1</${parameterPrefix}name1>
33179
- <${parameterPrefix}name2>value2</${parameterPrefix}name2>
33180
- ...
33181
- </${toolNamePrefix}tool_name>
33182
-
33183
- For example:
33184
-
33185
- <${toolNamePrefix}read_file>
33186
- <${parameterPrefix}path>src/main.js</${parameterPrefix}path>
33187
- </${toolNamePrefix}read_file>
33188
-
33189
- Always adhere to this format for the tool use to ensure proper parsing and execution.
33190
-
33191
- # Tools
33192
- ${tools.map((tool) => toolInfoPrompt(tool, toolNamePrefix, parameterPrefix)).join(`
33193
- `)}
33194
-
33195
- # Tool Use Examples
33196
- ${tools.map((tool) => {
33197
- let promp = "";
33198
- for (const example of tool.examples ?? []) {
33199
- promp += toolInfoExamplesPrompt(exampleIndex++, tool, example, toolNamePrefix, parameterPrefix);
33233
+ return ret.split(",").map((s2) => s2.trim());
33234
+ };
33235
+ var getBoolean = (args, name, defaultValue) => {
33236
+ const ret = args[name];
33237
+ if (ret === undefined) {
33238
+ if (defaultValue === undefined) {
33239
+ throw new Error(`Missing required argument: ${name}`);
33200
33240
  }
33201
- return promp;
33202
- }).join("")}
33203
- # Tool Use Guidelines
33204
-
33205
- 1. **In \`<thinking>\` tags**, assess what information you have and what you need to proceed.
33206
- 2. **Choose one tool at a time per message** based on the task and its description. Do not assume a tool’s outcome without explicit confirmation.
33207
- 3. **Formulate tool use only in the specified XML format** for each tool.
33208
- 4. **Wait for the user’s response** after each tool use. Do not proceed until you have their confirmation.
33209
- 5. The user’s response may include:
33210
- - Tool success or failure details
33211
- - Linter errors
33212
- - Terminal output or other relevant feedback
33213
- 6. **Never repeat or quote the entire tool command** in your final user-facing message. Summarize outcomes clearly and avoid echoing commands verbatim.
33214
- 7. **Respond concisely** and move the conversation forward. Do not re-issue the same command or re-trigger tool use without necessity.
33215
- 8. Follow these steps **iteratively**, confirming success and addressing issues as you go.
33216
-
33217
- By adhering to these guidelines:
33218
- - You maintain clarity without accidentally re-invoking tools.
33219
- - You confirm each step’s results before proceeding.
33220
- - You provide only the necessary information in user-facing replies to prevent re-interpretation as new commands.`;
33221
- };
33222
- var agentsPrompt = (agents, name) => `
33223
- ====
33224
-
33225
- AVAILABLE AGENTS
33226
-
33227
- The following agents are available for task handover:
33228
- ${agents.map((agent) => `
33229
- - **${agent.name}**
33230
- - Responsibilities:
33231
- ${agent.responsibilities.map((resp) => ` - ${resp}`).join(`
33232
- `)}`).join(`
33233
- `)}
33234
-
33235
- - **Current Agent Role**
33236
- You are currently acting as **${name}**. If you identify the task is beyond your current scope, use the handover tool to transition to the other agent. Include sufficient context so the new agent can seamlessly continue the work.
33237
- `;
33238
- var capabilities = (toolNamePrefix) => `
33239
- ====
33240
-
33241
- CAPABILITIES
33242
-
33243
- - You have access to a range of tools to aid you in your work. These tools help you effectively accomplish a wide range of tasks.
33244
- - When the user initially gives you a task, a recursive list of all filepaths in the current working directory will be included in context. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further.`;
33245
- var systemInformation = (info) => `
33246
- ====
33247
-
33248
- SYSTEM INFORMATION
33249
-
33250
- Operating System: ${info.os}`;
33251
- var interactiveMode = (interactive) => {
33252
- if (interactive) {
33253
- return `
33254
- ====
33255
-
33256
- INTERACTIVE MODE
33257
-
33258
- You are in interactive mode. This means you may ask user questions to gather additional information to complete the task.
33259
- `;
33241
+ return defaultValue;
33260
33242
  }
33261
- return `
33262
- ====
33263
-
33264
- NON-INTERACTIVE MODE
33265
-
33266
- You are in non-interactive mode. This means you will not be able to ask user questions to gather additional information to complete the task. You should try to use available tools to accomplish the task. If unable to precede further, you may try to end the task and provide a reason.
33267
- `;
33268
- };
33269
- var customInstructions = (customInstructions2) => {
33270
- const joined = customInstructions2.join(`
33271
- `);
33272
- if (joined.trim() === "") {
33273
- return "";
33243
+ switch (ret.toLowerCase()) {
33244
+ case "true":
33245
+ return true;
33246
+ case "false":
33247
+ return false;
33248
+ default:
33249
+ throw new Error(`Invalid argument value: ${name}`);
33274
33250
  }
33275
- return `
33276
- ====
33277
-
33278
- USER'S CUSTOM INSTRUCTIONS
33279
-
33280
- The following additional instructions are provided by the user, and should be followed to the best of your ability without interfering with the TOOL USE guidelines.
33281
-
33282
- ${joined}`;
33283
33251
  };
33284
- var customScripts = (commands) => {
33285
- const joined = Object.entries(commands).map(([name, command]) => {
33286
- if (typeof command === "string") {
33287
- return `- ${name}
33288
- - Command: \`${command}\``;
33252
+ var getInt = (args, name, defaultValue) => {
33253
+ const ret = args[name];
33254
+ if (ret === undefined) {
33255
+ if (defaultValue === undefined) {
33256
+ throw new Error(`Missing required argument: ${name}`);
33289
33257
  }
33290
- return `- ${name}
33291
- - Command: \`${command.command}\`
33292
- - Description: ${command.description}`;
33293
- }).join(`
33294
- `);
33295
- if (joined.trim() === "") {
33296
- return "";
33258
+ return defaultValue;
33297
33259
  }
33298
- return `
33299
- ====
33300
-
33301
- USER'S CUSTOM COMMANDS
33302
-
33303
- The following additional commands are provided by the user, and should be followed to the best of your ability without interfering with the TOOL USE guidelines.
33304
-
33305
- ${joined}`;
33306
- };
33307
- var responsePrompts = {
33308
- errorInvokeTool: (tool, error) => `An error occurred while invoking the tool "${tool}": ${error}`,
33309
- requireUseTool: "Error: You must use a tool before proceeding. Making sure the tool is invoked using xml tags.",
33310
- toolResults: (tool, result) => `<tool_response>
33311
- <tool_name>${tool}</tool_name>
33312
- <tool_result>
33313
- ${result}
33314
- </tool_result>
33315
- </tool_response>`
33260
+ const parsed = Number.parseInt(ret);
33261
+ if (Number.isNaN(parsed)) {
33262
+ throw new Error(`Invalid argument value: ${name}`);
33263
+ }
33264
+ return parsed;
33316
33265
  };
33317
-
33318
- // ../core/src/Agent/AgentBase.ts
33319
- class AgentBase {
33320
- ai;
33321
- config;
33322
- handlers;
33323
- constructor(name, ai, config) {
33324
- this.ai = ai;
33325
- if (config.agents && Object.keys(config.agents).length > 0) {
33326
- const agents = agentsPrompt(config.agents, name);
33327
- config.systemPrompt += `
33328
- ${agents}`;
33266
+ // ../core/src/tools/askFollowupQuestion.ts
33267
+ var toolInfo = {
33268
+ name: "ask_followup_question",
33269
+ description: "Whenever you need extra details or clarification to complete the task, pose a direct question to the user. Use this tool sparingly to avoid excessive back-and-forth. If helpful, offer multiple-choice options or examples to guide the user’s response.",
33270
+ parameters: [
33271
+ {
33272
+ name: "question",
33273
+ description: "The question to ask the user. This should be a clear, specific question that addresses the information you need.",
33274
+ required: true,
33275
+ usageValue: "Your question here"
33276
+ },
33277
+ {
33278
+ name: "options",
33279
+ description: "A comma separated list of possible answers to the question. If not provided, the user will be prompted to provide an answer.",
33280
+ required: false,
33281
+ usageValue: "A comma separated list of possible answers (optional)"
33329
33282
  }
33330
- this.config = config;
33331
- const handlers = {};
33332
- for (const tool of config.tools) {
33333
- handlers[tool.name] = tool;
33283
+ ],
33284
+ examples: [
33285
+ {
33286
+ description: "Request to ask a question",
33287
+ parameters: [
33288
+ {
33289
+ name: "question",
33290
+ value: "What is the name of the project?"
33291
+ }
33292
+ ]
33293
+ },
33294
+ {
33295
+ description: "Request to ask a question with options",
33296
+ parameters: [
33297
+ {
33298
+ name: "question",
33299
+ value: "What framework do you use?"
33300
+ },
33301
+ {
33302
+ name: "options",
33303
+ value: "React,Angular,Vue,Svelte"
33304
+ }
33305
+ ]
33334
33306
  }
33335
- this.handlers = handlers;
33307
+ ]
33308
+ };
33309
+ var handler = async (provider, args) => {
33310
+ if (!provider.askFollowupQuestion) {
33311
+ return {
33312
+ type: "Error" /* Error */,
33313
+ message: "Not possible to ask followup question. Abort."
33314
+ };
33336
33315
  }
33337
- async startTask({
33338
- task,
33339
- context,
33340
- maxIterations = 50,
33341
- callback = () => {
33316
+ const question = getString(args, "question");
33317
+ const options = getStringArray(args, "options", []);
33318
+ const answer = await provider.askFollowupQuestion(question, options);
33319
+ return {
33320
+ type: "Reply" /* Reply */,
33321
+ message: `<ask_followup_question_question>${question}</ask_followup_question_question>
33322
+ <ask_followup_question_answer>${answer}</ask_followup_question_answer>`
33323
+ };
33324
+ };
33325
+ var isAvailable = (provider) => {
33326
+ return !!provider.askFollowupQuestion;
33327
+ };
33328
+ var askFollowupQuestion_default = {
33329
+ ...toolInfo,
33330
+ handler,
33331
+ isAvailable
33332
+ };
33333
+ // ../core/src/tools/attemptCompletion.ts
33334
+ var toolInfo2 = {
33335
+ name: "attempt_completion",
33336
+ description: "Use this tool when you believe the user’s 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.",
33337
+ parameters: [
33338
+ {
33339
+ name: "result",
33340
+ 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.",
33341
+ required: true,
33342
+ usageValue: "Your final result description here"
33342
33343
  }
33343
- }) {
33344
- if (maxIterations < 1) {
33345
- throw new Error("Max iterations must be greater than 0");
33344
+ ],
33345
+ examples: [
33346
+ {
33347
+ description: "Request to present the result of the task",
33348
+ parameters: [
33349
+ {
33350
+ name: "result",
33351
+ value: "Your final result description here"
33352
+ }
33353
+ ]
33346
33354
  }
33347
- const taskInfo = {
33348
- options: {
33349
- maxIterations
33350
- },
33351
- messages: [],
33352
- inputTokens: 0,
33353
- outputTokens: 0,
33354
- cacheWriteTokens: 0,
33355
- cacheReadTokens: 0,
33356
- totalCost: 0
33355
+ ]
33356
+ };
33357
+ var handler2 = async (provider, args) => {
33358
+ const result = getString(args, "result");
33359
+ const moreMessage = await provider.attemptCompletion?.(result);
33360
+ if (!moreMessage) {
33361
+ return {
33362
+ type: "Exit" /* Exit */,
33363
+ message: result
33357
33364
  };
33358
- let text = `<task>${task}</task>`;
33359
- if (context) {
33360
- text += `
33361
- <context>${context}</context>`;
33362
- }
33363
- callback({ kind: "StartTask" /* StartTask */, info: taskInfo, systemPrompt: this.config.systemPrompt });
33364
- return await this.#processLoop(text, taskInfo, callback);
33365
33365
  }
33366
- async#processLoop(userMessage, taskInfo, callback) {
33367
- let nextRequest = userMessage;
33368
- while (nextRequest) {
33369
- if (taskInfo.messages.length > taskInfo.options.maxIterations * 2) {
33370
- callback({ kind: "MaxIterationsReached" /* MaxIterationsReached */, info: taskInfo });
33371
- return ["MaxIterations", taskInfo];
33372
- }
33373
- const response = await this.#request(taskInfo, nextRequest, callback);
33374
- const [newMessage, exitReason] = await this.#handleResponse(taskInfo, response, callback);
33375
- if (exitReason) {
33376
- callback({ kind: "EndTask" /* EndTask */, info: taskInfo });
33377
- return [exitReason, taskInfo];
33378
- }
33379
- nextRequest = newMessage;
33366
+ return {
33367
+ type: "Reply" /* Reply */,
33368
+ message: `<user_message>${moreMessage}</user_message>`
33369
+ };
33370
+ };
33371
+ var isAvailable2 = (provider) => {
33372
+ return true;
33373
+ };
33374
+ var attemptCompletion_default = {
33375
+ ...toolInfo2,
33376
+ handler: handler2,
33377
+ isAvailable: isAvailable2
33378
+ };
33379
+ // ../core/src/tools/executeCommand.ts
33380
+ var toolInfo3 = {
33381
+ name: "execute_command",
33382
+ description: `Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will also be executed in the project root directory regardless of executed commands in previous tool uses.`,
33383
+ parameters: [
33384
+ {
33385
+ name: "command",
33386
+ description: "The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.",
33387
+ required: true,
33388
+ usageValue: "Your command here"
33389
+ },
33390
+ {
33391
+ name: "requires_approval",
33392
+ description: `A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.`,
33393
+ required: false,
33394
+ usageValue: "true or false"
33380
33395
  }
33381
- callback({ kind: "EndTask" /* EndTask */, info: taskInfo });
33382
- return [{ type: "Exit" /* Exit */, message: "Task completed successfully" }, taskInfo];
33396
+ ],
33397
+ examples: [
33398
+ {
33399
+ description: "Request to execute a command",
33400
+ parameters: [
33401
+ {
33402
+ name: "command",
33403
+ value: "npm run dev"
33404
+ },
33405
+ {
33406
+ name: "requires_approval",
33407
+ value: "false"
33408
+ }
33409
+ ]
33410
+ }
33411
+ ]
33412
+ };
33413
+ var handler3 = async (provider, args) => {
33414
+ if (!provider.executeCommand) {
33415
+ return {
33416
+ type: "Error" /* Error */,
33417
+ message: "Not possible to execute command. Abort."
33418
+ };
33383
33419
  }
33384
- async continueTask(userMessage, taskInfo, callback = () => {
33385
- }) {
33386
- return await this.#processLoop(userMessage, taskInfo, callback);
33420
+ const command = getString(args, "command");
33421
+ const requiresApproval = getBoolean(args, "requires_approval", false);
33422
+ const result = await provider.executeCommand?.(command, requiresApproval);
33423
+ const message = `<command>${command}</command>
33424
+ <command_exit_code>${result.exitCode}</command_exit_code>
33425
+ <command_stdout>
33426
+ ${result.stdout}
33427
+ </command_stdout>
33428
+ <command_stderr>
33429
+ ${result.stderr}
33430
+ </command_stderr>`;
33431
+ if (result.exitCode === 0) {
33432
+ return {
33433
+ type: "Reply" /* Reply */,
33434
+ message
33435
+ };
33387
33436
  }
33388
- async#request(info, userMessage, callback) {
33389
- await callback({ kind: "StartRequest" /* StartRequest */, info, userMessage });
33390
- info.messages.push({
33391
- role: "user",
33392
- content: userMessage
33393
- });
33394
- const stream = this.ai.send(this.config.systemPrompt, info.messages);
33395
- let currentAssistantMessage = "";
33396
- for await (const chunk of stream) {
33397
- switch (chunk.type) {
33398
- case "usage":
33399
- info.inputTokens = chunk.inputTokens ?? 0;
33400
- info.outputTokens = chunk.outputTokens ?? 0;
33401
- info.cacheWriteTokens = chunk.cacheWriteTokens ?? 0;
33402
- info.cacheReadTokens = chunk.cacheReadTokens ?? 0;
33403
- info.totalCost = chunk.totalCost;
33404
- await callback({ kind: "Usage" /* Usage */, info });
33405
- break;
33406
- case "text":
33407
- currentAssistantMessage += chunk.text;
33408
- await callback({ kind: "Text" /* Text */, info, newText: chunk.text });
33409
- break;
33410
- case "reasoning":
33411
- await callback({ kind: "Reasoning" /* Reasoning */, info, newText: chunk.text });
33412
- break;
33413
- }
33414
- }
33415
- if (!currentAssistantMessage) {
33416
- throw new Error("No assistant message received");
33437
+ return {
33438
+ type: "Error" /* Error */,
33439
+ message
33440
+ };
33441
+ };
33442
+ var isAvailable3 = (provider) => {
33443
+ return !!provider.executeCommand;
33444
+ };
33445
+ var executeCommand_default = {
33446
+ ...toolInfo3,
33447
+ handler: handler3,
33448
+ isAvailable: isAvailable3
33449
+ };
33450
+ // ../core/src/tools/listCodeDefinitionNames.ts
33451
+ var toolInfo4 = {
33452
+ name: "list_code_definition_names",
33453
+ description: "Request to list definition names (classes, functions, methods, etc.) used in a file. This tool provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.",
33454
+ parameters: [
33455
+ {
33456
+ name: "path",
33457
+ description: "The path of a code file to list top level source code definitions for.",
33458
+ required: true,
33459
+ usageValue: "Directory path here"
33417
33460
  }
33418
- info.messages.push({
33419
- role: "assistant",
33420
- content: currentAssistantMessage
33421
- });
33422
- const ret = parseAssistantMessage(currentAssistantMessage, this.config.tools, this.config.toolNamePrefix);
33423
- await callback({ kind: "EndRequest" /* EndRequest */, info });
33424
- return ret;
33461
+ ]
33462
+ };
33463
+ var handler4 = async (provider, args) => {
33464
+ if (!provider.listCodeDefinitionNames) {
33465
+ return {
33466
+ type: "Error" /* Error */,
33467
+ message: "Not possible to list code definition names. Abort."
33468
+ };
33425
33469
  }
33426
- async#handleResponse(info, response, callback) {
33427
- const toolReponses = [];
33428
- outer:
33429
- for (const content of response) {
33430
- switch (content.type) {
33431
- case "text":
33432
- break;
33433
- case "tool_use": {
33434
- await callback({ kind: "ToolUse" /* ToolUse */, info, tool: content.name });
33435
- const toolResp = await this.#invokeTool(content.name, content.params);
33436
- switch (toolResp.type) {
33437
- case "Reply" /* Reply */:
33438
- await callback({ kind: "ToolReply" /* ToolReply */, info, tool: content.name });
33439
- toolReponses.push({ tool: content.name, response: toolResp.message });
33440
- break;
33441
- case "Exit" /* Exit */:
33442
- return [undefined, toolResp];
33443
- case "Invalid" /* Invalid */:
33444
- await callback({ kind: "ToolInvalid" /* ToolInvalid */, info, tool: content.name });
33445
- toolReponses.push({ tool: content.name, response: toolResp.message });
33446
- break outer;
33447
- case "Error" /* Error */:
33448
- await callback({ kind: "ToolError" /* ToolError */, info, tool: content.name });
33449
- toolReponses.push({ tool: content.name, response: toolResp.message });
33450
- break outer;
33451
- case "Interrupted" /* Interrupted */:
33452
- await callback({ kind: "ToolInterrupted" /* ToolInterrupted */, info, tool: content.name });
33453
- return [undefined, toolResp];
33454
- case "HandOver" /* HandOver */:
33455
- await callback({
33456
- kind: "ToolHandOver" /* ToolHandOver */,
33457
- info,
33458
- tool: content.name,
33459
- agentName: toolResp.agentName,
33460
- task: toolResp.task,
33461
- context: toolResp.context,
33462
- files: toolResp.files
33463
- });
33464
- return [undefined, toolResp];
33465
- }
33466
- break;
33467
- }
33470
+ const path = getString(args, "path");
33471
+ const files = await provider.listCodeDefinitionNames(path);
33472
+ return {
33473
+ type: "Reply" /* Reply */,
33474
+ message: `<list_code_definition_names_path>${path}</list_code_definition_names_path>
33475
+ <list_code_definition_names_files>
33476
+ ${files.join(`
33477
+ `)}
33478
+ </list_code_definition_names_files>`
33479
+ };
33480
+ };
33481
+ var isAvailable4 = (provider) => {
33482
+ return !!provider.listCodeDefinitionNames;
33483
+ };
33484
+ var listCodeDefinitionNames_default = {
33485
+ ...toolInfo4,
33486
+ handler: handler4,
33487
+ isAvailable: isAvailable4
33488
+ };
33489
+ // ../core/src/tools/listFiles.ts
33490
+ var toolInfo5 = {
33491
+ name: "list_files",
33492
+ 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.",
33493
+ parameters: [
33494
+ {
33495
+ name: "path",
33496
+ description: "The path of the directory to list contents for (relative to the current working directory)",
33497
+ required: true,
33498
+ usageValue: "Directory path here"
33499
+ },
33500
+ {
33501
+ name: "max_count",
33502
+ description: "The maximum number of files to list. Default to 2000",
33503
+ required: false,
33504
+ usageValue: "Maximum number of files to list (optional)"
33505
+ },
33506
+ {
33507
+ name: "recursive",
33508
+ description: "Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.",
33509
+ required: false,
33510
+ usageValue: "true or false (optional)"
33511
+ }
33512
+ ],
33513
+ examples: [
33514
+ {
33515
+ description: "Request to list files",
33516
+ parameters: [
33517
+ {
33518
+ name: "path",
33519
+ value: "src"
33520
+ },
33521
+ {
33522
+ name: "max_count",
33523
+ value: "100"
33468
33524
  }
33469
- }
33470
- if (toolReponses.length === 0 && !this.config.interactive) {
33471
- return [responsePrompts.requireUseTool, undefined];
33525
+ ]
33472
33526
  }
33473
- const finalResp = toolReponses.map(({ tool, response: response2 }) => responsePrompts.toolResults(tool, response2)).join(`
33474
-
33475
- `);
33476
- return [finalResp, undefined];
33527
+ ]
33528
+ };
33529
+ var handler5 = async (provider, args) => {
33530
+ if (!provider.listFiles) {
33531
+ return {
33532
+ type: "Error" /* Error */,
33533
+ message: "Not possible to list files. Abort."
33534
+ };
33477
33535
  }
33478
- async#invokeTool(name, args) {
33479
- try {
33480
- const handler = this.handlers[name]?.handler;
33481
- if (!handler) {
33482
- return {
33483
- type: "Error" /* Error */,
33484
- message: responsePrompts.errorInvokeTool(name, "Tool not found"),
33485
- canRetry: false
33486
- };
33487
- }
33488
- return await handler(this.config.provider, args);
33489
- } catch (error) {
33490
- return {
33491
- type: "Error" /* Error */,
33492
- message: responsePrompts.errorInvokeTool(name, error),
33493
- canRetry: false
33494
- };
33495
- }
33496
- }
33497
- get model() {
33498
- return this.ai.model;
33499
- }
33500
- }
33501
- // ../core/src/tools/allTools.ts
33502
- var exports_allTools = {};
33503
- __export(exports_allTools, {
33504
- writeToFile: () => writeToFile_default,
33505
- searchFiles: () => searchFiles_default,
33506
- replaceInFile: () => replaceInFile_default,
33507
- renameFile: () => renameFile_default,
33508
- removeFile: () => removeFile_default,
33509
- readFile: () => readFile_default,
33510
- listFiles: () => listFiles_default,
33511
- listCodeDefinitionNames: () => listCodeDefinitionNames_default,
33512
- handOver: () => handOver_default,
33513
- executeCommand: () => executeCommand_default,
33514
- attemptCompletion: () => attemptCompletion_default,
33515
- askFollowupQuestion: () => askFollowupQuestion_default
33516
- });
33517
-
33518
- // ../core/src/tools/utils/replaceInFile.ts
33519
- var replaceInFile = async (fileContent, diff) => {
33520
- const blockPattern = /<<<<<+ SEARCH\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
33521
- const blocks = [];
33522
- for (let match = blockPattern.exec(diff);match !== null; match = blockPattern.exec(diff)) {
33523
- blocks.push({ search: match[1], replace: match[2] });
33524
- }
33525
- if (blocks.length === 0) {
33526
- throw new Error("No valid diff blocks found.");
33527
- }
33528
- const findAndReplace = (content, search, replace) => {
33529
- let index = content.indexOf(search);
33530
- if (index !== -1) {
33531
- return content.slice(0, index) + replace + content.slice(index + search.length);
33532
- }
33533
- const trimmedSearch = search.trim();
33534
- const trimmedContent = content.trim();
33535
- const offset = content.indexOf(trimmedContent);
33536
- index = trimmedContent.indexOf(trimmedSearch);
33537
- if (index !== -1) {
33538
- const absoluteIndex = offset + index;
33539
- return content.slice(0, absoluteIndex) + replace + content.slice(absoluteIndex + trimmedSearch.length);
33540
- }
33541
- const normalizedSearch = trimmedSearch.replace(/\s+/g, " ");
33542
- const normalizedContent = trimmedContent.replace(/\s+/g, " ");
33543
- index = normalizedContent.indexOf(normalizedSearch);
33544
- if (index !== -1) {
33545
- let runningIndex = 0;
33546
- let actualPos = offset;
33547
- for (const segment of trimmedSearch.replace(/\s+/g, " ").split(" ")) {
33548
- const segIndex = content.indexOf(segment, actualPos);
33549
- if (segIndex === -1) {
33550
- break;
33551
- }
33552
- if (runningIndex === 0) {
33553
- actualPos = segIndex;
33554
- } else {
33555
- actualPos = segIndex + segment.length;
33556
- }
33557
- runningIndex++;
33558
- }
33559
- const strippedSearch = trimmedSearch.replace(/\s+/g, "");
33560
- const endPos = actualPos;
33561
- const startPos = endPos - strippedSearch.length;
33562
- return content.slice(0, startPos) + replace + content.slice(endPos);
33563
- }
33564
- throw new Error(`Could not find the following text in file:
33565
- ${search}`);
33536
+ const path = getString(args, "path");
33537
+ const maxCount = getInt(args, "max_count", 2000);
33538
+ const recursive = getBoolean(args, "recursive", true);
33539
+ const [files, limitReached] = await provider.listFiles(path, recursive, maxCount);
33540
+ return {
33541
+ type: "Reply" /* Reply */,
33542
+ message: `<list_files_path>${path}</list_files_path>
33543
+ <list_files_files>
33544
+ ${files.join(`
33545
+ `)}
33546
+ </list_files_files>
33547
+ <list_files_truncated>${limitReached}</list_files_truncated>`
33566
33548
  };
33567
- let updatedFile = fileContent;
33568
- for (const { search, replace } of blocks) {
33569
- updatedFile = findAndReplace(updatedFile, search, replace);
33570
- }
33571
- return updatedFile;
33572
- };
33573
- // ../core/src/tools/utils/getArg.ts
33574
- var getString = (args, name, defaultValue) => {
33575
- const ret = args[name] ?? defaultValue;
33576
- if (ret === undefined) {
33577
- throw new Error(`Missing required argument: ${name}`);
33578
- }
33579
- return ret;
33580
- };
33581
- var getStringArray = (args, name, defaultValue) => {
33582
- const ret = args[name];
33583
- if (ret === undefined) {
33584
- if (defaultValue === undefined) {
33585
- throw new Error(`Missing required argument: ${name}`);
33586
- }
33587
- return defaultValue;
33588
- }
33589
- if (ret === "") {
33590
- return [];
33591
- }
33592
- return ret.split(",").map((s2) => s2.trim());
33593
33549
  };
33594
- var getBoolean = (args, name, defaultValue) => {
33595
- const ret = args[name];
33596
- if (ret === undefined) {
33597
- if (defaultValue === undefined) {
33598
- throw new Error(`Missing required argument: ${name}`);
33599
- }
33600
- return defaultValue;
33601
- }
33602
- switch (ret.toLowerCase()) {
33603
- case "true":
33604
- return true;
33605
- case "false":
33606
- return false;
33607
- default:
33608
- throw new Error(`Invalid argument value: ${name}`);
33609
- }
33550
+ var isAvailable5 = (provider) => {
33551
+ return !!provider.listFiles;
33610
33552
  };
33611
- var getInt = (args, name, defaultValue) => {
33612
- const ret = args[name];
33613
- if (ret === undefined) {
33614
- if (defaultValue === undefined) {
33615
- throw new Error(`Missing required argument: ${name}`);
33616
- }
33617
- return defaultValue;
33618
- }
33619
- const parsed = Number.parseInt(ret);
33620
- if (Number.isNaN(parsed)) {
33621
- throw new Error(`Invalid argument value: ${name}`);
33622
- }
33623
- return parsed;
33553
+ var listFiles_default = {
33554
+ ...toolInfo5,
33555
+ handler: handler5,
33556
+ isAvailable: isAvailable5
33624
33557
  };
33625
- // ../core/src/tools/askFollowupQuestion.ts
33626
- var toolInfo = {
33627
- name: "ask_followup_question",
33628
- description: "Whenever you need extra details or clarification to complete the task, pose a direct question to the user. Use this tool sparingly to avoid excessive back-and-forth. If helpful, offer multiple-choice options or examples to guide the user’s response.",
33558
+ // ../core/src/tools/readFile.ts
33559
+ var toolInfo6 = {
33560
+ name: "read_file",
33561
+ 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.",
33629
33562
  parameters: [
33630
33563
  {
33631
- name: "question",
33632
- description: "The question to ask the user. This should be a clear, specific question that addresses the information you need.",
33564
+ name: "path",
33565
+ description: "The path of the file to read",
33633
33566
  required: true,
33634
- usageValue: "Your question here"
33635
- },
33636
- {
33637
- name: "options",
33638
- description: "A comma separated list of possible answers to the question. If not provided, the user will be prompted to provide an answer.",
33639
- required: false,
33640
- usageValue: "A comma separated list of possible answers (optional)"
33567
+ usageValue: "Comma separated paths here"
33641
33568
  }
33642
33569
  ],
33643
33570
  examples: [
33644
33571
  {
33645
- description: "Request to ask a question",
33572
+ description: "Request to read the contents of a file",
33646
33573
  parameters: [
33647
33574
  {
33648
- name: "question",
33649
- value: "What is the name of the project?"
33575
+ name: "path",
33576
+ value: "src/main.js"
33650
33577
  }
33651
33578
  ]
33652
33579
  },
33653
33580
  {
33654
- description: "Request to ask a question with options",
33581
+ description: "Request to read multiple files",
33655
33582
  parameters: [
33656
33583
  {
33657
- name: "question",
33658
- value: "What framework do you use?"
33659
- },
33660
- {
33661
- name: "options",
33662
- value: "React,Angular,Vue,Svelte"
33584
+ name: "path",
33585
+ value: "src/main.js,src/index.js"
33663
33586
  }
33664
33587
  ]
33665
33588
  }
33666
33589
  ]
33667
33590
  };
33668
- var handler = async (provider, args) => {
33669
- if (!provider.askFollowupQuestion) {
33591
+ var handler6 = async (provider, args) => {
33592
+ if (!provider.readFile) {
33670
33593
  return {
33671
33594
  type: "Error" /* Error */,
33672
- message: "Not possible to ask followup question. Abort."
33595
+ message: "Not possible to read file. Abort."
33673
33596
  };
33674
33597
  }
33675
- const question = getString(args, "question");
33676
- const options = getStringArray(args, "options", []);
33677
- const answer = await provider.askFollowupQuestion(question, options);
33598
+ const paths = getStringArray(args, "path");
33599
+ const resp = [];
33600
+ for (const path of paths) {
33601
+ const fileContent = await provider.readFile(path);
33602
+ const isEmpty = fileContent.trim().length === 0;
33603
+ if (isEmpty) {
33604
+ resp.push(`<read_file_file_content path="${path}" is_empty="true" />`);
33605
+ } else {
33606
+ resp.push(`<read_file_file_conten path="${path}">${fileContent}</read_file_file_content>`);
33607
+ }
33608
+ }
33678
33609
  return {
33679
33610
  type: "Reply" /* Reply */,
33680
- message: `<ask_followup_question_question>${question}</ask_followup_question_question>
33681
- <ask_followup_question_answer>${answer}</ask_followup_question_answer>`
33611
+ message: resp.join(`
33612
+ `)
33682
33613
  };
33683
33614
  };
33684
- var isAvailable = (provider) => {
33685
- return !!provider.askFollowupQuestion;
33615
+ var isAvailable6 = (provider) => {
33616
+ return !!provider.readFile;
33686
33617
  };
33687
- var askFollowupQuestion_default = {
33688
- ...toolInfo,
33689
- handler,
33690
- isAvailable
33618
+ var readFile_default = {
33619
+ ...toolInfo6,
33620
+ handler: handler6,
33621
+ isAvailable: isAvailable6
33691
33622
  };
33692
- // ../core/src/tools/attemptCompletion.ts
33693
- var toolInfo2 = {
33694
- name: "attempt_completion",
33695
- description: "Use this tool when you believe the user’s 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.",
33623
+ // ../core/src/tools/replaceInFile.ts
33624
+ var toolInfo7 = {
33625
+ name: "replace_in_file",
33626
+ 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.",
33696
33627
  parameters: [
33697
33628
  {
33698
- name: "result",
33699
- 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.",
33629
+ name: "path",
33630
+ description: "The path of the file to modify",
33700
33631
  required: true,
33701
- usageValue: "Your final result description here"
33702
- }
33703
- ],
33704
- examples: [
33632
+ usageValue: "File path here"
33633
+ },
33705
33634
  {
33706
- description: "Request to present the result of the task",
33707
- parameters: [
33708
- {
33709
- name: "result",
33710
- value: "Your final result description here"
33711
- }
33712
- ]
33713
- }
33714
- ]
33715
- };
33716
- var handler2 = async (provider, args) => {
33717
- const result = getString(args, "result");
33718
- const moreMessage = await provider.attemptCompletion?.(result);
33719
- if (!moreMessage) {
33720
- return {
33721
- type: "Exit" /* Exit */,
33722
- message: "<completed>true</completed>"
33723
- };
33724
- }
33725
- return {
33726
- type: "Reply" /* Reply */,
33727
- message: `<user_message>${moreMessage}</user_message>`
33728
- };
33729
- };
33730
- var isAvailable2 = (provider) => {
33731
- return true;
33732
- };
33733
- var attemptCompletion_default = {
33734
- ...toolInfo2,
33735
- handler: handler2,
33736
- isAvailable: isAvailable2
33737
- };
33738
- // ../core/src/tools/executeCommand.ts
33739
- var toolInfo3 = {
33740
- name: "execute_command",
33741
- description: `Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will also be executed in the project root directory regardless of executed commands in previous tool uses.`,
33742
- parameters: [
33743
- {
33744
- name: "command",
33745
- description: "The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.",
33635
+ name: "diff",
33636
+ description: `One or more SEARCH/REPLACE blocks following this exact format:
33637
+ \`\`\`
33638
+ <<<<<<< SEARCH
33639
+ [exact content to find]
33640
+ =======
33641
+ [new content to replace with]
33642
+ >>>>>>> REPLACE
33643
+ \`\`\`
33644
+ Critical rules:
33645
+ 1. SEARCH content must match the associated file section to find EXACTLY:
33646
+ * Match character-for-character including whitespace, indentation, line endings
33647
+ * Include all comments, docstrings, etc.
33648
+ 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.
33649
+ * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.
33650
+ * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.
33651
+ * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.
33652
+ 3. Keep SEARCH/REPLACE blocks concise:
33653
+ * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.
33654
+ * Include just the changing lines, and a few surrounding lines if needed for uniqueness.
33655
+ * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.
33656
+ * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.
33657
+ 4. Special operations:
33658
+ * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
33659
+ * To delete code: Use empty REPLACE section`,
33746
33660
  required: true,
33747
- usageValue: "Your command here"
33748
- },
33749
- {
33750
- name: "requires_approval",
33751
- description: `A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.`,
33752
- required: false,
33753
- usageValue: "true or false"
33661
+ usageValue: "Search and replace blocks here"
33754
33662
  }
33755
33663
  ],
33756
33664
  examples: [
33757
33665
  {
33758
- description: "Request to execute a command",
33666
+ description: "Request to replace sections of content in a file",
33759
33667
  parameters: [
33760
33668
  {
33761
- name: "command",
33762
- value: "npm run dev"
33669
+ name: "path",
33670
+ value: "src/main.js"
33763
33671
  },
33764
33672
  {
33765
- name: "requires_approval",
33766
- value: "false"
33673
+ name: "diff",
33674
+ value: `
33675
+ <<<<<<< SEARCH
33676
+ import React from 'react';
33677
+ =======
33678
+ import React, { useState } from 'react';
33679
+ >>>>>>> REPLACE
33680
+
33681
+ <<<<<<< SEARCH
33682
+ function handleSubmit() {
33683
+ saveData();
33684
+ setLoading(false);
33685
+ }
33686
+
33687
+ =======
33688
+ >>>>>>> REPLACE
33689
+
33690
+ <<<<<<< SEARCH
33691
+ return (
33692
+ <div>
33693
+ =======
33694
+ function handleSubmit() {
33695
+ saveData();
33696
+ setLoading(false);
33697
+ }
33698
+
33699
+ return (
33700
+ <div>
33701
+ >>>>>>> REPLACE
33702
+ `
33767
33703
  }
33768
33704
  ]
33769
33705
  }
33770
33706
  ]
33771
33707
  };
33772
- var handler3 = async (provider, args) => {
33773
- if (!provider.executeCommand) {
33774
- return {
33775
- type: "Error" /* Error */,
33776
- message: "Not possible to execute command. Abort."
33777
- };
33778
- }
33779
- const command = getString(args, "command");
33780
- const requiresApproval = getBoolean(args, "requires_approval", false);
33781
- const result = await provider.executeCommand?.(command, requiresApproval);
33782
- const message = `<command>${command}</command>
33783
- <command_exit_code>${result.exitCode}</command_exit_code>
33784
- <command_stdout>
33785
- ${result.stdout}
33786
- </command_stdout>
33787
- <command_stderr>
33788
- ${result.stderr}
33789
- </command_stderr>`;
33790
- if (result.exitCode === 0) {
33791
- return {
33792
- type: "Reply" /* Reply */,
33793
- message
33794
- };
33795
- }
33796
- return {
33797
- type: "Error" /* Error */,
33798
- message
33799
- };
33800
- };
33801
- var isAvailable3 = (provider) => {
33802
- return !!provider.executeCommand;
33803
- };
33804
- var executeCommand_default = {
33805
- ...toolInfo3,
33806
- handler: handler3,
33807
- isAvailable: isAvailable3
33808
- };
33809
- // ../core/src/tools/listCodeDefinitionNames.ts
33810
- var toolInfo4 = {
33811
- name: "list_code_definition_names",
33812
- description: "Request to list definition names (classes, functions, methods, etc.) used in a file. This tool provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.",
33813
- parameters: [
33814
- {
33815
- name: "path",
33816
- description: "The path of a code file to list top level source code definitions for.",
33817
- required: true,
33818
- usageValue: "Directory path here"
33819
- }
33820
- ]
33821
- };
33822
- var handler4 = async (provider, args) => {
33823
- if (!provider.listCodeDefinitionNames) {
33708
+ var handler7 = async (provider, args) => {
33709
+ if (!provider.readFile || !provider.writeFile) {
33824
33710
  return {
33825
33711
  type: "Error" /* Error */,
33826
- message: "Not possible to list code definition names. Abort."
33712
+ message: "Not possible to replace in file. Abort."
33827
33713
  };
33828
33714
  }
33829
33715
  const path = getString(args, "path");
33830
- const files = await provider.listCodeDefinitionNames(path);
33716
+ const diff = getString(args, "diff");
33717
+ const fileContent = await provider.readFile(path);
33718
+ const result = await replaceInFile(fileContent, diff);
33719
+ await provider.writeFile(path, result);
33831
33720
  return {
33832
33721
  type: "Reply" /* Reply */,
33833
- message: `<list_code_definition_names_path>${path}</list_code_definition_names_path>
33834
- <list_code_definition_names_files>
33835
- ${files.join(`
33836
- `)}
33837
- </list_code_definition_names_files>`
33722
+ message: `<replace_in_file_path>${path}</replace_in_file_path>`
33838
33723
  };
33839
33724
  };
33840
- var isAvailable4 = (provider) => {
33841
- return !!provider.listCodeDefinitionNames;
33725
+ var isAvailable7 = (provider) => {
33726
+ return !!provider.readFile && !!provider.writeFile;
33842
33727
  };
33843
- var listCodeDefinitionNames_default = {
33844
- ...toolInfo4,
33845
- handler: handler4,
33846
- isAvailable: isAvailable4
33728
+ var replaceInFile_default = {
33729
+ ...toolInfo7,
33730
+ handler: handler7,
33731
+ isAvailable: isAvailable7
33847
33732
  };
33848
- // ../core/src/tools/listFiles.ts
33849
- var toolInfo5 = {
33850
- name: "list_files",
33851
- 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.",
33733
+ // ../core/src/tools/searchFiles.ts
33734
+ var toolInfo8 = {
33735
+ name: "search_files",
33736
+ 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.",
33852
33737
  parameters: [
33853
33738
  {
33854
33739
  name: "path",
33855
- description: "The path of the directory to list contents for (relative to the current working directory)",
33740
+ description: "The path of the directory to search in (relative to the current working directory). This directory will be recursively searched.",
33856
33741
  required: true,
33857
33742
  usageValue: "Directory path here"
33858
33743
  },
33859
33744
  {
33860
- name: "max_count",
33861
- description: "The maximum number of files to list. Default to 2000",
33862
- required: false,
33863
- usageValue: "Maximum number of files to list (optional)"
33745
+ name: "regex",
33746
+ description: "The regular expression pattern to search for. Uses Rust regex syntax.",
33747
+ required: true,
33748
+ usageValue: "Your regex pattern here"
33864
33749
  },
33865
33750
  {
33866
- name: "recursive",
33867
- description: "Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.",
33751
+ name: "file_pattern",
33752
+ description: 'Glob pattern to filter files (e.g., "*.ts" for TypeScript files). If not provided, it will search all files (*).',
33868
33753
  required: false,
33869
- usageValue: "true or false (optional)"
33754
+ usageValue: "file pattern here (optional)"
33870
33755
  }
33871
33756
  ],
33872
33757
  examples: [
33873
33758
  {
33874
- description: "Request to list files",
33759
+ description: "Request to perform a regex search across files",
33875
33760
  parameters: [
33876
33761
  {
33877
33762
  name: "path",
33878
33763
  value: "src"
33879
33764
  },
33880
33765
  {
33881
- name: "max_count",
33882
- value: "100"
33766
+ name: "regex",
33767
+ value: "^components/"
33768
+ },
33769
+ {
33770
+ name: "file_pattern",
33771
+ value: "*.ts"
33883
33772
  }
33884
33773
  ]
33885
33774
  }
33886
33775
  ]
33887
33776
  };
33888
- var handler5 = async (provider, args) => {
33889
- if (!provider.listFiles) {
33777
+ var handler8 = async (provider, args) => {
33778
+ if (!provider.searchFiles) {
33890
33779
  return {
33891
33780
  type: "Error" /* Error */,
33892
- message: "Not possible to list files. Abort."
33781
+ message: "Not possible to search files. Abort."
33893
33782
  };
33894
33783
  }
33895
33784
  const path = getString(args, "path");
33896
- const maxCount = getInt(args, "max_count", 2000);
33897
- const recursive = getBoolean(args, "recursive", true);
33898
- const [files, limitReached] = await provider.listFiles(path, recursive, maxCount);
33785
+ const regex = getString(args, "regex");
33786
+ const filePattern = getString(args, "file_pattern", "*");
33787
+ const files = await provider.searchFiles(path, regex, filePattern);
33899
33788
  return {
33900
33789
  type: "Reply" /* Reply */,
33901
- message: `<list_files_path>${path}</list_files_path>
33902
- <list_files_files>
33790
+ message: `<search_files_path>${path}</search_files_path>
33791
+ <search_files_regex>${regex}</search_files_regex>
33792
+ <search_files_file_pattern>${filePattern}</search_files_file_pattern>
33793
+ <search_files_files>
33903
33794
  ${files.join(`
33904
33795
  `)}
33905
- </list_files_files>
33906
- <list_files_truncated>${limitReached}</list_files_truncated>`
33796
+ </search_files_files>
33797
+ `
33907
33798
  };
33908
33799
  };
33909
- var isAvailable5 = (provider) => {
33910
- return !!provider.listFiles;
33800
+ var isAvailable8 = (provider) => {
33801
+ return !!provider.searchFiles;
33911
33802
  };
33912
- var listFiles_default = {
33913
- ...toolInfo5,
33914
- handler: handler5,
33915
- isAvailable: isAvailable5
33916
- };
33917
- // ../core/src/tools/readFile.ts
33918
- var toolInfo6 = {
33919
- name: "read_file",
33920
- 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.",
33921
- parameters: [
33922
- {
33923
- name: "path",
33924
- description: "The path of the file to read",
33925
- required: true,
33926
- usageValue: "Comma separated paths here"
33927
- }
33928
- ],
33929
- examples: [
33930
- {
33931
- description: "Request to read the contents of a file",
33932
- parameters: [
33933
- {
33934
- name: "path",
33935
- value: "src/main.js"
33936
- }
33937
- ]
33938
- },
33939
- {
33940
- description: "Request to read multiple files",
33941
- parameters: [
33942
- {
33943
- name: "path",
33944
- value: "src/main.js,src/index.js"
33945
- }
33946
- ]
33947
- }
33948
- ]
33949
- };
33950
- var handler6 = async (provider, args) => {
33951
- if (!provider.readFile) {
33952
- return {
33953
- type: "Error" /* Error */,
33954
- message: "Not possible to read file. Abort."
33955
- };
33956
- }
33957
- const paths = getStringArray(args, "path");
33958
- const resp = [];
33959
- for (const path of paths) {
33960
- const fileContent = await provider.readFile(path);
33961
- const isEmpty = fileContent.trim().length === 0;
33962
- if (isEmpty) {
33963
- resp.push(`<read_file_file_content path="${path}" is_empty="true" />`);
33964
- } else {
33965
- resp.push(`<read_file_file_conten path="${path}">${fileContent}</read_file_file_content>`);
33966
- }
33967
- }
33968
- return {
33969
- type: "Reply" /* Reply */,
33970
- message: resp.join(`
33971
- `)
33972
- };
33973
- };
33974
- var isAvailable6 = (provider) => {
33975
- return !!provider.readFile;
33976
- };
33977
- var readFile_default = {
33978
- ...toolInfo6,
33979
- handler: handler6,
33980
- isAvailable: isAvailable6
33981
- };
33982
- // ../core/src/tools/replaceInFile.ts
33983
- var toolInfo7 = {
33984
- name: "replace_in_file",
33985
- 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.",
33986
- parameters: [
33987
- {
33988
- name: "path",
33989
- description: "The path of the file to modify",
33990
- required: true,
33991
- usageValue: "File path here"
33992
- },
33993
- {
33994
- name: "diff",
33995
- description: `One or more SEARCH/REPLACE blocks following this exact format:
33996
- \`\`\`
33997
- <<<<<<< SEARCH
33998
- [exact content to find]
33999
- =======
34000
- [new content to replace with]
34001
- >>>>>>> REPLACE
34002
- \`\`\`
34003
- Critical rules:
34004
- 1. SEARCH content must match the associated file section to find EXACTLY:
34005
- * Match character-for-character including whitespace, indentation, line endings
34006
- * Include all comments, docstrings, etc.
34007
- 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.
34008
- * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.
34009
- * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.
34010
- * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.
34011
- 3. Keep SEARCH/REPLACE blocks concise:
34012
- * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.
34013
- * Include just the changing lines, and a few surrounding lines if needed for uniqueness.
34014
- * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.
34015
- * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.
34016
- 4. Special operations:
34017
- * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
34018
- * To delete code: Use empty REPLACE section`,
34019
- required: true,
34020
- usageValue: "Search and replace blocks here"
34021
- }
34022
- ],
34023
- examples: [
34024
- {
34025
- description: "Request to replace sections of content in a file",
34026
- parameters: [
34027
- {
34028
- name: "path",
34029
- value: "src/main.js"
34030
- },
34031
- {
34032
- name: "diff",
34033
- value: `
34034
- <<<<<<< SEARCH
34035
- import React from 'react';
34036
- =======
34037
- import React, { useState } from 'react';
34038
- >>>>>>> REPLACE
34039
-
34040
- <<<<<<< SEARCH
34041
- function handleSubmit() {
34042
- saveData();
34043
- setLoading(false);
34044
- }
34045
-
34046
- =======
34047
- >>>>>>> REPLACE
34048
-
34049
- <<<<<<< SEARCH
34050
- return (
34051
- <div>
34052
- =======
34053
- function handleSubmit() {
34054
- saveData();
34055
- setLoading(false);
34056
- }
34057
-
34058
- return (
34059
- <div>
34060
- >>>>>>> REPLACE
34061
- `
34062
- }
34063
- ]
34064
- }
34065
- ]
34066
- };
34067
- var handler7 = async (provider, args) => {
34068
- if (!provider.readFile || !provider.writeFile) {
34069
- return {
34070
- type: "Error" /* Error */,
34071
- message: "Not possible to replace in file. Abort."
34072
- };
34073
- }
34074
- const path = getString(args, "path");
34075
- const diff = getString(args, "diff");
34076
- const fileContent = await provider.readFile(path);
34077
- const result = await replaceInFile(fileContent, diff);
34078
- await provider.writeFile(path, result);
34079
- return {
34080
- type: "Reply" /* Reply */,
34081
- message: `<replace_in_file_path>${path}</replace_in_file_path>`
34082
- };
34083
- };
34084
- var isAvailable7 = (provider) => {
34085
- return !!provider.readFile && !!provider.writeFile;
34086
- };
34087
- var replaceInFile_default = {
34088
- ...toolInfo7,
34089
- handler: handler7,
34090
- isAvailable: isAvailable7
34091
- };
34092
- // ../core/src/tools/searchFiles.ts
34093
- var toolInfo8 = {
34094
- name: "search_files",
34095
- 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.",
34096
- parameters: [
34097
- {
34098
- name: "path",
34099
- description: "The path of the directory to search in (relative to the current working directory). This directory will be recursively searched.",
34100
- required: true,
34101
- usageValue: "Directory path here"
34102
- },
34103
- {
34104
- name: "regex",
34105
- description: "The regular expression pattern to search for. Uses Rust regex syntax.",
34106
- required: true,
34107
- usageValue: "Your regex pattern here"
34108
- },
34109
- {
34110
- name: "file_pattern",
34111
- description: 'Glob pattern to filter files (e.g., "*.ts" for TypeScript files). If not provided, it will search all files (*).',
34112
- required: false,
34113
- usageValue: "file pattern here (optional)"
34114
- }
34115
- ],
34116
- examples: [
34117
- {
34118
- description: "Request to perform a regex search across files",
34119
- parameters: [
34120
- {
34121
- name: "path",
34122
- value: "src"
34123
- },
34124
- {
34125
- name: "regex",
34126
- value: "^components/"
34127
- },
34128
- {
34129
- name: "file_pattern",
34130
- value: "*.ts"
34131
- }
34132
- ]
34133
- }
34134
- ]
34135
- };
34136
- var handler8 = async (provider, args) => {
34137
- if (!provider.searchFiles) {
34138
- return {
34139
- type: "Error" /* Error */,
34140
- message: "Not possible to search files. Abort."
34141
- };
34142
- }
34143
- const path = getString(args, "path");
34144
- const regex = getString(args, "regex");
34145
- const filePattern = getString(args, "file_pattern", "*");
34146
- const files = await provider.searchFiles(path, regex, filePattern);
34147
- return {
34148
- type: "Reply" /* Reply */,
34149
- message: `<search_files_path>${path}</search_files_path>
34150
- <search_files_regex>${regex}</search_files_regex>
34151
- <search_files_file_pattern>${filePattern}</search_files_file_pattern>
34152
- <search_files_files>
34153
- ${files.join(`
34154
- `)}
34155
- </search_files_files>
34156
- `
34157
- };
34158
- };
34159
- var isAvailable8 = (provider) => {
34160
- return !!provider.searchFiles;
34161
- };
34162
- var searchFiles_default = {
34163
- ...toolInfo8,
34164
- handler: handler8,
34165
- isAvailable: isAvailable8
33803
+ var searchFiles_default = {
33804
+ ...toolInfo8,
33805
+ handler: handler8,
33806
+ isAvailable: isAvailable8
34166
33807
  };
34167
33808
  // ../core/src/tools/writeToFile.ts
34168
33809
  var toolInfo9 = {
@@ -34268,7 +33909,7 @@ var toolInfo10 = {
34268
33909
  parameters: [
34269
33910
  {
34270
33911
  name: "agent_name",
34271
- value: "Coder"
33912
+ value: "coder"
34272
33913
  },
34273
33914
  {
34274
33915
  name: "task",
@@ -34394,22 +34035,608 @@ var handler12 = async (provider, args) => {
34394
34035
  message: "Not possible to rename file. Abort."
34395
34036
  };
34396
34037
  }
34397
- const sourcePath = getString(args, "sourcePath");
34398
- const targetPath = getString(args, "targetPath");
34399
- await provider.renameFile(sourcePath, targetPath);
34400
- return {
34401
- type: "Reply" /* Reply */,
34402
- message: `<rename_file_path>${targetPath}</rename_file_path><status>Success</status>`
34403
- };
34404
- };
34405
- var isAvailable12 = (provider) => {
34406
- return !!provider.renameFile;
34407
- };
34408
- var renameFile_default = {
34409
- ...toolInfo12,
34410
- handler: handler12,
34411
- isAvailable: isAvailable12
34038
+ const sourcePath = getString(args, "sourcePath");
34039
+ const targetPath = getString(args, "targetPath");
34040
+ await provider.renameFile(sourcePath, targetPath);
34041
+ return {
34042
+ type: "Reply" /* Reply */,
34043
+ message: `<rename_file_path>${targetPath}</rename_file_path><status>Success</status>`
34044
+ };
34045
+ };
34046
+ var isAvailable12 = (provider) => {
34047
+ return !!provider.renameFile;
34048
+ };
34049
+ var renameFile_default = {
34050
+ ...toolInfo12,
34051
+ handler: handler12,
34052
+ isAvailable: isAvailable12
34053
+ };
34054
+ // ../core/src/Agent/parseAssistantMessage.ts
34055
+ function parseAssistantMessage(assistantMessage, tools, toolNamePrefix) {
34056
+ const parameterPrefix = `${toolNamePrefix}parameter_`;
34057
+ const results = [];
34058
+ const toolTags = tools.map((tool) => `${toolNamePrefix}${tool.name}`);
34059
+ const toolPattern = toolTags.join("|");
34060
+ let remainingMessage = assistantMessage;
34061
+ let match;
34062
+ const tagRegex = new RegExp(`<(${toolPattern})>([\\s\\S]*?)<\\/\\1>`, "s");
34063
+ while (true) {
34064
+ match = tagRegex.exec(remainingMessage);
34065
+ if (match === null)
34066
+ break;
34067
+ const beforeTag = remainingMessage.slice(0, match.index).trim();
34068
+ if (beforeTag) {
34069
+ results.push({
34070
+ type: "text",
34071
+ content: beforeTag
34072
+ });
34073
+ }
34074
+ const tagName = match[1];
34075
+ const toolName = tagName.replace(toolNamePrefix, "");
34076
+ const tool = tools.find((t2) => t2.name === toolName);
34077
+ const fullTagContent = match[0];
34078
+ if (tool) {
34079
+ const params = {};
34080
+ for (const param of tool.parameters) {
34081
+ const paramName = `${parameterPrefix}${param.name}`;
34082
+ const escapedParamName = paramName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
34083
+ const paramPattern = `<${escapedParamName}>([\\s\\S]*?)<\\/${escapedParamName}>`;
34084
+ const paramMatch = fullTagContent.match(new RegExp(paramPattern, "s"));
34085
+ if (paramMatch) {
34086
+ params[param.name] = paramMatch[1].trim();
34087
+ }
34088
+ }
34089
+ results.push({
34090
+ type: "tool_use",
34091
+ name: toolName,
34092
+ params
34093
+ });
34094
+ } else {
34095
+ results.push({
34096
+ type: "text",
34097
+ content: fullTagContent
34098
+ });
34099
+ }
34100
+ remainingMessage = remainingMessage.slice(match.index + fullTagContent.length);
34101
+ }
34102
+ if (remainingMessage.trim()) {
34103
+ results.push({
34104
+ type: "text",
34105
+ content: remainingMessage.trim()
34106
+ });
34107
+ }
34108
+ if (results.length === 0) {
34109
+ results.push({
34110
+ type: "text",
34111
+ content: assistantMessage
34112
+ });
34113
+ }
34114
+ return results;
34115
+ }
34116
+
34117
+ // ../core/src/Agent/prompts.ts
34118
+ var toolInfoPrompt = (tool, toolNamePrefix, parameterPrefix) => `
34119
+ ## ${toolNamePrefix}${tool.name}
34120
+
34121
+ Description: ${tool.description}
34122
+
34123
+ Parameters:
34124
+ ${tool.parameters.map((param) => `- ${parameterPrefix}${param.name}: (${param.required ? "required" : "optional"}) ${param.description}`).join(`
34125
+ `)}
34126
+
34127
+ Usage:
34128
+ <${toolNamePrefix}${tool.name}>
34129
+ ${tool.parameters.map((param) => `<${parameterPrefix}${param.name}>${param.usageValue}</${parameterPrefix}${param.name}>`).join(`
34130
+ `)}
34131
+ </${toolNamePrefix}${tool.name}>`;
34132
+ var toolInfoExamplesPrompt = (idx, tool, example, toolNamePrefix, parameterPrefix) => `
34133
+ ## Example ${idx + 1}: ${example.description}
34134
+
34135
+ <${toolNamePrefix}${tool.name}>
34136
+ ${example.parameters.map((param) => `<${parameterPrefix}${param.name}>${param.value}</${parameterPrefix}${param.name}>`).join(`
34137
+ `)}
34138
+ </${toolNamePrefix}${tool.name}>
34139
+ `;
34140
+ var toolUsePrompt = (tools, toolNamePrefix) => {
34141
+ if (tools.length === 0) {
34142
+ return "";
34143
+ }
34144
+ const parameterPrefix = `${toolNamePrefix}parameter_`;
34145
+ let exampleIndex = 0;
34146
+ return `
34147
+ ====
34148
+
34149
+ TOOL USE
34150
+
34151
+ You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
34152
+
34153
+ # Tool Use Formatting
34154
+
34155
+ Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
34156
+
34157
+ <${toolNamePrefix}tool_name>
34158
+ <${parameterPrefix}name1>value1</${parameterPrefix}name1>
34159
+ <${parameterPrefix}name2>value2</${parameterPrefix}name2>
34160
+ ...
34161
+ </${toolNamePrefix}tool_name>
34162
+
34163
+ For example:
34164
+
34165
+ <${toolNamePrefix}read_file>
34166
+ <${parameterPrefix}path>src/main.js</${parameterPrefix}path>
34167
+ </${toolNamePrefix}read_file>
34168
+
34169
+ Always adhere to this format for the tool use to ensure proper parsing and execution.
34170
+
34171
+ # Tools
34172
+ ${tools.map((tool) => toolInfoPrompt(tool, toolNamePrefix, parameterPrefix)).join(`
34173
+ `)}
34174
+
34175
+ # Tool Use Examples
34176
+ ${tools.map((tool) => {
34177
+ let promp = "";
34178
+ for (const example of tool.examples ?? []) {
34179
+ promp += toolInfoExamplesPrompt(exampleIndex++, tool, example, toolNamePrefix, parameterPrefix);
34180
+ }
34181
+ return promp;
34182
+ }).join("")}
34183
+ # Tool Use Guidelines
34184
+
34185
+ 1. **In \`<thinking>\` tags**, assess what information you have and what you need to proceed.
34186
+ 2. **Choose one tool at a time per message** based on the task and its description. Do not assume a tool’s outcome without explicit confirmation.
34187
+ 3. **Formulate tool use only in the specified XML format** for each tool.
34188
+ 4. **Wait for the user’s response** after each tool use. Do not proceed until you have their confirmation.
34189
+ 5. The user’s response may include:
34190
+ - Tool success or failure details
34191
+ - Linter errors
34192
+ - Terminal output or other relevant feedback
34193
+ 6. **Never repeat or quote the entire tool command** in your final user-facing message. Summarize outcomes clearly and avoid echoing commands verbatim.
34194
+ 7. **Respond concisely** and move the conversation forward. Do not re-issue the same command or re-trigger tool use without necessity.
34195
+ 8. Follow these steps **iteratively**, confirming success and addressing issues as you go.
34196
+
34197
+ By adhering to these guidelines:
34198
+ - You maintain clarity without accidentally re-invoking tools.
34199
+ - You confirm each step’s results before proceeding.
34200
+ - You provide only the necessary information in user-facing replies to prevent re-interpretation as new commands.`;
34201
+ };
34202
+ var agentsPrompt = (agents, name) => `
34203
+ ====
34204
+
34205
+ AVAILABLE AGENTS
34206
+
34207
+ The following agents are available for task handover:
34208
+ ${agents.map((agent) => `
34209
+ - **${agent.name}**
34210
+ - Responsibilities:
34211
+ ${agent.responsibilities.map((resp) => ` - ${resp}`).join(`
34212
+ `)}`).join(`
34213
+ `)}
34214
+
34215
+ - **Current Agent Role**
34216
+ You are currently acting as **${name}**. If you identify the task is beyond your current scope, use the handover tool to transition to the other agent. Include sufficient context so the new agent can seamlessly continue the work.
34217
+ `;
34218
+ var capabilities = (toolNamePrefix) => `
34219
+ ====
34220
+
34221
+ CAPABILITIES
34222
+
34223
+ - You have access to a range of tools to aid you in your work. These tools help you effectively accomplish a wide range of tasks.
34224
+ - When the user initially gives you a task, a recursive list of all filepaths in the current working directory will be included in context. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further.`;
34225
+ var systemInformation = (info) => `
34226
+ ====
34227
+
34228
+ SYSTEM INFORMATION
34229
+
34230
+ Operating System: ${info.os}`;
34231
+ var interactiveMode = (interactive) => {
34232
+ if (interactive) {
34233
+ return `
34234
+ ====
34235
+
34236
+ INTERACTIVE MODE
34237
+
34238
+ You are in interactive mode. This means you may ask user questions to gather additional information to complete the task.
34239
+ `;
34240
+ }
34241
+ return `
34242
+ ====
34243
+
34244
+ NON-INTERACTIVE MODE
34245
+
34246
+ You are in non-interactive mode. This means you will not be able to ask user questions to gather additional information to complete the task. You should try to use available tools to accomplish the task. If unable to precede further, you may try to end the task and provide a reason.
34247
+ `;
34248
+ };
34249
+ var customInstructions = (customInstructions2) => {
34250
+ const joined = customInstructions2.join(`
34251
+ `);
34252
+ if (joined.trim() === "") {
34253
+ return "";
34254
+ }
34255
+ return `
34256
+ ====
34257
+
34258
+ USER'S CUSTOM INSTRUCTIONS
34259
+
34260
+ The following additional instructions are provided by the user, and should be followed to the best of your ability without interfering with the TOOL USE guidelines.
34261
+
34262
+ ${joined}`;
34263
+ };
34264
+ var customScripts = (commands) => {
34265
+ const joined = Object.entries(commands).map(([name, command]) => {
34266
+ if (typeof command === "string") {
34267
+ return `- ${name}
34268
+ - Command: \`${command}\``;
34269
+ }
34270
+ return `- ${name}
34271
+ - Command: \`${command.command}\`
34272
+ - Description: ${command.description}`;
34273
+ }).join(`
34274
+ `);
34275
+ if (joined.trim() === "") {
34276
+ return "";
34277
+ }
34278
+ return `
34279
+ ====
34280
+
34281
+ USER'S CUSTOM COMMANDS
34282
+
34283
+ The following additional commands are provided by the user, and should be followed to the best of your ability without interfering with the TOOL USE guidelines.
34284
+
34285
+ ${joined}`;
34286
+ };
34287
+ var responsePrompts = {
34288
+ errorInvokeTool: (tool, error) => `An error occurred while invoking the tool "${tool}": ${error}`,
34289
+ requireUseTool: "Error: You must use a tool before proceeding. Making sure the tool is invoked using xml tags.",
34290
+ toolResults: (tool, result) => `<tool_response>
34291
+ <tool_name>${tool}</tool_name>
34292
+ <tool_result>
34293
+ ${result}
34294
+ </tool_result>
34295
+ </tool_response>`
34296
+ };
34297
+
34298
+ // ../core/src/Agent/AgentBase.ts
34299
+ class AgentBase {
34300
+ ai;
34301
+ config;
34302
+ handlers;
34303
+ constructor(name, ai, config) {
34304
+ this.ai = ai;
34305
+ if (config.agents && Object.keys(config.agents).length > 0) {
34306
+ const agents = agentsPrompt(config.agents, name);
34307
+ config.systemPrompt += `
34308
+ ${agents}`;
34309
+ }
34310
+ this.config = config;
34311
+ const handlers = {};
34312
+ for (const tool of config.tools) {
34313
+ handlers[tool.name] = tool;
34314
+ }
34315
+ this.handlers = handlers;
34316
+ }
34317
+ async startTask({
34318
+ task,
34319
+ context,
34320
+ callback = () => {
34321
+ }
34322
+ }) {
34323
+ const taskInfo = {
34324
+ messages: [],
34325
+ inputTokens: 0,
34326
+ outputTokens: 0,
34327
+ cacheWriteTokens: 0,
34328
+ cacheReadTokens: 0,
34329
+ totalCost: 0
34330
+ };
34331
+ let text = `<task>${task}</task>`;
34332
+ if (context) {
34333
+ text += `
34334
+ <context>${context}</context>`;
34335
+ }
34336
+ callback({ kind: "StartTask" /* StartTask */, info: taskInfo, systemPrompt: this.config.systemPrompt });
34337
+ return await this.#processLoop(text, taskInfo, callback);
34338
+ }
34339
+ async#processLoop(userMessage, taskInfo, callback) {
34340
+ let nextRequest = userMessage;
34341
+ while (nextRequest) {
34342
+ if (this.ai.usageMeter.isLimitExceeded().result) {
34343
+ callback({ kind: "UsageExceeded" /* UsageExceeded */, info: taskInfo });
34344
+ return [{ type: "UsageExceeded" }, taskInfo];
34345
+ }
34346
+ const response = await this.#request(taskInfo, nextRequest, callback);
34347
+ const [newMessage, exitReason] = await this.#handleResponse(taskInfo, response, callback);
34348
+ if (exitReason) {
34349
+ callback({ kind: "EndTask" /* EndTask */, info: taskInfo });
34350
+ return [exitReason, taskInfo];
34351
+ }
34352
+ nextRequest = newMessage;
34353
+ }
34354
+ callback({ kind: "EndTask" /* EndTask */, info: taskInfo });
34355
+ return [{ type: "Exit" /* Exit */, message: "Task completed successfully" }, taskInfo];
34356
+ }
34357
+ async continueTask(userMessage, taskInfo, callback = () => {
34358
+ }) {
34359
+ return await this.#processLoop(userMessage, taskInfo, callback);
34360
+ }
34361
+ async#request(info, userMessage, callback) {
34362
+ await callback({ kind: "StartRequest" /* StartRequest */, info, userMessage });
34363
+ info.messages.push({
34364
+ role: "user",
34365
+ content: userMessage
34366
+ });
34367
+ const stream = this.ai.send(this.config.systemPrompt, info.messages);
34368
+ let currentAssistantMessage = "";
34369
+ for await (const chunk of stream) {
34370
+ switch (chunk.type) {
34371
+ case "usage":
34372
+ info.inputTokens = chunk.inputTokens ?? 0;
34373
+ info.outputTokens = chunk.outputTokens ?? 0;
34374
+ info.cacheWriteTokens = chunk.cacheWriteTokens ?? 0;
34375
+ info.cacheReadTokens = chunk.cacheReadTokens ?? 0;
34376
+ info.totalCost = chunk.totalCost;
34377
+ await callback({ kind: "Usage" /* Usage */, info });
34378
+ break;
34379
+ case "text":
34380
+ currentAssistantMessage += chunk.text;
34381
+ await callback({ kind: "Text" /* Text */, info, newText: chunk.text });
34382
+ break;
34383
+ case "reasoning":
34384
+ await callback({ kind: "Reasoning" /* Reasoning */, info, newText: chunk.text });
34385
+ break;
34386
+ }
34387
+ }
34388
+ if (!currentAssistantMessage) {
34389
+ throw new Error("No assistant message received");
34390
+ }
34391
+ info.messages.push({
34392
+ role: "assistant",
34393
+ content: currentAssistantMessage
34394
+ });
34395
+ const ret = parseAssistantMessage(currentAssistantMessage, this.config.tools, this.config.toolNamePrefix);
34396
+ await callback({ kind: "EndRequest" /* EndRequest */, info });
34397
+ return ret;
34398
+ }
34399
+ async#handleResponse(info, response, callback) {
34400
+ const toolReponses = [];
34401
+ outer:
34402
+ for (const content of response) {
34403
+ switch (content.type) {
34404
+ case "text":
34405
+ break;
34406
+ case "tool_use": {
34407
+ await callback({ kind: "ToolUse" /* ToolUse */, info, tool: content.name });
34408
+ const toolResp = await this.#invokeTool(content.name, content.params);
34409
+ switch (toolResp.type) {
34410
+ case "Reply" /* Reply */:
34411
+ await callback({ kind: "ToolReply" /* ToolReply */, info, tool: content.name });
34412
+ toolReponses.push({ tool: content.name, response: toolResp.message });
34413
+ break;
34414
+ case "Exit" /* Exit */:
34415
+ return [undefined, toolResp];
34416
+ case "Invalid" /* Invalid */:
34417
+ await callback({ kind: "ToolInvalid" /* ToolInvalid */, info, tool: content.name });
34418
+ toolReponses.push({ tool: content.name, response: toolResp.message });
34419
+ break outer;
34420
+ case "Error" /* Error */:
34421
+ await callback({ kind: "ToolError" /* ToolError */, info, tool: content.name });
34422
+ toolReponses.push({ tool: content.name, response: toolResp.message });
34423
+ break outer;
34424
+ case "Interrupted" /* Interrupted */:
34425
+ await callback({ kind: "ToolInterrupted" /* ToolInterrupted */, info, tool: content.name });
34426
+ return [undefined, toolResp];
34427
+ case "HandOver" /* HandOver */:
34428
+ await callback({
34429
+ kind: "ToolHandOver" /* ToolHandOver */,
34430
+ info,
34431
+ tool: content.name,
34432
+ agentName: toolResp.agentName,
34433
+ task: toolResp.task,
34434
+ context: toolResp.context,
34435
+ files: toolResp.files
34436
+ });
34437
+ return [undefined, toolResp];
34438
+ }
34439
+ break;
34440
+ }
34441
+ }
34442
+ }
34443
+ if (toolReponses.length === 0 && !this.config.interactive) {
34444
+ return [responsePrompts.requireUseTool, undefined];
34445
+ }
34446
+ const finalResp = toolReponses.map(({ tool, response: response2 }) => responsePrompts.toolResults(tool, response2)).join(`
34447
+
34448
+ `);
34449
+ return [finalResp, undefined];
34450
+ }
34451
+ async#invokeTool(name, args) {
34452
+ try {
34453
+ const handler13 = this.handlers[name]?.handler;
34454
+ if (!handler13) {
34455
+ return {
34456
+ type: "Error" /* Error */,
34457
+ message: responsePrompts.errorInvokeTool(name, "Tool not found"),
34458
+ canRetry: false
34459
+ };
34460
+ }
34461
+ return await handler13(this.config.provider, args);
34462
+ } catch (error) {
34463
+ return {
34464
+ type: "Error" /* Error */,
34465
+ message: responsePrompts.errorInvokeTool(name, error),
34466
+ canRetry: false
34467
+ };
34468
+ }
34469
+ }
34470
+ get model() {
34471
+ return this.ai.model;
34472
+ }
34473
+ get usage() {
34474
+ return this.ai.usageMeter.usage;
34475
+ }
34476
+ }
34477
+
34478
+ // ../core/src/Agent/AnalyzerAgent/prompts.ts
34479
+ var fullSystemPrompt = (info, tools, toolNamePrefix, instructions, scripts, interactive) => `
34480
+ # Analyzer Agent
34481
+
34482
+ ## Role
34483
+ You are the **Analyzer** agent, responsible for:
34484
+ 1. **Project Structure Analysis** – Understand codebase organization and architecture.
34485
+ 2. **Code Pattern Analysis** – Identify common patterns, conventions, and best practices.
34486
+ 3. **Dependency Analysis** – Examine project dependencies and their usage.
34487
+ 4. **Workflow Analysis** – Understand development tools, scripts, and processes.
34488
+ 5. **Documentation Review** – Analyze documentation and code comments.
34489
+
34490
+ > **Note**: The **Analyzer** agent focuses on understanding and analyzing the codebase without making modifications. Your role is to provide insights and understanding that can inform development decisions.
34491
+
34492
+ ## Rules
34493
+ 1. **Thoroughness**: Conduct comprehensive analysis of relevant project aspects.
34494
+ 2. **Pattern Recognition**: Identify recurring patterns, conventions, and architectural decisions.
34495
+ 3. **Dependency Mapping**: Track and understand relationships between components.
34496
+ 4. **Workflow Understanding**: Analyze build processes, testing approaches, and development tools.
34497
+ 5. **Documentation Assessment**: Review documentation quality and completeness.
34498
+ 6. **Non-Modification**: Never modify code or files - focus solely on analysis.
34499
+
34500
+ ${toolUsePrompt(tools, toolNamePrefix)}
34501
+ ${capabilities(toolNamePrefix)}
34502
+ ${systemInformation(info)}
34503
+ ${customInstructions(instructions)}
34504
+ ${customScripts(scripts)}
34505
+ ${interactiveMode(interactive)}
34506
+ `;
34507
+
34508
+ // ../core/src/Agent/AnalyzerAgent/index.ts
34509
+ class AnalyzerAgent extends AgentBase {
34510
+ constructor(options) {
34511
+ const agentTools = [
34512
+ ...options.additionalTools ?? [],
34513
+ askFollowupQuestion_default,
34514
+ attemptCompletion_default,
34515
+ handOver_default,
34516
+ listCodeDefinitionNames_default,
34517
+ listFiles_default,
34518
+ readFile_default,
34519
+ searchFiles_default
34520
+ ];
34521
+ const tools = getAvailableTools(options.provider, agentTools);
34522
+ const toolNamePrefix = "tool_";
34523
+ const systemPrompt = fullSystemPrompt({
34524
+ os: options.os
34525
+ }, tools, toolNamePrefix, options.customInstructions ?? [], options.scripts ?? {}, options.interactive);
34526
+ super(analyzerAgentInfo.name, options.ai, {
34527
+ systemPrompt,
34528
+ tools,
34529
+ toolNamePrefix,
34530
+ provider: options.provider,
34531
+ interactive: options.interactive,
34532
+ agents: options.agents
34533
+ });
34534
+ }
34535
+ }
34536
+ var analyzerAgentInfo = {
34537
+ name: "analyzer",
34538
+ responsibilities: [
34539
+ "Analyzing project structure and organization",
34540
+ "Identifying key source code files and their relationships",
34541
+ "Understanding common coding patterns and conventions",
34542
+ "Examining development workflow and tooling",
34543
+ "Analyzing dependencies and their usage patterns"
34544
+ ]
34545
+ };
34546
+
34547
+ // ../core/src/Agent/ArchitectAgent/prompts.ts
34548
+ var fullSystemPrompt2 = (info, tools, toolNamePrefix, instructions, scripts, interactive) => `
34549
+ # Architect Agent
34550
+
34551
+ ## Role
34552
+ You are the **Architect** agent, responsible for:
34553
+ 1. **Task Analysis** – Understand requirements.
34554
+ 2. **File Identification** – Find and select relevant files.
34555
+ 3. **File Reading** – Use the provided tools to gather information from these files.
34556
+ 4. **Implementation Plan** – Draft a concise plan detailing steps, resources, and dependencies.
34557
+ 5. **Review & Improve** – Evaluate and refine the plan.
34558
+ 6. **Handover** – Provide the final plan, context, and files to the **Coder** agent.
34559
+
34560
+ > **Note**: The **Architect** agent must not make any direct modifications. Your role is limited to creating the implementation plan and handing it over to the **Coder** agent, who will perform any actual changes.
34561
+
34562
+ ## Rules
34563
+ 1. **Consistency**: Maintain alignment with the user’s instructions and the system’s objectives at all times.
34564
+ 2. **Relevance**: Only read and use files directly related to the task. Avoid unnecessary or tangential information.
34565
+ 3. **Conciseness**: Keep all communications and plans succinct, avoiding superfluous or repetitive details.
34566
+ 4. **Accuracy**: Ensure the information you gather and any conclusions you draw are correct and verifiable.
34567
+ 5. **Clarity**: Present the final plan and any supporting details in a structured and easily understandable format.
34568
+ 6. **Minimal Queries**: Ask clarifying questions only when essential, and avoid repeated questioning that does not add value.
34569
+
34570
+ ## Steps
34571
+ 1. **Analyze Task**
34572
+ - Gather and understand the user’s requirements.
34573
+ - Note any potential constraints or objectives that may influence the plan.
34574
+
34575
+ 2. **Identify Relevant Files**
34576
+ - Determine which files or documents are necessary.
34577
+ - Justify why these files are relevant.
34578
+
34579
+ 3. **Read Files via Tools**
34580
+ - Utilize the provided tools to access and extract information from the identified files.
34581
+ - Summarize key insights or data for the solution.
34582
+
34583
+ 4. **Create Implementation Plan**
34584
+ - Outline tasks, define milestones, and detail resources or dependencies.
34585
+ - Provide clear, concise instructions for each step.
34586
+
34587
+ 5. **Review & Improve**
34588
+ - Check the plan for consistency, clarity, and feasibility.
34589
+ - Make adjustments or refinements to ensure accuracy and efficiency.
34590
+
34591
+ 6. **Handover**
34592
+ - Deliver the final implementation plan, context, and relevant files to the **Coder** agent.
34593
+ - Provide any additional instructions or clarifications needed for successful implementation.
34594
+ ${toolUsePrompt(tools, toolNamePrefix)}
34595
+ ${capabilities(toolNamePrefix)}
34596
+ ${systemInformation(info)}
34597
+ ${customInstructions(instructions)}
34598
+ ${customScripts(scripts)}
34599
+ ${interactiveMode(interactive)}
34600
+ `;
34601
+
34602
+ // ../core/src/Agent/ArchitectAgent/index.ts
34603
+ class ArchitectAgent extends AgentBase {
34604
+ constructor(options) {
34605
+ const agentTools = [
34606
+ ...options.additionalTools ?? [],
34607
+ askFollowupQuestion_default,
34608
+ attemptCompletion_default,
34609
+ handOver_default,
34610
+ listCodeDefinitionNames_default,
34611
+ listFiles_default,
34612
+ readFile_default,
34613
+ searchFiles_default
34614
+ ];
34615
+ const tools = getAvailableTools(options.provider, agentTools);
34616
+ const toolNamePrefix = "tool_";
34617
+ const systemPrompt = fullSystemPrompt2({
34618
+ os: options.os
34619
+ }, tools, toolNamePrefix, options.customInstructions ?? [], options.scripts ?? {}, options.interactive);
34620
+ super(architectAgentInfo.name, options.ai, {
34621
+ systemPrompt,
34622
+ tools,
34623
+ toolNamePrefix,
34624
+ provider: options.provider,
34625
+ interactive: options.interactive,
34626
+ agents: options.agents
34627
+ });
34628
+ }
34629
+ }
34630
+ var architectAgentInfo = {
34631
+ name: "architect",
34632
+ responsibilities: [
34633
+ "Analyzing the user’s overall task and requirements.",
34634
+ "Creating plans and making higher-level decisions about system structure and design.",
34635
+ "Reviewing and analyzing existing code or components for maintainability and scalability.",
34636
+ "Laying out the roadmap for implementation."
34637
+ ]
34412
34638
  };
34639
+
34413
34640
  // ../core/src/Agent/CoderAgent/prompts.ts
34414
34641
  var basePrompt = "You are a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.";
34415
34642
  var editingFilesPrompt = (toolNamePrefix) => `
@@ -34511,7 +34738,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
34511
34738
  3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within <thinking></thinking> tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Then, think about which of the provided tools is the most relevant tool to accomplish the user's task. Next, go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use.
34512
34739
  4. Once you've completed the user's task, you must use the ${toolNamePrefix}attempt_completion tool to present the result of the task to the user.
34513
34740
  5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.`;
34514
- var fullSystemPrompt = (info, tools, toolNamePrefix, instructions, scripts, interactive) => `
34741
+ var fullSystemPrompt3 = (info, tools, toolNamePrefix, instructions, scripts, interactive) => `
34515
34742
  ${basePrompt}
34516
34743
  ${toolUsePrompt(tools, toolNamePrefix)}
34517
34744
  ${editingFilesPrompt(toolNamePrefix)}
@@ -34530,7 +34757,7 @@ class CoderAgent extends AgentBase {
34530
34757
  const combinedTools = [...options.additionalTools ?? [], ...Object.values(exports_allTools)];
34531
34758
  const tools = getAvailableTools(options.provider, combinedTools);
34532
34759
  const toolNamePrefix = "tool_";
34533
- const systemPrompt = fullSystemPrompt({
34760
+ const systemPrompt = fullSystemPrompt3({
34534
34761
  os: options.os
34535
34762
  }, tools, toolNamePrefix, options.customInstructions ?? [], options.scripts ?? {}, options.interactive);
34536
34763
  super(coderAgentInfo.name, options.ai, {
@@ -34544,7 +34771,7 @@ class CoderAgent extends AgentBase {
34544
34771
  }
34545
34772
  }
34546
34773
  var coderAgentInfo = {
34547
- name: "Coder",
34774
+ name: "coder",
34548
34775
  responsibilities: [
34549
34776
  "Editing and refactoring existing code.",
34550
34777
  "Creating new features or modules.",
@@ -34552,98 +34779,6 @@ var coderAgentInfo = {
34552
34779
  "Maintaining coding standards, lint rules, and general code quality."
34553
34780
  ]
34554
34781
  };
34555
- // ../core/src/Agent/ArchitectAgent/prompts.ts
34556
- var fullSystemPrompt2 = (info, tools, toolNamePrefix, instructions, scripts, interactive) => `
34557
- # Architect Agent
34558
-
34559
- ## Role
34560
- You are the **Architect** agent, responsible for:
34561
- 1. **Task Analysis** – Understand requirements.
34562
- 2. **File Identification** – Find and select relevant files.
34563
- 3. **File Reading** – Use the provided tools to gather information from these files.
34564
- 4. **Implementation Plan** – Draft a concise plan detailing steps, resources, and dependencies.
34565
- 5. **Review & Improve** – Evaluate and refine the plan.
34566
- 6. **Handover** – Provide the final plan, context, and files to the **Coder** agent.
34567
-
34568
- > **Note**: The **Architect** agent must not make any direct modifications. Your role is limited to creating the implementation plan and handing it over to the **Coder** agent, who will perform any actual changes.
34569
-
34570
- ## Rules
34571
- 1. **Consistency**: Maintain alignment with the user’s instructions and the system’s objectives at all times.
34572
- 2. **Relevance**: Only read and use files directly related to the task. Avoid unnecessary or tangential information.
34573
- 3. **Conciseness**: Keep all communications and plans succinct, avoiding superfluous or repetitive details.
34574
- 4. **Accuracy**: Ensure the information you gather and any conclusions you draw are correct and verifiable.
34575
- 5. **Clarity**: Present the final plan and any supporting details in a structured and easily understandable format.
34576
- 6. **Minimal Queries**: Ask clarifying questions only when essential, and avoid repeated questioning that does not add value.
34577
-
34578
- ## Steps
34579
- 1. **Analyze Task**
34580
- - Gather and understand the user’s requirements.
34581
- - Note any potential constraints or objectives that may influence the plan.
34582
-
34583
- 2. **Identify Relevant Files**
34584
- - Determine which files or documents are necessary.
34585
- - Justify why these files are relevant.
34586
-
34587
- 3. **Read Files via Tools**
34588
- - Utilize the provided tools to access and extract information from the identified files.
34589
- - Summarize key insights or data for the solution.
34590
-
34591
- 4. **Create Implementation Plan**
34592
- - Outline tasks, define milestones, and detail resources or dependencies.
34593
- - Provide clear, concise instructions for each step.
34594
-
34595
- 5. **Review & Improve**
34596
- - Check the plan for consistency, clarity, and feasibility.
34597
- - Make adjustments or refinements to ensure accuracy and efficiency.
34598
-
34599
- 6. **Handover**
34600
- - Deliver the final implementation plan, context, and relevant files to the **Coder** agent.
34601
- - Provide any additional instructions or clarifications needed for successful implementation.
34602
- ${toolUsePrompt(tools, toolNamePrefix)}
34603
- ${capabilities(toolNamePrefix)}
34604
- ${systemInformation(info)}
34605
- ${customInstructions(instructions)}
34606
- ${customScripts(scripts)}
34607
- ${interactiveMode(interactive)}
34608
- `;
34609
-
34610
- // ../core/src/Agent/ArchitectAgent/index.ts
34611
- class ArchitectAgent extends AgentBase {
34612
- constructor(options) {
34613
- const agentTools = [
34614
- ...options.additionalTools ?? [],
34615
- askFollowupQuestion_default,
34616
- attemptCompletion_default,
34617
- handOver_default,
34618
- listCodeDefinitionNames_default,
34619
- listFiles_default,
34620
- readFile_default,
34621
- searchFiles_default
34622
- ];
34623
- const tools = getAvailableTools(options.provider, agentTools);
34624
- const toolNamePrefix = "tool_";
34625
- const systemPrompt = fullSystemPrompt2({
34626
- os: options.os
34627
- }, tools, toolNamePrefix, options.customInstructions ?? [], options.scripts ?? {}, options.interactive);
34628
- super(architectAgentInfo.name, options.ai, {
34629
- systemPrompt,
34630
- tools,
34631
- toolNamePrefix,
34632
- provider: options.provider,
34633
- interactive: options.interactive,
34634
- agents: options.agents
34635
- });
34636
- }
34637
- }
34638
- var architectAgentInfo = {
34639
- name: "Architect",
34640
- responsibilities: [
34641
- "Analyzing the user’s overall task and requirements.",
34642
- "Creating plans and making higher-level decisions about system structure and design.",
34643
- "Reviewing and analyzing existing code or components for maintainability and scalability.",
34644
- "Laying out the roadmap for implementation."
34645
- ]
34646
- };
34647
34782
  // ../core/src/Agent/MultiAgent.ts
34648
34783
  class MultiAgent {
34649
34784
  #config;
@@ -34654,30 +34789,19 @@ class MultiAgent {
34654
34789
  get model() {
34655
34790
  return this.#activeAgent?.model;
34656
34791
  }
34657
- async#startTask(agentName, task, context, maxIterations, callback) {
34792
+ async#startTask(agentName, task, context, callback) {
34658
34793
  this.#activeAgent = await this.#config.createAgent(agentName);
34659
34794
  const [exitReason, info] = await this.#activeAgent.startTask({
34660
34795
  task,
34661
34796
  context,
34662
- maxIterations,
34663
34797
  callback
34664
34798
  });
34665
34799
  if (typeof exitReason === "string") {
34666
34800
  return [exitReason, info];
34667
34801
  }
34668
34802
  if (exitReason.type === "HandOver") {
34669
- const remainIteration = maxIterations - Math.floor(info.messages.length / 2);
34670
- if (remainIteration < 1) {
34671
- return ["MaxIterations", info];
34672
- }
34673
- const context2 = await this.#config.getContext(agentName, exitReason.context, exitReason.files);
34674
- const [exitReason2, info2] = await this.#startTask(exitReason.agentName, exitReason.task, context2, remainIteration, callback);
34675
- info2.inputTokens += info.inputTokens;
34676
- info2.outputTokens += info.outputTokens;
34677
- info2.cacheWriteTokens += info.cacheWriteTokens;
34678
- info2.cacheReadTokens += info.cacheReadTokens;
34679
- info2.totalCost = (info.totalCost ?? 0) + (info2.totalCost ?? 0);
34680
- return [exitReason2, info2];
34803
+ const context2 = await this.#config.getContext?.(agentName, exitReason.context, exitReason.files);
34804
+ return await this.#startTask(exitReason.agentName, exitReason.task, context2, callback);
34681
34805
  }
34682
34806
  return [exitReason, info];
34683
34807
  }
@@ -34685,8 +34809,7 @@ class MultiAgent {
34685
34809
  if (this.#activeAgent) {
34686
34810
  throw new Error("An active agent already exists");
34687
34811
  }
34688
- const maxIterations = options.maxIterations ?? 50;
34689
- return this.#startTask(options.agentName, options.task, options.context, maxIterations, options.callback);
34812
+ return this.#startTask(options.agentName, options.task, options.context, options.callback);
34690
34813
  }
34691
34814
  async continueTask(userMessage, taskInfo, callback = () => {
34692
34815
  }) {
@@ -34696,6 +34819,9 @@ class MultiAgent {
34696
34819
  return this.#activeAgent.continueTask(userMessage, taskInfo, callback);
34697
34820
  }
34698
34821
  }
34822
+
34823
+ // ../core/src/Agent/index.ts
34824
+ var allAgents = [architectAgentInfo, coderAgentInfo, analyzerAgentInfo];
34699
34825
  // ../core/src/AiTool/generateGitCommitMessage.ts
34700
34826
  var prompt = `
34701
34827
  You are an advanced assistant specialized in creating concise and accurate Git commit messages. When you receive:
@@ -34768,6 +34894,9 @@ You are given:
34768
34894
 
34769
34895
  Your task:
34770
34896
  1. Consider the optional context (if provided).
34897
+ - If an issue number is found, add "Closes #xxx" at the beginning of the PR description
34898
+ - IMPORTANT: Use ONLY the exact format "Closes #xxx" at the beginning of the description
34899
+ - DO NOT use variations like "Closes issue #xxx" or other formats
34771
34900
  2. Analyze the combined commit messages and diffs.
34772
34901
  3. Produce a single GitHub Pull Request title.
34773
34902
  4. Produce a Pull Request description that explains the changes.
@@ -34803,7 +34932,7 @@ Below is an **example** of the input and output:
34803
34932
  Example Input:
34804
34933
  <tool_input>
34805
34934
  <tool_input_branch_name>feature/refactor-logging</tool_input_branch_name>
34806
- <tool_input_context>Focus on clean code and maintainability</tool_input_context>
34935
+ <tool_input_context>Implementing changes for issue #123 - Focus on clean code and maintainability</tool_input_context>
34807
34936
  <tool_input_commit_messages>
34808
34937
  Remove debug logs
34809
34938
  Refactor order validation logic
@@ -34824,6 +34953,8 @@ Example Output:
34824
34953
  <tool_output>
34825
34954
  <tool_output_pr_title>Refactor Order Validation and Remove Debug Logs</tool_output_pr_title>
34826
34955
  <tool_output_pr_description>
34956
+ closes #123
34957
+
34827
34958
  This PR removes unnecessary debug print statements and updates order validation
34828
34959
  to use the new validate_and_process method for improved maintainability.
34829
34960
  </tool_output_pr_description>
@@ -34868,21 +34999,102 @@ ${output}`);
34868
34999
  }
34869
35000
  };
34870
35001
 
35002
+ // ../core/src/AiTool/generateProjectConfig.ts
35003
+ var prompt3 = `You are an analyzer agent responsible for examining project files and generating appropriate polkacodes configuration. Your task is to:
35004
+
35005
+ 1. Read and analyze the provided files using tool_read_file to understand:
35006
+ - Build tools and package manager (e.g., bun, npm)
35007
+ - Testing frameworks and patterns
35008
+ - Code style tools and rules
35009
+ - Project structure and conventions
35010
+ - Common development workflows
35011
+
35012
+ 2. Generate a YAML configuration that captures:
35013
+ - scripts section based on package.json scripts and CI workflows
35014
+ - rules section based on project conventions, tools, and patterns
35015
+
35016
+ 3. Use tool_attempt_completion to return the final configuration in this format:
35017
+
35018
+ <tool_attempt_completion>
35019
+ <tool_parameter_result>
35020
+ scripts:
35021
+ test:
35022
+ command: "bun test"
35023
+ description: "Run tests with bun:test"
35024
+ lint:
35025
+ command: "biome check ."
35026
+ description: "Check code style with Biome"
35027
+
35028
+ rules:
35029
+ - "Use \`bun\` as package manager"
35030
+ - "Write tests using bun:test with snapshots"
35031
+ - "Follow Biome code style"
35032
+ </tool_parameter_result>
35033
+ </tool_attempt_completion>
35034
+
35035
+ Focus on:
35036
+ - Package manager and dependency management
35037
+ - Testing frameworks and patterns
35038
+ - Code style and linting rules
35039
+ - File organization and naming conventions
35040
+ - Build and development workflows
35041
+
35042
+ The configuration should accurately reflect the project's structure, tools, and conventions.
35043
+ `;
35044
+ var generateProjectConfig_default = {
35045
+ name: "generateProjectConfig",
35046
+ description: "Analyzes project files to generate polkacodes config sections",
35047
+ prompt: prompt3,
35048
+ formatInput: (params) => {
35049
+ return `<tool_input>
35050
+ ${params.join(`
35051
+ `)}
35052
+ </tool_input>`;
35053
+ },
35054
+ parseOutput: (output) => {
35055
+ return output.trim();
35056
+ },
35057
+ agent: "analyzer"
35058
+ };
35059
+
34871
35060
  // ../core/src/AiTool/index.ts
34872
35061
  var executeTool = async (definition, ai, params) => {
34873
- const { response, usage } = await ai.request(definition.prompt, [{ role: "user", content: definition.formatInput(params) }]);
35062
+ const { response, usage } = await ai.request(definition.prompt, [
35063
+ { role: "user", content: definition.formatInput(params) }
35064
+ ]);
34874
35065
  return {
34875
35066
  response: definition.parseOutput(response),
34876
35067
  usage
34877
35068
  };
34878
35069
  };
35070
+ var executeAgentTool = async (definition, agent, params, callback) => {
35071
+ if (!definition.agent) {
35072
+ throw new Error("Agent not specified");
35073
+ }
35074
+ const [exitReason] = await agent.startTask({
35075
+ agentName: definition.agent,
35076
+ task: definition.prompt,
35077
+ context: definition.formatInput(params),
35078
+ callback
35079
+ });
35080
+ if (exitReason.type === "Exit" /* Exit */) {
35081
+ return definition.parseOutput(exitReason.message);
35082
+ }
35083
+ throw new Error(`Tool execution failed: ${exitReason.type}`);
35084
+ };
34879
35085
  var makeTool = (definition) => {
34880
35086
  return async (ai, params) => {
34881
35087
  return executeTool(definition, ai, params);
34882
35088
  };
34883
35089
  };
35090
+ var makeAgentTool = (definition) => {
35091
+ return async (agent, params, callback) => {
35092
+ return executeAgentTool(definition, agent, params, callback);
35093
+ };
35094
+ };
34884
35095
  var generateGitCommitMessage = makeTool(generateGitCommitMessage_default);
34885
35096
  var generateGithubPullRequestDetails = makeTool(generateGithubPullRequestDetails_default);
35097
+ var generateProjectConfig = makeAgentTool(generateProjectConfig_default);
34886
35098
  // src/Chat.ts
34887
35099
  import readline from "node:readline";
34888
35100
 
@@ -35149,7 +35361,7 @@ async function searchFiles(path2, regex, filePattern, cwd, excludeFiles) {
35149
35361
  }
35150
35362
 
35151
35363
  // src/provider.ts
35152
- var getProvider = (agentName, config, options) => {
35364
+ var getProvider = (agentName, config, options = {}) => {
35153
35365
  const ig = import_ignore2.default().add(options.excludeFiles ?? []);
35154
35366
  const provider2 = {
35155
35367
  readFile: async (path2) => {
@@ -35185,7 +35397,7 @@ var getProvider = (agentName, config, options) => {
35185
35397
  },
35186
35398
  executeCommand: (command, needApprove) => {
35187
35399
  return new Promise((resolve2, reject) => {
35188
- options.command.onStarted(command);
35400
+ options.command?.onStarted(command);
35189
35401
  const child = spawn2(command, [], {
35190
35402
  shell: true,
35191
35403
  stdio: "pipe"
@@ -35194,16 +35406,16 @@ var getProvider = (agentName, config, options) => {
35194
35406
  let stderrText = "";
35195
35407
  child.stdout.on("data", (data) => {
35196
35408
  const dataStr = data.toString();
35197
- options.command.onStdout(dataStr);
35409
+ options.command?.onStdout(dataStr);
35198
35410
  stdoutText += dataStr;
35199
35411
  });
35200
35412
  child.stderr.on("data", (data) => {
35201
35413
  const dataStr = data.toString();
35202
- options.command.onStderr(dataStr);
35414
+ options.command?.onStderr(dataStr);
35203
35415
  stderrText += dataStr;
35204
35416
  });
35205
35417
  child.on("close", (code) => {
35206
- options.command.onExit(code ?? 0);
35418
+ options.command?.onExit(code ?? 0);
35207
35419
  resolve2({
35208
35420
  stdout: stdoutText,
35209
35421
  stderr: stderrText,
@@ -35211,7 +35423,7 @@ var getProvider = (agentName, config, options) => {
35211
35423
  });
35212
35424
  });
35213
35425
  child.on("error", (err) => {
35214
- options.command.onError(err);
35426
+ options.command?.onError(err);
35215
35427
  reject(err);
35216
35428
  });
35217
35429
  });
@@ -35246,18 +35458,17 @@ ${stderr}
35246
35458
  class Runner {
35247
35459
  #options;
35248
35460
  #multiAgent;
35249
- #usage = {
35250
- inputTokens: 0,
35251
- outputTokens: 0,
35252
- cacheWriteTokens: 0,
35253
- cacheReadTokens: 0,
35254
- totalCost: 0
35255
- };
35461
+ #usageMeter;
35256
35462
  constructor(options) {
35257
35463
  this.#options = options;
35464
+ this.#usageMeter = new UsageMeter({
35465
+ maxCost: options.budget,
35466
+ maxMessageCount: options.maxMessageCount
35467
+ });
35258
35468
  const service = createService(options.provider, {
35259
35469
  apiKey: options.apiKey,
35260
- model: options.model
35470
+ model: options.model,
35471
+ usageMeter: this.#usageMeter
35261
35472
  });
35262
35473
  let rules2 = options.config.rules;
35263
35474
  if (typeof rules2 === "string") {
@@ -35289,7 +35500,7 @@ class Runner {
35289
35500
  createAgent: async (name) => {
35290
35501
  const agentName = name.trim().toLowerCase();
35291
35502
  switch (agentName) {
35292
- case coderAgentInfo.name.toLowerCase():
35503
+ case coderAgentInfo.name:
35293
35504
  return new CoderAgent({
35294
35505
  ai: service,
35295
35506
  os: platform,
@@ -35299,7 +35510,7 @@ class Runner {
35299
35510
  interactive: options.interactive,
35300
35511
  agents
35301
35512
  });
35302
- case architectAgentInfo.name.toLowerCase():
35513
+ case architectAgentInfo.name:
35303
35514
  return new ArchitectAgent({
35304
35515
  ai: service,
35305
35516
  os: platform,
@@ -35309,12 +35520,23 @@ class Runner {
35309
35520
  interactive: options.interactive,
35310
35521
  agents
35311
35522
  });
35523
+ case analyzerAgentInfo.name:
35524
+ return new AnalyzerAgent({
35525
+ ai: service,
35526
+ os: platform,
35527
+ customInstructions: rules2,
35528
+ scripts: options.config.scripts,
35529
+ provider: getProvider("analyzer", options.config, providerOptions),
35530
+ interactive: options.interactive,
35531
+ agents
35532
+ });
35312
35533
  default:
35313
35534
  throw new Error(`Unknown agent: ${name}`);
35314
35535
  }
35315
35536
  },
35316
35537
  getContext: async (name, context, files) => {
35317
35538
  let ret = await this.#defaultContext(name);
35539
+ const unreadableFiles = [];
35318
35540
  if (files) {
35319
35541
  for (const file of files) {
35320
35542
  try {
@@ -35323,7 +35545,18 @@ class Runner {
35323
35545
  <file_content path="${file}">${fileContent}</file_content>`;
35324
35546
  } catch (error) {
35325
35547
  console.warn(`Failed to read file: ${file}`, error);
35548
+ unreadableFiles.push(file);
35549
+ }
35550
+ }
35551
+ if (unreadableFiles.length > 0) {
35552
+ ret += `
35553
+ <unreadable_files>
35554
+ `;
35555
+ for (const file of unreadableFiles) {
35556
+ ret += `${file}
35557
+ `;
35326
35558
  }
35559
+ ret += "</unreadable_files>";
35327
35560
  }
35328
35561
  }
35329
35562
  if (context) {
@@ -35355,45 +35588,18 @@ ${fileList.join(`
35355
35588
  agentName,
35356
35589
  task,
35357
35590
  context: await this.#defaultContext(agentName),
35358
- callback: this.#taskEventCallback
35591
+ callback: this.#options.eventCallback
35359
35592
  });
35360
35593
  return [exitReason, info];
35361
35594
  }
35362
- #taskEventCallback = (event) => {
35363
- if (event.kind === "Usage" /* Usage */) {
35364
- this.#usage.inputTokens += event.info.inputTokens;
35365
- this.#usage.outputTokens += event.info.outputTokens;
35366
- this.#usage.cacheReadTokens += event.info.cacheReadTokens;
35367
- this.#usage.cacheWriteTokens += event.info.cacheWriteTokens;
35368
- let totalCost = event.info.totalCost ?? 0;
35369
- if (!totalCost) {
35370
- const modelInfo = this.#multiAgent.model?.info;
35371
- const inputCost = (modelInfo?.inputPrice ?? 0) * event.info.inputTokens;
35372
- const outputCost = (modelInfo?.outputPrice ?? 0) * event.info.outputTokens;
35373
- const cacheReadCost = (modelInfo?.cacheReadsPrice ?? 0) * event.info.cacheReadTokens;
35374
- const cacheWriteCost = (modelInfo?.cacheWritesPrice ?? 0) * event.info.cacheWriteTokens;
35375
- totalCost = (inputCost + outputCost + cacheReadCost + cacheWriteCost) / 1e6;
35376
- }
35377
- this.#usage.totalCost += totalCost;
35378
- }
35379
- this.#options.eventCallback(event);
35380
- };
35381
35595
  async continueTask(message, taskInfo) {
35382
- return await this.#multiAgent.continueTask(message, taskInfo, this.#taskEventCallback);
35596
+ return await this.#multiAgent.continueTask(message, taskInfo, this.#options.eventCallback);
35383
35597
  }
35384
35598
  get usage() {
35385
- return this.#usage;
35599
+ return this.#usageMeter.usage;
35386
35600
  }
35387
35601
  printUsage() {
35388
- if (!this.#usage.totalCost) {
35389
- return;
35390
- }
35391
- console.log("Usages:");
35392
- console.log(`Input tokens: ${this.#usage.inputTokens}`);
35393
- console.log(`Output tokens: ${this.#usage.outputTokens}`);
35394
- console.log(`Cache read tokens: ${this.#usage.cacheReadTokens}`);
35395
- console.log(`Cache write tokens: ${this.#usage.cacheWriteTokens}`);
35396
- console.log(`Total cost: ${this.#usage.totalCost}`);
35602
+ this.#usageMeter.printUsage();
35397
35603
  }
35398
35604
  }
35399
35605
 
@@ -39444,7 +39650,8 @@ var z2 = /* @__PURE__ */ Object.freeze({
39444
39650
  });
39445
39651
 
39446
39652
  // src/config.ts
39447
- var agentNames = z2.enum(["coder", "architect"]);
39653
+ var agentNameValues = allAgents.map((agent) => agent.name);
39654
+ var agentNames = z2.enum([agentNameValues[0], ...agentNameValues.slice(1)]);
39448
39655
  var agentNameOrDefault = z2.union([agentNames, z2.literal("default")]);
39449
39656
  var providerModelSchema = z2.object({
39450
39657
  provider: z2.string().optional(),
@@ -39463,7 +39670,8 @@ var configSchema = z2.object({
39463
39670
  })).optional(),
39464
39671
  defaultProvider: z2.string().optional(),
39465
39672
  defaultModel: z2.string().optional(),
39466
- maxIterations: z2.number().int().positive().optional(),
39673
+ maxMessageCount: z2.number().int().positive().optional(),
39674
+ budget: z2.number().int().positive().optional(),
39467
39675
  hooks: z2.object({
39468
39676
  agents: z2.record(agentNameOrDefault, z2.object({ beforeCompletion: z2.string().optional() })).optional()
39469
39677
  }).optional(),
@@ -39554,10 +39762,17 @@ var readConfig = (path2) => {
39554
39762
  const config = $parse(file);
39555
39763
  return configSchema.parse(config);
39556
39764
  };
39765
+ var readLocalConfig = (path2) => {
39766
+ try {
39767
+ return readConfig(path2 ?? localConfigFileName);
39768
+ } catch (error) {
39769
+ return;
39770
+ }
39771
+ };
39557
39772
 
39558
39773
  // src/options.ts
39559
39774
  function addSharedOptions(command) {
39560
- return command.option("-c --config <path>", "Path to config file").option("--api-provider <provider>", "API provider").option("--model <model>", "Model ID").option("--api-key <key>", "API key").option("--max-iterations <iterations>", "Maximum number of iterations to run. Default to 30", Number.parseInt).option("-v --verbose", "Enable verbose output. Use -v for level 1, -vv for level 2", (value, prev) => prev + 1, 0);
39775
+ return command.option("-c --config <path>", "Path to config file").option("--api-provider <provider>", "API provider").option("--model <model>", "Model ID").option("--api-key <key>", "API key").option("--max-messages <iterations>", "Maximum number of messages to send. Default to 50", Number.parseInt, 50).option("--budget <budget>", "Budget for the AI service. Default to $1000", Number.parseFloat, 1000).option("-v --verbose", "Enable verbose output. Use -v for level 1, -vv for level 2", (value, prev) => prev + 1, 0);
39561
39776
  }
39562
39777
 
39563
39778
  class ApiProviderConfig {
@@ -39625,7 +39840,8 @@ function parseOptions(options, cwd = process.cwd(), home = os2.homedir()) {
39625
39840
  ...config
39626
39841
  });
39627
39842
  return {
39628
- maxIterations: options.maxIterations ?? 30,
39843
+ maxMessageCount: options.maxMessageCount ?? config.maxMessageCount ?? 30,
39844
+ budget: options.budget ?? Number(process.env.POLKA_BUDGET) ?? config.budget ?? 1000,
39629
39845
  verbose: options.verbose ?? 0,
39630
39846
  config,
39631
39847
  providerConfig
@@ -40186,8 +40402,11 @@ ${event.systemPrompt}`);
40186
40402
  console.log("Files:", event.files);
40187
40403
  console.log();
40188
40404
  break;
40189
- case "MaxIterationsReached" /* MaxIterationsReached */:
40190
- console.log("Max iterations reached");
40405
+ case "UsageExceeded" /* UsageExceeded */:
40406
+ console.log(`
40407
+
40408
+ ======= Usage Exceeded ========
40409
+ `);
40191
40410
  break;
40192
40411
  case "EndTask" /* EndTask */:
40193
40412
  break;
@@ -41121,11 +41340,11 @@ class ScreenManager {
41121
41340
  render(content, bottomContent = "") {
41122
41341
  const promptLine = lastLine(content);
41123
41342
  const rawPromptLine = import_strip_ansi.default(promptLine);
41124
- let prompt3 = rawPromptLine;
41343
+ let prompt4 = rawPromptLine;
41125
41344
  if (this.rl.line.length > 0) {
41126
- prompt3 = prompt3.slice(0, -this.rl.line.length);
41345
+ prompt4 = prompt4.slice(0, -this.rl.line.length);
41127
41346
  }
41128
- this.rl.setPrompt(prompt3);
41347
+ this.rl.setPrompt(prompt4);
41129
41348
  this.cursorPos = this.rl.getCursorPos();
41130
41349
  const width = readlineWidth();
41131
41350
  content = breakLines(content, width);
@@ -41195,7 +41414,7 @@ function getCallSites() {
41195
41414
  function createPrompt(view) {
41196
41415
  const callSites = getCallSites();
41197
41416
  const callerFilename = callSites[1]?.getFileName?.();
41198
- const prompt3 = (config, context = {}) => {
41417
+ const prompt4 = (config, context = {}) => {
41199
41418
  const { input = process.stdin, signal } = context;
41200
41419
  const cleanups = new Set;
41201
41420
  const output = new import_mute_stream.default;
@@ -41256,7 +41475,7 @@ function createPrompt(view) {
41256
41475
  }).then(() => promise), { cancel });
41257
41476
  });
41258
41477
  };
41259
- return prompt3;
41478
+ return prompt4;
41260
41479
  }
41261
41480
  // ../../node_modules/@inquirer/core/dist/esm/lib/Separator.js
41262
41481
  var import_yoctocolors_cjs2 = __toESM(require_yoctocolors_cjs(), 1);
@@ -41728,8 +41947,9 @@ ${provider2.toUpperCase()}_API_KEY=${apiKey}`;
41728
41947
  });
41729
41948
 
41730
41949
  // src/commands/chat.ts
41731
- var runChat = async (options) => {
41732
- const { config, providerConfig, maxIterations, verbose } = parseOptions(options);
41950
+ var runChat = async (opts, command) => {
41951
+ const options = command?.parent?.opts() ?? opts ?? {};
41952
+ const { config, providerConfig, maxMessageCount, verbose, budget } = parseOptions(options);
41733
41953
  let { provider: provider2, model, apiKey } = providerConfig.getConfigForAgent("coder") ?? {};
41734
41954
  if (!provider2) {
41735
41955
  const newConfig = await configPrompt({ provider: provider2, model, apiKey });
@@ -41747,7 +41967,8 @@ var runChat = async (options) => {
41747
41967
  model: model ?? defaultModels[provider2],
41748
41968
  apiKey,
41749
41969
  config: config ?? {},
41750
- maxIterations,
41970
+ maxMessageCount,
41971
+ budget,
41751
41972
  interactive: true,
41752
41973
  eventCallback: printEvent(verbose)
41753
41974
  });
@@ -41764,24 +41985,20 @@ var runChat = async (options) => {
41764
41985
  taskInfo = info;
41765
41986
  exitReason = reason;
41766
41987
  }
41767
- switch (exitReason) {
41768
- case "MaxIterations":
41769
- console.log("Max iterations reached.");
41988
+ switch (exitReason.type) {
41989
+ case "UsageExceeded":
41990
+ console.log("Usage exceeded.");
41770
41991
  chat2.close();
41771
41992
  break;
41772
41993
  case "WaitForUserInput":
41773
41994
  break;
41774
- default: {
41775
- switch (exitReason.type) {
41776
- case "Interrupted" /* Interrupted */:
41777
- console.log("Interrupted.");
41778
- chat2.close();
41779
- break;
41780
- case "Exit" /* Exit */:
41781
- chat2.close();
41782
- return;
41783
- }
41784
- }
41995
+ case "Interrupted" /* Interrupted */:
41996
+ console.log("Interrupted.");
41997
+ chat2.close();
41998
+ break;
41999
+ case "Exit" /* Exit */:
42000
+ chat2.close();
42001
+ return;
41785
42002
  }
41786
42003
  },
41787
42004
  onExit: async () => {
@@ -41793,7 +42010,7 @@ var runChat = async (options) => {
41793
42010
  };
41794
42011
 
41795
42012
  // src/commands/commit.ts
41796
- import { execSync } from "node:child_process";
42013
+ import { execSync, spawnSync } from "node:child_process";
41797
42014
 
41798
42015
  // ../../node_modules/ora/index.js
41799
42016
  import process10 from "node:process";
@@ -42400,8 +42617,9 @@ function ora(options) {
42400
42617
  }
42401
42618
 
42402
42619
  // src/commands/commit.ts
42403
- var commitCommand = new Command("commit").description("Create a commit with AI-generated message").option("-a, --all", "Stage all files before committing").argument("[message]", "Optional context for the commit message generation").action(async (message, options) => {
42620
+ var commitCommand = new Command("commit").description("Create a commit with AI-generated message").option("-a, --all", "Stage all files before committing").argument("[message]", "Optional context for the commit message generation").action(async (message, localOptions, command) => {
42404
42621
  const spinner = ora("Gathering information...").start();
42622
+ const options = command.parent?.opts() ?? {};
42405
42623
  const { providerConfig } = parseOptions(options);
42406
42624
  const { provider: provider2, model, apiKey } = providerConfig.getConfigForCommand("commit") ?? {};
42407
42625
  console.log("Provider:", provider2);
@@ -42419,7 +42637,7 @@ var commitCommand = new Command("commit").description("Create a commit with AI-g
42419
42637
  const stagedFiles = status.split(`
42420
42638
  `).filter((line) => line.match(/^[MADRC]/));
42421
42639
  if (stagedFiles.length === 0) {
42422
- if (options.all) {
42640
+ if (localOptions.all) {
42423
42641
  execSync("git add .");
42424
42642
  } else {
42425
42643
  spinner.stopAndPersist();
@@ -42440,25 +42658,110 @@ var commitCommand = new Command("commit").description("Create a commit with AI-g
42440
42658
  spinner.text = "Generating commit message...";
42441
42659
  const result = await generateGitCommitMessage(ai, { diff, context: message });
42442
42660
  spinner.succeed("Commit message generated");
42661
+ console.log(`
42662
+ Commit message:
42663
+ ${result.response}`);
42443
42664
  try {
42444
- execSync(`git commit -m "${result.response}"`);
42665
+ spawnSync("git", ["commit", "-m", result.response], { stdio: "inherit" });
42445
42666
  } catch {
42446
42667
  console.error("Error: Commit failed");
42447
42668
  process.exit(1);
42448
42669
  }
42449
- console.log(`
42450
- Commit message:
42451
- ${result.response}`);
42452
42670
  } catch (error) {
42453
42671
  console.error("Error:", error);
42454
42672
  process.exit(1);
42455
42673
  }
42456
42674
  });
42457
42675
 
42676
+ // src/commands/init.ts
42677
+ import os4 from "node:os";
42678
+ import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
42679
+ var initCommand = new Command("init").description("Initialize polkacodes configuration");
42680
+ initCommand.action(async (_options, command) => {
42681
+ const options = command.parent?.opts() ?? {};
42682
+ try {
42683
+ const localConfig = readLocalConfig() ?? {};
42684
+ if (localConfig) {
42685
+ const proceed = await esm_default2({
42686
+ message: `Found existing config at ${localConfigFileName}. Do you want to proceed? This will overwrite the existing config.`,
42687
+ default: false
42688
+ });
42689
+ if (!proceed) {
42690
+ console.log("Cancelled");
42691
+ return;
42692
+ }
42693
+ }
42694
+ const { config: existingConfig, providerConfig, verbose } = parseOptions(options);
42695
+ let { provider: provider2, model, apiKey } = providerConfig.getConfigForCommand("init") ?? {};
42696
+ console.log("Provider:", provider2);
42697
+ console.log("Model:", model);
42698
+ if (!provider2) {
42699
+ const newConfig = await configPrompt({ provider: provider2, model, apiKey });
42700
+ provider2 = newConfig.provider;
42701
+ model = newConfig.model;
42702
+ apiKey = newConfig.apiKey;
42703
+ localConfig.defaultProvider = provider2;
42704
+ localConfig.defaultModel = model;
42705
+ }
42706
+ const service = createService(provider2, {
42707
+ apiKey: apiKey ?? process.env.POLKA_API_KEY ?? options.apiKey ?? existingConfig.providers?.[provider2]?.apiKey,
42708
+ model
42709
+ });
42710
+ const multiAgent = new MultiAgent({
42711
+ createAgent: async (name) => {
42712
+ const agentName = name.trim().toLowerCase();
42713
+ switch (agentName) {
42714
+ case analyzerAgentInfo.name:
42715
+ return new AnalyzerAgent({
42716
+ ai: service,
42717
+ os: os4.platform(),
42718
+ provider: getProvider("analyzer", existingConfig),
42719
+ interactive: false
42720
+ });
42721
+ default:
42722
+ throw new Error(`Unknown agent: ${name}`);
42723
+ }
42724
+ }
42725
+ });
42726
+ console.log("Analyzing project files...");
42727
+ const files = {};
42728
+ const [relevantFiles] = await listFiles(".", true, 1000, process.cwd());
42729
+ for (const filePath of relevantFiles) {
42730
+ if (typeof filePath === "string" && existsSync3(filePath)) {
42731
+ try {
42732
+ const content = readFileSync3(filePath, "utf8");
42733
+ files[filePath] = content;
42734
+ } catch (error) {
42735
+ console.warn(`Failed to read file: ${filePath}`);
42736
+ }
42737
+ }
42738
+ }
42739
+ const { response: generatedConfig } = await generateProjectConfig(multiAgent, relevantFiles, printEvent(verbose));
42740
+ const parsedConfig = generatedConfig ? $parse(generatedConfig) : {};
42741
+ const config = {
42742
+ ...localConfig,
42743
+ ...parsedConfig
42744
+ };
42745
+ if (apiKey) {
42746
+ config.providers = {
42747
+ [provider2]: {
42748
+ apiKey
42749
+ }
42750
+ };
42751
+ }
42752
+ writeFileSync2(localConfigFileName, $stringify(config));
42753
+ console.log(`Configuration saved to ${localConfigFileName}`);
42754
+ } catch (error) {
42755
+ console.error("Failed to generate configuration:", error);
42756
+ process.exit(1);
42757
+ }
42758
+ });
42759
+
42458
42760
  // src/commands/pr.ts
42459
- import { execSync as execSync2, spawnSync } from "node:child_process";
42460
- var prCommand = new Command("pr").description("Create a GitHub pull request").argument("[message]", "Optional context for the commit message generation").action(async (message, options) => {
42761
+ import { execSync as execSync2, spawnSync as spawnSync2 } from "node:child_process";
42762
+ var prCommand = new Command("pr").description("Create a GitHub pull request").argument("[message]", "Optional context for the commit message generation").action(async (message, _options, command) => {
42461
42763
  const spinner = ora("Gathering information...").start();
42764
+ const options = command.parent?.opts() ?? {};
42462
42765
  const { providerConfig } = parseOptions(options);
42463
42766
  const { provider: provider2, model, apiKey } = providerConfig.getConfigForCommand("pr") ?? {};
42464
42767
  console.log("Provider:", provider2);
@@ -42508,7 +42811,7 @@ var prCommand = new Command("pr").description("Create a GitHub pull request").ar
42508
42811
  });
42509
42812
  spinner.succeed("Pull request details generated");
42510
42813
  await new Promise((resolve2) => setTimeout(resolve2, 10));
42511
- spawnSync("gh", ["pr", "create", "--title", prDetails.response.title.trim(), "--body", prDetails.response.description.trim()], {
42814
+ spawnSync2("gh", ["pr", "create", "--title", prDetails.response.title.trim(), "--body", prDetails.response.description.trim()], {
42512
42815
  stdio: "inherit"
42513
42816
  });
42514
42817
  } catch (error) {
@@ -42568,7 +42871,7 @@ var runTask = async (taskArg, options) => {
42568
42871
  process.exit(1);
42569
42872
  }
42570
42873
  }
42571
- const { providerConfig, config, maxIterations, verbose } = parseOptions(options);
42874
+ const { providerConfig, config, maxMessageCount, verbose, budget } = parseOptions(options);
42572
42875
  let { provider: provider2, model, apiKey } = providerConfig.getConfigForAgent("coder") ?? {};
42573
42876
  if (!provider2) {
42574
42877
  const newConfig = await configPrompt({ provider: provider2, model, apiKey });
@@ -42583,7 +42886,8 @@ var runTask = async (taskArg, options) => {
42583
42886
  model: model ?? defaultModels[provider2],
42584
42887
  apiKey,
42585
42888
  config: config ?? {},
42586
- maxIterations,
42889
+ maxMessageCount,
42890
+ budget,
42587
42891
  interactive: false,
42588
42892
  eventCallback: printEvent(verbose)
42589
42893
  });
@@ -42597,6 +42901,7 @@ program2.name("polka-codes").description("Polka Codes CLI").version(version);
42597
42901
  program2.argument("[task]", "The task to execute").action(runTask);
42598
42902
  program2.command("chat").description("Start an interactive chat session").action(runChat);
42599
42903
  program2.addCommand(configCommand);
42904
+ program2.addCommand(initCommand);
42600
42905
  program2.addCommand(commitCommand);
42601
42906
  program2.addCommand(prCommand);
42602
42907
  addSharedOptions(program2);