@polka-codes/core 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +989 -554
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7985,265 +7985,704 @@ var createService = (provider, options) => {
7985
7985
  return new DeepSeekService(options);
7986
7986
  }
7987
7987
  };
7988
- // src/tools/types.ts
7989
- var ToolResponseType;
7990
- ((ToolResponseType2) => {
7991
- ToolResponseType2["Reply"] = "Reply";
7992
- ToolResponseType2["Exit"] = "Exit";
7993
- ToolResponseType2["Invalid"] = "Invalid";
7994
- ToolResponseType2["Error"] = "Error";
7995
- ToolResponseType2["Interrupted"] = "Interrupted";
7996
- })(ToolResponseType ||= {});
7997
- // src/tools/tools.ts
7998
- var exports_tools = {};
7999
- __export(exports_tools, {
8000
- writeToFile: () => writeToFile,
8001
- searchFiles: () => searchFiles,
8002
- replaceInFile: () => replaceInFile,
8003
- readFile: () => readFile,
8004
- listFiles: () => listFiles,
8005
- listCodeDefinitionNames: () => listCodeDefinitionNames,
8006
- executeCommand: () => executeCommand,
8007
- attemptCompletion: () => attemptCompletion,
8008
- askFollowupQuestion: () => askFollowupQuestion
8009
- });
8010
- var executeCommand = {
8011
- name: "execute_command",
8012
- 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 be executed in the current working directory.`,
8013
- parameters: [
8014
- {
8015
- name: "command",
8016
- 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.",
8017
- required: true,
8018
- usageValue: "Your command here"
8019
- },
8020
- {
8021
- name: "requires_approval",
8022
- 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.`,
8023
- required: false,
8024
- usageValue: "true or false"
7988
+ // src/tool.ts
7989
+ var getAvailableTools = (provider, allTools) => {
7990
+ return allTools.filter((tool) => tool.isAvailable(provider));
7991
+ };
7992
+
7993
+ // src/Agent/parseAssistantMessage.ts
7994
+ function parseAssistantMessage(assistantMessage, tools, toolNamePrefix) {
7995
+ const parameterPrefix = `${toolNamePrefix}parameter_`;
7996
+ const results = [];
7997
+ const toolTags = tools.map((tool) => `${toolNamePrefix}${tool.name}`);
7998
+ const toolPattern = toolTags.join("|");
7999
+ const tagRegex = new RegExp(`<(${toolPattern})>(.*)<\\/\\1>`, "s");
8000
+ const match = assistantMessage.match(tagRegex);
8001
+ if (match) {
8002
+ const beforeTag = assistantMessage.slice(0, match.index).trim();
8003
+ const fullTagContent = match[0];
8004
+ if (beforeTag) {
8005
+ results.push({
8006
+ type: "text",
8007
+ content: beforeTag
8008
+ });
8025
8009
  }
8026
- ],
8027
- examples: [
8028
- {
8029
- description: "Request to execute a command",
8030
- parameters: [
8031
- {
8032
- name: "command",
8033
- value: "npm run dev"
8034
- },
8035
- {
8036
- name: "requires_approval",
8037
- value: "false"
8010
+ const tagName = match[1];
8011
+ const toolName = tagName.replace(toolNamePrefix, "");
8012
+ const tool = tools.find((t) => t.name === toolName);
8013
+ if (tool) {
8014
+ const params = {};
8015
+ for (const param of tool.parameters) {
8016
+ const paramName = `${parameterPrefix}${param.name}`;
8017
+ const escapedParamName = paramName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8018
+ const paramPattern = `<${escapedParamName}>([\\s\\S]*?)<\\/${escapedParamName}>`;
8019
+ const paramMatch = fullTagContent.match(new RegExp(paramPattern, "s"));
8020
+ if (paramMatch) {
8021
+ params[param.name] = paramMatch[1].trim();
8022
+ }
8023
+ }
8024
+ results.push({
8025
+ type: "tool_use",
8026
+ name: toolName,
8027
+ params
8028
+ });
8029
+ } else {
8030
+ results.push({
8031
+ type: "text",
8032
+ content: fullTagContent
8033
+ });
8034
+ }
8035
+ const afterTag = assistantMessage.slice((match.index ?? 0) + fullTagContent.length).trim();
8036
+ if (afterTag) {
8037
+ results.push({
8038
+ type: "text",
8039
+ content: afterTag
8040
+ });
8041
+ }
8042
+ } else {
8043
+ results.push({
8044
+ type: "text",
8045
+ content: assistantMessage
8046
+ });
8047
+ }
8048
+ return results;
8049
+ }
8050
+
8051
+ // src/Agent/prompts.ts
8052
+ var toolInfoPrompt = (tool, toolNamePrefix, parameterPrefix) => `
8053
+ ## ${toolNamePrefix}${tool.name}
8054
+
8055
+ Description: ${tool.description}
8056
+
8057
+ Parameters:
8058
+ ${tool.parameters.map((param) => `- ${parameterPrefix}${param.name}: (${param.required ? "required" : "optional"}) ${param.description}`).join(`
8059
+ `)}
8060
+
8061
+ Usage:
8062
+ <${toolNamePrefix}${tool.name}>
8063
+ ${tool.parameters.map((param) => `<${parameterPrefix}${param.name}>${param.usageValue}</${parameterPrefix}${param.name}>`).join(`
8064
+ `)}
8065
+ </${toolNamePrefix}${tool.name}>`;
8066
+ var toolInfoExamplesPrompt = (idx, tool, example, toolNamePrefix, parameterPrefix) => `
8067
+ ## Example ${idx + 1}: ${example.description}
8068
+
8069
+ <${toolNamePrefix}${tool.name}>
8070
+ ${example.parameters.map((param) => `<${parameterPrefix}${param.name}>${param.value}</${parameterPrefix}${param.name}>`).join(`
8071
+ `)}
8072
+ </${toolNamePrefix}${tool.name}>
8073
+ `;
8074
+ var toolUsePrompt = (tools, toolNamePrefix) => {
8075
+ if (tools.length === 0) {
8076
+ return "";
8077
+ }
8078
+ const parameterPrefix = `${toolNamePrefix}parameter_`;
8079
+ let exampleIndex = 0;
8080
+ return `
8081
+ ====
8082
+
8083
+ TOOL USE
8084
+
8085
+ 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.
8086
+
8087
+ # Tool Use Formatting
8088
+
8089
+ 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:
8090
+
8091
+ <${toolNamePrefix}tool_name>
8092
+ <${parameterPrefix}name1>value1</${parameterPrefix}name1>
8093
+ <${parameterPrefix}name2>value2</${parameterPrefix}name2>
8094
+ ...
8095
+ </${toolNamePrefix}tool_name>
8096
+
8097
+ For example:
8098
+
8099
+ <${toolNamePrefix}read_file>
8100
+ <${parameterPrefix}path>src/main.js</${parameterPrefix}path>
8101
+ </${toolNamePrefix}read_file>
8102
+
8103
+ Always adhere to this format for the tool use to ensure proper parsing and execution.
8104
+
8105
+ # Tools
8106
+ ${tools.map((tool) => toolInfoPrompt(tool, toolNamePrefix, parameterPrefix)).join(`
8107
+ `)}
8108
+
8109
+ # Tool Use Examples
8110
+ ${tools.map((tool) => {
8111
+ let promp = "";
8112
+ for (const example of tool.examples ?? []) {
8113
+ promp += toolInfoExamplesPrompt(exampleIndex++, tool, example, toolNamePrefix, parameterPrefix);
8114
+ }
8115
+ return promp;
8116
+ }).join("")}
8117
+ # Tool Use Guidelines
8118
+
8119
+ 1. **In \`<thinking>\` tags**, assess what information you have and what you need to proceed.
8120
+ 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.
8121
+ 3. **Formulate tool use only in the specified XML format** for each tool.
8122
+ 4. **Wait for the user’s response** after each tool use. Do not proceed until you have their confirmation.
8123
+ 5. The user’s response may include:
8124
+ - Tool success or failure details
8125
+ - Linter errors
8126
+ - Terminal output or other relevant feedback
8127
+ 6. **Never repeat or quote the entire tool command** in your final user-facing message. Summarize outcomes clearly and avoid echoing commands verbatim.
8128
+ 7. **Respond concisely** and move the conversation forward. Do not re-issue the same command or re-trigger tool use without necessity.
8129
+ 8. Follow these steps **iteratively**, confirming success and addressing issues as you go.
8130
+
8131
+ By adhering to these guidelines:
8132
+ - You maintain clarity without accidentally re-invoking tools.
8133
+ - You confirm each step’s results before proceeding.
8134
+ - You provide only the necessary information in user-facing replies to prevent re-interpretation as new commands.`;
8135
+ };
8136
+ var responsePrompts = {
8137
+ errorInvokeTool: (tool, error) => `An error occurred while invoking the tool "${tool}": ${error}`,
8138
+ requireUseTool: "Error: You must use a tool before proceeding",
8139
+ toolResults: (tool, result) => `<tool_response>
8140
+ <tool_name>${tool}</tool_name>
8141
+ <tool_result>
8142
+ ${result}
8143
+ </tool_result>
8144
+ </tool_response>`
8145
+ };
8146
+
8147
+ // src/Agent/AgentBase.ts
8148
+ var ExitReason;
8149
+ ((ExitReason2) => {
8150
+ ExitReason2["Completed"] = "Completed";
8151
+ ExitReason2["MaxIterations"] = "MaxIterations";
8152
+ ExitReason2["WaitForUserInput"] = "WaitForUserInput";
8153
+ ExitReason2["Interrupted"] = "Interrupted";
8154
+ })(ExitReason ||= {});
8155
+
8156
+ class AgentBase {
8157
+ ai;
8158
+ config;
8159
+ logger;
8160
+ handlers;
8161
+ constructor(ai, config, logger6) {
8162
+ this.ai = ai;
8163
+ this.config = config;
8164
+ this.logger = logger6;
8165
+ const handlers = {};
8166
+ for (const tool of config.tools) {
8167
+ handlers[tool.name] = tool;
8168
+ }
8169
+ this.handlers = handlers;
8170
+ }
8171
+ async startTask({
8172
+ task,
8173
+ context,
8174
+ maxIterations = 50,
8175
+ callback = () => {
8176
+ }
8177
+ }) {
8178
+ const taskInfo = {
8179
+ options: {
8180
+ maxIterations
8181
+ },
8182
+ messages: [],
8183
+ inputTokens: 0,
8184
+ outputTokens: 0,
8185
+ cacheWriteTokens: 0,
8186
+ cacheReadTokens: 0,
8187
+ totalCost: 0
8188
+ };
8189
+ let text = `<task>${task}</task>`;
8190
+ if (context) {
8191
+ text += `
8192
+ <context>${context}</context>`;
8193
+ }
8194
+ return await this.#processLoop(text, taskInfo, callback);
8195
+ }
8196
+ async#processLoop(userMessage, taskInfo, callback) {
8197
+ let nextRequest = userMessage;
8198
+ while (nextRequest) {
8199
+ if (taskInfo.messages.length > taskInfo.options.maxIterations * 2) {
8200
+ callback({ kind: "max_iterations_reached", info: taskInfo });
8201
+ return ["MaxIterations" /* MaxIterations */, taskInfo];
8202
+ }
8203
+ const response = await this.#request(taskInfo, nextRequest, callback);
8204
+ const [newMessage, exitReason] = await this.#handleResponse(taskInfo, response, callback);
8205
+ if (exitReason) {
8206
+ return [exitReason, taskInfo];
8207
+ }
8208
+ nextRequest = newMessage;
8209
+ }
8210
+ callback({ kind: "end_task", info: taskInfo });
8211
+ return ["Completed" /* Completed */, taskInfo];
8212
+ }
8213
+ async continueTask(userMessage, taskInfo, callback) {
8214
+ return await this.#processLoop(userMessage, taskInfo, callback);
8215
+ }
8216
+ async#request(info, userMessage, callback) {
8217
+ await callback({ kind: "start_request", info, userMessage });
8218
+ info.messages.push({
8219
+ role: "user",
8220
+ content: userMessage
8221
+ });
8222
+ this.logger.trace(info.messages, "Sending messages to AI");
8223
+ const stream = this.ai.send(this.config.systemPrompt, info.messages);
8224
+ let currentAssistantMessage = "";
8225
+ for await (const chunk of stream) {
8226
+ switch (chunk.type) {
8227
+ case "usage":
8228
+ info.inputTokens = chunk.inputTokens;
8229
+ info.outputTokens = chunk.outputTokens;
8230
+ info.cacheWriteTokens = chunk.cacheWriteTokens ?? 0;
8231
+ info.cacheReadTokens = chunk.cacheReadTokens ?? 0;
8232
+ info.totalCost = chunk.totalCost;
8233
+ await callback({ kind: "usage", info });
8234
+ break;
8235
+ case "text":
8236
+ currentAssistantMessage += chunk.text;
8237
+ await callback({ kind: "text", info, newText: chunk.text });
8238
+ break;
8239
+ }
8240
+ }
8241
+ if (!currentAssistantMessage) {
8242
+ throw new Error("No assistant message received");
8243
+ }
8244
+ info.messages.push({
8245
+ role: "assistant",
8246
+ content: currentAssistantMessage
8247
+ });
8248
+ const ret = parseAssistantMessage(currentAssistantMessage, this.config.tools, this.config.toolNamePrefix);
8249
+ await callback({ kind: "end_request", info });
8250
+ return ret;
8251
+ }
8252
+ async#handleResponse(info, response, callback) {
8253
+ const toolReponses = [];
8254
+ for (const content of response) {
8255
+ switch (content.type) {
8256
+ case "text":
8257
+ break;
8258
+ case "tool_use": {
8259
+ await callback({ kind: "tool_use", info, tool: content.name });
8260
+ const toolResp = await this.#invokeTool(content.name, content.params);
8261
+ switch (toolResp.type) {
8262
+ case "Reply" /* Reply */:
8263
+ await callback({ kind: "tool_reply", info, tool: content.name });
8264
+ toolReponses.push({ tool: content.name, response: toolResp.message });
8265
+ break;
8266
+ case "Exit" /* Exit */:
8267
+ return [undefined, "Completed" /* Completed */];
8268
+ case "Invalid" /* Invalid */:
8269
+ await callback({ kind: "tool_invalid", info, tool: content.name });
8270
+ toolReponses.push({ tool: content.name, response: toolResp.message });
8271
+ break;
8272
+ case "Error" /* Error */:
8273
+ await callback({ kind: "tool_error", info, tool: content.name });
8274
+ toolReponses.push({ tool: content.name, response: toolResp.message });
8275
+ break;
8276
+ case "Interrupted" /* Interrupted */:
8277
+ await callback({ kind: "tool_interrupted", info, tool: content.name });
8278
+ return [undefined, "Interrupted" /* Interrupted */];
8279
+ }
8280
+ break;
8281
+ }
8282
+ }
8283
+ }
8284
+ if (toolReponses.length === 0 && !this.config.interactive) {
8285
+ return [responsePrompts.requireUseTool, undefined];
8286
+ }
8287
+ const finalResp = toolReponses.map(({ tool, response: response2 }) => responsePrompts.toolResults(tool, response2)).join(`
8288
+
8289
+ `);
8290
+ return [finalResp, undefined];
8291
+ }
8292
+ async#invokeTool(name, args) {
8293
+ try {
8294
+ const handler = this.handlers[name]?.handler;
8295
+ if (!handler) {
8296
+ return {
8297
+ type: "Error" /* Error */,
8298
+ message: responsePrompts.errorInvokeTool(name, "Tool not found"),
8299
+ canRetry: false
8300
+ };
8301
+ }
8302
+ return await handler(this.config.provider, args);
8303
+ } catch (error) {
8304
+ this.logger.debug(error, "Error invoking tool");
8305
+ return {
8306
+ type: "Error" /* Error */,
8307
+ message: responsePrompts.errorInvokeTool(name, error),
8308
+ canRetry: false
8309
+ };
8310
+ }
8311
+ }
8312
+ get model() {
8313
+ return this.ai.model;
8314
+ }
8315
+ }
8316
+ // src/tools/provider.ts
8317
+ class MockProvider {
8318
+ async readFile(path) {
8319
+ return "mock content";
8320
+ }
8321
+ async writeFile(path, content) {
8322
+ return;
8323
+ }
8324
+ async listFiles(path, recursive, maxCount) {
8325
+ return [["mock-file.txt"], false];
8326
+ }
8327
+ async searchFiles(path, regex, filePattern) {
8328
+ return ["mock-file.txt"];
8329
+ }
8330
+ async listCodeDefinitionNames(path) {
8331
+ return ["mockDefinition"];
8332
+ }
8333
+ async executeCommand(command, needApprove) {
8334
+ return { stdout: "mock output", stderr: "", exitCode: 0 };
8335
+ }
8336
+ async askFollowupQuestion(question, options) {
8337
+ return "mock answer";
8338
+ }
8339
+ async attemptCompletion(result) {
8340
+ return "mock completion";
8341
+ }
8342
+ }
8343
+ // src/tools/allTools.ts
8344
+ var exports_allTools = {};
8345
+ __export(exports_allTools, {
8346
+ writeToFile: () => writeToFile_default,
8347
+ searchFiles: () => searchFiles_default,
8348
+ replaceInFile: () => replaceInFile_default,
8349
+ readFile: () => readFile_default,
8350
+ listFiles: () => listFiles_default,
8351
+ listCodeDefinitionNames: () => listCodeDefinitionNames_default,
8352
+ executeCommand: () => executeCommand_default,
8353
+ attemptCompletion: () => attemptCompletion_default,
8354
+ askFollowupQuestion: () => askFollowupQuestion_default
8355
+ });
8356
+
8357
+ // src/tools/utils/replaceInFile.ts
8358
+ var replaceInFile = async (fileContent, diff) => {
8359
+ const blockPattern = /<<<<<+ SEARCH\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
8360
+ const blocks = [];
8361
+ for (let match = blockPattern.exec(diff);match !== null; match = blockPattern.exec(diff)) {
8362
+ blocks.push({ search: match[1], replace: match[2] });
8363
+ }
8364
+ if (blocks.length === 0) {
8365
+ throw new Error("No valid diff blocks found.");
8366
+ }
8367
+ const findAndReplace = (content, search, replace) => {
8368
+ let index = content.indexOf(search);
8369
+ if (index !== -1) {
8370
+ return content.slice(0, index) + replace + content.slice(index + search.length);
8371
+ }
8372
+ const trimmedSearch = search.trim();
8373
+ const trimmedContent = content.trim();
8374
+ const offset = content.indexOf(trimmedContent);
8375
+ index = trimmedContent.indexOf(trimmedSearch);
8376
+ if (index !== -1) {
8377
+ const absoluteIndex = offset + index;
8378
+ return content.slice(0, absoluteIndex) + replace + content.slice(absoluteIndex + trimmedSearch.length);
8379
+ }
8380
+ const normalizedSearch = trimmedSearch.replace(/\s+/g, " ");
8381
+ const normalizedContent = trimmedContent.replace(/\s+/g, " ");
8382
+ index = normalizedContent.indexOf(normalizedSearch);
8383
+ if (index !== -1) {
8384
+ let runningIndex = 0;
8385
+ let actualPos = offset;
8386
+ for (const segment of trimmedSearch.replace(/\s+/g, " ").split(" ")) {
8387
+ const segIndex = content.indexOf(segment, actualPos);
8388
+ if (segIndex === -1) {
8389
+ break;
8038
8390
  }
8039
- ]
8391
+ if (runningIndex === 0) {
8392
+ actualPos = segIndex;
8393
+ } else {
8394
+ actualPos = segIndex + segment.length;
8395
+ }
8396
+ runningIndex++;
8397
+ }
8398
+ const strippedSearch = trimmedSearch.replace(/\s+/g, "");
8399
+ const endPos = actualPos;
8400
+ const startPos = endPos - strippedSearch.length;
8401
+ return content.slice(0, startPos) + replace + content.slice(endPos);
8040
8402
  }
8041
- ]
8403
+ throw new Error(`Could not find the following text in file:
8404
+ ${search}`);
8405
+ };
8406
+ let updatedFile = fileContent;
8407
+ for (const { search, replace } of blocks) {
8408
+ updatedFile = findAndReplace(updatedFile, search, replace);
8409
+ }
8410
+ return updatedFile;
8042
8411
  };
8043
- var readFile = {
8044
- name: "read_file",
8045
- 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.",
8412
+ // src/tools/utils/getArg.ts
8413
+ var getString = (args, name, defaultValue) => {
8414
+ const ret = args[name] ?? defaultValue;
8415
+ if (!ret) {
8416
+ throw new Error(`Missing required argument: ${name}`);
8417
+ }
8418
+ return ret;
8419
+ };
8420
+ var getStringArray = (args, name, defaultValue) => {
8421
+ const ret = args[name];
8422
+ if (!ret) {
8423
+ if (defaultValue === undefined) {
8424
+ throw new Error(`Missing required argument: ${name}`);
8425
+ }
8426
+ return defaultValue;
8427
+ }
8428
+ return ret.split(",");
8429
+ };
8430
+ var getBoolean = (args, name, defaultValue) => {
8431
+ const ret = args[name];
8432
+ if (!ret) {
8433
+ if (defaultValue === undefined) {
8434
+ throw new Error(`Missing required argument: ${name}`);
8435
+ }
8436
+ return defaultValue;
8437
+ }
8438
+ switch (ret.toLowerCase()) {
8439
+ case "true":
8440
+ return true;
8441
+ case "false":
8442
+ return false;
8443
+ default:
8444
+ throw new Error(`Invalid argument value: ${name}`);
8445
+ }
8446
+ };
8447
+ var getInt = (args, name, defaultValue) => {
8448
+ const ret = args[name];
8449
+ if (!ret) {
8450
+ if (defaultValue === undefined) {
8451
+ throw new Error(`Missing required argument: ${name}`);
8452
+ }
8453
+ return defaultValue;
8454
+ }
8455
+ const parsed = Number.parseInt(ret);
8456
+ if (Number.isNaN(parsed)) {
8457
+ throw new Error(`Invalid argument value: ${name}`);
8458
+ }
8459
+ return parsed;
8460
+ };
8461
+ // src/tools/askFollowupQuestion.ts
8462
+ var toolInfo = {
8463
+ name: "ask_followup_question",
8464
+ 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.",
8046
8465
  parameters: [
8047
8466
  {
8048
- name: "path",
8049
- description: "The path of the file to read",
8467
+ name: "question",
8468
+ description: "The question to ask the user. This should be a clear, specific question that addresses the information you need.",
8050
8469
  required: true,
8051
- usageValue: "Comma separated paths here"
8470
+ usageValue: "Your question here"
8471
+ },
8472
+ {
8473
+ name: "options",
8474
+ description: "A comma separated list of possible answers to the question. If not provided, the user will be prompted to provide an answer.",
8475
+ required: false,
8476
+ usageValue: "A comma separated list of possible answers (optional)"
8052
8477
  }
8053
8478
  ],
8054
8479
  examples: [
8055
8480
  {
8056
- description: "Request to read the contents of a file",
8481
+ description: "Request to ask a question",
8057
8482
  parameters: [
8058
8483
  {
8059
- name: "path",
8060
- value: "src/main.js"
8484
+ name: "question",
8485
+ value: "What is the name of the project?"
8061
8486
  }
8062
8487
  ]
8063
8488
  },
8064
8489
  {
8065
- description: "Request to read multiple files",
8490
+ description: "Request to ask a question with options",
8066
8491
  parameters: [
8067
8492
  {
8068
- name: "path",
8069
- value: "src/main.js,src/index.js"
8493
+ name: "question",
8494
+ value: "What framework do you use?"
8495
+ },
8496
+ {
8497
+ name: "options",
8498
+ value: "React,Angular,Vue,Svelte"
8070
8499
  }
8071
8500
  ]
8072
8501
  }
8073
8502
  ]
8074
8503
  };
8075
- var writeToFile = {
8076
- name: "write_to_file",
8077
- description: "Request to write content to a file at the specified path. If the file exists, it will be overwritten with the provided content. If the file doesn't exist, it will be created. This tool will automatically create any directories needed to write the file.",
8504
+ var handler = async (provider, args) => {
8505
+ if (!provider.askFollowupQuestion) {
8506
+ return {
8507
+ type: "Error" /* Error */,
8508
+ message: "Not possible to ask followup question. Abort."
8509
+ };
8510
+ }
8511
+ const question = getString(args, "question");
8512
+ const options = getStringArray(args, "options", []);
8513
+ const answer = await provider.askFollowupQuestion(question, options);
8514
+ return {
8515
+ type: "Reply" /* Reply */,
8516
+ message: `<ask_followup_question_question>${question}</ask_followup_question_question>
8517
+ <ask_followup_question_answer>${answer}</ask_followup_question_answer>`
8518
+ };
8519
+ };
8520
+ var isAvailable = (provider) => {
8521
+ return !!provider.askFollowupQuestion;
8522
+ };
8523
+ var askFollowupQuestion_default = {
8524
+ ...toolInfo,
8525
+ handler,
8526
+ isAvailable
8527
+ };
8528
+ // src/tools/attemptCompletion.ts
8529
+ var toolInfo2 = {
8530
+ name: "attempt_completion",
8531
+ 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.",
8078
8532
  parameters: [
8079
8533
  {
8080
- name: "path",
8081
- description: "The path of the file to write to",
8082
- required: true,
8083
- usageValue: "File path here"
8084
- },
8085
- {
8086
- name: "content",
8087
- description: "The content to write to the file. ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified.",
8534
+ name: "result",
8535
+ 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.",
8088
8536
  required: true,
8089
- usageValue: "Your file content here"
8537
+ usageValue: "Your final result description here"
8090
8538
  }
8091
8539
  ],
8092
8540
  examples: [
8093
8541
  {
8094
- description: "Request to write content to a file",
8542
+ description: "Request to present the result of the task",
8095
8543
  parameters: [
8096
8544
  {
8097
- name: "path",
8098
- value: "src/main.js"
8099
- },
8100
- {
8101
- name: "content",
8102
- value: `import React from 'react';
8103
-
8104
- function App() {
8105
- return (
8106
- <div>
8107
- <h1>Hello, World!</h1>
8108
- </div>
8109
- );
8110
- }
8111
-
8112
- export default App;
8113
- `
8545
+ name: "result",
8546
+ value: "Your final result description here"
8114
8547
  }
8115
8548
  ]
8116
8549
  }
8117
8550
  ]
8118
8551
  };
8119
- var replaceInFile = {
8120
- name: "replace_in_file",
8121
- 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.",
8552
+ var handler2 = async (provider, args) => {
8553
+ const result = getString(args, "result");
8554
+ const moreMessage = await provider.attemptCompletion?.(result);
8555
+ if (!moreMessage) {
8556
+ return {
8557
+ type: "Exit" /* Exit */,
8558
+ message: "<completed>true</completed>"
8559
+ };
8560
+ }
8561
+ return {
8562
+ type: "Reply" /* Reply */,
8563
+ message: `<user_message>${moreMessage}</user_message>`
8564
+ };
8565
+ };
8566
+ var isAvailable2 = (provider) => {
8567
+ return true;
8568
+ };
8569
+ var attemptCompletion_default = {
8570
+ ...toolInfo2,
8571
+ handler: handler2,
8572
+ isAvailable: isAvailable2
8573
+ };
8574
+ // src/tools/executeCommand.ts
8575
+ var toolInfo3 = {
8576
+ name: "execute_command",
8577
+ 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 be executed in the current working directory.`,
8122
8578
  parameters: [
8123
8579
  {
8124
- name: "path",
8125
- description: "The path of the file to modify",
8580
+ name: "command",
8581
+ 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.",
8126
8582
  required: true,
8127
- usageValue: "File path here"
8583
+ usageValue: "Your command here"
8128
8584
  },
8129
8585
  {
8130
- name: "diff",
8131
- description: `One or more SEARCH/REPLACE blocks following this exact format:
8132
- \`\`\`
8133
- <<<<<<< SEARCH
8134
- [exact content to find]
8135
- =======
8136
- [new content to replace with]
8137
- >>>>>>> REPLACE
8138
- \`\`\`
8139
- Critical rules:
8140
- 1. SEARCH content must match the associated file section to find EXACTLY:
8141
- * Match character-for-character including whitespace, indentation, line endings
8142
- * Include all comments, docstrings, etc.
8143
- 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.
8144
- * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.
8145
- * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.
8146
- * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.
8147
- 3. Keep SEARCH/REPLACE blocks concise:
8148
- * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.
8149
- * Include just the changing lines, and a few surrounding lines if needed for uniqueness.
8150
- * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.
8151
- * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.
8152
- 4. Special operations:
8153
- * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
8154
- * To delete code: Use empty REPLACE section`,
8155
- required: true,
8156
- usageValue: "Search and replace blocks here"
8586
+ name: "requires_approval",
8587
+ 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.`,
8588
+ required: false,
8589
+ usageValue: "true or false"
8157
8590
  }
8158
8591
  ],
8159
8592
  examples: [
8160
8593
  {
8161
- description: "Request to replace sections of content in a file",
8594
+ description: "Request to execute a command",
8162
8595
  parameters: [
8163
8596
  {
8164
- name: "path",
8165
- value: "src/main.js"
8597
+ name: "command",
8598
+ value: "npm run dev"
8166
8599
  },
8167
8600
  {
8168
- name: "diff",
8169
- value: `
8170
- <<<<<<< SEARCH
8171
- import React from 'react';
8172
- =======
8173
- import React, { useState } from 'react';
8174
- >>>>>>> REPLACE
8175
-
8176
- <<<<<<< SEARCH
8177
- function handleSubmit() {
8178
- saveData();
8179
- setLoading(false);
8180
- }
8181
-
8182
- =======
8183
- >>>>>>> REPLACE
8184
-
8185
- <<<<<<< SEARCH
8186
- return (
8187
- <div>
8188
- =======
8189
- function handleSubmit() {
8190
- saveData();
8191
- setLoading(false);
8192
- }
8193
-
8194
- return (
8195
- <div>
8196
- >>>>>>> REPLACE
8197
- `
8601
+ name: "requires_approval",
8602
+ value: "false"
8198
8603
  }
8199
8604
  ]
8200
8605
  }
8201
8606
  ]
8202
8607
  };
8203
- var searchFiles = {
8204
- name: "search_files",
8205
- 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.",
8608
+ var handler3 = async (provider, args) => {
8609
+ if (!provider.executeCommand) {
8610
+ return {
8611
+ type: "Error" /* Error */,
8612
+ message: "Not possible to execute command. Abort."
8613
+ };
8614
+ }
8615
+ const command = getString(args, "command");
8616
+ const requiresApproval = getBoolean(args, "requires_approval", false);
8617
+ const result = await provider.executeCommand?.(command, requiresApproval);
8618
+ const message = `<command>${command}</command>
8619
+ <command_exit_code>${result.exitCode}</command_exit_code>
8620
+ <command_stdout>
8621
+ ${result.stdout}
8622
+ </command_stdout>
8623
+ <command_stderr>
8624
+ ${result.stderr}
8625
+ </command_stderr>`;
8626
+ if (result.exitCode === 0) {
8627
+ return {
8628
+ type: "Reply" /* Reply */,
8629
+ message
8630
+ };
8631
+ }
8632
+ return {
8633
+ type: "Error" /* Error */,
8634
+ message
8635
+ };
8636
+ };
8637
+ var isAvailable3 = (provider) => {
8638
+ return !!provider.executeCommand;
8639
+ };
8640
+ var executeCommand_default = {
8641
+ ...toolInfo3,
8642
+ handler: handler3,
8643
+ isAvailable: isAvailable3
8644
+ };
8645
+ // src/tools/listCodeDefinitionNames.ts
8646
+ var toolInfo4 = {
8647
+ name: "list_code_definition_names",
8648
+ 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.",
8206
8649
  parameters: [
8207
8650
  {
8208
8651
  name: "path",
8209
- description: "The path of the directory to search in (relative to the current working directory). This directory will be recursively searched.",
8652
+ description: "The path of a code file to list top level source code definitions for.",
8210
8653
  required: true,
8211
8654
  usageValue: "Directory path here"
8212
- },
8213
- {
8214
- name: "regex",
8215
- description: "The regular expression pattern to search for. Uses Rust regex syntax.",
8216
- required: true,
8217
- usageValue: "Your regex pattern here"
8218
- },
8219
- {
8220
- name: "file_pattern",
8221
- description: 'Glob pattern to filter files (e.g., "*.ts" for TypeScript files). If not provided, it will search all files (*).',
8222
- required: false,
8223
- usageValue: "file pattern here (optional)"
8224
- }
8225
- ],
8226
- examples: [
8227
- {
8228
- description: "Request to perform a regex search across files",
8229
- parameters: [
8230
- {
8231
- name: "path",
8232
- value: "src"
8233
- },
8234
- {
8235
- name: "regex",
8236
- value: "^src/components/"
8237
- },
8238
- {
8239
- name: "file_pattern",
8240
- value: "*.ts"
8241
- }
8242
- ]
8243
8655
  }
8244
8656
  ]
8245
8657
  };
8246
- var listFiles = {
8658
+ var handler4 = async (provider, args) => {
8659
+ if (!provider.listCodeDefinitionNames) {
8660
+ return {
8661
+ type: "Error" /* Error */,
8662
+ message: "Not possible to list code definition names. Abort."
8663
+ };
8664
+ }
8665
+ const path = getString(args, "path");
8666
+ const files = await provider.listCodeDefinitionNames(path);
8667
+ return {
8668
+ type: "Reply" /* Reply */,
8669
+ message: `<list_code_definition_names_path>${path}</list_code_definition_names_path>
8670
+ <list_code_definition_names_files>
8671
+ ${files.join(`
8672
+ `)}
8673
+ </list_code_definition_names_files>`
8674
+ };
8675
+ };
8676
+ var isAvailable4 = (provider) => {
8677
+ return !!provider.listCodeDefinitionNames;
8678
+ };
8679
+ var listCodeDefinitionNames_default = {
8680
+ ...toolInfo4,
8681
+ handler: handler4,
8682
+ isAvailable: isAvailable4
8683
+ };
8684
+ // src/tools/listFiles.ts
8685
+ var toolInfo5 = {
8247
8686
  name: "list_files",
8248
8687
  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.",
8249
8688
  parameters: [
@@ -8254,10 +8693,16 @@ var listFiles = {
8254
8693
  usageValue: "Directory path here"
8255
8694
  },
8256
8695
  {
8257
- name: "depth",
8258
- description: "The depth of the directory to list contents for. Use 0 for the top-level directory only, 1 for the top-level directory and its children, and so on.",
8696
+ name: "max_count",
8697
+ description: "The maximum number of files to list. Default to 2000",
8698
+ required: false,
8699
+ usageValue: "Maximum number of files to list (optional)"
8700
+ },
8701
+ {
8702
+ name: "recursive",
8703
+ description: "Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.",
8259
8704
  required: false,
8260
- usageValue: "a number (optional)"
8705
+ usageValue: "true or false (optional)"
8261
8706
  }
8262
8707
  ],
8263
8708
  examples: [
@@ -8269,377 +8714,355 @@ var listFiles = {
8269
8714
  value: "src"
8270
8715
  },
8271
8716
  {
8272
- name: "recursive",
8273
- value: "true"
8717
+ name: "max_count",
8718
+ value: "100"
8274
8719
  }
8275
8720
  ]
8276
8721
  }
8277
8722
  ]
8278
8723
  };
8279
- var listCodeDefinitionNames = {
8280
- name: "list_code_definition_names",
8281
- description: "Request to list definition names (classes, functions, methods, etc.) used in source code files at the top level of the specified directory. This tool provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.",
8282
- parameters: [
8283
- {
8284
- name: "path",
8285
- description: "The path of the directory (relative to the current working directory ${cwd.toPosix()}) to list top level source code definitions for.",
8286
- required: true,
8287
- usageValue: "Directory path here"
8288
- }
8289
- ]
8724
+ var handler5 = async (provider, args) => {
8725
+ if (!provider.listFiles) {
8726
+ return {
8727
+ type: "Error" /* Error */,
8728
+ message: "Not possible to list files. Abort."
8729
+ };
8730
+ }
8731
+ const path = getString(args, "path");
8732
+ const maxCount = getInt(args, "max_count", 2000);
8733
+ const recursive = getBoolean(args, "recursive", true);
8734
+ const [files, limitReached] = await provider.listFiles(path, recursive, maxCount);
8735
+ return {
8736
+ type: "Reply" /* Reply */,
8737
+ message: `<list_files_path>${path}</list_files_path>
8738
+ <list_files_files>
8739
+ ${files.join(`
8740
+ `)}
8741
+ </list_files_files>
8742
+ <list_files_truncated>${limitReached}</list_files_truncated>`
8743
+ };
8290
8744
  };
8291
- var askFollowupQuestion = {
8292
- name: "ask_followup_question",
8293
- description: "Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.",
8745
+ var isAvailable5 = (provider) => {
8746
+ return !!provider.listFiles;
8747
+ };
8748
+ var listFiles_default = {
8749
+ ...toolInfo5,
8750
+ handler: handler5,
8751
+ isAvailable: isAvailable5
8752
+ };
8753
+ // src/tools/readFile.ts
8754
+ var toolInfo6 = {
8755
+ name: "read_file",
8756
+ 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.",
8294
8757
  parameters: [
8295
8758
  {
8296
- name: "question",
8297
- description: "The question to ask the user. This should be a clear, specific question that addresses the information you need.",
8759
+ name: "path",
8760
+ description: "The path of the file to read",
8298
8761
  required: true,
8299
- usageValue: "Your question here"
8762
+ usageValue: "Comma separated paths here"
8300
8763
  }
8301
8764
  ],
8302
8765
  examples: [
8303
8766
  {
8304
- description: "Request to ask a question",
8767
+ description: "Request to read the contents of a file",
8305
8768
  parameters: [
8306
8769
  {
8307
- name: "question",
8308
- value: "What is the name of the project?"
8770
+ name: "path",
8771
+ value: "src/main.js"
8772
+ }
8773
+ ]
8774
+ },
8775
+ {
8776
+ description: "Request to read multiple files",
8777
+ parameters: [
8778
+ {
8779
+ name: "path",
8780
+ value: "src/main.js,src/index.js"
8309
8781
  }
8310
8782
  ]
8311
8783
  }
8312
8784
  ]
8313
8785
  };
8314
- var attemptCompletion = {
8315
- name: "attempt_completion",
8316
- description: "After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user.",
8786
+ var handler6 = async (provider, args) => {
8787
+ if (!provider.readFile) {
8788
+ return {
8789
+ type: "Error" /* Error */,
8790
+ message: "Not possible to read file. Abort."
8791
+ };
8792
+ }
8793
+ const paths = getStringArray(args, "path");
8794
+ const resp = [];
8795
+ for (const path of paths) {
8796
+ const fileContent = await provider.readFile(path);
8797
+ resp.push(`<read_file_file_conten path="${path}">${fileContent}</read_file_file_content>`);
8798
+ }
8799
+ return {
8800
+ type: "Reply" /* Reply */,
8801
+ message: resp.join(`
8802
+ `)
8803
+ };
8804
+ };
8805
+ var isAvailable6 = (provider) => {
8806
+ return !!provider.readFile;
8807
+ };
8808
+ var readFile_default = {
8809
+ ...toolInfo6,
8810
+ handler: handler6,
8811
+ isAvailable: isAvailable6
8812
+ };
8813
+ // src/tools/replaceInFile.ts
8814
+ var toolInfo7 = {
8815
+ name: "replace_in_file",
8816
+ 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.",
8317
8817
  parameters: [
8318
8818
  {
8319
- name: "result",
8320
- 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.",
8819
+ name: "path",
8820
+ description: "The path of the file to modify",
8321
8821
  required: true,
8322
- usageValue: "Your final result description here"
8822
+ usageValue: "File path here"
8823
+ },
8824
+ {
8825
+ name: "diff",
8826
+ description: `One or more SEARCH/REPLACE blocks following this exact format:
8827
+ \`\`\`
8828
+ <<<<<<< SEARCH
8829
+ [exact content to find]
8830
+ =======
8831
+ [new content to replace with]
8832
+ >>>>>>> REPLACE
8833
+ \`\`\`
8834
+ Critical rules:
8835
+ 1. SEARCH content must match the associated file section to find EXACTLY:
8836
+ * Match character-for-character including whitespace, indentation, line endings
8837
+ * Include all comments, docstrings, etc.
8838
+ 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.
8839
+ * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.
8840
+ * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.
8841
+ * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.
8842
+ 3. Keep SEARCH/REPLACE blocks concise:
8843
+ * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.
8844
+ * Include just the changing lines, and a few surrounding lines if needed for uniqueness.
8845
+ * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.
8846
+ * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.
8847
+ 4. Special operations:
8848
+ * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
8849
+ * To delete code: Use empty REPLACE section`,
8850
+ required: true,
8851
+ usageValue: "Search and replace blocks here"
8323
8852
  }
8324
8853
  ],
8325
8854
  examples: [
8326
8855
  {
8327
- description: "Request to present the result of the task",
8856
+ description: "Request to replace sections of content in a file",
8328
8857
  parameters: [
8329
8858
  {
8330
- name: "result",
8331
- value: "Your final result description here"
8332
- }
8333
- ]
8334
- }
8335
- ]
8336
- };
8337
- // src/Agent/parseAssistantMessage.ts
8338
- function parseAssistantMessage(assistantMessage, tools2, toolNamePrefix) {
8339
- const parameterPrefix = `${toolNamePrefix}parameter_`;
8340
- const results = [];
8341
- const toolTags = tools2.map((tool) => `${toolNamePrefix}${tool.name}`);
8342
- const toolPattern = toolTags.join("|");
8343
- const tagRegex = new RegExp(`<(${toolPattern})>(.*)<\\/\\1>`, "s");
8344
- const match = assistantMessage.match(tagRegex);
8345
- if (match) {
8346
- const beforeTag = assistantMessage.slice(0, match.index).trim();
8347
- const fullTagContent = match[0];
8348
- if (beforeTag) {
8349
- results.push({
8350
- type: "text",
8351
- content: beforeTag
8352
- });
8353
- }
8354
- const tagName = match[1];
8355
- const toolName = tagName.replace(toolNamePrefix, "");
8356
- const tool = tools2.find((t) => t.name === toolName);
8357
- if (tool) {
8358
- const params = {};
8359
- for (const param of tool.parameters) {
8360
- const paramName = `${parameterPrefix}${param.name}`;
8361
- const escapedParamName = paramName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8362
- const paramPattern = `<${escapedParamName}>([\\s\\S]*?)<\\/${escapedParamName}>`;
8363
- const paramMatch = fullTagContent.match(new RegExp(paramPattern, "s"));
8364
- if (paramMatch) {
8365
- params[param.name] = paramMatch[1].trim();
8366
- }
8367
- }
8368
- results.push({
8369
- type: "tool_use",
8370
- name: toolName,
8371
- params
8372
- });
8373
- } else {
8374
- results.push({
8375
- type: "text",
8376
- content: fullTagContent
8377
- });
8378
- }
8379
- const afterTag = assistantMessage.slice((match.index ?? 0) + fullTagContent.length).trim();
8380
- if (afterTag) {
8381
- results.push({
8382
- type: "text",
8383
- content: afterTag
8384
- });
8385
- }
8386
- } else {
8387
- results.push({
8388
- type: "text",
8389
- content: assistantMessage
8390
- });
8391
- }
8392
- return results;
8393
- }
8394
-
8395
- // src/Agent/prompts.ts
8396
- var toolInfoPrompt = (tool, toolNamePrefix, parameterPrefix) => `
8397
- ## ${toolNamePrefix}${tool.name}
8398
-
8399
- Description: ${tool.description}
8400
-
8401
- Parameters:
8402
- ${tool.parameters.map((param) => `- ${parameterPrefix}${param.name}: (${param.required ? "required" : "optional"}) ${param.description}`).join(`
8403
- `)}
8404
-
8405
- Usage:
8406
- <${toolNamePrefix}${tool.name}>
8407
- ${tool.parameters.map((param) => `<${parameterPrefix}${param.name}>${param.usageValue}</${parameterPrefix}${param.name}>`).join(`
8408
- `)}
8409
- </${toolNamePrefix}${tool.name}>`;
8410
- var toolInfoExamplesPrompt = (idx, tool, example, toolNamePrefix, parameterPrefix) => `
8411
- ## Example ${idx + 1}: ${example.description}
8412
-
8413
- <${toolNamePrefix}${tool.name}>
8414
- ${example.parameters.map((param) => `<${parameterPrefix}${param.name}>${param.value}</${parameterPrefix}${param.name}>`).join(`
8415
- `)}
8416
- </${toolNamePrefix}${tool.name}>
8417
- `;
8418
- var toolUsePrompt = (tools2, toolNamePrefix) => {
8419
- if (tools2.length === 0) {
8420
- return "";
8421
- }
8422
- const parameterPrefix = `${toolNamePrefix}parameter_`;
8423
- let exampleIndex = 0;
8424
- return `
8425
- ====
8426
-
8427
- TOOL USE
8428
-
8429
- 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.
8430
-
8431
- # Tool Use Formatting
8432
-
8433
- 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:
8434
-
8435
- <${toolNamePrefix}tool_name>
8436
- <${parameterPrefix}name1>value1</${parameterPrefix}name1>
8437
- <${parameterPrefix}name2>value2</${parameterPrefix}name2>
8438
- ...
8439
- </${toolNamePrefix}tool_name>
8440
-
8441
- For example:
8442
-
8443
- <${toolNamePrefix}read_file>
8444
- <${parameterPrefix}path>src/main.js</${parameterPrefix}path>
8445
- </${toolNamePrefix}read_file>
8446
-
8447
- Always adhere to this format for the tool use to ensure proper parsing and execution.
8448
-
8449
- # Tools
8450
- ${tools2.map((tool) => toolInfoPrompt(tool, toolNamePrefix, parameterPrefix)).join(`
8451
- `)}
8452
-
8453
- # Tool Use Examples
8454
- ${tools2.map((tool) => {
8455
- let promp = "";
8456
- for (const example of tool.examples ?? []) {
8457
- promp += toolInfoExamplesPrompt(exampleIndex++, tool, example, toolNamePrefix, parameterPrefix);
8458
- }
8459
- return promp;
8460
- }).join("")}
8461
- # Tool Use Guidelines
8859
+ name: "path",
8860
+ value: "src/main.js"
8861
+ },
8862
+ {
8863
+ name: "diff",
8864
+ value: `
8865
+ <<<<<<< SEARCH
8866
+ import React from 'react';
8867
+ =======
8868
+ import React, { useState } from 'react';
8869
+ >>>>>>> REPLACE
8462
8870
 
8463
- 1. **In \`<thinking>\` tags**, assess what information you have and what you need to proceed.
8464
- 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.
8465
- 3. **Formulate tool use only in the specified XML format** for each tool.
8466
- 4. **Wait for the user’s response** after each tool use. Do not proceed until you have their confirmation.
8467
- 5. The user’s response may include:
8468
- - Tool success or failure details
8469
- - Linter errors
8470
- - Terminal output or other relevant feedback
8471
- 6. **Never repeat or quote the entire tool command** in your final user-facing message. Summarize outcomes clearly and avoid echoing commands verbatim.
8472
- 7. **Respond concisely** and move the conversation forward. Do not re-issue the same command or re-trigger tool use without necessity.
8473
- 8. Follow these steps **iteratively**, confirming success and addressing issues as you go.
8871
+ <<<<<<< SEARCH
8872
+ function handleSubmit() {
8873
+ saveData();
8874
+ setLoading(false);
8875
+ }
8474
8876
 
8475
- By adhering to these guidelines:
8476
- - You maintain clarity without accidentally re-invoking tools.
8477
- - You confirm each step’s results before proceeding.
8478
- - You provide only the necessary information in user-facing replies to prevent re-interpretation as new commands.`;
8479
- };
8480
- var responsePrompts = {
8481
- errorInvokeTool: (tool, error) => `An error occurred while invoking the tool "${tool}": ${error}`,
8482
- requireUseTool: "Error: You must use a tool before proceeding",
8483
- toolResults: (tool, result) => `<tool_response>
8484
- <tool_name>${tool}</tool_name>
8485
- <tool_result>
8486
- ${result}
8487
- </tool_result>
8488
- </tool_response>`
8489
- };
8877
+ =======
8878
+ >>>>>>> REPLACE
8490
8879
 
8491
- // src/Agent/AgentBase.ts
8492
- class AgentBase {
8493
- ai;
8494
- config;
8495
- logger;
8496
- constructor(ai, config, logger6) {
8497
- this.ai = ai;
8498
- this.config = config;
8499
- this.logger = logger6;
8500
- }
8501
- async startTask({
8502
- task,
8503
- context,
8504
- maxIterations = 50,
8505
- callback = () => {
8880
+ <<<<<<< SEARCH
8881
+ return (
8882
+ <div>
8883
+ =======
8884
+ function handleSubmit() {
8885
+ saveData();
8886
+ setLoading(false);
8887
+ }
8888
+
8889
+ return (
8890
+ <div>
8891
+ >>>>>>> REPLACE
8892
+ `
8893
+ }
8894
+ ]
8506
8895
  }
8507
- }) {
8508
- const taskInfo = {
8509
- options: {
8510
- maxIterations
8511
- },
8512
- messages: [],
8513
- inputTokens: 0,
8514
- outputTokens: 0,
8515
- cacheWriteTokens: 0,
8516
- cacheReadTokens: 0,
8517
- totalCost: 0
8896
+ ]
8897
+ };
8898
+ var handler7 = async (provider, args) => {
8899
+ if (!provider.readFile || !provider.writeFile) {
8900
+ return {
8901
+ type: "Error" /* Error */,
8902
+ message: "Not possible to replace in file. Abort."
8518
8903
  };
8519
- let text = `<task>${task}</task>`;
8520
- if (context) {
8521
- text += `
8522
- <context>${context}</context>`;
8523
- }
8524
- let nextRequest = [
8525
- {
8526
- type: "text",
8527
- text
8528
- }
8529
- ];
8530
- let iterations = 0;
8531
- while (nextRequest) {
8532
- if (iterations >= taskInfo.options.maxIterations) {
8533
- callback({ kind: "max_iterations_reached", info: taskInfo });
8534
- break;
8535
- }
8536
- const response = await this.#request(taskInfo, nextRequest, callback);
8537
- nextRequest = await this.#handleResponse(taskInfo, response, callback);
8538
- ++iterations;
8539
- }
8540
- callback({ kind: "end_task", info: taskInfo });
8541
- return taskInfo;
8542
8904
  }
8543
- async#request(info, userContent, callback) {
8544
- await callback({ kind: "start_request", info, userContent });
8545
- info.messages.push({
8546
- role: "user",
8547
- content: userContent
8548
- });
8549
- this.logger.trace(info.messages, "Sending messages to AI");
8550
- const stream = this.ai.send(this.config.systemPrompt, info.messages);
8551
- let currentAssistantMessage = "";
8552
- for await (const chunk of stream) {
8553
- switch (chunk.type) {
8554
- case "usage":
8555
- info.inputTokens = chunk.inputTokens;
8556
- info.outputTokens = chunk.outputTokens;
8557
- info.cacheWriteTokens = chunk.cacheWriteTokens ?? 0;
8558
- info.cacheReadTokens = chunk.cacheReadTokens ?? 0;
8559
- info.totalCost = chunk.totalCost;
8560
- await callback({ kind: "usage", info });
8561
- break;
8562
- case "text":
8563
- currentAssistantMessage += chunk.text;
8564
- await callback({ kind: "text", info, newText: chunk.text });
8565
- break;
8566
- }
8905
+ const path = getString(args, "path");
8906
+ const diff = getString(args, "diff");
8907
+ const fileContent = await provider.readFile(path);
8908
+ const result = await replaceInFile(fileContent, diff);
8909
+ await provider.writeFile(path, result);
8910
+ return {
8911
+ type: "Reply" /* Reply */,
8912
+ message: `<replace_in_file_path>${path}</replace_in_file_path>`
8913
+ };
8914
+ };
8915
+ var isAvailable7 = (provider) => {
8916
+ return !!provider.readFile && !!provider.writeFile;
8917
+ };
8918
+ var replaceInFile_default = {
8919
+ ...toolInfo7,
8920
+ handler: handler7,
8921
+ isAvailable: isAvailable7
8922
+ };
8923
+ // src/tools/searchFiles.ts
8924
+ var toolInfo8 = {
8925
+ name: "search_files",
8926
+ 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.",
8927
+ parameters: [
8928
+ {
8929
+ name: "path",
8930
+ description: "The path of the directory to search in (relative to the current working directory). This directory will be recursively searched.",
8931
+ required: true,
8932
+ usageValue: "Directory path here"
8933
+ },
8934
+ {
8935
+ name: "regex",
8936
+ description: "The regular expression pattern to search for. Uses Rust regex syntax.",
8937
+ required: true,
8938
+ usageValue: "Your regex pattern here"
8939
+ },
8940
+ {
8941
+ name: "file_pattern",
8942
+ description: 'Glob pattern to filter files (e.g., "*.ts" for TypeScript files). If not provided, it will search all files (*).',
8943
+ required: false,
8944
+ usageValue: "file pattern here (optional)"
8567
8945
  }
8568
- if (!currentAssistantMessage) {
8569
- throw new Error("No assistant message received");
8946
+ ],
8947
+ examples: [
8948
+ {
8949
+ description: "Request to perform a regex search across files",
8950
+ parameters: [
8951
+ {
8952
+ name: "path",
8953
+ value: "src"
8954
+ },
8955
+ {
8956
+ name: "regex",
8957
+ value: "^components/"
8958
+ },
8959
+ {
8960
+ name: "file_pattern",
8961
+ value: "*.ts"
8962
+ }
8963
+ ]
8570
8964
  }
8571
- info.messages.push({
8572
- role: "assistant",
8573
- content: currentAssistantMessage
8574
- });
8575
- const ret = parseAssistantMessage(currentAssistantMessage, this.config.tools, this.config.toolNamePrefix);
8576
- await callback({ kind: "end_request", info });
8577
- return ret;
8965
+ ]
8966
+ };
8967
+ var handler8 = async (provider, args) => {
8968
+ if (!provider.searchFiles) {
8969
+ return {
8970
+ type: "Error" /* Error */,
8971
+ message: "Not possible to search files. Abort."
8972
+ };
8578
8973
  }
8579
- async#handleResponse(info, response, callback) {
8580
- const toolReponses = [];
8581
- for (const content of response) {
8582
- switch (content.type) {
8583
- case "text":
8584
- break;
8585
- case "tool_use": {
8586
- await callback({ kind: "tool_use", info, tool: content.name });
8587
- const toolResp = await this.#invokeTool(content.name, content.params);
8588
- switch (toolResp.type) {
8589
- case "Reply" /* Reply */:
8590
- await callback({ kind: "tool_reply", info, tool: content.name });
8591
- toolReponses.push({ tool: content.name, response: toolResp.message });
8592
- break;
8593
- case "Exit" /* Exit */:
8594
- return;
8595
- case "Invalid" /* Invalid */:
8596
- await callback({ kind: "tool_invalid", info, tool: content.name });
8597
- toolReponses.push({ tool: content.name, response: toolResp.message });
8598
- break;
8599
- case "Error" /* Error */:
8600
- await callback({ kind: "tool_error", info, tool: content.name });
8601
- toolReponses.push({ tool: content.name, response: toolResp.message });
8602
- break;
8603
- case "Interrupted" /* Interrupted */:
8604
- await callback({ kind: "tool_interrupted", info, tool: content.name });
8605
- return;
8606
- }
8607
- break;
8608
- }
8609
- }
8974
+ const path = getString(args, "path");
8975
+ const regex = getString(args, "regex");
8976
+ const filePattern = getString(args, "file_pattern", "*");
8977
+ const files = await provider.searchFiles(path, regex, filePattern);
8978
+ return {
8979
+ type: "Reply" /* Reply */,
8980
+ message: `<search_files_path>${path}</search_files_path>
8981
+ <search_files_regex>${regex}</search_files_regex>
8982
+ <search_files_file_pattern>${filePattern}</search_files_file_pattern>
8983
+ <search_files_files>
8984
+ ${files.join(`
8985
+ `)}
8986
+ </search_files_files>
8987
+ `
8988
+ };
8989
+ };
8990
+ var isAvailable8 = (provider) => {
8991
+ return !!provider.searchFiles;
8992
+ };
8993
+ var searchFiles_default = {
8994
+ ...toolInfo8,
8995
+ handler: handler8,
8996
+ isAvailable: isAvailable8
8997
+ };
8998
+ // src/tools/writeToFile.ts
8999
+ var toolInfo9 = {
9000
+ name: "write_to_file",
9001
+ description: "Request to write content to a file at the specified path. If the file exists, it will be overwritten with the provided content. If the file doesn't exist, it will be created. This tool will automatically create any directories needed to write the file.",
9002
+ parameters: [
9003
+ {
9004
+ name: "path",
9005
+ description: "The path of the file to write to",
9006
+ required: true,
9007
+ usageValue: "File path here"
9008
+ },
9009
+ {
9010
+ name: "content",
9011
+ description: "The content to write to the file. ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified.",
9012
+ required: true,
9013
+ usageValue: "Your file content here"
8610
9014
  }
8611
- if (toolReponses.length === 0) {
8612
- return [
9015
+ ],
9016
+ examples: [
9017
+ {
9018
+ description: "Request to write content to a file",
9019
+ parameters: [
8613
9020
  {
8614
- type: "text",
8615
- text: responsePrompts.requireUseTool
9021
+ name: "path",
9022
+ value: "src/main.js"
9023
+ },
9024
+ {
9025
+ name: "content",
9026
+ value: `import React from 'react';
9027
+
9028
+ function App() {
9029
+ return (
9030
+ <div>
9031
+ <h1>Hello, World!</h1>
9032
+ </div>
9033
+ );
9034
+ }
9035
+
9036
+ export default App;
9037
+ `
8616
9038
  }
8617
- ];
8618
- }
8619
- const finalResp = toolReponses.map(({ tool, response: response2 }) => responsePrompts.toolResults(tool, response2)).join(`
8620
- `);
8621
- return [
8622
- {
8623
- type: "text",
8624
- text: finalResp
8625
- }
8626
- ];
8627
- }
8628
- async#invokeTool(name, args) {
8629
- try {
8630
- return await this.config.toolHandler(name, args);
8631
- } catch (error) {
8632
- return {
8633
- type: "Error" /* Error */,
8634
- message: responsePrompts.errorInvokeTool(name, error),
8635
- canRetry: false
8636
- };
9039
+ ]
8637
9040
  }
9041
+ ]
9042
+ };
9043
+ var handler9 = async (provider, args) => {
9044
+ if (!provider.writeFile) {
9045
+ return {
9046
+ type: "Error" /* Error */,
9047
+ message: "Not possible to write file. Abort."
9048
+ };
8638
9049
  }
8639
- get model() {
8640
- return this.ai.model;
8641
- }
8642
- }
9050
+ const path = getString(args, "path");
9051
+ const content = getString(args, "content");
9052
+ await provider.writeFile(path, content);
9053
+ return {
9054
+ type: "Reply" /* Reply */,
9055
+ message: `<write_file_path>${path}</write_file_path><status>Success</status>`
9056
+ };
9057
+ };
9058
+ var isAvailable9 = (provider) => {
9059
+ return !!provider.writeFile;
9060
+ };
9061
+ var writeToFile_default = {
9062
+ ...toolInfo9,
9063
+ handler: handler9,
9064
+ isAvailable: isAvailable9
9065
+ };
8643
9066
  // src/Agent/CoderAgent/prompts.ts
8644
9067
  var basePrompt = "You are a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.";
8645
9068
  var editingFilesPrompt = (toolNamePrefix) => `
@@ -8721,7 +9144,7 @@ RULES
8721
9144
 
8722
9145
  - You may use \`cd\` to enter any child directory within the current working directory. For example, \`cd myChildDir\`. But you may never move to a parent directory or any directory outside your current path. For example, do not use \`cd ..\`, \`cd /\`, or any absolute path.
8723
9146
  - Always work with relative path names, and never use absolute paths.
8724
- - When generating code file, add a comment on top of the file indicating this file is generated by "polka.codes".
9147
+ - When generating code or test or any file that support comments, add a comment on top of the file with a description of the file's purpose and a note that this file is generated by "polka.codes".
8725
9148
  - When generate text file such as README.md, add a footer indicating this file is generated by "polka.codes".
8726
9149
  - Before using the ${toolNamePrefix}execute_command tool, you must first think about the SYSTEM INFORMATION context provided to understand the user's environment and tailor your commands to ensure they are compatible with their system. You must also consider if the command you need to run should be executed in a specific directory outside of the current working directory, and if so prepend with \`cd\`'ing into that directory && then executing the command (as one command). For example, if you needed to run \`npm install\` in a project that's not in the current working directory, you would need to prepend with a \`cd\` i.e. pseudocode for this would be \`cd (path to project) && (command, in this case npm install)\`. However, you can only cd into child directory, but never parent directory or root directory or home directory.
8727
9150
  - When using the ${toolNamePrefix}search_files tool, craft your regex patterns carefully to balance specificity and flexibility. Based on the user's task you may use it to find code patterns, TODO comments, function definitions, or any text-based information across the project. The results include context, so analyze the surrounding code to better understand the matches. Leverage the ${toolNamePrefix}search_files tool in combination with other tools for more comprehensive analysis. For example, use it to find specific code patterns, then use ${toolNamePrefix}read_file to examine the full context of interesting matches before using ${toolNamePrefix}replace_in_file to make informed changes.
@@ -8794,9 +9217,27 @@ The following additional commands are provided by the user, and should be follow
8794
9217
 
8795
9218
  ${joined}`;
8796
9219
  };
8797
- var fullSystemPrompt = (info, tools2, toolNamePrefix, instructions, commands) => `
9220
+ var interactiveMode = (interactive) => {
9221
+ if (interactive) {
9222
+ return `
9223
+ ====
9224
+
9225
+ INTERACTIVE MODE
9226
+
9227
+ You are in interactive mode. This means you may ask user questions to gather additional information to complete the task.
9228
+ `;
9229
+ }
9230
+ return `
9231
+ ====
9232
+
9233
+ NON-INTERACTIVE MODE
9234
+
9235
+ 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.
9236
+ `;
9237
+ };
9238
+ var fullSystemPrompt = (info, tools, toolNamePrefix, instructions, commands, interactive) => `
8798
9239
  ${basePrompt}
8799
- ${toolUsePrompt(tools2, toolNamePrefix)}
9240
+ ${toolUsePrompt(tools, toolNamePrefix)}
8800
9241
  ${editingFilesPrompt(toolNamePrefix)}
8801
9242
  ${capabilities(toolNamePrefix)}
8802
9243
  ${rules(toolNamePrefix)}
@@ -8804,51 +9245,45 @@ ${objectives(toolNamePrefix)}
8804
9245
  ${systemInformation(info)}
8805
9246
  ${customInstructions(instructions)}
8806
9247
  ${customCommands(commands)}
9248
+ ${interactiveMode(interactive)}
8807
9249
  `;
8808
9250
 
8809
9251
  // src/Agent/CoderAgent/index.ts
8810
- var defaultTools = [
8811
- exports_tools.executeCommand,
8812
- exports_tools.readFile,
8813
- exports_tools.writeToFile,
8814
- exports_tools.replaceInFile,
8815
- exports_tools.listFiles,
8816
- exports_tools.attemptCompletion
8817
- ];
8818
-
8819
9252
  class CoderAgent extends AgentBase {
8820
9253
  constructor(options) {
8821
- const tools2 = options.tools || defaultTools;
9254
+ const combinedTools = [...options.additionalTools ?? [], ...Object.values(exports_allTools)];
9255
+ const tools = getAvailableTools(options.provider, combinedTools);
8822
9256
  const toolNamePrefix = "tool_";
8823
9257
  const systemPrompt = fullSystemPrompt({
8824
9258
  os: options.os
8825
- }, tools2, toolNamePrefix, options.customInstructions ?? [], options.commands ?? {});
9259
+ }, tools, toolNamePrefix, options.customInstructions ?? [], options.commands ?? {}, options.interactive);
8826
9260
  super(options.ai, {
8827
9261
  systemPrompt,
8828
- tools: tools2,
9262
+ tools,
8829
9263
  toolNamePrefix,
8830
- toolHandler: options.toolHandler,
8831
- customInstructions: options.customInstructions
9264
+ provider: options.provider,
9265
+ interactive: options.interactive
8832
9266
  }, createServiceLogger("CoderAgent"));
8833
9267
  }
8834
9268
  }
8835
9269
  export {
8836
- writeToFile,
9270
+ writeToFile_default as writeToFile,
8837
9271
  setLogger,
8838
- searchFiles,
8839
- replaceInFile,
8840
- readFile,
8841
- listFiles,
8842
- listCodeDefinitionNames,
9272
+ searchFiles_default as searchFiles,
9273
+ replaceInFile_default as replaceInFile,
9274
+ readFile_default as readFile,
9275
+ listFiles_default as listFiles,
9276
+ listCodeDefinitionNames_default as listCodeDefinitionNames,
8843
9277
  getLogger,
8844
- executeCommand,
9278
+ executeCommand_default as executeCommand,
8845
9279
  defaultModels,
8846
9280
  createServiceLogger,
8847
9281
  createService,
8848
- attemptCompletion,
8849
- askFollowupQuestion,
8850
- exports_tools as allTools,
8851
- ToolResponseType,
9282
+ attemptCompletion_default as attemptCompletion,
9283
+ askFollowupQuestion_default as askFollowupQuestion,
9284
+ exports_allTools as allTools,
9285
+ MockProvider,
9286
+ ExitReason,
8852
9287
  CoderAgent,
8853
9288
  AiServiceProvider,
8854
9289
  AgentBase