wave-agent-sdk 0.0.7 → 0.0.10

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 (240) hide show
  1. package/dist/agent.d.ts +105 -24
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +438 -53
  4. package/dist/index.d.ts +4 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +4 -0
  7. package/dist/managers/aiManager.d.ts +18 -7
  8. package/dist/managers/aiManager.d.ts.map +1 -1
  9. package/dist/managers/aiManager.js +254 -142
  10. package/dist/managers/backgroundBashManager.d.ts.map +1 -1
  11. package/dist/managers/backgroundBashManager.js +11 -9
  12. package/dist/managers/hookManager.d.ts +6 -6
  13. package/dist/managers/hookManager.d.ts.map +1 -1
  14. package/dist/managers/hookManager.js +81 -39
  15. package/dist/managers/liveConfigManager.d.ts +95 -0
  16. package/dist/managers/liveConfigManager.d.ts.map +1 -0
  17. package/dist/managers/liveConfigManager.js +442 -0
  18. package/dist/managers/lspManager.d.ts +43 -0
  19. package/dist/managers/lspManager.d.ts.map +1 -0
  20. package/dist/managers/lspManager.js +326 -0
  21. package/dist/managers/messageManager.d.ts +41 -24
  22. package/dist/managers/messageManager.d.ts.map +1 -1
  23. package/dist/managers/messageManager.js +184 -73
  24. package/dist/managers/permissionManager.d.ts +66 -0
  25. package/dist/managers/permissionManager.d.ts.map +1 -0
  26. package/dist/managers/permissionManager.js +208 -0
  27. package/dist/managers/skillManager.d.ts +1 -0
  28. package/dist/managers/skillManager.d.ts.map +1 -1
  29. package/dist/managers/skillManager.js +2 -1
  30. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  31. package/dist/managers/slashCommandManager.js +4 -2
  32. package/dist/managers/subagentManager.d.ts +42 -6
  33. package/dist/managers/subagentManager.d.ts.map +1 -1
  34. package/dist/managers/subagentManager.js +213 -62
  35. package/dist/managers/toolManager.d.ts +38 -1
  36. package/dist/managers/toolManager.d.ts.map +1 -1
  37. package/dist/managers/toolManager.js +66 -2
  38. package/dist/services/aiService.d.ts +15 -5
  39. package/dist/services/aiService.d.ts.map +1 -1
  40. package/dist/services/aiService.js +446 -77
  41. package/dist/services/configurationService.d.ts +116 -0
  42. package/dist/services/configurationService.d.ts.map +1 -0
  43. package/dist/services/configurationService.js +585 -0
  44. package/dist/services/fileWatcher.d.ts +69 -0
  45. package/dist/services/fileWatcher.d.ts.map +1 -0
  46. package/dist/services/fileWatcher.js +212 -0
  47. package/dist/services/hook.d.ts +5 -40
  48. package/dist/services/hook.d.ts.map +1 -1
  49. package/dist/services/hook.js +47 -109
  50. package/dist/services/jsonlHandler.d.ts +71 -0
  51. package/dist/services/jsonlHandler.d.ts.map +1 -0
  52. package/dist/services/jsonlHandler.js +236 -0
  53. package/dist/services/memory.d.ts.map +1 -1
  54. package/dist/services/memory.js +33 -11
  55. package/dist/services/session.d.ts +116 -52
  56. package/dist/services/session.d.ts.map +1 -1
  57. package/dist/services/session.js +415 -143
  58. package/dist/tools/bashTool.d.ts.map +1 -1
  59. package/dist/tools/bashTool.js +77 -17
  60. package/dist/tools/deleteFileTool.d.ts.map +1 -1
  61. package/dist/tools/deleteFileTool.js +27 -1
  62. package/dist/tools/editTool.d.ts.map +1 -1
  63. package/dist/tools/editTool.js +33 -8
  64. package/dist/tools/lspTool.d.ts +6 -0
  65. package/dist/tools/lspTool.d.ts.map +1 -0
  66. package/dist/tools/lspTool.js +589 -0
  67. package/dist/tools/multiEditTool.d.ts.map +1 -1
  68. package/dist/tools/multiEditTool.js +30 -10
  69. package/dist/tools/readTool.d.ts.map +1 -1
  70. package/dist/tools/readTool.js +113 -3
  71. package/dist/tools/skillTool.js +2 -2
  72. package/dist/tools/todoWriteTool.d.ts.map +1 -1
  73. package/dist/tools/todoWriteTool.js +23 -0
  74. package/dist/tools/types.d.ts +11 -8
  75. package/dist/tools/types.d.ts.map +1 -1
  76. package/dist/tools/writeTool.d.ts.map +1 -1
  77. package/dist/tools/writeTool.js +30 -15
  78. package/dist/types/commands.d.ts +4 -1
  79. package/dist/types/commands.d.ts.map +1 -1
  80. package/dist/types/config.d.ts +4 -0
  81. package/dist/types/config.d.ts.map +1 -1
  82. package/dist/types/configuration.d.ts +69 -0
  83. package/dist/types/configuration.d.ts.map +1 -0
  84. package/dist/types/configuration.js +8 -0
  85. package/dist/types/core.d.ts +45 -0
  86. package/dist/types/core.d.ts.map +1 -1
  87. package/dist/types/environment.d.ts +83 -0
  88. package/dist/types/environment.d.ts.map +1 -0
  89. package/dist/types/environment.js +21 -0
  90. package/dist/types/fileSearch.d.ts +5 -0
  91. package/dist/types/fileSearch.d.ts.map +1 -0
  92. package/dist/types/fileSearch.js +1 -0
  93. package/dist/types/hooks.d.ts +18 -3
  94. package/dist/types/hooks.d.ts.map +1 -1
  95. package/dist/types/hooks.js +8 -8
  96. package/dist/types/index.d.ts +7 -0
  97. package/dist/types/index.d.ts.map +1 -1
  98. package/dist/types/index.js +7 -0
  99. package/dist/types/lsp.d.ts +90 -0
  100. package/dist/types/lsp.d.ts.map +1 -0
  101. package/dist/types/lsp.js +4 -0
  102. package/dist/types/messaging.d.ts +19 -12
  103. package/dist/types/messaging.d.ts.map +1 -1
  104. package/dist/types/permissions.d.ts +35 -0
  105. package/dist/types/permissions.d.ts.map +1 -0
  106. package/dist/types/permissions.js +12 -0
  107. package/dist/types/session.d.ts +15 -0
  108. package/dist/types/session.d.ts.map +1 -0
  109. package/dist/types/session.js +7 -0
  110. package/dist/types/skills.d.ts +1 -0
  111. package/dist/types/skills.d.ts.map +1 -1
  112. package/dist/types/tools.d.ts +35 -0
  113. package/dist/types/tools.d.ts.map +1 -0
  114. package/dist/types/tools.js +4 -0
  115. package/dist/utils/abortUtils.d.ts +34 -0
  116. package/dist/utils/abortUtils.d.ts.map +1 -0
  117. package/dist/utils/abortUtils.js +92 -0
  118. package/dist/utils/bashHistory.d.ts +4 -0
  119. package/dist/utils/bashHistory.d.ts.map +1 -1
  120. package/dist/utils/bashHistory.js +48 -30
  121. package/dist/utils/builtinSubagents.d.ts +7 -0
  122. package/dist/utils/builtinSubagents.d.ts.map +1 -0
  123. package/dist/utils/builtinSubagents.js +65 -0
  124. package/dist/utils/cacheControlUtils.d.ts +96 -0
  125. package/dist/utils/cacheControlUtils.d.ts.map +1 -0
  126. package/dist/utils/cacheControlUtils.js +324 -0
  127. package/dist/utils/commandPathResolver.d.ts +52 -0
  128. package/dist/utils/commandPathResolver.d.ts.map +1 -0
  129. package/dist/utils/commandPathResolver.js +145 -0
  130. package/dist/utils/configPaths.d.ts +85 -0
  131. package/dist/utils/configPaths.d.ts.map +1 -0
  132. package/dist/utils/configPaths.js +121 -0
  133. package/dist/utils/constants.d.ts +1 -13
  134. package/dist/utils/constants.d.ts.map +1 -1
  135. package/dist/utils/constants.js +2 -14
  136. package/dist/utils/convertMessagesForAPI.d.ts +2 -1
  137. package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
  138. package/dist/utils/convertMessagesForAPI.js +39 -18
  139. package/dist/utils/customCommands.d.ts.map +1 -1
  140. package/dist/utils/customCommands.js +66 -21
  141. package/dist/utils/fileSearch.d.ts +14 -0
  142. package/dist/utils/fileSearch.d.ts.map +1 -0
  143. package/dist/utils/fileSearch.js +88 -0
  144. package/dist/utils/fileUtils.d.ts +27 -0
  145. package/dist/utils/fileUtils.d.ts.map +1 -0
  146. package/dist/utils/fileUtils.js +145 -0
  147. package/dist/utils/globalLogger.d.ts +88 -0
  148. package/dist/utils/globalLogger.d.ts.map +1 -0
  149. package/dist/utils/globalLogger.js +120 -0
  150. package/dist/utils/largeOutputHandler.d.ts +15 -0
  151. package/dist/utils/largeOutputHandler.d.ts.map +1 -0
  152. package/dist/utils/largeOutputHandler.js +40 -0
  153. package/dist/utils/markdownParser.d.ts.map +1 -1
  154. package/dist/utils/markdownParser.js +1 -17
  155. package/dist/utils/mcpUtils.d.ts.map +1 -1
  156. package/dist/utils/mcpUtils.js +25 -3
  157. package/dist/utils/messageOperations.d.ts +20 -18
  158. package/dist/utils/messageOperations.d.ts.map +1 -1
  159. package/dist/utils/messageOperations.js +30 -38
  160. package/dist/utils/pathEncoder.d.ts +108 -0
  161. package/dist/utils/pathEncoder.d.ts.map +1 -0
  162. package/dist/utils/pathEncoder.js +279 -0
  163. package/dist/utils/subagentParser.d.ts +2 -2
  164. package/dist/utils/subagentParser.d.ts.map +1 -1
  165. package/dist/utils/subagentParser.js +12 -8
  166. package/dist/utils/tokenCalculation.d.ts +26 -0
  167. package/dist/utils/tokenCalculation.d.ts.map +1 -0
  168. package/dist/utils/tokenCalculation.js +36 -0
  169. package/dist/utils/tokenEstimator.d.ts +39 -0
  170. package/dist/utils/tokenEstimator.d.ts.map +1 -0
  171. package/dist/utils/tokenEstimator.js +55 -0
  172. package/package.json +6 -6
  173. package/src/agent.ts +586 -78
  174. package/src/index.ts +4 -0
  175. package/src/managers/aiManager.ts +341 -192
  176. package/src/managers/backgroundBashManager.ts +11 -9
  177. package/src/managers/hookManager.ts +102 -54
  178. package/src/managers/liveConfigManager.ts +634 -0
  179. package/src/managers/lspManager.ts +434 -0
  180. package/src/managers/messageManager.ts +258 -121
  181. package/src/managers/permissionManager.ts +276 -0
  182. package/src/managers/skillManager.ts +3 -1
  183. package/src/managers/slashCommandManager.ts +5 -3
  184. package/src/managers/subagentManager.ts +295 -76
  185. package/src/managers/toolManager.ts +95 -3
  186. package/src/services/aiService.ts +656 -84
  187. package/src/services/configurationService.ts +762 -0
  188. package/src/services/fileWatcher.ts +300 -0
  189. package/src/services/hook.ts +54 -144
  190. package/src/services/jsonlHandler.ts +303 -0
  191. package/src/services/memory.ts +34 -11
  192. package/src/services/session.ts +522 -173
  193. package/src/tools/bashTool.ts +94 -20
  194. package/src/tools/deleteFileTool.ts +38 -1
  195. package/src/tools/editTool.ts +44 -9
  196. package/src/tools/lspTool.ts +760 -0
  197. package/src/tools/multiEditTool.ts +41 -11
  198. package/src/tools/readTool.ts +127 -3
  199. package/src/tools/skillTool.ts +2 -2
  200. package/src/tools/todoWriteTool.ts +33 -1
  201. package/src/tools/types.ts +15 -9
  202. package/src/tools/writeTool.ts +43 -16
  203. package/src/types/commands.ts +6 -1
  204. package/src/types/config.ts +5 -0
  205. package/src/types/configuration.ts +73 -0
  206. package/src/types/core.ts +55 -0
  207. package/src/types/environment.ts +104 -0
  208. package/src/types/fileSearch.ts +4 -0
  209. package/src/types/hooks.ts +32 -16
  210. package/src/types/index.ts +7 -0
  211. package/src/types/lsp.ts +96 -0
  212. package/src/types/messaging.ts +21 -14
  213. package/src/types/permissions.ts +48 -0
  214. package/src/types/session.ts +20 -0
  215. package/src/types/skills.ts +1 -0
  216. package/src/types/tools.ts +38 -0
  217. package/src/utils/abortUtils.ts +118 -0
  218. package/src/utils/bashHistory.ts +55 -31
  219. package/src/utils/builtinSubagents.ts +71 -0
  220. package/src/utils/cacheControlUtils.ts +475 -0
  221. package/src/utils/commandPathResolver.ts +189 -0
  222. package/src/utils/configPaths.ts +163 -0
  223. package/src/utils/constants.ts +2 -17
  224. package/src/utils/convertMessagesForAPI.ts +44 -18
  225. package/src/utils/customCommands.ts +90 -22
  226. package/src/utils/fileSearch.ts +107 -0
  227. package/src/utils/fileUtils.ts +160 -0
  228. package/src/utils/globalLogger.ts +128 -0
  229. package/src/utils/largeOutputHandler.ts +55 -0
  230. package/src/utils/markdownParser.ts +1 -19
  231. package/src/utils/mcpUtils.ts +34 -3
  232. package/src/utils/messageOperations.ts +47 -53
  233. package/src/utils/pathEncoder.ts +394 -0
  234. package/src/utils/subagentParser.ts +13 -9
  235. package/src/utils/tokenCalculation.ts +43 -0
  236. package/src/utils/tokenEstimator.ts +68 -0
  237. package/dist/utils/configResolver.d.ts +0 -38
  238. package/dist/utils/configResolver.d.ts.map +0 -1
  239. package/dist/utils/configResolver.js +0 -106
  240. package/src/utils/configResolver.ts +0 -142
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import fs from "fs";
6
6
  import { BASH_HISTORY_FILE, DATA_DIRECTORY } from "./constants.js";
7
+ import { logger } from "./globalLogger.js";
7
8
  const HISTORY_VERSION = 1;
8
9
  const MAX_HISTORY_SIZE = 1000;
9
10
  /**
@@ -15,8 +16,8 @@ const ensureDataDirectory = () => {
15
16
  fs.mkdirSync(DATA_DIRECTORY, { recursive: true });
16
17
  }
17
18
  }
18
- catch {
19
- // logger.debug("Failed to create data directory:", error);
19
+ catch (error) {
20
+ logger.debug("Failed to create data directory:", error);
20
21
  }
21
22
  };
22
23
  /**
@@ -35,7 +36,7 @@ export const loadBashHistory = () => {
35
36
  const history = JSON.parse(data);
36
37
  // Version compatibility check
37
38
  if (history.version !== HISTORY_VERSION) {
38
- // logger.debug("Bash history version mismatch, resetting history");
39
+ logger.debug("Bash history version mismatch, resetting history");
39
40
  return {
40
41
  commands: [],
41
42
  version: HISTORY_VERSION,
@@ -43,8 +44,8 @@ export const loadBashHistory = () => {
43
44
  }
44
45
  return history;
45
46
  }
46
- catch {
47
- // logger.debug("Failed to load bash history:", error);
47
+ catch (error) {
48
+ logger.debug("Failed to load bash history:", error);
48
49
  return {
49
50
  commands: [],
50
51
  version: HISTORY_VERSION,
@@ -58,7 +59,7 @@ export const saveBashHistory = (history) => {
58
59
  try {
59
60
  // Skip saving to file when in test environment
60
61
  if (process.env.NODE_ENV === "test") {
61
- // logger.debug("Skipping bash history save in test environment");
62
+ logger.debug("Skipping bash history save in test environment");
62
63
  return;
63
64
  }
64
65
  ensureDataDirectory();
@@ -69,8 +70,8 @@ export const saveBashHistory = (history) => {
69
70
  const data = JSON.stringify(history, null, 2);
70
71
  fs.writeFileSync(BASH_HISTORY_FILE, data, "utf-8");
71
72
  }
72
- catch {
73
- // logger.debug("Failed to save bash history:", error);
73
+ catch (error) {
74
+ logger.debug("Failed to save bash history:", error);
74
75
  }
75
76
  };
76
77
  /**
@@ -78,11 +79,6 @@ export const saveBashHistory = (history) => {
78
79
  */
79
80
  export const addBashCommandToHistory = (command, workdir) => {
80
81
  try {
81
- // Filter system-generated commands, do not add to history
82
- if (command.startsWith("git add . && git commit -m")) {
83
- // logger.debug("Skipping system-generated command:", { command, workdir });
84
- return;
85
- }
86
82
  const history = loadBashHistory();
87
83
  const timestamp = Date.now();
88
84
  // Check if it's a duplicate consecutive command to avoid duplicate recording
@@ -102,10 +98,10 @@ export const addBashCommandToHistory = (command, workdir) => {
102
98
  });
103
99
  }
104
100
  saveBashHistory(history);
105
- // logger.debug("Added bash command to history:", { command, workdir });
101
+ logger.debug("Added bash command to history:", { command, workdir });
106
102
  }
107
- catch {
108
- // logger.debug("Failed to add bash command to history:", error);
103
+ catch (error) {
104
+ logger.debug("Failed to add bash command to history:", error);
109
105
  }
110
106
  };
111
107
  /**
@@ -121,7 +117,7 @@ export const searchBashHistory = (query, limit = 10, workdir) => {
121
117
  if (!normalizedQuery) {
122
118
  // If no search query, return recent commands (deduplicated)
123
119
  const deduped = deduplicateCommands(filteredCommands);
124
- return deduped.slice(-limit).reverse(); // Latest first
120
+ return deduped.slice(0, limit); // Latest first
125
121
  }
126
122
  // Search by relevance
127
123
  const matches = filteredCommands
@@ -156,11 +152,16 @@ export const searchBashHistory = (query, limit = 10, workdir) => {
156
152
  // Deduplicate search results, keep latest record
157
153
  const dedupedMatches = deduplicateCommands(matches);
158
154
  const result = dedupedMatches.slice(0, limit);
159
- // logger.debug("Bash history search results:", { query, workdir: process.cwd(), originalCount: matches.length, dedupedCount: result.length });
155
+ logger.debug("Bash history search results:", {
156
+ query,
157
+ workdir: process.cwd(),
158
+ originalCount: matches.length,
159
+ dedupedCount: result.length,
160
+ });
160
161
  return result;
161
162
  }
162
- catch {
163
- // logger.debug("Failed to search bash history:", error);
163
+ catch (error) {
164
+ logger.debug("Failed to search bash history:", error);
164
165
  return [];
165
166
  }
166
167
  };
@@ -176,8 +177,8 @@ const deduplicateCommands = (commands) => {
176
177
  commandMap.set(entry.command, entry);
177
178
  }
178
179
  }
179
- // Sort by timestamp and return
180
- return Array.from(commandMap.values()).sort((a, b) => a.timestamp - b.timestamp);
180
+ // Sort by timestamp and return (new to old)
181
+ return Array.from(commandMap.values()).sort((a, b) => b.timestamp - a.timestamp);
181
182
  };
182
183
  /**
183
184
  * Get recently used bash commands
@@ -188,13 +189,30 @@ export const getRecentBashCommands = (workdir, limit = 10) => {
188
189
  const filtered = history.commands.filter((entry) => entry.workdir === workdir);
189
190
  // Return recent commands after deduplication
190
191
  const deduped = deduplicateCommands(filtered);
191
- return deduped.slice(-limit).reverse(); // Latest first
192
+ return deduped.slice(0, limit); // Latest first
192
193
  }
193
- catch {
194
- // logger.debug("Failed to get recent bash commands:", error);
194
+ catch (error) {
195
+ logger.debug("Failed to get recent bash commands:", error);
195
196
  return [];
196
197
  }
197
198
  };
199
+ /**
200
+ * Delete a specific command from bash history
201
+ */
202
+ export const deleteBashCommandFromHistory = (command, workdir) => {
203
+ try {
204
+ const history = loadBashHistory();
205
+ const initialLength = history.commands.length;
206
+ history.commands = history.commands.filter((entry) => !(entry.command === command && entry.workdir === workdir));
207
+ if (history.commands.length !== initialLength) {
208
+ saveBashHistory(history);
209
+ logger.debug("Deleted bash command from history:", { command, workdir });
210
+ }
211
+ }
212
+ catch (error) {
213
+ logger.debug("Failed to delete bash command from history:", error);
214
+ }
215
+ };
198
216
  /**
199
217
  * Clear bash history
200
218
  */
@@ -205,10 +223,10 @@ export const clearBashHistory = () => {
205
223
  version: HISTORY_VERSION,
206
224
  };
207
225
  saveBashHistory(history);
208
- // logger.debug("Bash history cleared");
226
+ logger.debug("Bash history cleared");
209
227
  }
210
- catch {
211
- // logger.debug("Failed to clear bash history:", error);
228
+ catch (error) {
229
+ logger.debug("Failed to clear bash history:", error);
212
230
  }
213
231
  };
214
232
  /**
@@ -225,8 +243,8 @@ export const getBashCommandStats = () => {
225
243
  workdirs,
226
244
  };
227
245
  }
228
- catch {
229
- // logger.debug("Failed to get bash command stats:", error);
246
+ catch (error) {
247
+ logger.debug("Failed to get bash command stats:", error);
230
248
  return {
231
249
  totalCommands: 0,
232
250
  uniqueCommands: 0,
@@ -0,0 +1,7 @@
1
+ import type { SubagentConfiguration } from "./subagentParser.js";
2
+ /**
3
+ * Get all built-in subagent configurations
4
+ * Built-in subagents have priority 3 (lowest) and can be overridden by user/project configs
5
+ */
6
+ export declare function getBuiltinSubagents(): SubagentConfiguration[];
7
+ //# sourceMappingURL=builtinSubagents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtinSubagents.d.ts","sourceRoot":"","sources":["../../src/utils/builtinSubagents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjE;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,qBAAqB,EAAE,CAK7D"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Get all built-in subagent configurations
3
+ * Built-in subagents have priority 3 (lowest) and can be overridden by user/project configs
4
+ */
5
+ export function getBuiltinSubagents() {
6
+ return [
7
+ createExploreSubagent(),
8
+ // Add more built-in subagents here as needed
9
+ ];
10
+ }
11
+ /**
12
+ * Create the Explore built-in subagent configuration
13
+ * Specialized for codebase exploration and file search tasks
14
+ */
15
+ function createExploreSubagent() {
16
+ const systemPrompt = `You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
17
+
18
+ === CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS ===
19
+ This is a READ-ONLY exploration task. You are STRICTLY PROHIBITED from:
20
+ - Creating new files (no Write, touch, or file creation of any kind)
21
+ - Modifying existing files (no Edit operations)
22
+ - Deleting files (no rm or deletion)
23
+ - Moving or copying files (no mv or cp)
24
+ - Creating temporary files anywhere, including /tmp
25
+ - Using redirect operators (>, >>, |) or heredocs to write to files
26
+ - Running ANY commands that change system state
27
+
28
+ Your role is EXCLUSIVELY to search and analyze existing code. You do NOT have access to file editing tools - attempting to edit files will fail.
29
+
30
+ Your strengths:
31
+ - Rapidly finding files using glob patterns
32
+ - Searching code and text with powerful regex patterns
33
+ - Reading and analyzing file contents
34
+ - Using Language Server Protocol (LSP) for deep code intelligence (definitions, references, etc.)
35
+
36
+ Guidelines:
37
+ - Use Glob for broad file pattern matching
38
+ - Use Grep for searching file contents with regex
39
+ - Use Read when you know the specific file path you need to read
40
+ - Use LSP for code intelligence features like finding definitions, references, implementations, and symbols. This is especially useful for understanding complex code relationships.
41
+ - Use Bash ONLY for read-only operations (ls, git status, git log, git diff, find, cat, head, tail)
42
+ - NEVER use Bash for: mkdir, touch, rm, cp, mv, git add, git commit, npm install, pip install, or any file creation/modification
43
+ - Adapt your search approach based on the thoroughness level specified by the caller
44
+ - Return file paths as absolute paths in your final response
45
+ - For clear communication, avoid using emojis
46
+ - Communicate your final report directly as a regular message - do NOT attempt to create files
47
+
48
+ NOTE: You are meant to be a fast agent that returns output as quickly as possible. In order to achieve this you must:
49
+ - Make efficient use of the tools that you have at your disposal: be smart about how you search for files and implementations
50
+ - Wherever possible you should try to spawn multiple parallel tool calls for grepping and reading files
51
+
52
+ Complete the user's search request efficiently and report your findings clearly.`;
53
+ // Define allowed tools for read-only operations
54
+ const allowedTools = ["Glob", "Grep", "Read", "Bash", "LS", "LSP"];
55
+ return {
56
+ name: "Explore",
57
+ description: 'Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?"). When calling this agent, specify the desired thoroughness level: "quick" for basic searches, "medium" for moderate exploration, or "very thorough" for comprehensive analysis across multiple locations and naming conventions.',
58
+ systemPrompt,
59
+ tools: allowedTools,
60
+ model: "fastModel", // Special value that will use parent's fastModel
61
+ filePath: "<builtin:Explore>",
62
+ scope: "builtin",
63
+ priority: 3, // Lowest priority - can be overridden by user configs
64
+ };
65
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Cache Control Utilities for Claude Models
3
+ *
4
+ * This module provides utilities for adding cache_control markers to Claude models
5
+ * to optimize token usage and reduce costs. Cache control is only applied to Claude
6
+ * models and preserves backward compatibility with existing message formats.
7
+ */
8
+ import type { ChatCompletionMessageParam, ChatCompletionContentPart, ChatCompletionContentPartText, ChatCompletionFunctionTool, CompletionUsage } from "openai/resources";
9
+ /**
10
+ * Cache control directive for Claude models
11
+ */
12
+ export interface CacheControl {
13
+ type: "ephemeral";
14
+ }
15
+ /**
16
+ * Extended text content part with cache control support
17
+ */
18
+ export interface ClaudeChatCompletionContentPartText extends ChatCompletionContentPartText {
19
+ type: "text";
20
+ text: string;
21
+ cache_control?: CacheControl;
22
+ }
23
+ /**
24
+ * Extended tool definition with cache control support
25
+ */
26
+ export interface ClaudeChatCompletionFunctionTool extends ChatCompletionFunctionTool {
27
+ type: "function";
28
+ function: ChatCompletionFunctionTool["function"];
29
+ cache_control?: CacheControl;
30
+ }
31
+ /**
32
+ * Enhanced usage metrics including Claude cache information
33
+ */
34
+ export interface ClaudeUsage extends CompletionUsage {
35
+ prompt_tokens: number;
36
+ completion_tokens: number;
37
+ total_tokens: number;
38
+ cache_read_input_tokens?: number;
39
+ cache_creation_input_tokens?: number;
40
+ cache_creation?: {
41
+ ephemeral_5m_input_tokens: number;
42
+ ephemeral_1h_input_tokens: number;
43
+ };
44
+ }
45
+ /**
46
+ * Determines if a model supports cache control
47
+ * @param modelName - Model identifier
48
+ * @returns True if model name contains 'claude' (case-insensitive)
49
+ */
50
+ export declare function isClaudeModel(modelName: string): boolean;
51
+ /**
52
+ * Validates cache control structure
53
+ * @param control - Object to validate
54
+ * @returns True if valid cache control object
55
+ */
56
+ export declare function isValidCacheControl(control: unknown): control is CacheControl;
57
+ /**
58
+ * Adds cache control markers to message content
59
+ * @param content - Original content (string or structured)
60
+ * @param shouldCache - Whether to add cache control
61
+ * @returns Structured content with cache control markers
62
+ */
63
+ export declare function addCacheControlToContent(content: string | ChatCompletionContentPart[], shouldCache: boolean): ClaudeChatCompletionContentPartText[];
64
+ /**
65
+ * Adds cache control to the last tool in tools array
66
+ * @param tools - Array of tool definitions
67
+ * @returns Tools array with cache control on last tool
68
+ */
69
+ export declare function addCacheControlToLastTool(tools: ChatCompletionFunctionTool[]): ClaudeChatCompletionFunctionTool[];
70
+ /**
71
+ * Finds the latest message index at 20-message intervals (sliding window approach)
72
+ * @param messages - Array of chat completion messages
73
+ * @returns Index of the latest interval message (20th, 40th, 60th, etc.) or -1 if none
74
+ */
75
+ export declare function findIntervalMessageIndex(messages: ChatCompletionMessageParam[]): number;
76
+ /**
77
+ * Transforms messages for Claude cache control with hardcoded strategy
78
+ * @param messages - Original OpenAI message array
79
+ * @param modelName - Model name for cache detection
80
+ * @returns Messages with cache control markers applied
81
+ */
82
+ export declare function transformMessagesForClaudeCache(messages: ChatCompletionMessageParam[], modelName: string): ChatCompletionMessageParam[];
83
+ /**
84
+ * Extends standard usage with cache metrics
85
+ * @param standardUsage - OpenAI usage response
86
+ * @param cacheMetrics - Additional cache metrics from Claude
87
+ * @returns Extended usage with cache information
88
+ */
89
+ export declare function extendUsageWithCacheMetrics(standardUsage: CompletionUsage, cacheMetrics?: Partial<ClaudeUsage>): ClaudeUsage;
90
+ /**
91
+ * Validates Claude usage structure
92
+ * @param usage - Usage object to validate
93
+ * @returns True if usage structure is valid
94
+ */
95
+ export declare function isValidClaudeUsage(usage: unknown): usage is ClaudeUsage;
96
+ //# sourceMappingURL=cacheControlUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cacheControlUtils.d.ts","sourceRoot":"","sources":["../../src/utils/cacheControlUtils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,6BAA6B,EAC7B,0BAA0B,EAE1B,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAO1B;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,WAAW,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,mCACf,SAAQ,6BAA6B;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,YAAY,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,gCACf,SAAQ,0BAA0B;IAClC,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC;IACjD,aAAa,CAAC,EAAE,YAAY,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,eAAe;IAClD,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IAGrB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,cAAc,CAAC,EAAE;QACf,yBAAyB,EAAE,MAAM,CAAC;QAClC,yBAAyB,EAAE,MAAM,CAAC;KACnC,CAAC;CACH;AAUD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAaxD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,YAAY,CAQ7E;AA0BD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,GAAG,yBAAyB,EAAE,EAC7C,WAAW,EAAE,OAAO,GACnB,mCAAmC,EAAE,CAkEvC;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,0BAA0B,EAAE,GAClC,gCAAgC,EAAE,CAwCpC;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,0BAA0B,EAAE,GACrC,MAAM,CAoBR;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,0BAA0B,EAAE,EACtC,SAAS,EAAE,MAAM,GAChB,0BAA0B,EAAE,CAoF9B;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,eAAe,EAC9B,YAAY,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAClC,WAAW,CAkCb;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAyCvE"}
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Cache Control Utilities for Claude Models
3
+ *
4
+ * This module provides utilities for adding cache_control markers to Claude models
5
+ * to optimize token usage and reduce costs. Cache control is only applied to Claude
6
+ * models and preserves backward compatibility with existing message formats.
7
+ */
8
+ import { logger } from "./globalLogger.js";
9
+ // ============================================================================
10
+ // Default Configuration
11
+ // ============================================================================
12
+ // ============================================================================
13
+ // Utility Functions (Basic Structure - to be implemented)
14
+ // ============================================================================
15
+ /**
16
+ * Determines if a model supports cache control
17
+ * @param modelName - Model identifier
18
+ * @returns True if model name contains 'claude' (case-insensitive)
19
+ */
20
+ export function isClaudeModel(modelName) {
21
+ // Handle null, undefined, and non-string inputs
22
+ if (!modelName || typeof modelName !== "string") {
23
+ return false;
24
+ }
25
+ // Handle empty strings and whitespace-only strings
26
+ const trimmed = modelName.trim();
27
+ if (trimmed.length === 0) {
28
+ return false;
29
+ }
30
+ return trimmed.toLowerCase().includes("claude");
31
+ }
32
+ /**
33
+ * Validates cache control structure
34
+ * @param control - Object to validate
35
+ * @returns True if valid cache control object
36
+ */
37
+ export function isValidCacheControl(control) {
38
+ return (control !== null &&
39
+ typeof control === "object" &&
40
+ control !== undefined &&
41
+ "type" in control &&
42
+ control.type === "ephemeral");
43
+ }
44
+ /**
45
+ * Adds cache control to the last tool call in an array
46
+ * @param toolCalls - Array of tool calls
47
+ * @returns Tool calls array with cache control on the last tool call
48
+ */
49
+ function addCacheControlToLastToolCall(toolCalls) {
50
+ if (!toolCalls || toolCalls.length === 0) {
51
+ return toolCalls;
52
+ }
53
+ const result = [...toolCalls];
54
+ const lastIndex = result.length - 1;
55
+ // Add cache control to the last tool call
56
+ result[lastIndex] = {
57
+ ...result[lastIndex],
58
+ cache_control: { type: "ephemeral" },
59
+ };
60
+ return result;
61
+ }
62
+ /**
63
+ * Adds cache control markers to message content
64
+ * @param content - Original content (string or structured)
65
+ * @param shouldCache - Whether to add cache control
66
+ * @returns Structured content with cache control markers
67
+ */
68
+ export function addCacheControlToContent(content, shouldCache) {
69
+ // Handle null/undefined content
70
+ if (content == null) {
71
+ return [];
72
+ }
73
+ // If shouldCache is false, return content as text parts without cache control
74
+ if (!shouldCache) {
75
+ if (typeof content === "string") {
76
+ return [{ type: "text", text: content }];
77
+ }
78
+ // Validate array input
79
+ if (!Array.isArray(content)) {
80
+ logger.warn("Invalid content type for cache control transformation:", typeof content);
81
+ return [];
82
+ }
83
+ // Filter and convert only text parts with validation
84
+ return content
85
+ .filter((part) => {
86
+ if (!part || typeof part !== "object") {
87
+ return false;
88
+ }
89
+ return part.type === "text" && typeof part.text === "string";
90
+ })
91
+ .map((part) => ({ type: "text", text: part.text }));
92
+ }
93
+ // shouldCache is true - add cache control markers
94
+ if (typeof content === "string") {
95
+ // Transform string content to structured array with cache control
96
+ return [
97
+ {
98
+ type: "text",
99
+ text: content,
100
+ cache_control: { type: "ephemeral" },
101
+ },
102
+ ];
103
+ }
104
+ // Validate array input
105
+ if (!Array.isArray(content)) {
106
+ logger.warn("Invalid content type for cache control transformation:", typeof content);
107
+ return [];
108
+ }
109
+ // Handle structured content - preserve existing structure, add cache control to text parts
110
+ return content
111
+ .filter((part) => {
112
+ if (!part || typeof part !== "object") {
113
+ return false;
114
+ }
115
+ return part.type === "text" && typeof part.text === "string";
116
+ })
117
+ .map((part) => ({
118
+ type: "text",
119
+ text: part.text,
120
+ cache_control: { type: "ephemeral" },
121
+ }));
122
+ }
123
+ /**
124
+ * Adds cache control to the last tool in tools array
125
+ * @param tools - Array of tool definitions
126
+ * @returns Tools array with cache control on last tool
127
+ */
128
+ export function addCacheControlToLastTool(tools) {
129
+ // Handle null, undefined, or empty arrays
130
+ if (!tools || !Array.isArray(tools) || tools.length === 0) {
131
+ return [];
132
+ }
133
+ // Validate tools structure
134
+ const validTools = tools.filter((tool) => {
135
+ if (!tool || typeof tool !== "object") {
136
+ logger.warn("Invalid tool structure detected, skipping:", tool);
137
+ return false;
138
+ }
139
+ if (tool.type !== "function" || !tool.function) {
140
+ logger.warn("Tool is not a function type or missing function property:", tool);
141
+ return false;
142
+ }
143
+ return true;
144
+ });
145
+ if (validTools.length === 0) {
146
+ logger.warn("No valid tools found for cache control");
147
+ return [];
148
+ }
149
+ // Create a copy of the valid tools array
150
+ const result = validTools.map((tool) => ({
151
+ ...tool,
152
+ }));
153
+ // Add cache control to the last tool only
154
+ const lastIndex = result.length - 1;
155
+ result[lastIndex] = {
156
+ ...result[lastIndex],
157
+ cache_control: { type: "ephemeral" },
158
+ };
159
+ return result;
160
+ }
161
+ /**
162
+ * Finds the latest message index at 20-message intervals (sliding window approach)
163
+ * @param messages - Array of chat completion messages
164
+ * @returns Index of the latest interval message (20th, 40th, 60th, etc.) or -1 if none
165
+ */
166
+ export function findIntervalMessageIndex(messages) {
167
+ if (!Array.isArray(messages) || messages.length === 0) {
168
+ return -1;
169
+ }
170
+ const interval = 20; // Hardcoded interval
171
+ const messageCount = messages.length;
172
+ // Find the largest interval that fits within the message count
173
+ // Math.floor(messageCount / interval) gives us how many complete intervals we have
174
+ // Multiply by interval to get the position of the latest interval message
175
+ const latestIntervalPosition = Math.floor(messageCount / interval) * interval;
176
+ // If no complete intervals exist, return -1
177
+ if (latestIntervalPosition === 0) {
178
+ return -1;
179
+ }
180
+ // Convert from 1-based position to 0-based index
181
+ return latestIntervalPosition - 1;
182
+ }
183
+ /**
184
+ * Transforms messages for Claude cache control with hardcoded strategy
185
+ * @param messages - Original OpenAI message array
186
+ * @param modelName - Model name for cache detection
187
+ * @returns Messages with cache control markers applied
188
+ */
189
+ export function transformMessagesForClaudeCache(messages, modelName) {
190
+ // Validate inputs
191
+ if (!messages || !Array.isArray(messages)) {
192
+ logger.warn("Invalid messages array provided to transformMessagesForClaudeCache");
193
+ return [];
194
+ }
195
+ if (messages.length === 0) {
196
+ return [];
197
+ }
198
+ // Only apply cache control for Claude models
199
+ if (!isClaudeModel(modelName)) {
200
+ return messages;
201
+ }
202
+ // Find the latest interval message index (20th, 40th, 60th, etc.)
203
+ const intervalMessageIndex = findIntervalMessageIndex(messages);
204
+ // Find last system message index
205
+ let lastSystemIndex = -1;
206
+ for (let i = messages.length - 1; i >= 0; i--) {
207
+ if (messages[i].role === "system") {
208
+ lastSystemIndex = i;
209
+ break;
210
+ }
211
+ }
212
+ const result = messages.map((message, index) => {
213
+ // Validate message structure
214
+ if (!message || typeof message !== "object" || !message.role) {
215
+ logger.warn("Invalid message structure at index", index, ":", message);
216
+ return message; // Return as-is to avoid breaking the flow
217
+ }
218
+ // Last system message: always cached (hardcoded)
219
+ if (message.role === "system" && index === lastSystemIndex) {
220
+ return {
221
+ ...message,
222
+ content: addCacheControlToContent(message.content || "", true),
223
+ };
224
+ }
225
+ // Interval-based message caching: cache message at latest interval position (sliding window)
226
+ if (index === intervalMessageIndex) {
227
+ // If the message is a tool role, add cache control directly to the message
228
+ if (message.role === "tool") {
229
+ return {
230
+ ...message,
231
+ cache_control: { type: "ephemeral" },
232
+ };
233
+ }
234
+ // If the message has tool calls, cache the last tool call instead of content
235
+ else if (message.role === "assistant" &&
236
+ message.tool_calls &&
237
+ message.tool_calls.length > 0) {
238
+ return {
239
+ ...message,
240
+ tool_calls: addCacheControlToLastToolCall(message.tool_calls),
241
+ };
242
+ }
243
+ else {
244
+ // For other message types without tool calls, cache the content
245
+ return {
246
+ ...message,
247
+ content: addCacheControlToContent(message.content || "", true),
248
+ };
249
+ }
250
+ }
251
+ // Return message unchanged
252
+ return message;
253
+ });
254
+ return result;
255
+ }
256
+ /**
257
+ * Extends standard usage with cache metrics
258
+ * @param standardUsage - OpenAI usage response
259
+ * @param cacheMetrics - Additional cache metrics from Claude
260
+ * @returns Extended usage with cache information
261
+ */
262
+ export function extendUsageWithCacheMetrics(standardUsage, cacheMetrics) {
263
+ const baseUsage = {
264
+ prompt_tokens: standardUsage.prompt_tokens,
265
+ completion_tokens: standardUsage.completion_tokens,
266
+ total_tokens: standardUsage.total_tokens,
267
+ };
268
+ // Add cache metrics if provided
269
+ if (cacheMetrics) {
270
+ if (typeof cacheMetrics.cache_read_input_tokens === "number") {
271
+ baseUsage.cache_read_input_tokens = cacheMetrics.cache_read_input_tokens;
272
+ }
273
+ if (typeof cacheMetrics.cache_creation_input_tokens === "number") {
274
+ baseUsage.cache_creation_input_tokens =
275
+ cacheMetrics.cache_creation_input_tokens;
276
+ }
277
+ if (cacheMetrics.cache_creation &&
278
+ typeof cacheMetrics.cache_creation.ephemeral_5m_input_tokens ===
279
+ "number" &&
280
+ typeof cacheMetrics.cache_creation.ephemeral_1h_input_tokens === "number") {
281
+ baseUsage.cache_creation = {
282
+ ephemeral_5m_input_tokens: cacheMetrics.cache_creation.ephemeral_5m_input_tokens,
283
+ ephemeral_1h_input_tokens: cacheMetrics.cache_creation.ephemeral_1h_input_tokens,
284
+ };
285
+ }
286
+ }
287
+ return baseUsage;
288
+ }
289
+ /**
290
+ * Validates Claude usage structure
291
+ * @param usage - Usage object to validate
292
+ * @returns True if usage structure is valid
293
+ */
294
+ export function isValidClaudeUsage(usage) {
295
+ if (!usage || typeof usage !== "object") {
296
+ return false;
297
+ }
298
+ const usageObj = usage;
299
+ // Check required standard fields
300
+ const hasStandardFields = typeof usageObj.prompt_tokens === "number" &&
301
+ typeof usageObj.completion_tokens === "number" &&
302
+ typeof usageObj.total_tokens === "number";
303
+ if (!hasStandardFields) {
304
+ return false;
305
+ }
306
+ // Check optional cache fields
307
+ const hasCacheFields = (usageObj.cache_read_input_tokens === undefined ||
308
+ typeof usageObj.cache_read_input_tokens === "number") &&
309
+ (usageObj.cache_creation_input_tokens === undefined ||
310
+ typeof usageObj.cache_creation_input_tokens === "number");
311
+ if (!hasCacheFields) {
312
+ return false;
313
+ }
314
+ // Check cache_creation object if present
315
+ if (usageObj.cache_creation !== undefined) {
316
+ const cacheCreation = usageObj.cache_creation;
317
+ if (typeof cacheCreation !== "object" ||
318
+ typeof cacheCreation.ephemeral_5m_input_tokens !== "number" ||
319
+ typeof cacheCreation.ephemeral_1h_input_tokens !== "number") {
320
+ return false;
321
+ }
322
+ }
323
+ return true;
324
+ }