@polka-codes/core 0.8.11 → 0.8.13

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",
@@ -1319,11 +1401,11 @@ var delegate_default = {
1319
1401
  // src/tools/executeCommand.ts
1320
1402
  var toolInfo4 = {
1321
1403
  name: "execute_command",
1322
- description: "Run a single CLI command. The command is always executed in the project-root working directory (regardless of earlier commands). Prefer one-off shell commands over wrapper scripts for flexibility. After an `execute_command` call, no other tool calls are allowed in the same assistant response.",
1404
+ description: "Run a single CLI command. The command is always executed in the project-root working directory (regardless of earlier commands). Prefer one-off shell commands over wrapper scripts for flexibility. **IMPORTANT**: After an `execute_command` call, you MUST stop and NOT allowed to make further tool calls in the same message.",
1323
1405
  parameters: [
1324
1406
  {
1325
1407
  name: "command",
1326
- description: "The exact command to run (valid for the current OS). It must be correctly formatted and free of harmful instructions.",
1408
+ description: "The exact command to run (valid for the current OS). It must be correctly formatted and free of harmful instructions.",
1327
1409
  required: true,
1328
1410
  usageValue: "your-command-here"
1329
1411
  },
@@ -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,
@@ -2438,7 +2678,7 @@ var toolUsePrompt = (tools, toolNamePrefix) => {
2438
2678
 
2439
2679
  TOOL USE
2440
2680
 
2441
- 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.
2681
+ You have access to a set of tools that are executed upon the user's approval. You can use up to 5 tool calls per message, and will receive the results of those tool uses 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.
2442
2682
 
2443
2683
  # Tool Use Formatting
2444
2684
 
@@ -2503,18 +2743,16 @@ ${tools.map((tool) => {
2503
2743
 
2504
2744
  1. **Outline Your Thought Process**
2505
2745
  - Before using a tool, wrap your reasoning inside \`<thinking>\` tags. Be concise\u2014just enough to clarify your plan and the rationale behind selecting a specific tool.
2506
-
2507
2746
  2. **Wait for Feedback**
2508
2747
  - After using a tool, wait for the user's response indicating success/failure or any output logs. Do not assume the result of a tool without explicit confirmation.
2509
-
2510
2748
  3. **Error Handling**
2511
2749
  - If a tool fails or produces an unexpected result, analyze the error, decide on an alternative approach or tool, and proceed carefully.
2512
-
2513
2750
  4. **Avoid Repetition**
2514
2751
  - Do not quote or repeat previous commands or prompts verbatim. Move the conversation forward by focusing on the latest required action.
2515
-
2516
2752
  5. **No Unnecessary Re-invocations**
2517
- - Only invoke the same tool again if a genuine need arises (e.g., different parameters or updated context).`;
2753
+ - Only invoke the same tool again if a genuine need arises (e.g., different parameters or updated context).
2754
+ 6. **Tool Call Limit**
2755
+ - Do not make more than 5 tool calls in a single message.`;
2518
2756
  };
2519
2757
  var agentsPrompt = (agents, name) => `
2520
2758
  ====
@@ -2658,6 +2896,9 @@ ${instance.prompt}`;
2658
2896
  this.config = config;
2659
2897
  this.#policies = policies;
2660
2898
  }
2899
+ get parameters() {
2900
+ return this.ai.options.parameters;
2901
+ }
2661
2902
  get messages() {
2662
2903
  return this.#messages;
2663
2904
  }
@@ -2851,8 +3092,8 @@ ${instance.prompt}`;
2851
3092
  }
2852
3093
  async #invokeTool(name, args) {
2853
3094
  try {
2854
- const handler14 = this.handlers[name]?.handler;
2855
- if (!handler14) {
3095
+ const handler15 = this.handlers[name]?.handler;
3096
+ if (!handler15) {
2856
3097
  return {
2857
3098
  type: "Error" /* Error */,
2858
3099
  message: responsePrompts.errorInvokeTool(name, "Tool not found"),
@@ -2871,7 +3112,7 @@ ${instance.prompt}`;
2871
3112
  if (resp) {
2872
3113
  return resp;
2873
3114
  }
2874
- return await handler14(this.config.provider, args);
3115
+ return await handler15(this.config.provider, args);
2875
3116
  } catch (error) {
2876
3117
  return {
2877
3118
  type: "Error" /* Error */,
@@ -3229,7 +3470,7 @@ var editingFilesPrompt = (toolNamePrefix) => `
3229
3470
 
3230
3471
  EDITING FILES
3231
3472
 
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.
3473
+ 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
3474
 
3234
3475
  # ${toolNamePrefix}write_to_file
3235
3476
 
@@ -3241,16 +3482,16 @@ You have access to two tools for working with files: **${toolNamePrefix}write_to
3241
3482
 
3242
3483
  - Initial file creation, such as when scaffolding a new project.
3243
3484
  - 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.
3485
+ - When the complexity or number of changes would make ${toolNamePrefix}edit_file unwieldy or error-prone.
3245
3486
  - When you need to completely restructure a file's content or change its fundamental organization.
3246
3487
 
3247
3488
  ## Important Considerations
3248
3489
 
3249
3490
  - 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.
3491
+ - 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
3492
  - 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
3493
 
3253
- # ${toolNamePrefix}replace_in_file
3494
+ # ${toolNamePrefix}edit_file
3254
3495
 
3255
3496
  ## Purpose
3256
3497
 
@@ -3269,10 +3510,10 @@ You have access to two tools for working with files: **${toolNamePrefix}write_to
3269
3510
 
3270
3511
  # Choosing the Appropriate Tool
3271
3512
 
3272
- - **Default to ${toolNamePrefix}replace_in_file** for most changes. It's the safer, more precise option that minimizes potential issues.
3513
+ - **Default to ${toolNamePrefix}edit_file** for most changes. It keeps diffs small and reduces risk.
3273
3514
  - **Use ${toolNamePrefix}write_to_file** when:
3274
3515
  - Creating new files
3275
- - The changes are so extensive that using ${toolNamePrefix}replace_in_file would be more complex or risky
3516
+ - The changes are so extensive that using ${toolNamePrefix}edit_file would be more complex or risky
3276
3517
  - You need to completely reorganize or restructure a file
3277
3518
  - The file is relatively small and the changes affect most of its content
3278
3519
  - You're generating boilerplate or template files
@@ -3280,11 +3521,12 @@ You have access to two tools for working with files: **${toolNamePrefix}write_to
3280
3521
  # Workflow Tips
3281
3522
 
3282
3523
  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.
3524
+ 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
3525
  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.
3526
+ 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
3527
 
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.`;
3528
+ Picking the right tool keeps edits minimal, safe, and easy to review.
3529
+ `;
3288
3530
  var rules = (toolNamePrefix) => `
3289
3531
  ====
3290
3532
 
@@ -3295,10 +3537,10 @@ RULES
3295
3537
  For text files (e.g. README.md), append a footer with the same notice.
3296
3538
  - Never describe what changed inside code comments; comments must focus on purpose or usage only.
3297
3539
  - 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.
3540
+ - 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.
3541
+ - Prefer ${toolNamePrefix}edit_file for focused edits; choose ${toolNamePrefix}write_to_file for new files or complete rewrites.
3300
3542
  - 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.
3543
+ - Use before/after text anchors in ${toolNamePrefix}edit_file to target changes. If multiple operations are needed, list them in file order.
3302
3544
  - Do not guess unseen content. Read existing files first unless creating new ones.
3303
3545
  - Follow existing style, lint, and naming conventions. Ensure all changes compile and pass tests where applicable.
3304
3546
  - ALWAYS wait for the user's confirmation after each tool call before starting the next step.
@@ -3564,6 +3806,7 @@ var configSchema = z.object({
3564
3806
  }).strict();
3565
3807
  var Policies = /* @__PURE__ */ ((Policies2) => {
3566
3808
  Policies2["KnowledgeManagement"] = "knowledgemanagement";
3809
+ Policies2["TruncateContext"] = "truncatecontext";
3567
3810
  return Policies2;
3568
3811
  })(Policies || {});
3569
3812
 
@@ -3711,6 +3954,67 @@ var KnowledgeManagementPolicy = (tools) => {
3711
3954
  };
3712
3955
  };
3713
3956
 
3957
+ // src/Agent/policies/TruncateContext.ts
3958
+ var DEFAULT_MAX_TOKENS_ESTIMATE = 8e3;
3959
+ function getMaxTokens(agent) {
3960
+ const params = agent.parameters || {};
3961
+ if (params.maxTokens && typeof params.maxTokens === "number" && params.maxTokens > 0) {
3962
+ return params.maxTokens;
3963
+ }
3964
+ return DEFAULT_MAX_TOKENS_ESTIMATE;
3965
+ }
3966
+ function estimateTokens(text) {
3967
+ return Math.ceil(text.length / 4);
3968
+ }
3969
+ var TruncateContextPolicy = (tools) => {
3970
+ return {
3971
+ name: "truncatecontext" /* TruncateContext */,
3972
+ async onBeforeRequest(agent) {
3973
+ const messages = agent.messages;
3974
+ if (messages.length < 3) {
3975
+ return;
3976
+ }
3977
+ let totalTokens = 0;
3978
+ for (const msg of messages) {
3979
+ if (typeof msg.content === "string") {
3980
+ totalTokens += estimateTokens(msg.content);
3981
+ } else if (Array.isArray(msg.content)) {
3982
+ for (const block of msg.content) {
3983
+ if (typeof block === "object" && "text" in block && typeof block.text === "string") {
3984
+ totalTokens += estimateTokens(block.text);
3985
+ }
3986
+ }
3987
+ }
3988
+ }
3989
+ const maxTokens = getMaxTokens(agent);
3990
+ if (totalTokens <= maxTokens) {
3991
+ return;
3992
+ }
3993
+ const totalMessages = messages.length;
3994
+ const messagesToKeep = Math.ceil(totalMessages / 2);
3995
+ const minKeep = Math.max(2, messagesToKeep);
3996
+ if (minKeep >= totalMessages) {
3997
+ return;
3998
+ }
3999
+ const keepFromStart = Math.floor(minKeep / 2);
4000
+ const keepFromEnd = minKeep - keepFromStart;
4001
+ const startMessages = messages.slice(0, keepFromStart);
4002
+ const endMessages = messages.slice(-keepFromEnd);
4003
+ const truncatedCount = totalMessages - minKeep;
4004
+ const truncatedMessages = [
4005
+ ...startMessages,
4006
+ // Add a message explaining truncation
4007
+ {
4008
+ role: "user",
4009
+ content: `Note: ${truncatedCount} messages were truncated from the middle to prevent context overflow.`
4010
+ },
4011
+ ...endMessages
4012
+ ];
4013
+ agent.setMessages(truncatedMessages);
4014
+ }
4015
+ };
4016
+ };
4017
+
3714
4018
  // src/Agent/index.ts
3715
4019
  var allAgents = [architectAgentInfo, coderAgentInfo, analyzerAgentInfo, codeFixerAgentInfo];
3716
4020
 
@@ -4109,6 +4413,7 @@ export {
4109
4413
  Policies,
4110
4414
  TaskEventKind,
4111
4415
  ToolResponseType,
4416
+ TruncateContextPolicy,
4112
4417
  UsageMeter,
4113
4418
  agentsPrompt,
4114
4419
  allAgents,
@@ -4131,6 +4436,8 @@ export {
4131
4436
  deepSeekModels,
4132
4437
  defaultModels,
4133
4438
  delegate_default as delegate,
4439
+ editFile_default as editFile,
4440
+ editFile as editFileHelper,
4134
4441
  executeAgentTool,
4135
4442
  executeCommand_default as executeCommand,
4136
4443
  executeTool,