@polka-codes/core 0.8.11 → 0.8.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7,8 +7,10 @@ var __export = (target, all) => {
7
7
  // src/AiService/AiServiceBase.ts
8
8
  var AiServiceBase = class {
9
9
  usageMeter;
10
- constructor(usageMeter) {
11
- this.usageMeter = usageMeter;
10
+ options;
11
+ constructor(options) {
12
+ this.options = options;
13
+ this.usageMeter = options.usageMeter;
12
14
  }
13
15
  async *send(systemPrompt, messages) {
14
16
  this.usageMeter.checkLimit();
@@ -169,7 +171,7 @@ var AnthropicService = class extends AiServiceBase {
169
171
  #client;
170
172
  model;
171
173
  constructor(options) {
172
- super(options.usageMeter);
174
+ super(options);
173
175
  this.#options = options;
174
176
  this.#client = new Anthropic({
175
177
  apiKey: options.apiKey,
@@ -448,7 +450,7 @@ var DeepSeekService = class extends AiServiceBase {
448
450
  #client;
449
451
  model;
450
452
  constructor(options) {
451
- super(options.usageMeter);
453
+ super(options);
452
454
  this.#client = new OpenAI({
453
455
  baseURL: "https://api.deepseek.com/v1",
454
456
  apiKey: options.apiKey
@@ -511,7 +513,7 @@ var OllamaService = class extends AiServiceBase {
511
513
  #client;
512
514
  model;
513
515
  constructor(options) {
514
- super(options.usageMeter);
516
+ super(options);
515
517
  this.#client = new OpenAI2({
516
518
  baseURL: `${options.baseUrl || "http://localhost:11434"}/v1`,
517
519
  apiKey: "ollama"
@@ -554,7 +556,7 @@ var OpenRouterService = class extends AiServiceBase {
554
556
  #modelProviderInfo;
555
557
  model;
556
558
  constructor(options) {
557
- super(options.usageMeter);
559
+ super(options);
558
560
  if (!options.model) {
559
561
  throw new Error("OpenRouter requires a model");
560
562
  }
@@ -893,13 +895,13 @@ __export(allTools_exports, {
893
895
  askFollowupQuestion: () => askFollowupQuestion_default,
894
896
  attemptCompletion: () => attemptCompletion_default,
895
897
  delegate: () => delegate_default,
898
+ editFile: () => editFile_default,
896
899
  executeCommand: () => executeCommand_default,
897
900
  handOver: () => handOver_default,
898
901
  listFiles: () => listFiles_default,
899
902
  readFile: () => readFile_default,
900
903
  removeFile: () => removeFile_default,
901
904
  renameFile: () => renameFile_default,
902
- replaceInFile: () => replaceInFile_default,
903
905
  searchFiles: () => searchFiles_default,
904
906
  updateKnowledge: () => updateKnowledge_default,
905
907
  writeToFile: () => writeToFile_default
@@ -925,61 +927,85 @@ var ToolResponseType = /* @__PURE__ */ ((ToolResponseType2) => {
925
927
  return ToolResponseType2;
926
928
  })(ToolResponseType || {});
927
929
 
928
- // src/tools/utils/replaceInFile.ts
929
- var replaceInFile = async (fileContent, diff) => {
930
- const blockPattern = /<<<<<+ SEARCH\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
931
- const blocks = [];
932
- for (let match = blockPattern.exec(diff); match !== null; match = blockPattern.exec(diff)) {
933
- blocks.push({ search: match[1], replace: match[2] });
930
+ // src/tools/utils/editFile.ts
931
+ var START_OF_FILE = "<<<START_OF_FILE>>>";
932
+ var END_OF_FILE = "<<<END_OF_FILE>>>";
933
+ var editFile = async (fileContent, operations) => {
934
+ if (!operations || operations.length === 0) {
935
+ throw new Error("At least one edit operation is required");
934
936
  }
935
- if (blocks.length === 0) {
936
- throw new Error("No valid diff blocks found.");
937
+ const originalLines = fileContent.split("\n");
938
+ let updatedContent = fileContent;
939
+ for (const operation of operations) {
940
+ updatedContent = await applyEditOperation(updatedContent, operation, originalLines);
937
941
  }
938
- const findAndReplace = (content, search, replace) => {
939
- let index = content.indexOf(search);
940
- if (index !== -1) {
941
- return content.slice(0, index) + replace + content.slice(index + search.length);
942
+ return updatedContent;
943
+ };
944
+ async function applyEditOperation(fileContent, operation, originalLines) {
945
+ const { before_text, after_text, new_text, before_text_line_start, after_text_line_start } = operation;
946
+ if (before_text === START_OF_FILE && after_text === END_OF_FILE) {
947
+ return new_text;
948
+ }
949
+ if (before_text === START_OF_FILE) {
950
+ if (!after_text) {
951
+ return new_text + fileContent;
942
952
  }
943
- const trimmedSearch = search.trim();
944
- const trimmedContent = content.trim();
945
- const offset = content.indexOf(trimmedContent);
946
- index = trimmedContent.indexOf(trimmedSearch);
947
- if (index !== -1) {
948
- const absoluteIndex = offset + index;
949
- return content.slice(0, absoluteIndex) + replace + content.slice(absoluteIndex + trimmedSearch.length);
953
+ const afterIndex = findTextWithHint(fileContent, after_text, after_text_line_start, originalLines);
954
+ return new_text + fileContent.slice(afterIndex);
955
+ }
956
+ if (after_text === END_OF_FILE) {
957
+ if (!before_text) {
958
+ return fileContent + new_text;
950
959
  }
951
- const normalizedSearch = trimmedSearch.replace(/\s+/g, " ");
952
- const normalizedContent = trimmedContent.replace(/\s+/g, " ");
953
- index = normalizedContent.indexOf(normalizedSearch);
954
- if (index !== -1) {
955
- let runningIndex = 0;
956
- let actualPos = offset;
957
- for (const segment of trimmedSearch.replace(/\s+/g, " ").split(" ")) {
958
- const segIndex = content.indexOf(segment, actualPos);
959
- if (segIndex === -1) {
960
- break;
961
- }
962
- if (runningIndex === 0) {
963
- actualPos = segIndex;
964
- } else {
965
- actualPos = segIndex + segment.length;
966
- }
967
- runningIndex++;
960
+ const beforeIndex = findTextWithHint(fileContent, before_text, before_text_line_start, originalLines);
961
+ const beforeEndIndex = beforeIndex + before_text.length;
962
+ return fileContent.slice(0, beforeEndIndex) + new_text;
963
+ }
964
+ if (before_text && after_text) {
965
+ const beforeIndex = findTextWithHint(fileContent, before_text, before_text_line_start, originalLines);
966
+ const beforeEndIndex = beforeIndex + before_text.length;
967
+ const afterIndex = findTextWithHint(fileContent, after_text, after_text_line_start, originalLines, beforeEndIndex);
968
+ return fileContent.slice(0, beforeEndIndex) + new_text + fileContent.slice(afterIndex);
969
+ }
970
+ if (before_text) {
971
+ const beforeIndex = findTextWithHint(fileContent, before_text, before_text_line_start, originalLines);
972
+ const beforeEndIndex = beforeIndex + before_text.length;
973
+ return fileContent.slice(0, beforeEndIndex) + new_text + fileContent.slice(beforeEndIndex);
974
+ }
975
+ if (after_text) {
976
+ const afterIndex = findTextWithHint(fileContent, after_text, after_text_line_start, originalLines);
977
+ return fileContent.slice(0, afterIndex) + new_text + fileContent.slice(afterIndex);
978
+ }
979
+ throw new Error("Either before_text or after_text must be specified");
980
+ }
981
+ function findTextWithHint(content, searchText, lineHint, originalLines, startIndex = 0) {
982
+ if (lineHint && lineHint > 0 && lineHint <= originalLines.length) {
983
+ const hintIndex = getLineStartIndex(originalLines, lineHint - 1);
984
+ const searchRadius = 5;
985
+ const windowStart = Math.max(0, hintIndex - searchRadius * 50);
986
+ const windowEnd = Math.min(content.length, hintIndex + searchRadius * 50);
987
+ const windowContent = content.slice(windowStart, windowEnd);
988
+ const relativeIndex = windowContent.indexOf(searchText);
989
+ if (relativeIndex !== -1) {
990
+ const absoluteIndex = windowStart + relativeIndex;
991
+ if (absoluteIndex >= startIndex) {
992
+ return absoluteIndex;
968
993
  }
969
- const strippedSearch = trimmedSearch.replace(/\s+/g, "");
970
- const endPos = actualPos;
971
- const startPos = endPos - strippedSearch.length;
972
- return content.slice(0, startPos) + replace + content.slice(endPos);
973
994
  }
974
- throw new Error(`Could not find the following text in file:
975
- ${search}`);
976
- };
977
- let updatedFile = fileContent;
978
- for (const { search, replace } of blocks) {
979
- updatedFile = findAndReplace(updatedFile, search, replace);
980
995
  }
981
- return updatedFile;
982
- };
996
+ const index = content.indexOf(searchText, startIndex);
997
+ if (index === -1) {
998
+ throw new Error(`Could not find text: ${searchText}`);
999
+ }
1000
+ return index;
1001
+ }
1002
+ function getLineStartIndex(lines, lineIndex) {
1003
+ let index = 0;
1004
+ for (let i = 0; i < lineIndex && i < lines.length; i++) {
1005
+ index += lines[i].length + 1;
1006
+ }
1007
+ return index;
1008
+ }
983
1009
 
984
1010
  // src/tools/utils/getArg.ts
985
1011
  var getString = (args, name, defaultValue) => {
@@ -1073,6 +1099,62 @@ var getArray = (args, name, defaultValue) => {
1073
1099
  return [ret];
1074
1100
  };
1075
1101
 
1102
+ // src/tools/utils/replaceInFile.ts
1103
+ var replaceInFile = async (fileContent, diff) => {
1104
+ const blockPattern = /<<<<<+ SEARCH\s*\r?\n([\s\S]*?)\r?\n=======[ \t]*\r?\n([\s\S]*?)\r?\n?>>>>>+ REPLACE/g;
1105
+ const blocks = [];
1106
+ for (let match = blockPattern.exec(diff); match !== null; match = blockPattern.exec(diff)) {
1107
+ blocks.push({ search: match[1], replace: match[2] });
1108
+ }
1109
+ if (blocks.length === 0) {
1110
+ throw new Error("No valid diff blocks found.");
1111
+ }
1112
+ const findAndReplace = (content, search, replace) => {
1113
+ let index = content.indexOf(search);
1114
+ if (index !== -1) {
1115
+ return content.slice(0, index) + replace + content.slice(index + search.length);
1116
+ }
1117
+ const trimmedSearch = search.trim();
1118
+ const trimmedContent = content.trim();
1119
+ const offset = content.indexOf(trimmedContent);
1120
+ index = trimmedContent.indexOf(trimmedSearch);
1121
+ if (index !== -1) {
1122
+ const absoluteIndex = offset + index;
1123
+ return content.slice(0, absoluteIndex) + replace + content.slice(absoluteIndex + trimmedSearch.length);
1124
+ }
1125
+ const normalizedSearch = trimmedSearch.replace(/\s+/g, " ");
1126
+ const normalizedContent = trimmedContent.replace(/\s+/g, " ");
1127
+ index = normalizedContent.indexOf(normalizedSearch);
1128
+ if (index !== -1) {
1129
+ let runningIndex = 0;
1130
+ let actualPos = offset;
1131
+ for (const segment of trimmedSearch.replace(/\s+/g, " ").split(" ")) {
1132
+ const segIndex = content.indexOf(segment, actualPos);
1133
+ if (segIndex === -1) {
1134
+ break;
1135
+ }
1136
+ if (runningIndex === 0) {
1137
+ actualPos = segIndex;
1138
+ } else {
1139
+ actualPos = segIndex + segment.length;
1140
+ }
1141
+ runningIndex++;
1142
+ }
1143
+ const strippedSearch = trimmedSearch.replace(/\s+/g, "");
1144
+ const endPos = actualPos;
1145
+ const startPos = endPos - strippedSearch.length;
1146
+ return content.slice(0, startPos) + replace + content.slice(endPos);
1147
+ }
1148
+ throw new Error(`Could not find the following text in file:
1149
+ ${search}`);
1150
+ };
1151
+ let updatedFile = fileContent;
1152
+ for (const { search, replace } of blocks) {
1153
+ updatedFile = findAndReplace(updatedFile, search, replace);
1154
+ }
1155
+ return updatedFile;
1156
+ };
1157
+
1076
1158
  // src/tools/askFollowupQuestion.ts
1077
1159
  var toolInfo = {
1078
1160
  name: "ask_followup_question",
@@ -1523,126 +1605,8 @@ var readFile_default = {
1523
1605
  isAvailable: isAvailable6
1524
1606
  };
1525
1607
 
1526
- // src/tools/replaceInFile.ts
1527
- var toolInfo7 = {
1528
- name: "replace_in_file",
1529
- 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.",
1530
- parameters: [
1531
- {
1532
- name: "path",
1533
- description: "The path of the file to modify",
1534
- required: true,
1535
- usageValue: "File path here"
1536
- },
1537
- {
1538
- name: "diff",
1539
- description: `One or more SEARCH/REPLACE blocks following this exact format:
1540
- \`\`\`
1541
- <<<<<<< SEARCH
1542
- [exact content to find]
1543
- =======
1544
- [new content to replace with]
1545
- >>>>>>> REPLACE
1546
- \`\`\`
1547
- Critical rules:
1548
- 1. SEARCH content must match the associated file section to find EXACTLY:
1549
- * Match character-for-character including whitespace, indentation, line endings
1550
- * Include all comments, docstrings, etc.
1551
- 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.
1552
- * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.
1553
- * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.
1554
- * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.
1555
- 3. Keep SEARCH/REPLACE blocks concise:
1556
- * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.
1557
- * Include just the changing lines, and a few surrounding lines if needed for uniqueness.
1558
- * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.
1559
- * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.
1560
- 4. Special operations:
1561
- * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
1562
- * To delete code: Use empty REPLACE section`,
1563
- required: true,
1564
- usageValue: "Search and replace blocks here"
1565
- }
1566
- ],
1567
- examples: [
1568
- {
1569
- description: "Request to replace sections of content in a file",
1570
- parameters: [
1571
- {
1572
- name: "path",
1573
- value: "src/main.js"
1574
- },
1575
- {
1576
- name: "diff",
1577
- value: `
1578
- <<<<<<< SEARCH
1579
- import React from 'react';
1580
- =======
1581
- import React, { useState } from 'react';
1582
- >>>>>>> REPLACE
1583
-
1584
- <<<<<<< SEARCH
1585
- function handleSubmit() {
1586
- saveData();
1587
- setLoading(false);
1588
- }
1589
-
1590
- =======
1591
- >>>>>>> REPLACE
1592
-
1593
- <<<<<<< SEARCH
1594
- return (
1595
- <div>
1596
- =======
1597
- function handleSubmit() {
1598
- saveData();
1599
- setLoading(false);
1600
- }
1601
-
1602
- return (
1603
- <div>
1604
- >>>>>>> REPLACE
1605
- `
1606
- }
1607
- ]
1608
- }
1609
- ],
1610
- permissionLevel: 2 /* Write */
1611
- };
1612
- var handler7 = async (provider, args) => {
1613
- if (!provider.readFile || !provider.writeFile) {
1614
- return {
1615
- type: "Error" /* Error */,
1616
- message: "Not possible to replace in file. Abort."
1617
- };
1618
- }
1619
- const path = getString(args, "path");
1620
- const diff = getString(args, "diff");
1621
- const fileContent = await provider.readFile(path);
1622
- if (fileContent == null) {
1623
- return {
1624
- type: "Error" /* Error */,
1625
- message: `<error><replace_in_file_path>${path}</replace_in_file_path><error_message>File not found</error_message></error>`
1626
- };
1627
- }
1628
- const result = await replaceInFile(fileContent, diff);
1629
- await provider.writeFile(path, result);
1630
- return {
1631
- type: "Reply" /* Reply */,
1632
- message: `<replace_in_file_path>${path}</replace_in_file_path>`
1633
- };
1634
- };
1635
- var isAvailable7 = (provider) => {
1636
- return !!provider.readFile && !!provider.writeFile;
1637
- };
1638
- var replaceInFile_default = {
1639
- ...toolInfo7,
1640
- handler: handler7,
1641
- isAvailable: isAvailable7
1642
- };
1643
-
1644
1608
  // src/tools/searchFiles.ts
1645
- var toolInfo8 = {
1609
+ var toolInfo7 = {
1646
1610
  name: "search_files",
1647
1611
  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.",
1648
1612
  parameters: [
@@ -1686,7 +1650,7 @@ var toolInfo8 = {
1686
1650
  ],
1687
1651
  permissionLevel: 1 /* Read */
1688
1652
  };
1689
- var handler8 = async (provider, args) => {
1653
+ var handler7 = async (provider, args) => {
1690
1654
  if (!provider.searchFiles) {
1691
1655
  return {
1692
1656
  type: "Error" /* Error */,
@@ -1708,19 +1672,19 @@ ${files.join("\n")}
1708
1672
  `
1709
1673
  };
1710
1674
  };
1711
- var isAvailable8 = (provider) => {
1675
+ var isAvailable7 = (provider) => {
1712
1676
  return !!provider.searchFiles;
1713
1677
  };
1714
1678
  var searchFiles_default = {
1715
- ...toolInfo8,
1716
- handler: handler8,
1717
- isAvailable: isAvailable8
1679
+ ...toolInfo7,
1680
+ handler: handler7,
1681
+ isAvailable: isAvailable7
1718
1682
  };
1719
1683
 
1720
1684
  // src/tools/updateKnowledge.ts
1721
1685
  import { join } from "node:path";
1722
1686
  import YAML from "yaml";
1723
- var toolInfo9 = {
1687
+ var toolInfo8 = {
1724
1688
  name: "update_knowledge",
1725
1689
  description: "Update knowledge in a knowledge.ai.yml file with smart merging capabilities. This tool lets you add, update, or remove information using path-based updates and special directives.",
1726
1690
  parameters: [
@@ -1894,7 +1858,7 @@ function deepMerge(target, source) {
1894
1858
  }
1895
1859
  return output;
1896
1860
  }
1897
- var handler9 = async (provider, args) => {
1861
+ var handler8 = async (provider, args) => {
1898
1862
  if (!provider.readFile || !provider.writeFile) {
1899
1863
  return {
1900
1864
  type: "Error" /* Error */,
@@ -1966,17 +1930,17 @@ var handler9 = async (provider, args) => {
1966
1930
  };
1967
1931
  }
1968
1932
  };
1969
- var isAvailable9 = (provider) => {
1933
+ var isAvailable8 = (provider) => {
1970
1934
  return !!provider.readFile && !!provider.writeFile;
1971
1935
  };
1972
1936
  var updateKnowledge_default = {
1973
- ...toolInfo9,
1974
- handler: handler9,
1975
- isAvailable: isAvailable9
1937
+ ...toolInfo8,
1938
+ handler: handler8,
1939
+ isAvailable: isAvailable8
1976
1940
  };
1977
1941
 
1978
1942
  // src/tools/writeToFile.ts
1979
- var toolInfo10 = {
1943
+ var toolInfo9 = {
1980
1944
  name: "write_to_file",
1981
1945
  description: "Request to write content to a file at the specified path. If the file exists, it will be overwritten with the provided content. If the file doesn't exist, it will be created. This tool will automatically create any directories needed to write the file. Ensure that the output content does not include incorrect escaped character patterns such as `&lt;` and `&gt;`.",
1982
1946
  parameters: [
@@ -2021,7 +1985,7 @@ export default App;
2021
1985
  ],
2022
1986
  permissionLevel: 2 /* Write */
2023
1987
  };
2024
- var handler10 = async (provider, args) => {
1988
+ var handler9 = async (provider, args) => {
2025
1989
  if (!provider.writeFile) {
2026
1990
  return {
2027
1991
  type: "Error" /* Error */,
@@ -2036,17 +2000,17 @@ var handler10 = async (provider, args) => {
2036
2000
  message: `<write_to_file_path>${path}</write_to_file_path><status>Success</status>`
2037
2001
  };
2038
2002
  };
2039
- var isAvailable10 = (provider) => {
2003
+ var isAvailable9 = (provider) => {
2040
2004
  return !!provider.writeFile;
2041
2005
  };
2042
2006
  var writeToFile_default = {
2043
- ...toolInfo10,
2044
- handler: handler10,
2045
- isAvailable: isAvailable10
2007
+ ...toolInfo9,
2008
+ handler: handler9,
2009
+ isAvailable: isAvailable9
2046
2010
  };
2047
2011
 
2048
2012
  // src/tools/handOver.ts
2049
- var toolInfo11 = {
2013
+ var toolInfo10 = {
2050
2014
  name: "hand_over",
2051
2015
  description: "Hand over the current task to another agent to complete. This tool MUST NOT to be used with any other tool.",
2052
2016
  parameters: [
@@ -2100,7 +2064,7 @@ var toolInfo11 = {
2100
2064
  ],
2101
2065
  permissionLevel: 0 /* None */
2102
2066
  };
2103
- var handler11 = async (_provider, args) => {
2067
+ var handler10 = async (_provider, args) => {
2104
2068
  const agentName = getString(args, "agent_name");
2105
2069
  const task = getString(args, "task");
2106
2070
  const context = getString(args, "context", void 0);
@@ -2114,17 +2078,17 @@ var handler11 = async (_provider, args) => {
2114
2078
  // originalTask will be set by AgentBase
2115
2079
  };
2116
2080
  };
2117
- var isAvailable11 = (_provider) => {
2081
+ var isAvailable10 = (_provider) => {
2118
2082
  return true;
2119
2083
  };
2120
2084
  var handOver_default = {
2121
- ...toolInfo11,
2122
- handler: handler11,
2123
- isAvailable: isAvailable11
2085
+ ...toolInfo10,
2086
+ handler: handler10,
2087
+ isAvailable: isAvailable10
2124
2088
  };
2125
2089
 
2126
2090
  // src/tools/removeFile.ts
2127
- var toolInfo12 = {
2091
+ var toolInfo11 = {
2128
2092
  name: "remove_file",
2129
2093
  description: "Request to remove a file at the specified path.",
2130
2094
  parameters: [
@@ -2148,7 +2112,7 @@ var toolInfo12 = {
2148
2112
  ],
2149
2113
  permissionLevel: 2 /* Write */
2150
2114
  };
2151
- var handler12 = async (provider, args) => {
2115
+ var handler11 = async (provider, args) => {
2152
2116
  if (!provider.removeFile) {
2153
2117
  return {
2154
2118
  type: "Error" /* Error */,
@@ -2162,28 +2126,28 @@ var handler12 = async (provider, args) => {
2162
2126
  message: `<remove_file_path>${path}</remove_file_path><status>Success</status>`
2163
2127
  };
2164
2128
  };
2165
- var isAvailable12 = (provider) => {
2129
+ var isAvailable11 = (provider) => {
2166
2130
  return !!provider.removeFile;
2167
2131
  };
2168
2132
  var removeFile_default = {
2169
- ...toolInfo12,
2170
- handler: handler12,
2171
- isAvailable: isAvailable12
2133
+ ...toolInfo11,
2134
+ handler: handler11,
2135
+ isAvailable: isAvailable11
2172
2136
  };
2173
2137
 
2174
2138
  // src/tools/renameFile.ts
2175
- var toolInfo13 = {
2139
+ var toolInfo12 = {
2176
2140
  name: "rename_file",
2177
2141
  description: "Request to rename a file from source path to target path.",
2178
2142
  parameters: [
2179
2143
  {
2180
- name: "sourcePath",
2144
+ name: "source_path",
2181
2145
  description: "The current path of the file",
2182
2146
  required: true,
2183
2147
  usageValue: "Source file path here"
2184
2148
  },
2185
2149
  {
2186
- name: "targetPath",
2150
+ name: "target_path",
2187
2151
  description: "The new path for the file",
2188
2152
  required: true,
2189
2153
  usageValue: "Target file path here"
@@ -2194,11 +2158,11 @@ var toolInfo13 = {
2194
2158
  description: "Request to rename a file",
2195
2159
  parameters: [
2196
2160
  {
2197
- name: "sourcePath",
2161
+ name: "source_path",
2198
2162
  value: "src/old-name.js"
2199
2163
  },
2200
2164
  {
2201
- name: "targetPath",
2165
+ name: "target_path",
2202
2166
  value: "src/new-name.js"
2203
2167
  }
2204
2168
  ]
@@ -2206,30 +2170,306 @@ var toolInfo13 = {
2206
2170
  ],
2207
2171
  permissionLevel: 2 /* Write */
2208
2172
  };
2209
- var handler13 = async (provider, args) => {
2173
+ var handler12 = async (provider, args) => {
2210
2174
  if (!provider.renameFile) {
2211
2175
  return {
2212
2176
  type: "Error" /* Error */,
2213
2177
  message: "Not possible to rename file. Abort."
2214
2178
  };
2215
2179
  }
2216
- const sourcePath = getString(args, "sourcePath");
2217
- const targetPath = getString(args, "targetPath");
2180
+ const sourcePath = getString(args, "source_path");
2181
+ const targetPath = getString(args, "target_path");
2218
2182
  await provider.renameFile(sourcePath, targetPath);
2219
2183
  return {
2220
2184
  type: "Reply" /* Reply */,
2221
2185
  message: `<rename_file_path>${targetPath}</rename_file_path><status>Success</status>`
2222
2186
  };
2223
2187
  };
2224
- var isAvailable13 = (provider) => {
2188
+ var isAvailable12 = (provider) => {
2225
2189
  return !!provider.renameFile;
2226
2190
  };
2227
2191
  var renameFile_default = {
2192
+ ...toolInfo12,
2193
+ handler: handler12,
2194
+ isAvailable: isAvailable12
2195
+ };
2196
+
2197
+ // src/tools/editFile.ts
2198
+ var toolInfo13 = {
2199
+ name: "edit_file",
2200
+ description: "Request to edit file contents using before/after text anchors with flexible operations. Supports multiple edit operations in a single call.",
2201
+ parameters: [
2202
+ {
2203
+ name: "path",
2204
+ description: "The path of the file to edit",
2205
+ required: true,
2206
+ usageValue: "File path here"
2207
+ },
2208
+ {
2209
+ name: "operations",
2210
+ description: "Edit operation with before_text, after_text, new_text, and optional line range hints",
2211
+ required: true,
2212
+ allowMultiple: true,
2213
+ children: [
2214
+ {
2215
+ name: "before_text",
2216
+ description: `Text to find as the start anchor (use ${START_OF_FILE} for file start)`,
2217
+ required: false,
2218
+ usageValue: "Text before the edit location"
2219
+ },
2220
+ {
2221
+ name: "after_text",
2222
+ description: `Text to find as the end anchor (use ${END_OF_FILE} for file end)`,
2223
+ required: false,
2224
+ usageValue: "Text after the edit location"
2225
+ },
2226
+ {
2227
+ name: "new_text",
2228
+ description: "Text to replace the content between before_text and after_text",
2229
+ required: true,
2230
+ usageValue: "New text content"
2231
+ },
2232
+ {
2233
+ name: "before_text_line_start",
2234
+ description: "Optional line number hint for before_text location (1-based)",
2235
+ required: false,
2236
+ usageValue: "10"
2237
+ },
2238
+ {
2239
+ name: "after_text_line_start",
2240
+ description: "Optional line number hint for after_text location (1-based)",
2241
+ required: false,
2242
+ usageValue: "20"
2243
+ }
2244
+ ],
2245
+ usageValue: "operations here"
2246
+ }
2247
+ ],
2248
+ examples: [
2249
+ {
2250
+ description: "Replace content between two text anchors",
2251
+ parameters: [
2252
+ {
2253
+ name: "path",
2254
+ value: "src/main.ts"
2255
+ },
2256
+ {
2257
+ name: "operations",
2258
+ value: {
2259
+ before_text: "function oldFunction() {",
2260
+ after_text: "}",
2261
+ new_text: '\n return "new implementation";\n'
2262
+ }
2263
+ }
2264
+ ]
2265
+ },
2266
+ {
2267
+ description: "Insert at start of file",
2268
+ parameters: [
2269
+ {
2270
+ name: "path",
2271
+ value: "src/header.ts"
2272
+ },
2273
+ {
2274
+ name: "operations",
2275
+ value: {
2276
+ before_text: START_OF_FILE,
2277
+ after_text: "export",
2278
+ new_text: "// File header comment\n"
2279
+ }
2280
+ }
2281
+ ]
2282
+ },
2283
+ {
2284
+ description: "Multiple operations in one call",
2285
+ parameters: [
2286
+ {
2287
+ name: "path",
2288
+ value: "src/utils.ts"
2289
+ },
2290
+ {
2291
+ name: "operations",
2292
+ value: [
2293
+ {
2294
+ before_text: "import React",
2295
+ after_text: 'from "react"',
2296
+ new_text: ", { useState }"
2297
+ },
2298
+ {
2299
+ before_text: "function Component() {",
2300
+ after_text: "return (",
2301
+ new_text: "\n const [state, setState] = useState(false);\n "
2302
+ }
2303
+ ]
2304
+ }
2305
+ ]
2306
+ }
2307
+ ],
2308
+ permissionLevel: 2 /* Write */
2309
+ };
2310
+ var handler13 = async (provider, args) => {
2311
+ if (!provider.readFile || !provider.writeFile) {
2312
+ return {
2313
+ type: "Error" /* Error */,
2314
+ message: "Not possible to edit file. Abort."
2315
+ };
2316
+ }
2317
+ const path = getString(args, "path");
2318
+ const operations = getArray(args, "operations");
2319
+ if (!operations || operations.length === 0) {
2320
+ return {
2321
+ type: "Error" /* Error */,
2322
+ message: `<error><edit_file_path>${path}</edit_file_path><error_message>At least one edit operation is required</error_message></error>`
2323
+ };
2324
+ }
2325
+ const fileContent = await provider.readFile(path);
2326
+ if (fileContent == null) {
2327
+ return {
2328
+ type: "Error" /* Error */,
2329
+ message: `<error><edit_file_path>${path}</edit_file_path><error_message>File not found</error_message></error>`
2330
+ };
2331
+ }
2332
+ try {
2333
+ const result = await editFile(fileContent, operations);
2334
+ await provider.writeFile(path, result);
2335
+ return {
2336
+ type: "Reply" /* Reply */,
2337
+ message: `<edit_file_path>${path}</edit_file_path>`
2338
+ };
2339
+ } catch (error) {
2340
+ return {
2341
+ type: "Error" /* Error */,
2342
+ message: `<error><edit_file_path>${path}</edit_file_path><error_message>${error instanceof Error ? error.message : String(error)}</error_message></error>`
2343
+ };
2344
+ }
2345
+ };
2346
+ var isAvailable13 = (provider) => {
2347
+ return !!provider.readFile && !!provider.writeFile;
2348
+ };
2349
+ var editFile_default = {
2228
2350
  ...toolInfo13,
2229
2351
  handler: handler13,
2230
2352
  isAvailable: isAvailable13
2231
2353
  };
2232
2354
 
2355
+ // src/tools/replaceInFile.ts
2356
+ var toolInfo14 = {
2357
+ name: "replace_in_file",
2358
+ 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.",
2359
+ parameters: [
2360
+ {
2361
+ name: "path",
2362
+ description: "The path of the file to modify",
2363
+ required: true,
2364
+ usageValue: "File path here"
2365
+ },
2366
+ {
2367
+ name: "diff",
2368
+ description: `One or more SEARCH/REPLACE blocks following this exact format:
2369
+ \`\`\`
2370
+ <<<<<<< SEARCH
2371
+ [exact content to find]
2372
+ =======
2373
+ [new content to replace with]
2374
+ >>>>>>> REPLACE
2375
+ \`\`\`
2376
+ Critical rules:
2377
+ 1. SEARCH content must match the associated file section to find EXACTLY:
2378
+ * Match character-for-character including whitespace, indentation, line endings
2379
+ * Include all comments, docstrings, etc.
2380
+ 2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.
2381
+ * Including multiple unique SEARCH/REPLACE blocks if you need to make multiple changes.
2382
+ * Include *just* enough lines in each SEARCH section to uniquely match each set of lines that need to change.
2383
+ * When using multiple SEARCH/REPLACE blocks, list them in the order they appear in the file.
2384
+ 3. Keep SEARCH/REPLACE blocks concise:
2385
+ * Break large SEARCH/REPLACE blocks into a series of smaller blocks that each change a small portion of the file.
2386
+ * Include just the changing lines, and a few surrounding lines if needed for uniqueness.
2387
+ * Do not include long runs of unchanging lines in SEARCH/REPLACE blocks.
2388
+ * Each line must be complete. Never truncate lines mid-way through as this can cause matching failures.
2389
+ 4. Special operations:
2390
+ * To move code: Use two SEARCH/REPLACE blocks (one to delete from original + one to insert at new location)
2391
+ * To delete code: Use empty REPLACE section`,
2392
+ required: true,
2393
+ usageValue: "Search and replace blocks here"
2394
+ }
2395
+ ],
2396
+ examples: [
2397
+ {
2398
+ description: "Request to replace sections of content in a file",
2399
+ parameters: [
2400
+ {
2401
+ name: "path",
2402
+ value: "src/main.js"
2403
+ },
2404
+ {
2405
+ name: "diff",
2406
+ value: `
2407
+ <<<<<<< SEARCH
2408
+ import React from 'react';
2409
+ =======
2410
+ import React, { useState } from 'react';
2411
+ >>>>>>> REPLACE
2412
+
2413
+ <<<<<<< SEARCH
2414
+ function handleSubmit() {
2415
+ saveData();
2416
+ setLoading(false);
2417
+ }
2418
+
2419
+ =======
2420
+ >>>>>>> REPLACE
2421
+
2422
+ <<<<<<< SEARCH
2423
+ return (
2424
+ <div>
2425
+ =======
2426
+ function handleSubmit() {
2427
+ saveData();
2428
+ setLoading(false);
2429
+ }
2430
+
2431
+ return (
2432
+ <div>
2433
+ >>>>>>> REPLACE
2434
+ `
2435
+ }
2436
+ ]
2437
+ }
2438
+ ],
2439
+ permissionLevel: 2 /* Write */
2440
+ };
2441
+ var handler14 = async (provider, args) => {
2442
+ if (!provider.readFile || !provider.writeFile) {
2443
+ return {
2444
+ type: "Error" /* Error */,
2445
+ message: "Not possible to replace in file. Abort."
2446
+ };
2447
+ }
2448
+ const path = getString(args, "path");
2449
+ const diff = getString(args, "diff");
2450
+ const fileContent = await provider.readFile(path);
2451
+ if (fileContent == null) {
2452
+ return {
2453
+ type: "Error" /* Error */,
2454
+ message: `<error><replace_in_file_path>${path}</replace_in_file_path><error_message>File not found</error_message></error>`
2455
+ };
2456
+ }
2457
+ const result = await replaceInFile(fileContent, diff);
2458
+ await provider.writeFile(path, result);
2459
+ return {
2460
+ type: "Reply" /* Reply */,
2461
+ message: `<replace_in_file_path>${path}</replace_in_file_path>`
2462
+ };
2463
+ };
2464
+ var isAvailable14 = (provider) => {
2465
+ return !!provider.readFile && !!provider.writeFile;
2466
+ };
2467
+ var replaceInFile_default = {
2468
+ ...toolInfo14,
2469
+ handler: handler14,
2470
+ isAvailable: isAvailable14
2471
+ };
2472
+
2233
2473
  // src/getAvailableTools.ts
2234
2474
  var getAvailableTools = ({
2235
2475
  provider,
@@ -2658,6 +2898,9 @@ ${instance.prompt}`;
2658
2898
  this.config = config;
2659
2899
  this.#policies = policies;
2660
2900
  }
2901
+ get parameters() {
2902
+ return this.ai.options.parameters;
2903
+ }
2661
2904
  get messages() {
2662
2905
  return this.#messages;
2663
2906
  }
@@ -2851,8 +3094,8 @@ ${instance.prompt}`;
2851
3094
  }
2852
3095
  async #invokeTool(name, args) {
2853
3096
  try {
2854
- const handler14 = this.handlers[name]?.handler;
2855
- if (!handler14) {
3097
+ const handler15 = this.handlers[name]?.handler;
3098
+ if (!handler15) {
2856
3099
  return {
2857
3100
  type: "Error" /* Error */,
2858
3101
  message: responsePrompts.errorInvokeTool(name, "Tool not found"),
@@ -2871,7 +3114,7 @@ ${instance.prompt}`;
2871
3114
  if (resp) {
2872
3115
  return resp;
2873
3116
  }
2874
- return await handler14(this.config.provider, args);
3117
+ return await handler15(this.config.provider, args);
2875
3118
  } catch (error) {
2876
3119
  return {
2877
3120
  type: "Error" /* Error */,
@@ -3229,7 +3472,7 @@ var editingFilesPrompt = (toolNamePrefix) => `
3229
3472
 
3230
3473
  EDITING FILES
3231
3474
 
3232
- You have access to two tools for working with files: **${toolNamePrefix}write_to_file** and **${toolNamePrefix}replace_in_file**. Understanding their roles and selecting the right one for the job will help ensure efficient and accurate modifications.
3475
+ You have two file-manipulation tools: **${toolNamePrefix}write_to_file** (full overwrite) and **${toolNamePrefix}edit_file** (targeted anchor-based edits). Choose the smallest safe operation for every change.
3233
3476
 
3234
3477
  # ${toolNamePrefix}write_to_file
3235
3478
 
@@ -3241,16 +3484,16 @@ You have access to two tools for working with files: **${toolNamePrefix}write_to
3241
3484
 
3242
3485
  - Initial file creation, such as when scaffolding a new project.
3243
3486
  - Overwriting large boilerplate files where you want to replace the entire content at once.
3244
- - When the complexity or number of changes would make ${toolNamePrefix}replace_in_file unwieldy or error-prone.
3487
+ - When the complexity or number of changes would make ${toolNamePrefix}edit_file unwieldy or error-prone.
3245
3488
  - When you need to completely restructure a file's content or change its fundamental organization.
3246
3489
 
3247
3490
  ## Important Considerations
3248
3491
 
3249
3492
  - Using ${toolNamePrefix}write_to_file requires providing the file's complete final content.
3250
- - If you only need to make small changes to an existing file, consider using ${toolNamePrefix}replace_in_file instead to avoid unnecessarily rewriting the entire file.
3493
+ - If you only need to make small changes to an existing file, consider using ${toolNamePrefix}edit_file instead to avoid unnecessarily rewriting the entire file.
3251
3494
  - While ${toolNamePrefix}write_to_file should not be your default choice, don't hesitate to use it when the situation truly calls for it.
3252
3495
 
3253
- # ${toolNamePrefix}replace_in_file
3496
+ # ${toolNamePrefix}edit_file
3254
3497
 
3255
3498
  ## Purpose
3256
3499
 
@@ -3269,10 +3512,10 @@ You have access to two tools for working with files: **${toolNamePrefix}write_to
3269
3512
 
3270
3513
  # Choosing the Appropriate Tool
3271
3514
 
3272
- - **Default to ${toolNamePrefix}replace_in_file** for most changes. It's the safer, more precise option that minimizes potential issues.
3515
+ - **Default to ${toolNamePrefix}edit_file** for most changes. It keeps diffs small and reduces risk.
3273
3516
  - **Use ${toolNamePrefix}write_to_file** when:
3274
3517
  - Creating new files
3275
- - The changes are so extensive that using ${toolNamePrefix}replace_in_file would be more complex or risky
3518
+ - The changes are so extensive that using ${toolNamePrefix}edit_file would be more complex or risky
3276
3519
  - You need to completely reorganize or restructure a file
3277
3520
  - The file is relatively small and the changes affect most of its content
3278
3521
  - You're generating boilerplate or template files
@@ -3280,11 +3523,12 @@ You have access to two tools for working with files: **${toolNamePrefix}write_to
3280
3523
  # Workflow Tips
3281
3524
 
3282
3525
  1. Before editing, assess the scope of your changes and decide which tool to use.
3283
- 2. For targeted edits, apply ${toolNamePrefix}replace_in_file with carefully crafted SEARCH/REPLACE blocks. If you need multiple changes, you can stack multiple SEARCH/REPLACE blocks within a single ${toolNamePrefix}replace_in_file call.
3526
+ 2. For targeted edits, apply ${toolNamePrefix}edit_file with carefully crafted before/after text anchors. If you need multiple changes, you can stack multiple operations within a single ${toolNamePrefix}edit_file call.
3284
3527
  3. For major overhauls or initial file creation, rely on ${toolNamePrefix}write_to_file.
3285
- 4. Once the file has been edited with either ${toolNamePrefix}write_to_file or ${toolNamePrefix}replace_in_file, the system will provide you with the final state of the modified file. Use this updated content as the reference point for any subsequent SEARCH/REPLACE operations, since it reflects any auto-formatting or user-applied changes.
3528
+ 4. Once the file has been edited with either ${toolNamePrefix}write_to_file or ${toolNamePrefix}edit_file, the system will provide you with the final state of the modified file. Use this updated content as the reference point for any subsequent operations, since it reflects any auto-formatting or user-applied changes.
3286
3529
 
3287
- By thoughtfully selecting between ${toolNamePrefix}write_to_file and ${toolNamePrefix}replace_in_file, you can make your file editing process smoother, safer, and more efficient.`;
3530
+ Picking the right tool keeps edits minimal, safe, and easy to review.
3531
+ `;
3288
3532
  var rules = (toolNamePrefix) => `
3289
3533
  ====
3290
3534
 
@@ -3295,10 +3539,10 @@ RULES
3295
3539
  For text files (e.g. README.md), append a footer with the same notice.
3296
3540
  - Never describe what changed inside code comments; comments must focus on purpose or usage only.
3297
3541
  - Before using ${toolNamePrefix}execute_command, consider SYSTEM INFORMATION to ensure commands suit the user's OS. If a command must run in a subdirectory, prepend a single \`cd childDir &&\` segment.
3298
- - Use ${toolNamePrefix}search_files for broad analysis, then ${toolNamePrefix}read_file to inspect context, and finally ${toolNamePrefix}replace_in_file or ${toolNamePrefix}write_to_file to modify.
3299
- - Prefer ${toolNamePrefix}replace_in_file for focused edits; choose ${toolNamePrefix}write_to_file for new files or complete rewrites.
3542
+ - Use ${toolNamePrefix}search_files for broad analysis, then ${toolNamePrefix}read_file to inspect context, and finally ${toolNamePrefix}edit_file or ${toolNamePrefix}write_to_file to modify.
3543
+ - Prefer ${toolNamePrefix}edit_file for focused edits; choose ${toolNamePrefix}write_to_file for new files or complete rewrites.
3300
3544
  - When creating a new file, look for existing files with similar content or patterns; if found, read them and use their structure or conventions as a reference.
3301
- - SEARCH blocks in ${toolNamePrefix}replace_in_file must match whole lines. If multiple blocks are needed, list them in file order.
3545
+ - Use before/after text anchors in ${toolNamePrefix}edit_file to target changes. If multiple operations are needed, list them in file order.
3302
3546
  - Do not guess unseen content. Read existing files first unless creating new ones.
3303
3547
  - Follow existing style, lint, and naming conventions. Ensure all changes compile and pass tests where applicable.
3304
3548
  - ALWAYS wait for the user's confirmation after each tool call before starting the next step.
@@ -3564,6 +3808,7 @@ var configSchema = z.object({
3564
3808
  }).strict();
3565
3809
  var Policies = /* @__PURE__ */ ((Policies2) => {
3566
3810
  Policies2["KnowledgeManagement"] = "knowledgemanagement";
3811
+ Policies2["TruncateContext"] = "truncatecontext";
3567
3812
  return Policies2;
3568
3813
  })(Policies || {});
3569
3814
 
@@ -3711,6 +3956,67 @@ var KnowledgeManagementPolicy = (tools) => {
3711
3956
  };
3712
3957
  };
3713
3958
 
3959
+ // src/Agent/policies/TruncateContext.ts
3960
+ var DEFAULT_MAX_TOKENS_ESTIMATE = 8e3;
3961
+ function getMaxTokens(agent) {
3962
+ const params = agent.parameters || {};
3963
+ if (params.maxTokens && typeof params.maxTokens === "number" && params.maxTokens > 0) {
3964
+ return params.maxTokens;
3965
+ }
3966
+ return DEFAULT_MAX_TOKENS_ESTIMATE;
3967
+ }
3968
+ function estimateTokens(text) {
3969
+ return Math.ceil(text.length / 4);
3970
+ }
3971
+ var TruncateContextPolicy = (tools) => {
3972
+ return {
3973
+ name: "truncatecontext" /* TruncateContext */,
3974
+ async onBeforeRequest(agent) {
3975
+ const messages = agent.messages;
3976
+ if (messages.length < 3) {
3977
+ return;
3978
+ }
3979
+ let totalTokens = 0;
3980
+ for (const msg of messages) {
3981
+ if (typeof msg.content === "string") {
3982
+ totalTokens += estimateTokens(msg.content);
3983
+ } else if (Array.isArray(msg.content)) {
3984
+ for (const block of msg.content) {
3985
+ if (typeof block === "object" && "text" in block && typeof block.text === "string") {
3986
+ totalTokens += estimateTokens(block.text);
3987
+ }
3988
+ }
3989
+ }
3990
+ }
3991
+ const maxTokens = getMaxTokens(agent);
3992
+ if (totalTokens <= maxTokens) {
3993
+ return;
3994
+ }
3995
+ const totalMessages = messages.length;
3996
+ const messagesToKeep = Math.ceil(totalMessages / 2);
3997
+ const minKeep = Math.max(2, messagesToKeep);
3998
+ if (minKeep >= totalMessages) {
3999
+ return;
4000
+ }
4001
+ const keepFromStart = Math.floor(minKeep / 2);
4002
+ const keepFromEnd = minKeep - keepFromStart;
4003
+ const startMessages = messages.slice(0, keepFromStart);
4004
+ const endMessages = messages.slice(-keepFromEnd);
4005
+ const truncatedCount = totalMessages - minKeep;
4006
+ const truncatedMessages = [
4007
+ ...startMessages,
4008
+ // Add a message explaining truncation
4009
+ {
4010
+ role: "user",
4011
+ content: `Note: ${truncatedCount} messages were truncated from the middle to prevent context overflow.`
4012
+ },
4013
+ ...endMessages
4014
+ ];
4015
+ agent.setMessages(truncatedMessages);
4016
+ }
4017
+ };
4018
+ };
4019
+
3714
4020
  // src/Agent/index.ts
3715
4021
  var allAgents = [architectAgentInfo, coderAgentInfo, analyzerAgentInfo, codeFixerAgentInfo];
3716
4022
 
@@ -4109,6 +4415,7 @@ export {
4109
4415
  Policies,
4110
4416
  TaskEventKind,
4111
4417
  ToolResponseType,
4418
+ TruncateContextPolicy,
4112
4419
  UsageMeter,
4113
4420
  agentsPrompt,
4114
4421
  allAgents,
@@ -4131,6 +4438,8 @@ export {
4131
4438
  deepSeekModels,
4132
4439
  defaultModels,
4133
4440
  delegate_default as delegate,
4441
+ editFile_default as editFile,
4442
+ editFile as editFileHelper,
4134
4443
  executeAgentTool,
4135
4444
  executeCommand_default as executeCommand,
4136
4445
  executeTool,