@polka-codes/core 0.4.4 → 0.4.6

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 +316 -18
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7951,17 +7951,169 @@ class OllamaService extends AiServiceBase {
7951
7951
  }
7952
7952
  }
7953
7953
 
7954
+ // src/AiService/OpenRouterService.ts
7955
+ class OpenRouterService extends AiServiceBase {
7956
+ #client;
7957
+ #apiKey;
7958
+ model;
7959
+ constructor(options) {
7960
+ super();
7961
+ if (!options.model) {
7962
+ throw new Error("OpenRouter requires a model");
7963
+ }
7964
+ if (!options.apiKey) {
7965
+ throw new Error("OpenRouter requires an API key");
7966
+ }
7967
+ this.#apiKey = options.apiKey;
7968
+ this.#client = new openai_default({
7969
+ baseURL: "https://openrouter.ai/api/v1",
7970
+ apiKey: options.apiKey,
7971
+ defaultHeaders: {
7972
+ "HTTP-Referer": "https://polka.codes",
7973
+ "X-Title": "Polka Codes"
7974
+ }
7975
+ });
7976
+ this.model = {
7977
+ id: options.model,
7978
+ info: {}
7979
+ };
7980
+ }
7981
+ async* send(systemPrompt, messages) {
7982
+ const openAiMessages = [
7983
+ { role: "system", content: systemPrompt },
7984
+ ...convertToOpenAiMessages(messages)
7985
+ ];
7986
+ switch (this.model.id) {
7987
+ case "anthropic/claude-3.5-sonnet":
7988
+ case "anthropic/claude-3.5-sonnet:beta":
7989
+ case "anthropic/claude-3.5-sonnet-20240620":
7990
+ case "anthropic/claude-3.5-sonnet-20240620:beta":
7991
+ case "anthropic/claude-3-5-haiku":
7992
+ case "anthropic/claude-3-5-haiku:beta":
7993
+ case "anthropic/claude-3-5-haiku-20241022":
7994
+ case "anthropic/claude-3-5-haiku-20241022:beta":
7995
+ case "anthropic/claude-3-haiku":
7996
+ case "anthropic/claude-3-haiku:beta":
7997
+ case "anthropic/claude-3-opus":
7998
+ case "anthropic/claude-3-opus:beta": {
7999
+ openAiMessages[0] = {
8000
+ role: "system",
8001
+ content: [
8002
+ {
8003
+ type: "text",
8004
+ text: systemPrompt,
8005
+ cache_control: { type: "ephemeral" }
8006
+ }
8007
+ ]
8008
+ };
8009
+ const lastTwoUserMessages = openAiMessages.filter((msg) => msg.role === "user").slice(-2);
8010
+ for (const msg of lastTwoUserMessages) {
8011
+ if (typeof msg.content === "string") {
8012
+ msg.content = [{ type: "text", text: msg.content }];
8013
+ }
8014
+ if (Array.isArray(msg.content)) {
8015
+ let lastTextPart = msg.content.filter((part) => part.type === "text").pop();
8016
+ if (!lastTextPart) {
8017
+ lastTextPart = { type: "text", text: "..." };
8018
+ msg.content.push(lastTextPart);
8019
+ }
8020
+ lastTextPart.cache_control = { type: "ephemeral" };
8021
+ }
8022
+ }
8023
+ break;
8024
+ }
8025
+ default:
8026
+ break;
8027
+ }
8028
+ let maxTokens;
8029
+ switch (this.model.id) {
8030
+ case "anthropic/claude-3.5-sonnet":
8031
+ case "anthropic/claude-3.5-sonnet:beta":
8032
+ case "anthropic/claude-3.5-sonnet-20240620":
8033
+ case "anthropic/claude-3.5-sonnet-20240620:beta":
8034
+ case "anthropic/claude-3-5-haiku":
8035
+ case "anthropic/claude-3-5-haiku:beta":
8036
+ case "anthropic/claude-3-5-haiku-20241022":
8037
+ case "anthropic/claude-3-5-haiku-20241022:beta":
8038
+ maxTokens = 8192;
8039
+ break;
8040
+ }
8041
+ let shouldApplyMiddleOutTransform = !this.model.info.supportsPromptCache;
8042
+ if (this.model.id === "deepseek/deepseek-chat") {
8043
+ shouldApplyMiddleOutTransform = true;
8044
+ }
8045
+ const stream = await this.#client.chat.completions.create({
8046
+ model: this.model.id,
8047
+ max_completion_tokens: maxTokens,
8048
+ messages: openAiMessages,
8049
+ temperature: 0,
8050
+ stream: true,
8051
+ transforms: shouldApplyMiddleOutTransform ? ["middle-out"] : undefined,
8052
+ include_reasoning: true
8053
+ });
8054
+ let genId;
8055
+ for await (const chunk of stream) {
8056
+ if ("error" in chunk) {
8057
+ const error = chunk.error;
8058
+ console.error(`OpenRouter API Error: ${error?.code} - ${error?.message}`);
8059
+ throw new Error(`OpenRouter API Error ${error?.code}: ${error?.message}`);
8060
+ }
8061
+ if (!genId && chunk.id) {
8062
+ genId = chunk.id;
8063
+ }
8064
+ const delta = chunk.choices[0]?.delta;
8065
+ if (delta?.reasoning) {
8066
+ yield {
8067
+ type: "reasoning",
8068
+ text: delta.reasoning
8069
+ };
8070
+ }
8071
+ if (delta?.content) {
8072
+ yield {
8073
+ type: "text",
8074
+ text: delta.content
8075
+ };
8076
+ }
8077
+ }
8078
+ await new Promise((resolve) => setTimeout(resolve, 1000));
8079
+ const controller = new AbortController;
8080
+ const timeout = setTimeout(() => controller.abort(), 5000);
8081
+ try {
8082
+ const response = await fetch(`https://openrouter.ai/api/v1/generation?id=${genId}`, {
8083
+ headers: {
8084
+ Authorization: `Bearer ${this.#apiKey}`
8085
+ },
8086
+ signal: controller.signal
8087
+ });
8088
+ const responseBody = await response.json();
8089
+ const generation = responseBody.data;
8090
+ yield {
8091
+ type: "usage",
8092
+ inputTokens: generation?.native_tokens_prompt || 0,
8093
+ outputTokens: generation?.native_tokens_completion || 0,
8094
+ totalCost: generation?.total_cost || 0
8095
+ };
8096
+ } catch (error) {
8097
+ console.error("Error fetching OpenRouter generation details:", error);
8098
+ } finally {
8099
+ clearTimeout(timeout);
8100
+ }
8101
+ }
8102
+ }
8103
+
7954
8104
  // src/AiService/index.ts
7955
8105
  var AiServiceProvider;
7956
8106
  ((AiServiceProvider2) => {
7957
8107
  AiServiceProvider2["Anthropic"] = "anthropic";
7958
8108
  AiServiceProvider2["Ollama"] = "ollama";
7959
8109
  AiServiceProvider2["DeepSeek"] = "deepseek";
8110
+ AiServiceProvider2["OpenRouter"] = "openrouter";
7960
8111
  })(AiServiceProvider ||= {});
7961
8112
  var defaultModels = {
7962
8113
  ["anthropic" /* Anthropic */]: "claude-3-5-sonnet-20241022",
7963
8114
  ["ollama" /* Ollama */]: "maryasov/qwen2.5-coder-cline:7b",
7964
- ["deepseek" /* DeepSeek */]: "deepseek-chat"
8115
+ ["deepseek" /* DeepSeek */]: "deepseek-chat",
8116
+ ["openrouter" /* OpenRouter */]: "anthropic/claude-3.5-sonnet"
7965
8117
  };
7966
8118
  var createService = (provider, options) => {
7967
8119
  switch (provider) {
@@ -7971,6 +8123,8 @@ var createService = (provider, options) => {
7971
8123
  return new OllamaService(options);
7972
8124
  case "deepseek" /* DeepSeek */:
7973
8125
  return new DeepSeekService(options);
8126
+ case "openrouter" /* OpenRouter */:
8127
+ return new OpenRouterService(options);
7974
8128
  }
7975
8129
  };
7976
8130
  // src/tool.ts
@@ -8156,12 +8310,8 @@ var capabilities = (toolNamePrefix) => `
8156
8310
 
8157
8311
  CAPABILITIES
8158
8312
 
8159
- - 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, such as writing code, making edits or improvements to existing files, understanding the current state of a project, performing system operations, and much more.
8160
- - When the user initially gives you a task, a recursive list of all filepaths in the current working directory will be included in environment_details. 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.
8161
- - You can use ${toolNamePrefix}search_files to perform regex searches across files in a specified directory, outputting context-rich results that include surrounding lines. This is particularly useful for understanding code patterns, finding specific implementations, or identifying areas that need refactoring.
8162
- - You can use the ${toolNamePrefix}list_code_definition_names tool to get an overview of source code definitions for all files at the top level of a specified directory. This can be particularly useful when you need to understand the broader context and relationships between certain parts of the code. You may need to call this tool multiple times to understand various parts of the codebase related to the task.
8163
- \t- For example, when asked to make edits or improvements you might analyze the file structure in the initial environment_details to get an overview of the project, then use ${toolNamePrefix}list_code_definition_names to get further insight using source code definitions for files located in relevant directories, then ${toolNamePrefix}read_file to examine the contents of relevant files, analyze the code and suggest improvements or make necessary edits, then use the ${toolNamePrefix}replace_in_file tool to implement changes. If you refactored code that could affect other parts of the codebase, you could use ${toolNamePrefix}search_files to ensure you update other files as needed.
8164
- - You can use the ${toolNamePrefix}execute_command tool to run commands on the user's computer whenever you feel it can help accomplish the user's task. When you need to execute a CLI command, you must provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, since they are more flexible and easier to run. Interactive and long-running commands are allowed, since the commands are run in the user's VSCode terminal. The user may keep commands running in the background and you will be kept updated on their status along the way. Each command you execute is run in a new terminal instance.`;
8313
+ - 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.
8314
+ - 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.`;
8165
8315
  var systemInformation = (info) => `
8166
8316
  ====
8167
8317
 
@@ -8226,7 +8376,7 @@ ${joined}`;
8226
8376
  };
8227
8377
  var responsePrompts = {
8228
8378
  errorInvokeTool: (tool, error) => `An error occurred while invoking the tool "${tool}": ${error}`,
8229
- requireUseTool: "Error: You must use a tool before proceeding",
8379
+ requireUseTool: "Error: You must use a tool before proceeding. Making sure the tool is invoked using xml tags.",
8230
8380
  toolResults: (tool, result) => `<tool_response>
8231
8381
  <tool_name>${tool}</tool_name>
8232
8382
  <tool_result>
@@ -8238,6 +8388,7 @@ ${result}
8238
8388
  // src/Agent/AgentBase.ts
8239
8389
  var TaskEventKind;
8240
8390
  ((TaskEventKind2) => {
8391
+ TaskEventKind2["StartTask"] = "StartTask";
8241
8392
  TaskEventKind2["StartRequest"] = "StartRequest";
8242
8393
  TaskEventKind2["EndRequest"] = "EndRequest";
8243
8394
  TaskEventKind2["Usage"] = "Usage";
@@ -8278,6 +8429,9 @@ ${agents}`;
8278
8429
  callback = () => {
8279
8430
  }
8280
8431
  }) {
8432
+ if (maxIterations < 1) {
8433
+ throw new Error("Max iterations must be greater than 0");
8434
+ }
8281
8435
  const taskInfo = {
8282
8436
  options: {
8283
8437
  maxIterations
@@ -8294,6 +8448,7 @@ ${agents}`;
8294
8448
  text += `
8295
8449
  <context>${context}</context>`;
8296
8450
  }
8451
+ callback({ kind: "StartTask" /* StartTask */, info: taskInfo, systemPrompt: this.config.systemPrompt });
8297
8452
  return await this.#processLoop(text, taskInfo, callback);
8298
8453
  }
8299
8454
  async#processLoop(userMessage, taskInfo, callback) {
@@ -8439,6 +8594,12 @@ class MockProvider {
8439
8594
  async writeFile(path, content) {
8440
8595
  return;
8441
8596
  }
8597
+ async removeFile(path) {
8598
+ return;
8599
+ }
8600
+ async renameFile(sourcePath, targetPath) {
8601
+ return;
8602
+ }
8442
8603
  async listFiles(path, recursive, maxCount) {
8443
8604
  return [["mock-file.txt"], false];
8444
8605
  }
@@ -8464,6 +8625,8 @@ __export(exports_allTools, {
8464
8625
  writeToFile: () => writeToFile_default,
8465
8626
  searchFiles: () => searchFiles_default,
8466
8627
  replaceInFile: () => replaceInFile_default,
8628
+ renameFile: () => renameFile_default,
8629
+ removeFile: () => removeFile_default,
8467
8630
  readFile: () => readFile_default,
8468
8631
  listFiles: () => listFiles_default,
8469
8632
  listCodeDefinitionNames: () => listCodeDefinitionNames_default,
@@ -8544,7 +8707,10 @@ var getStringArray = (args, name, defaultValue) => {
8544
8707
  }
8545
8708
  return defaultValue;
8546
8709
  }
8547
- return ret.split(",");
8710
+ if (ret === "") {
8711
+ return [];
8712
+ }
8713
+ return ret.split(",").map((s) => s.trim());
8548
8714
  };
8549
8715
  var getBoolean = (args, name, defaultValue) => {
8550
8716
  const ret = args[name];
@@ -9176,7 +9342,7 @@ var handler9 = async (provider, args) => {
9176
9342
  await provider.writeFile(path, content);
9177
9343
  return {
9178
9344
  type: "Reply" /* Reply */,
9179
- message: `<write_file_path>${path}</write_file_path><status>Success</status>`
9345
+ message: `<write_to_file_path>${path}</write_to_file_path><status>Success</status>`
9180
9346
  };
9181
9347
  };
9182
9348
  var isAvailable9 = (provider) => {
@@ -9213,7 +9379,7 @@ var toolInfo10 = {
9213
9379
  {
9214
9380
  name: "files",
9215
9381
  description: "The files relevant to the task",
9216
- required: true,
9382
+ required: false,
9217
9383
  usageValue: "Relevant files"
9218
9384
  }
9219
9385
  ],
@@ -9262,6 +9428,109 @@ var handOver_default = {
9262
9428
  handler: handler10,
9263
9429
  isAvailable: isAvailable10
9264
9430
  };
9431
+ // src/tools/removeFile.ts
9432
+ var toolInfo11 = {
9433
+ name: "remove_file",
9434
+ description: "Request to remove a file at the specified path.",
9435
+ parameters: [
9436
+ {
9437
+ name: "path",
9438
+ description: "The path of the file to remove",
9439
+ required: true,
9440
+ usageValue: "File path here"
9441
+ }
9442
+ ],
9443
+ examples: [
9444
+ {
9445
+ description: "Request to remove a file",
9446
+ parameters: [
9447
+ {
9448
+ name: "path",
9449
+ value: "src/main.js"
9450
+ }
9451
+ ]
9452
+ }
9453
+ ]
9454
+ };
9455
+ var handler11 = async (provider, args) => {
9456
+ if (!provider.removeFile) {
9457
+ return {
9458
+ type: "Error" /* Error */,
9459
+ message: "Not possible to remove file. Abort."
9460
+ };
9461
+ }
9462
+ const path = getString(args, "path");
9463
+ await provider.removeFile(path);
9464
+ return {
9465
+ type: "Reply" /* Reply */,
9466
+ message: `<remove_file_path>${path}</remove_file_path><status>Success</status>`
9467
+ };
9468
+ };
9469
+ var isAvailable11 = (provider) => {
9470
+ return !!provider.removeFile;
9471
+ };
9472
+ var removeFile_default = {
9473
+ ...toolInfo11,
9474
+ handler: handler11,
9475
+ isAvailable: isAvailable11
9476
+ };
9477
+ // src/tools/renameFile.ts
9478
+ var toolInfo12 = {
9479
+ name: "rename_file",
9480
+ description: "Request to rename a file from source path to target path.",
9481
+ parameters: [
9482
+ {
9483
+ name: "sourcePath",
9484
+ description: "The current path of the file",
9485
+ required: true,
9486
+ usageValue: "Source file path here"
9487
+ },
9488
+ {
9489
+ name: "targetPath",
9490
+ description: "The new path for the file",
9491
+ required: true,
9492
+ usageValue: "Target file path here"
9493
+ }
9494
+ ],
9495
+ examples: [
9496
+ {
9497
+ description: "Request to rename a file",
9498
+ parameters: [
9499
+ {
9500
+ name: "sourcePath",
9501
+ value: "src/old-name.js"
9502
+ },
9503
+ {
9504
+ name: "targetPath",
9505
+ value: "src/new-name.js"
9506
+ }
9507
+ ]
9508
+ }
9509
+ ]
9510
+ };
9511
+ var handler12 = async (provider, args) => {
9512
+ if (!provider.renameFile) {
9513
+ return {
9514
+ type: "Error" /* Error */,
9515
+ message: "Not possible to rename file. Abort."
9516
+ };
9517
+ }
9518
+ const sourcePath = getString(args, "sourcePath");
9519
+ const targetPath = getString(args, "targetPath");
9520
+ await provider.renameFile(sourcePath, targetPath);
9521
+ return {
9522
+ type: "Reply" /* Reply */,
9523
+ message: `<rename_file_path>${targetPath}</rename_file_path><status>Success</status>`
9524
+ };
9525
+ };
9526
+ var isAvailable12 = (provider) => {
9527
+ return !!provider.renameFile;
9528
+ };
9529
+ var renameFile_default = {
9530
+ ...toolInfo12,
9531
+ handler: handler12,
9532
+ isAvailable: isAvailable12
9533
+ };
9265
9534
  // src/Agent/CoderAgent/prompts.ts
9266
9535
  var basePrompt = "You are a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.";
9267
9536
  var editingFilesPrompt = (toolNamePrefix) => `
@@ -9506,19 +9775,24 @@ class MultiAgent {
9506
9775
  get model() {
9507
9776
  return this.#activeAgent?.model;
9508
9777
  }
9509
- async#startTask(agentName, task, context, callback) {
9778
+ async#startTask(agentName, task, context, maxIterations, callback) {
9510
9779
  this.#activeAgent = await this.#config.createAgent(agentName);
9511
9780
  const [exitReason, info] = await this.#activeAgent.startTask({
9512
9781
  task,
9513
9782
  context,
9783
+ maxIterations,
9514
9784
  callback
9515
9785
  });
9516
9786
  if (typeof exitReason === "string") {
9517
9787
  return [exitReason, info];
9518
9788
  }
9519
9789
  if (exitReason.type === "HandOver") {
9790
+ const remainIteration = maxIterations - Math.floor(info.messages.length / 2);
9791
+ if (remainIteration < 1) {
9792
+ return ["MaxIterations", info];
9793
+ }
9520
9794
  const context2 = await this.#config.getContext(agentName, exitReason.context, exitReason.files);
9521
- const [exitReason2, info2] = await this.#startTask(exitReason.agentName, exitReason.task, context2, callback);
9795
+ const [exitReason2, info2] = await this.#startTask(exitReason.agentName, exitReason.task, context2, remainIteration, callback);
9522
9796
  info2.inputTokens += info.inputTokens;
9523
9797
  info2.outputTokens += info.outputTokens;
9524
9798
  info2.cacheWriteTokens += info.cacheWriteTokens;
@@ -9532,7 +9806,8 @@ class MultiAgent {
9532
9806
  if (this.#activeAgent) {
9533
9807
  throw new Error("An active agent already exists");
9534
9808
  }
9535
- return this.#startTask(options.agentName, options.task, options.context, options.callback);
9809
+ const maxIterations = options.maxIterations ?? 50;
9810
+ return this.#startTask(options.agentName, options.task, options.context, maxIterations, options.callback);
9536
9811
  }
9537
9812
  async continueTask(userMessage, taskInfo, callback = () => {
9538
9813
  }) {
@@ -9604,6 +9879,8 @@ ${output}`);
9604
9879
 
9605
9880
  // src/AiTool/generateGithubPullRequestDetails.ts
9606
9881
  var prompt2 = `
9882
+ # Generate Github Pull Request Details
9883
+
9607
9884
  You are given:
9608
9885
  - A branch name in <tool_input_branch_name>.
9609
9886
  - An optional context message in <tool_input_context> (which may or may not be present).
@@ -9616,10 +9893,30 @@ Your task:
9616
9893
  3. Produce a single GitHub Pull Request title.
9617
9894
  4. Produce a Pull Request description that explains the changes.
9618
9895
 
9896
+ Use the following template for the Pull Request description:
9897
+
9898
+ ---
9899
+ **Context (if provided)**:
9900
+ - Acknowledge any guiding concerns or instructions.
9901
+
9902
+ **Summary of Changes**:
9903
+ - Provide a concise list or overview of what changed.
9904
+
9905
+ **Highlights of Changed Code**:
9906
+ - Mention only the specific sections or functionalities updated, without showing full surrounding context.
9907
+
9908
+ **Additional Information (if needed)**:
9909
+ - Testing steps (if applicable).
9910
+ - Any notes or caveats.
9911
+
9912
+ ---
9913
+
9619
9914
  Output format:
9620
9915
  <tool_output>
9621
9916
  <tool_output_pr_title>YOUR PR TITLE HERE</tool_output_pr_title>
9622
- <tool_output_pr_description>YOUR PR DESCRIPTION HERE</tool_output_pr_description>
9917
+ <tool_output_pr_description>
9918
+ YOUR PR DESCRIPTION HERE
9919
+ </tool_output_pr_description>
9623
9920
  </tool_output>
9624
9921
 
9625
9922
  Below is an **example** of the input and output:
@@ -9641,7 +9938,7 @@ diff --git a/order_service.py b/order_service.py
9641
9938
  - if is_valid_order(order):
9642
9939
  - process_order(order)
9643
9940
  + validate_and_process(order)
9644
- </tool_input_commit_diff>
9941
+ </tool_input_commit_diff>
9645
9942
  </tool_input>
9646
9943
 
9647
9944
  Example Output:
@@ -9655,8 +9952,7 @@ to use the new validate_and_process method for improved maintainability.
9655
9952
 
9656
9953
  ---
9657
9954
 
9658
- Use the above format whenever you receive \`<tool_input>\` that may include a branch name, an optional context, aggregated commit messages in a single tag, and a combined diff in a single tag. Provide your final output strictly in \`<tool_output>\` with \`<tool_output_pr_title>\` and \`<tool_output_pr_description>\`.
9659
- Only highlight the changed code and avoid including the context around the changes in the description.
9955
+ Use the above format whenever you receive <tool_input> that may include a branch name, an optional context, aggregated commit messages in a single tag, and a combined diff in a single tag. Provide your final output strictly in <tool_output> with <tool_output_pr_title> and <tool_output_pr_description>. Only highlight the changed code and avoid including the context around the changes in the description.
9660
9956
  `;
9661
9957
  var generateGithubPullRequestDetails_default = {
9662
9958
  name: "generateGithubPullRequestDetails",
@@ -9712,6 +10008,8 @@ export {
9712
10008
  writeToFile_default as writeToFile,
9713
10009
  searchFiles_default as searchFiles,
9714
10010
  replaceInFile_default as replaceInFile,
10011
+ renameFile_default as renameFile,
10012
+ removeFile_default as removeFile,
9715
10013
  readFile_default as readFile,
9716
10014
  openAiModelInfoSaneDefaults,
9717
10015
  makeTool,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polka-codes/core",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "license": "AGPL-3.0",
5
5
  "type": "module",
6
6
  "exports": {