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.
- package/dist/agent.d.ts +105 -24
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +438 -53
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/managers/aiManager.d.ts +18 -7
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +254 -142
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/managers/backgroundBashManager.js +11 -9
- package/dist/managers/hookManager.d.ts +6 -6
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +81 -39
- package/dist/managers/liveConfigManager.d.ts +95 -0
- package/dist/managers/liveConfigManager.d.ts.map +1 -0
- package/dist/managers/liveConfigManager.js +442 -0
- package/dist/managers/lspManager.d.ts +43 -0
- package/dist/managers/lspManager.d.ts.map +1 -0
- package/dist/managers/lspManager.js +326 -0
- package/dist/managers/messageManager.d.ts +41 -24
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +184 -73
- package/dist/managers/permissionManager.d.ts +66 -0
- package/dist/managers/permissionManager.d.ts.map +1 -0
- package/dist/managers/permissionManager.js +208 -0
- package/dist/managers/skillManager.d.ts +1 -0
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/skillManager.js +2 -1
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +4 -2
- package/dist/managers/subagentManager.d.ts +42 -6
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +213 -62
- package/dist/managers/toolManager.d.ts +38 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +66 -2
- package/dist/services/aiService.d.ts +15 -5
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +446 -77
- package/dist/services/configurationService.d.ts +116 -0
- package/dist/services/configurationService.d.ts.map +1 -0
- package/dist/services/configurationService.js +585 -0
- package/dist/services/fileWatcher.d.ts +69 -0
- package/dist/services/fileWatcher.d.ts.map +1 -0
- package/dist/services/fileWatcher.js +212 -0
- package/dist/services/hook.d.ts +5 -40
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +47 -109
- package/dist/services/jsonlHandler.d.ts +71 -0
- package/dist/services/jsonlHandler.d.ts.map +1 -0
- package/dist/services/jsonlHandler.js +236 -0
- package/dist/services/memory.d.ts.map +1 -1
- package/dist/services/memory.js +33 -11
- package/dist/services/session.d.ts +116 -52
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +415 -143
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +77 -17
- package/dist/tools/deleteFileTool.d.ts.map +1 -1
- package/dist/tools/deleteFileTool.js +27 -1
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +33 -8
- package/dist/tools/lspTool.d.ts +6 -0
- package/dist/tools/lspTool.d.ts.map +1 -0
- package/dist/tools/lspTool.js +589 -0
- package/dist/tools/multiEditTool.d.ts.map +1 -1
- package/dist/tools/multiEditTool.js +30 -10
- package/dist/tools/readTool.d.ts.map +1 -1
- package/dist/tools/readTool.js +113 -3
- package/dist/tools/skillTool.js +2 -2
- package/dist/tools/todoWriteTool.d.ts.map +1 -1
- package/dist/tools/todoWriteTool.js +23 -0
- package/dist/tools/types.d.ts +11 -8
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/writeTool.d.ts.map +1 -1
- package/dist/tools/writeTool.js +30 -15
- package/dist/types/commands.d.ts +4 -1
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/types/config.d.ts +4 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/configuration.d.ts +69 -0
- package/dist/types/configuration.d.ts.map +1 -0
- package/dist/types/configuration.js +8 -0
- package/dist/types/core.d.ts +45 -0
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/environment.d.ts +83 -0
- package/dist/types/environment.d.ts.map +1 -0
- package/dist/types/environment.js +21 -0
- package/dist/types/fileSearch.d.ts +5 -0
- package/dist/types/fileSearch.d.ts.map +1 -0
- package/dist/types/fileSearch.js +1 -0
- package/dist/types/hooks.d.ts +18 -3
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +8 -8
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +7 -0
- package/dist/types/lsp.d.ts +90 -0
- package/dist/types/lsp.d.ts.map +1 -0
- package/dist/types/lsp.js +4 -0
- package/dist/types/messaging.d.ts +19 -12
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/permissions.d.ts +35 -0
- package/dist/types/permissions.d.ts.map +1 -0
- package/dist/types/permissions.js +12 -0
- package/dist/types/session.d.ts +15 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +7 -0
- package/dist/types/skills.d.ts +1 -0
- package/dist/types/skills.d.ts.map +1 -1
- package/dist/types/tools.d.ts +35 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +4 -0
- package/dist/utils/abortUtils.d.ts +34 -0
- package/dist/utils/abortUtils.d.ts.map +1 -0
- package/dist/utils/abortUtils.js +92 -0
- package/dist/utils/bashHistory.d.ts +4 -0
- package/dist/utils/bashHistory.d.ts.map +1 -1
- package/dist/utils/bashHistory.js +48 -30
- package/dist/utils/builtinSubagents.d.ts +7 -0
- package/dist/utils/builtinSubagents.d.ts.map +1 -0
- package/dist/utils/builtinSubagents.js +65 -0
- package/dist/utils/cacheControlUtils.d.ts +96 -0
- package/dist/utils/cacheControlUtils.d.ts.map +1 -0
- package/dist/utils/cacheControlUtils.js +324 -0
- package/dist/utils/commandPathResolver.d.ts +52 -0
- package/dist/utils/commandPathResolver.d.ts.map +1 -0
- package/dist/utils/commandPathResolver.js +145 -0
- package/dist/utils/configPaths.d.ts +85 -0
- package/dist/utils/configPaths.d.ts.map +1 -0
- package/dist/utils/configPaths.js +121 -0
- package/dist/utils/constants.d.ts +1 -13
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +2 -14
- package/dist/utils/convertMessagesForAPI.d.ts +2 -1
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/convertMessagesForAPI.js +39 -18
- package/dist/utils/customCommands.d.ts.map +1 -1
- package/dist/utils/customCommands.js +66 -21
- package/dist/utils/fileSearch.d.ts +14 -0
- package/dist/utils/fileSearch.d.ts.map +1 -0
- package/dist/utils/fileSearch.js +88 -0
- package/dist/utils/fileUtils.d.ts +27 -0
- package/dist/utils/fileUtils.d.ts.map +1 -0
- package/dist/utils/fileUtils.js +145 -0
- package/dist/utils/globalLogger.d.ts +88 -0
- package/dist/utils/globalLogger.d.ts.map +1 -0
- package/dist/utils/globalLogger.js +120 -0
- package/dist/utils/largeOutputHandler.d.ts +15 -0
- package/dist/utils/largeOutputHandler.d.ts.map +1 -0
- package/dist/utils/largeOutputHandler.js +40 -0
- package/dist/utils/markdownParser.d.ts.map +1 -1
- package/dist/utils/markdownParser.js +1 -17
- package/dist/utils/mcpUtils.d.ts.map +1 -1
- package/dist/utils/mcpUtils.js +25 -3
- package/dist/utils/messageOperations.d.ts +20 -18
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +30 -38
- package/dist/utils/pathEncoder.d.ts +108 -0
- package/dist/utils/pathEncoder.d.ts.map +1 -0
- package/dist/utils/pathEncoder.js +279 -0
- package/dist/utils/subagentParser.d.ts +2 -2
- package/dist/utils/subagentParser.d.ts.map +1 -1
- package/dist/utils/subagentParser.js +12 -8
- package/dist/utils/tokenCalculation.d.ts +26 -0
- package/dist/utils/tokenCalculation.d.ts.map +1 -0
- package/dist/utils/tokenCalculation.js +36 -0
- package/dist/utils/tokenEstimator.d.ts +39 -0
- package/dist/utils/tokenEstimator.d.ts.map +1 -0
- package/dist/utils/tokenEstimator.js +55 -0
- package/package.json +6 -6
- package/src/agent.ts +586 -78
- package/src/index.ts +4 -0
- package/src/managers/aiManager.ts +341 -192
- package/src/managers/backgroundBashManager.ts +11 -9
- package/src/managers/hookManager.ts +102 -54
- package/src/managers/liveConfigManager.ts +634 -0
- package/src/managers/lspManager.ts +434 -0
- package/src/managers/messageManager.ts +258 -121
- package/src/managers/permissionManager.ts +276 -0
- package/src/managers/skillManager.ts +3 -1
- package/src/managers/slashCommandManager.ts +5 -3
- package/src/managers/subagentManager.ts +295 -76
- package/src/managers/toolManager.ts +95 -3
- package/src/services/aiService.ts +656 -84
- package/src/services/configurationService.ts +762 -0
- package/src/services/fileWatcher.ts +300 -0
- package/src/services/hook.ts +54 -144
- package/src/services/jsonlHandler.ts +303 -0
- package/src/services/memory.ts +34 -11
- package/src/services/session.ts +522 -173
- package/src/tools/bashTool.ts +94 -20
- package/src/tools/deleteFileTool.ts +38 -1
- package/src/tools/editTool.ts +44 -9
- package/src/tools/lspTool.ts +760 -0
- package/src/tools/multiEditTool.ts +41 -11
- package/src/tools/readTool.ts +127 -3
- package/src/tools/skillTool.ts +2 -2
- package/src/tools/todoWriteTool.ts +33 -1
- package/src/tools/types.ts +15 -9
- package/src/tools/writeTool.ts +43 -16
- package/src/types/commands.ts +6 -1
- package/src/types/config.ts +5 -0
- package/src/types/configuration.ts +73 -0
- package/src/types/core.ts +55 -0
- package/src/types/environment.ts +104 -0
- package/src/types/fileSearch.ts +4 -0
- package/src/types/hooks.ts +32 -16
- package/src/types/index.ts +7 -0
- package/src/types/lsp.ts +96 -0
- package/src/types/messaging.ts +21 -14
- package/src/types/permissions.ts +48 -0
- package/src/types/session.ts +20 -0
- package/src/types/skills.ts +1 -0
- package/src/types/tools.ts +38 -0
- package/src/utils/abortUtils.ts +118 -0
- package/src/utils/bashHistory.ts +55 -31
- package/src/utils/builtinSubagents.ts +71 -0
- package/src/utils/cacheControlUtils.ts +475 -0
- package/src/utils/commandPathResolver.ts +189 -0
- package/src/utils/configPaths.ts +163 -0
- package/src/utils/constants.ts +2 -17
- package/src/utils/convertMessagesForAPI.ts +44 -18
- package/src/utils/customCommands.ts +90 -22
- package/src/utils/fileSearch.ts +107 -0
- package/src/utils/fileUtils.ts +160 -0
- package/src/utils/globalLogger.ts +128 -0
- package/src/utils/largeOutputHandler.ts +55 -0
- package/src/utils/markdownParser.ts +1 -19
- package/src/utils/mcpUtils.ts +34 -3
- package/src/utils/messageOperations.ts +47 -53
- package/src/utils/pathEncoder.ts +394 -0
- package/src/utils/subagentParser.ts +13 -9
- package/src/utils/tokenCalculation.ts +43 -0
- package/src/utils/tokenEstimator.ts +68 -0
- package/dist/utils/configResolver.d.ts +0 -38
- package/dist/utils/configResolver.d.ts.map +0 -1
- package/dist/utils/configResolver.js +0 -106
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
101
|
+
logger.debug("Added bash command to history:", { command, workdir });
|
|
106
102
|
}
|
|
107
|
-
catch {
|
|
108
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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) =>
|
|
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(
|
|
192
|
+
return deduped.slice(0, limit); // Latest first
|
|
192
193
|
}
|
|
193
|
-
catch {
|
|
194
|
-
|
|
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
|
-
|
|
226
|
+
logger.debug("Bash history cleared");
|
|
209
227
|
}
|
|
210
|
-
catch {
|
|
211
|
-
|
|
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
|
-
|
|
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
|
+
}
|