mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
Track edit_file variant tool usage in analytics
This commit is contained in:
parent
0126cb0b15
commit
33f3e402e5
24 changed files with 506 additions and 414 deletions
|
|
@ -15,8 +15,8 @@ export const geminiModels = {
|
|||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["low", "high"],
|
||||
reasoningEffort: "low",
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
supportsTemperature: true,
|
||||
defaultTemperature: 1,
|
||||
inputPrice: 4.0,
|
||||
|
|
@ -43,8 +43,8 @@ export const geminiModels = {
|
|||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
|
||||
reasoningEffort: "medium",
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
supportsTemperature: true,
|
||||
defaultTemperature: 1,
|
||||
inputPrice: 0.3,
|
||||
|
|
@ -60,8 +60,8 @@ export const geminiModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 2.5, // This is the pricing for prompts above 200k tokens.
|
||||
outputPrice: 15,
|
||||
cacheReadsPrice: 0.625,
|
||||
|
|
@ -91,8 +91,8 @@ export const geminiModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 2.5, // This is the pricing for prompts above 200k tokens.
|
||||
outputPrice: 15,
|
||||
cacheReadsPrice: 0.625,
|
||||
|
|
@ -121,8 +121,8 @@ export const geminiModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 2.5, // This is the pricing for prompts above 200k tokens.
|
||||
outputPrice: 15,
|
||||
cacheReadsPrice: 0.625,
|
||||
|
|
@ -149,8 +149,8 @@ export const geminiModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 2.5, // This is the pricing for prompts above 200k tokens.
|
||||
outputPrice: 15,
|
||||
cacheReadsPrice: 0.625,
|
||||
|
|
@ -181,8 +181,8 @@ export const geminiModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 2.5,
|
||||
cacheReadsPrice: 0.075,
|
||||
|
|
@ -197,8 +197,8 @@ export const geminiModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 2.5,
|
||||
cacheReadsPrice: 0.075,
|
||||
|
|
@ -213,8 +213,8 @@ export const geminiModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 2.5,
|
||||
cacheReadsPrice: 0.075,
|
||||
|
|
@ -231,8 +231,8 @@ export const geminiModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.4,
|
||||
cacheReadsPrice: 0.025,
|
||||
|
|
@ -247,8 +247,8 @@ export const geminiModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.4,
|
||||
cacheReadsPrice: 0.025,
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@ export const minimaxModels = {
|
|||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["search_and_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "anthropic",
|
||||
preserveReasoning: true,
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 1.2,
|
||||
|
|
@ -32,8 +31,7 @@ export const minimaxModels = {
|
|||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["search_and_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "anthropic",
|
||||
preserveReasoning: true,
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 1.2,
|
||||
|
|
@ -49,8 +47,7 @@ export const minimaxModels = {
|
|||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["search_and_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "anthropic",
|
||||
preserveReasoning: true,
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 1.2,
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
promptCacheRetention: "24h",
|
||||
|
|
@ -31,8 +31,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
promptCacheRetention: "24h",
|
||||
|
|
@ -54,8 +54,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 1.75,
|
||||
|
|
@ -68,8 +68,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
promptCacheRetention: "24h",
|
||||
|
|
@ -91,8 +91,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
promptCacheRetention: "24h",
|
||||
|
|
@ -110,8 +110,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
promptCacheRetention: "24h",
|
||||
|
|
@ -128,8 +128,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
|
||||
|
|
@ -150,8 +150,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
|
||||
|
|
@ -172,8 +172,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["low", "medium", "high"],
|
||||
|
|
@ -190,8 +190,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
|
||||
|
|
@ -209,8 +209,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 1.25,
|
||||
|
|
@ -223,8 +223,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 1_047_576,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 2,
|
||||
|
|
@ -240,8 +240,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 1_047_576,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0.4,
|
||||
|
|
@ -257,8 +257,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 1_047_576,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0.1,
|
||||
|
|
@ -483,8 +483,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
|
||||
|
|
@ -505,8 +505,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
|
||||
|
|
@ -527,8 +527,8 @@ export const openAiNativeModels = {
|
|||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ export const vertexModels = {
|
|||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["low", "high"],
|
||||
reasoningEffort: "low",
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
supportsTemperature: true,
|
||||
defaultTemperature: 1,
|
||||
inputPrice: 4.0,
|
||||
|
|
@ -43,8 +43,8 @@ export const vertexModels = {
|
|||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
|
||||
reasoningEffort: "medium",
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
supportsTemperature: true,
|
||||
defaultTemperature: 1,
|
||||
inputPrice: 0.3,
|
||||
|
|
@ -59,8 +59,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 3.5,
|
||||
maxThinkingTokens: 24_576,
|
||||
|
|
@ -74,8 +74,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.6,
|
||||
},
|
||||
|
|
@ -86,8 +86,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 2.5,
|
||||
cacheReadsPrice: 0.075,
|
||||
|
|
@ -102,8 +102,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 3.5,
|
||||
maxThinkingTokens: 24_576,
|
||||
|
|
@ -117,8 +117,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.6,
|
||||
},
|
||||
|
|
@ -129,8 +129,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 2.5,
|
||||
outputPrice: 15,
|
||||
},
|
||||
|
|
@ -141,8 +141,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 2.5,
|
||||
outputPrice: 15,
|
||||
},
|
||||
|
|
@ -153,8 +153,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 2.5,
|
||||
outputPrice: 15,
|
||||
maxThinkingTokens: 32_768,
|
||||
|
|
@ -167,8 +167,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 2.5,
|
||||
outputPrice: 15,
|
||||
maxThinkingTokens: 32_768,
|
||||
|
|
@ -196,8 +196,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
},
|
||||
|
|
@ -208,8 +208,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
},
|
||||
|
|
@ -220,8 +220,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.6,
|
||||
},
|
||||
|
|
@ -232,8 +232,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.075,
|
||||
outputPrice: 0.3,
|
||||
},
|
||||
|
|
@ -244,8 +244,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
},
|
||||
|
|
@ -256,8 +256,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.075,
|
||||
outputPrice: 0.3,
|
||||
},
|
||||
|
|
@ -268,8 +268,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 1.25,
|
||||
outputPrice: 5,
|
||||
},
|
||||
|
|
@ -463,8 +463,8 @@ export const vertexModels = {
|
|||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
includedTools: ["write_file", "edit_file"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "gemini",
|
||||
includedTools: ["write_file"],
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.4,
|
||||
cacheReadsPrice: 0.025,
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@ export const xaiModels = {
|
|||
cacheWritesPrice: 0.02,
|
||||
cacheReadsPrice: 0.02,
|
||||
description: "xAI's Grok Code Fast model with 256K context window",
|
||||
includedTools: ["search_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "grok",
|
||||
},
|
||||
"grok-4-1-fast-reasoning": {
|
||||
maxTokens: 65_536,
|
||||
|
|
@ -34,8 +33,7 @@ export const xaiModels = {
|
|||
cacheReadsPrice: 0.05,
|
||||
description:
|
||||
"xAI's Grok 4.1 Fast model with 2M context window, optimized for high-performance agentic tool calling with reasoning",
|
||||
includedTools: ["search_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "grok",
|
||||
},
|
||||
"grok-4-1-fast-non-reasoning": {
|
||||
maxTokens: 65_536,
|
||||
|
|
@ -50,8 +48,7 @@ export const xaiModels = {
|
|||
cacheReadsPrice: 0.05,
|
||||
description:
|
||||
"xAI's Grok 4.1 Fast model with 2M context window, optimized for high-performance agentic tool calling",
|
||||
includedTools: ["search_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "grok",
|
||||
},
|
||||
"grok-4-fast-reasoning": {
|
||||
maxTokens: 65_536,
|
||||
|
|
@ -66,8 +63,7 @@ export const xaiModels = {
|
|||
cacheReadsPrice: 0.05,
|
||||
description:
|
||||
"xAI's Grok 4 Fast model with 2M context window, optimized for high-performance agentic tool calling with reasoning",
|
||||
includedTools: ["search_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "grok",
|
||||
},
|
||||
"grok-4-fast-non-reasoning": {
|
||||
maxTokens: 65_536,
|
||||
|
|
@ -82,8 +78,7 @@ export const xaiModels = {
|
|||
cacheReadsPrice: 0.05,
|
||||
description:
|
||||
"xAI's Grok 4 Fast model with 2M context window, optimized for high-performance agentic tool calling",
|
||||
includedTools: ["search_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "grok",
|
||||
},
|
||||
"grok-4-0709": {
|
||||
maxTokens: 8192,
|
||||
|
|
@ -97,8 +92,7 @@ export const xaiModels = {
|
|||
cacheWritesPrice: 0.75,
|
||||
cacheReadsPrice: 0.75,
|
||||
description: "xAI's Grok-4 model with 256K context window",
|
||||
includedTools: ["search_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "grok",
|
||||
},
|
||||
"grok-3-mini": {
|
||||
maxTokens: 8192,
|
||||
|
|
@ -114,8 +108,7 @@ export const xaiModels = {
|
|||
description: "xAI's Grok-3 mini model with 128K context window",
|
||||
supportsReasoningEffort: ["low", "high"],
|
||||
reasoningEffort: "low",
|
||||
includedTools: ["search_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "grok",
|
||||
},
|
||||
"grok-3": {
|
||||
maxTokens: 8192,
|
||||
|
|
@ -129,7 +122,6 @@ export const xaiModels = {
|
|||
cacheWritesPrice: 0.75,
|
||||
cacheReadsPrice: 0.75,
|
||||
description: "xAI's Grok-3 model with 128K context window",
|
||||
includedTools: ["search_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
editToolVariant: "grok",
|
||||
},
|
||||
} as const satisfies Record<string, ModelInfo>
|
||||
|
|
|
|||
|
|
@ -30,13 +30,11 @@ export const toolNames = [
|
|||
"execute_command",
|
||||
"read_file",
|
||||
"write_to_file",
|
||||
// Legacy edit tool names (deprecated, use edit_file_* variants)
|
||||
// apply_diff is kept for XML protocol backward compatibility
|
||||
"apply_diff",
|
||||
"search_and_replace",
|
||||
"search_replace",
|
||||
// Unified edit tool for native protocol (variant selected via modelInfo.editToolVariant)
|
||||
"edit_file",
|
||||
"apply_patch",
|
||||
// New edit tool variant names
|
||||
// Internal edit tool variant names (used by native protocol, presented to LLM as "edit_file")
|
||||
"edit_file_roo",
|
||||
"edit_file_anthropic",
|
||||
"edit_file_grok",
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ describe("OpenRouterHandler", () => {
|
|||
expect(result.temperature).toBe(0)
|
||||
})
|
||||
|
||||
it("adds excludedTools and includedTools for OpenAI models", async () => {
|
||||
it("sets editToolVariant to codex for OpenAI models", async () => {
|
||||
const handler = new OpenRouterHandler({
|
||||
openRouterApiKey: "test-key",
|
||||
openRouterModelId: "openai/gpt-4o",
|
||||
|
|
@ -169,12 +169,10 @@ describe("OpenRouterHandler", () => {
|
|||
|
||||
const result = await handler.fetchModel()
|
||||
expect(result.id).toBe("openai/gpt-4o")
|
||||
expect(result.info.excludedTools).toContain("apply_diff")
|
||||
expect(result.info.excludedTools).toContain("write_to_file")
|
||||
expect(result.info.includedTools).toContain("apply_patch")
|
||||
expect(result.info.editToolVariant).toBe("codex")
|
||||
})
|
||||
|
||||
it("merges excludedTools and includedTools with existing values for OpenAI models", async () => {
|
||||
it("sets editToolVariant to codex for OpenAI models while preserving existing excludedTools/includedTools", async () => {
|
||||
const handler = new OpenRouterHandler({
|
||||
openRouterApiKey: "test-key",
|
||||
openRouterModelId: "openai/o1",
|
||||
|
|
@ -182,18 +180,14 @@ describe("OpenRouterHandler", () => {
|
|||
|
||||
const result = await handler.fetchModel()
|
||||
expect(result.id).toBe("openai/o1")
|
||||
// Should have the new exclusions
|
||||
expect(result.info.excludedTools).toContain("apply_diff")
|
||||
expect(result.info.excludedTools).toContain("write_to_file")
|
||||
// Should preserve existing exclusions
|
||||
// Should have editToolVariant set
|
||||
expect(result.info.editToolVariant).toBe("codex")
|
||||
// Should preserve existing exclusions/inclusions from model info
|
||||
expect(result.info.excludedTools).toContain("existing_excluded")
|
||||
// Should have the new inclusions
|
||||
expect(result.info.includedTools).toContain("apply_patch")
|
||||
// Should preserve existing inclusions
|
||||
expect(result.info.includedTools).toContain("existing_included")
|
||||
})
|
||||
|
||||
it("does not add excludedTools or includedTools for non-OpenAI models", async () => {
|
||||
it("does not set editToolVariant for non-OpenAI models", async () => {
|
||||
const handler = new OpenRouterHandler({
|
||||
openRouterApiKey: "test-key",
|
||||
openRouterModelId: "anthropic/claude-sonnet-4",
|
||||
|
|
@ -201,9 +195,8 @@ describe("OpenRouterHandler", () => {
|
|||
|
||||
const result = await handler.fetchModel()
|
||||
expect(result.id).toBe("anthropic/claude-sonnet-4")
|
||||
// Should NOT have the tool exclusions/inclusions
|
||||
expect(result.info.excludedTools).toBeUndefined()
|
||||
expect(result.info.includedTools).toBeUndefined()
|
||||
// Should NOT have editToolVariant set
|
||||
expect(result.info.editToolVariant).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -741,8 +741,8 @@ describe("getRooModels", () => {
|
|||
output: "0.0002",
|
||||
},
|
||||
settings: {
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
reasoningEffort: "high",
|
||||
},
|
||||
},
|
||||
|
|
@ -756,8 +756,8 @@ describe("getRooModels", () => {
|
|||
|
||||
const models = await getRooModels(baseUrl, apiKey)
|
||||
|
||||
expect(models["test/model-with-settings"].includedTools).toEqual(["apply_patch"])
|
||||
expect(models["test/model-with-settings"].excludedTools).toEqual(["apply_diff", "write_to_file"])
|
||||
expect(models["test/model-with-settings"].editToolVariant).toBe("codex")
|
||||
expect(models["test/model-with-settings"].excludedTools).toEqual(["write_to_file"])
|
||||
expect(models["test/model-with-settings"].reasoningEffort).toBe("high")
|
||||
})
|
||||
|
||||
|
|
@ -824,14 +824,14 @@ describe("getRooModels", () => {
|
|||
},
|
||||
// Plain settings for backward compatibility with old clients
|
||||
settings: {
|
||||
includedTools: ["apply_patch"],
|
||||
editToolVariant: "codex",
|
||||
excludedTools: ["write_to_file"],
|
||||
},
|
||||
// Versioned settings keyed by version number (low version - always met)
|
||||
versionedSettings: {
|
||||
"1.0.0": {
|
||||
includedTools: ["apply_patch", "search_replace"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
editToolVariant: "grok",
|
||||
excludedTools: ["write_to_file", "browser_action"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -846,8 +846,8 @@ describe("getRooModels", () => {
|
|||
const models = await getRooModels(baseUrl, apiKey)
|
||||
|
||||
// Versioned settings should be used instead of plain settings
|
||||
expect(models["test/versioned-model"].includedTools).toEqual(["apply_patch", "search_replace"])
|
||||
expect(models["test/versioned-model"].excludedTools).toEqual(["apply_diff", "write_to_file"])
|
||||
expect(models["test/versioned-model"].editToolVariant).toBe("grok")
|
||||
expect(models["test/versioned-model"].excludedTools).toEqual(["write_to_file", "browser_action"])
|
||||
})
|
||||
|
||||
it("should use plain settings when no versioned settings version matches", async () => {
|
||||
|
|
@ -870,12 +870,12 @@ describe("getRooModels", () => {
|
|||
output: "0.0002",
|
||||
},
|
||||
settings: {
|
||||
includedTools: ["apply_patch"],
|
||||
editToolVariant: "codex",
|
||||
},
|
||||
// Versioned settings keyed by very high version - never met
|
||||
versionedSettings: {
|
||||
"99.0.0": {
|
||||
includedTools: ["apply_patch", "search_replace"],
|
||||
editToolVariant: "grok",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -890,7 +890,7 @@ describe("getRooModels", () => {
|
|||
const models = await getRooModels(baseUrl, apiKey)
|
||||
|
||||
// Should use plain settings since no versioned settings match current version
|
||||
expect(models["test/old-version-model"].includedTools).toEqual(["apply_patch"])
|
||||
expect(models["test/old-version-model"].editToolVariant).toBe("codex")
|
||||
})
|
||||
|
||||
it("should handle model with only versionedSettings and no plain settings", async () => {
|
||||
|
|
|
|||
|
|
@ -3,12 +3,13 @@ import type { ModelInfo } from "@roo-code/types"
|
|||
/**
|
||||
* Apply tool preferences for models accessed through dynamic routers (OpenRouter, Requesty).
|
||||
*
|
||||
* Different model families perform better with specific tools:
|
||||
* - OpenAI models: Better results with apply_patch instead of apply_diff/write_to_file
|
||||
* - Gemini models: Higher quality results with write_file and edit_file
|
||||
* Different model families perform better with specific edit tool schemas:
|
||||
* - OpenAI models: Better results with the codex (patch) format
|
||||
* - Gemini models: Higher quality results with the gemini (search/replace) format
|
||||
* - xAI/Grok models: Better results with the grok format
|
||||
*
|
||||
* This function modifies the model info to apply these preferences consistently
|
||||
* across all dynamic router providers.
|
||||
* across all dynamic router providers via `editToolVariant`.
|
||||
*
|
||||
* @param modelId The model identifier (e.g., "openai/gpt-4", "google/gemini-2.5-pro")
|
||||
* @param info The original model info object
|
||||
|
|
@ -17,23 +18,32 @@ import type { ModelInfo } from "@roo-code/types"
|
|||
export function applyRouterToolPreferences(modelId: string, info: ModelInfo): ModelInfo {
|
||||
let result = info
|
||||
|
||||
// For OpenAI models via routers, exclude write_to_file and apply_diff, and include apply_patch
|
||||
// For OpenAI models via routers, use codex variant and exclude write_to_file
|
||||
// This matches the behavior of the native OpenAI provider
|
||||
if (modelId.includes("openai")) {
|
||||
result = {
|
||||
...result,
|
||||
excludedTools: [...new Set([...(result.excludedTools || []), "apply_diff", "write_to_file"])],
|
||||
includedTools: [...new Set([...(result.includedTools || []), "apply_patch"])],
|
||||
editToolVariant: result.editToolVariant ?? "codex",
|
||||
excludedTools: [...new Set([...(result.excludedTools || []), "write_to_file"])],
|
||||
}
|
||||
}
|
||||
|
||||
// For Gemini models via routers, include write_file and edit_file
|
||||
// For Gemini models via routers, use gemini variant
|
||||
// This matches the behavior of the native Gemini provider
|
||||
if (modelId.includes("gemini")) {
|
||||
result = {
|
||||
...result,
|
||||
excludedTools: [...new Set([...(result.excludedTools || []), "apply_diff"])],
|
||||
includedTools: [...new Set([...(result.includedTools || []), "write_file", "edit_file"])],
|
||||
editToolVariant: result.editToolVariant ?? "gemini",
|
||||
includedTools: [...new Set([...(result.includedTools || []), "write_file"])],
|
||||
}
|
||||
}
|
||||
|
||||
// For xAI/Grok models via routers, use grok variant
|
||||
// This matches the behavior of the native xAI provider
|
||||
if (modelId.includes("grok") || modelId.includes("xai")) {
|
||||
result = {
|
||||
...result,
|
||||
editToolVariant: result.editToolVariant ?? "grok",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -497,43 +497,36 @@ export class NativeToolCallParser {
|
|||
}
|
||||
break
|
||||
|
||||
case "apply_patch":
|
||||
if (partialArgs.patch !== undefined) {
|
||||
case "edit_file":
|
||||
// Handle unified edit_file with variant-aware argument detection
|
||||
// Detect variant based on which arguments are present:
|
||||
// - roo variant: { path, diff }
|
||||
// - anthropic variant: { path, edits: [{ old_text, new_text }] }
|
||||
// - grok/gemini variant: { file_path, old_string, new_string }
|
||||
// - codex variant: { patch }
|
||||
if (partialArgs.diff !== undefined) {
|
||||
// Roo variant (apply_diff format)
|
||||
nativeArgs = {
|
||||
patch: partialArgs.patch,
|
||||
path: partialArgs.path,
|
||||
diff: partialArgs.diff,
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
case "search_replace":
|
||||
if (
|
||||
partialArgs.file_path !== undefined ||
|
||||
partialArgs.old_string !== undefined ||
|
||||
partialArgs.new_string !== undefined
|
||||
) {
|
||||
nativeArgs = {
|
||||
file_path: partialArgs.file_path,
|
||||
old_string: partialArgs.old_string,
|
||||
new_string: partialArgs.new_string,
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
case "search_and_replace":
|
||||
if (partialArgs.path !== undefined || partialArgs.edits !== undefined) {
|
||||
} else if (partialArgs.edits !== undefined) {
|
||||
// Anthropic variant (search_and_replace format)
|
||||
nativeArgs = {
|
||||
path: partialArgs.path,
|
||||
edits: partialArgs.edits,
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
case "edit_file":
|
||||
if (
|
||||
} else if (partialArgs.patch !== undefined) {
|
||||
// Codex variant (apply_patch format)
|
||||
nativeArgs = {
|
||||
patch: partialArgs.patch,
|
||||
}
|
||||
} else if (
|
||||
partialArgs.file_path !== undefined ||
|
||||
partialArgs.old_string !== undefined ||
|
||||
partialArgs.new_string !== undefined
|
||||
) {
|
||||
// Grok/Gemini variant (search_replace/edit_file format)
|
||||
nativeArgs = {
|
||||
file_path: partialArgs.file_path,
|
||||
old_string: partialArgs.old_string,
|
||||
|
|
@ -660,15 +653,6 @@ export class NativeToolCallParser {
|
|||
}
|
||||
break
|
||||
|
||||
case "search_and_replace":
|
||||
if (args.path !== undefined && args.edits !== undefined && Array.isArray(args.edits)) {
|
||||
nativeArgs = {
|
||||
path: args.path,
|
||||
edits: args.edits,
|
||||
} as NativeArgsFor<TName>
|
||||
}
|
||||
break
|
||||
|
||||
case "ask_followup_question":
|
||||
if (args.question !== undefined && args.follow_up !== undefined) {
|
||||
nativeArgs = {
|
||||
|
|
@ -782,34 +766,36 @@ export class NativeToolCallParser {
|
|||
}
|
||||
break
|
||||
|
||||
case "apply_patch":
|
||||
if (args.patch !== undefined) {
|
||||
case "edit_file":
|
||||
// Handle unified edit_file with variant-aware argument detection
|
||||
// Detect variant based on which arguments are present:
|
||||
// - roo variant: { path, diff }
|
||||
// - anthropic variant: { path, edits: [{ old_text, new_text }] }
|
||||
// - grok/gemini variant: { file_path, old_string, new_string }
|
||||
// - codex variant: { patch }
|
||||
if (args.diff !== undefined && args.path !== undefined) {
|
||||
// Roo variant (apply_diff format)
|
||||
nativeArgs = {
|
||||
path: args.path,
|
||||
diff: args.diff,
|
||||
} as NativeArgsFor<TName>
|
||||
} else if (args.edits !== undefined && Array.isArray(args.edits) && args.path !== undefined) {
|
||||
// Anthropic variant (search_and_replace format)
|
||||
nativeArgs = {
|
||||
path: args.path,
|
||||
edits: args.edits,
|
||||
} as NativeArgsFor<TName>
|
||||
} else if (args.patch !== undefined) {
|
||||
// Codex variant (apply_patch format)
|
||||
nativeArgs = {
|
||||
patch: args.patch,
|
||||
} as NativeArgsFor<TName>
|
||||
}
|
||||
break
|
||||
|
||||
case "search_replace":
|
||||
if (
|
||||
args.file_path !== undefined &&
|
||||
args.old_string !== undefined &&
|
||||
args.new_string !== undefined
|
||||
) {
|
||||
nativeArgs = {
|
||||
file_path: args.file_path,
|
||||
old_string: args.old_string,
|
||||
new_string: args.new_string,
|
||||
} as NativeArgsFor<TName>
|
||||
}
|
||||
break
|
||||
|
||||
case "edit_file":
|
||||
if (
|
||||
} else if (
|
||||
args.file_path !== undefined &&
|
||||
args.old_string !== undefined &&
|
||||
args.new_string !== undefined
|
||||
) {
|
||||
// Grok/Gemini variant (search_replace/edit_file format)
|
||||
nativeArgs = {
|
||||
file_path: args.file_path,
|
||||
old_string: args.old_string,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
// npx vitest run core/assistant-message/__tests__/presentAssistantMessage-tool-usage-variants.spec.ts
|
||||
|
||||
import { describe, it, expect, beforeEach, vi } from "vitest"
|
||||
|
||||
vi.mock("../../tools/validateToolUse", () => ({
|
||||
validateToolUse: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock("@roo-code/telemetry", () => ({
|
||||
TelemetryService: {
|
||||
instance: {
|
||||
captureToolUsage: vi.fn(),
|
||||
captureConsecutiveMistakeError: vi.fn(),
|
||||
captureException: vi.fn(),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
const { mockEditToolHandle } = vi.hoisted(() => ({
|
||||
mockEditToolHandle: vi.fn(async (_task: unknown, _toolUse: unknown, callbacks: any) => {
|
||||
callbacks.pushToolResult("ok")
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock("../../tools/EditFileRooTool", () => ({
|
||||
editFileRooTool: { handle: mockEditToolHandle },
|
||||
}))
|
||||
|
||||
vi.mock("../../tools/EditFileAnthropicTool", () => ({
|
||||
editFileAnthropicTool: { handle: mockEditToolHandle },
|
||||
}))
|
||||
|
||||
vi.mock("../../tools/EditFileGrokTool", () => ({
|
||||
editFileGrokTool: { handle: mockEditToolHandle },
|
||||
}))
|
||||
|
||||
vi.mock("../../tools/EditFileGeminiTool", () => ({
|
||||
editFileGeminiTool: { handle: mockEditToolHandle },
|
||||
}))
|
||||
|
||||
vi.mock("../../tools/EditFileCodexTool", () => ({
|
||||
editFileCodexTool: { handle: mockEditToolHandle },
|
||||
}))
|
||||
|
||||
// Import AFTER mocks
|
||||
import { TelemetryService } from "@roo-code/telemetry"
|
||||
import { presentAssistantMessage } from "../presentAssistantMessage"
|
||||
|
||||
describe("presentAssistantMessage - tool usage analytics names", () => {
|
||||
let mockTask: any
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
|
||||
mockTask = {
|
||||
taskId: "test-task-id",
|
||||
instanceId: "test-instance",
|
||||
abort: false,
|
||||
presentAssistantMessageLocked: false,
|
||||
presentAssistantMessageHasPendingUpdates: false,
|
||||
currentStreamingContentIndex: 0,
|
||||
assistantMessageContent: [],
|
||||
userMessageContent: [],
|
||||
didCompleteReadingStream: false,
|
||||
didRejectTool: false,
|
||||
didAlreadyUseTool: false,
|
||||
diffEnabled: false,
|
||||
consecutiveMistakeCount: 0,
|
||||
consecutiveMistakeLimit: 3,
|
||||
clineMessages: [],
|
||||
currentStreamingDidCheckpoint: false,
|
||||
checkpointSave: vi.fn().mockResolvedValue(undefined),
|
||||
apiConfiguration: { apiProvider: "openai" },
|
||||
api: {
|
||||
getModel: () => ({ id: "test-model", info: { editToolVariant: "roo" } }),
|
||||
},
|
||||
browserSession: {
|
||||
closeBrowser: vi.fn().mockResolvedValue(undefined),
|
||||
},
|
||||
recordToolUsage: vi.fn(),
|
||||
recordToolError: vi.fn(),
|
||||
toolRepetitionDetector: {
|
||||
check: vi.fn().mockReturnValue({ allowExecution: true }),
|
||||
},
|
||||
providerRef: {
|
||||
deref: () => ({
|
||||
getState: vi.fn().mockResolvedValue({ mode: "code", customModes: [], experiments: {} }),
|
||||
}),
|
||||
},
|
||||
say: vi.fn().mockResolvedValue(undefined),
|
||||
ask: vi.fn().mockResolvedValue({ response: "yesButtonClicked" }),
|
||||
}
|
||||
})
|
||||
|
||||
it.each([
|
||||
["roo", "edit_file_roo"],
|
||||
["anthropic", "edit_file_anthropic"],
|
||||
["grok", "edit_file_grok"],
|
||||
["gemini", "edit_file_gemini"],
|
||||
["codex", "edit_file_codex"],
|
||||
] as const)("records derived analytics tool name for edit_file (%s)", async (variant, expected) => {
|
||||
mockTask.api.getModel = () => ({ id: "test-model", info: { editToolVariant: variant } })
|
||||
|
||||
mockTask.assistantMessageContent = [
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "tool_call_123",
|
||||
name: "edit_file",
|
||||
params: { path: "file.txt" },
|
||||
partial: false,
|
||||
},
|
||||
]
|
||||
|
||||
await presentAssistantMessage(mockTask)
|
||||
|
||||
expect(mockTask.recordToolUsage).toHaveBeenCalledWith(expected)
|
||||
expect(TelemetryService.instance.captureToolUsage).toHaveBeenCalledWith(
|
||||
mockTask.taskId,
|
||||
expected,
|
||||
expect.any(String),
|
||||
)
|
||||
})
|
||||
|
||||
it("does not change other tool names", async () => {
|
||||
mockTask.assistantMessageContent = [
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "tool_call_456",
|
||||
name: "read_file",
|
||||
params: { path: "file.txt" },
|
||||
partial: false,
|
||||
},
|
||||
]
|
||||
|
||||
await presentAssistantMessage(mockTask)
|
||||
|
||||
expect(mockTask.recordToolUsage).toHaveBeenCalledWith("read_file")
|
||||
expect(TelemetryService.instance.captureToolUsage).toHaveBeenCalledWith(
|
||||
mockTask.taskId,
|
||||
"read_file",
|
||||
expect.any(String),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
@ -22,10 +22,10 @@ import { readFileTool } from "../tools/ReadFileTool"
|
|||
import { TOOL_PROTOCOL } from "@roo-code/types"
|
||||
import { writeToFileTool } from "../tools/WriteToFileTool"
|
||||
import { applyDiffTool } from "../tools/MultiApplyDiffTool"
|
||||
import { searchAndReplaceTool } from "../tools/SearchAndReplaceTool"
|
||||
import { searchReplaceTool } from "../tools/SearchReplaceTool"
|
||||
import { editFileTool } from "../tools/EditFileTool"
|
||||
import { applyPatchTool } from "../tools/ApplyPatchTool"
|
||||
import { editFileAnthropicTool } from "../tools/EditFileAnthropicTool"
|
||||
import { editFileGrokTool } from "../tools/EditFileGrokTool"
|
||||
import { editFileGeminiTool } from "../tools/EditFileGeminiTool"
|
||||
import { editFileCodexTool } from "../tools/EditFileCodexTool"
|
||||
import { searchFilesTool } from "../tools/SearchFilesTool"
|
||||
import { browserActionTool } from "../tools/BrowserActionTool"
|
||||
import { executeCommandTool } from "../tools/ExecuteCommandTool"
|
||||
|
|
@ -38,12 +38,28 @@ import { newTaskTool } from "../tools/NewTaskTool"
|
|||
import { updateTodoListTool } from "../tools/UpdateTodoListTool"
|
||||
import { runSlashCommandTool } from "../tools/RunSlashCommandTool"
|
||||
import { generateImageTool } from "../tools/GenerateImageTool"
|
||||
import { applyDiffTool as applyDiffToolClass } from "../tools/ApplyDiffTool"
|
||||
import { editFileRooTool } from "../tools/EditFileRooTool"
|
||||
import { validateToolUse } from "../tools/validateToolUse"
|
||||
import { codebaseSearchTool } from "../tools/CodebaseSearchTool"
|
||||
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
|
||||
function getAnalyticsToolNameForToolUse(toolName: ToolName, editToolVariant: EditToolVariant): ToolName {
|
||||
if (toolName !== "edit_file") {
|
||||
return toolName
|
||||
}
|
||||
|
||||
const analyticsToolNameByVariant = {
|
||||
roo: "edit_file_roo",
|
||||
anthropic: "edit_file_anthropic",
|
||||
grok: "edit_file_grok",
|
||||
gemini: "edit_file_gemini",
|
||||
codex: "edit_file_codex",
|
||||
} satisfies Record<EditToolVariant, ToolName>
|
||||
|
||||
return analyticsToolNameByVariant[editToolVariant]
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes and presents assistant message content to the user interface.
|
||||
*
|
||||
|
|
@ -395,10 +411,6 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
return `[${block.name} for '${block.params.regex}'${
|
||||
block.params.file_pattern ? ` in '${block.params.file_pattern}'` : ""
|
||||
}]`
|
||||
case "search_and_replace":
|
||||
return `[${block.name} for '${block.params.path}']`
|
||||
case "search_replace":
|
||||
return `[${block.name} for '${block.params.file_path}']`
|
||||
case "edit_file": {
|
||||
// Unified edit_file tool - path location depends on variant
|
||||
// Gemini/Grok variants use file_path, Roo/Anthropic use path
|
||||
|
|
@ -412,8 +424,6 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
}
|
||||
return `[${block.name}]`
|
||||
}
|
||||
case "apply_patch":
|
||||
return `[${block.name}]`
|
||||
case "list_files":
|
||||
return `[${block.name} for '${block.params.path}']`
|
||||
case "browser_action":
|
||||
|
|
@ -706,11 +716,22 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
}
|
||||
|
||||
if (!block.partial) {
|
||||
// Determine the tool name for analytics
|
||||
let toolNameForAnalytics: ToolName = block.name
|
||||
|
||||
// Check if this is a custom tool - if so, record as "custom_tool" (like MCP tools)
|
||||
const isCustomTool = stateExperiments?.customTools && customToolRegistry.has(block.name)
|
||||
const recordName = isCustomTool ? "custom_tool" : block.name
|
||||
cline.recordToolUsage(recordName)
|
||||
TelemetryService.instance.captureToolUsage(cline.taskId, recordName, toolProtocol)
|
||||
if (isCustomTool) {
|
||||
toolNameForAnalytics = "custom_tool"
|
||||
} else if (toolNameForAnalytics === "edit_file") {
|
||||
// Map edit_file to specific variant for analytics
|
||||
const modelInfo = cline.api.getModel()
|
||||
const editToolVariant: EditToolVariant = modelInfo?.info?.editToolVariant ?? "roo"
|
||||
toolNameForAnalytics = getAnalyticsToolNameForToolUse(toolNameForAnalytics, editToolVariant)
|
||||
}
|
||||
|
||||
cline.recordToolUsage(toolNameForAnalytics)
|
||||
TelemetryService.instance.captureToolUsage(cline.taskId, toolNameForAnalytics, toolProtocol)
|
||||
}
|
||||
|
||||
// Validate tool use before execution - ONLY for complete (non-partial) blocks.
|
||||
|
|
@ -840,7 +861,7 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
// Check if this tool call came from native protocol by checking for ID
|
||||
// Native calls always have IDs, XML calls never do
|
||||
if (toolProtocol === TOOL_PROTOCOL.NATIVE) {
|
||||
await applyDiffToolClass.handle(cline, block as ToolUse<"apply_diff">, {
|
||||
await editFileRooTool.handle(cline, block as ToolUse<"edit_file_roo">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
|
|
@ -865,7 +886,7 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
if (isMultiFileApplyDiffEnabled) {
|
||||
await applyDiffTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
|
||||
} else {
|
||||
await applyDiffToolClass.handle(cline, block as ToolUse<"apply_diff">, {
|
||||
await editFileRooTool.handle(cline, block as ToolUse<"edit_file_roo">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
|
|
@ -875,26 +896,6 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
}
|
||||
break
|
||||
}
|
||||
case "search_and_replace":
|
||||
await checkpointSaveAndMark(cline)
|
||||
await searchAndReplaceTool.handle(cline, block as ToolUse<"search_and_replace">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
removeClosingTag,
|
||||
toolProtocol,
|
||||
})
|
||||
break
|
||||
case "search_replace":
|
||||
await checkpointSaveAndMark(cline)
|
||||
await searchReplaceTool.handle(cline, block as ToolUse<"search_replace">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
removeClosingTag,
|
||||
toolProtocol,
|
||||
})
|
||||
break
|
||||
case "edit_file": {
|
||||
// Unified edit_file tool - route to correct handler based on editToolVariant
|
||||
await checkpointSaveAndMark(cline)
|
||||
|
|
@ -903,8 +904,8 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
|
||||
switch (editToolVariant) {
|
||||
case "roo":
|
||||
// Route to apply_diff handler (Roo variant)
|
||||
await applyDiffToolClass.handle(cline, block as ToolUse<"apply_diff">, {
|
||||
// Route to Roo variant (unified diff format)
|
||||
await editFileRooTool.handle(cline, block as ToolUse<"edit_file_roo">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
|
|
@ -913,8 +914,8 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
})
|
||||
break
|
||||
case "anthropic":
|
||||
// Route to search_and_replace handler (Anthropic variant)
|
||||
await searchAndReplaceTool.handle(cline, block as ToolUse<"search_and_replace">, {
|
||||
// Route to Anthropic variant (multi-edit search/replace)
|
||||
await editFileAnthropicTool.handle(cline, block as ToolUse<"edit_file_anthropic">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
|
|
@ -923,8 +924,8 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
})
|
||||
break
|
||||
case "grok":
|
||||
// Route to search_replace handler (Grok variant)
|
||||
await searchReplaceTool.handle(cline, block as ToolUse<"search_replace">, {
|
||||
// Route to Grok variant (single search/replace)
|
||||
await editFileGrokTool.handle(cline, block as ToolUse<"edit_file_grok">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
|
|
@ -933,8 +934,8 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
})
|
||||
break
|
||||
case "gemini":
|
||||
// Route to edit_file handler (Gemini variant)
|
||||
await editFileTool.handle(cline, block as ToolUse<"edit_file">, {
|
||||
// Route to Gemini variant (search/replace with expected_replacements)
|
||||
await editFileGeminiTool.handle(cline, block as ToolUse<"edit_file">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
|
|
@ -943,8 +944,8 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
})
|
||||
break
|
||||
case "codex":
|
||||
// Route to apply_patch handler (Codex variant)
|
||||
await applyPatchTool.handle(cline, block as ToolUse<"apply_patch">, {
|
||||
// Route to Codex variant (unified patch format)
|
||||
await editFileCodexTool.handle(cline, block as ToolUse<"edit_file_codex">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
|
|
@ -955,7 +956,7 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
default: {
|
||||
// Should never happen, but default to roo variant
|
||||
const _exhaustiveCheck: never = editToolVariant
|
||||
await applyDiffToolClass.handle(cline, block as ToolUse<"apply_diff">, {
|
||||
await editFileRooTool.handle(cline, block as ToolUse<"edit_file_roo">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
|
|
@ -966,16 +967,6 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
}
|
||||
break
|
||||
}
|
||||
case "apply_patch":
|
||||
await checkpointSaveAndMark(cline)
|
||||
await applyPatchTool.handle(cline, block as ToolUse<"apply_patch">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
removeClosingTag,
|
||||
toolProtocol,
|
||||
})
|
||||
break
|
||||
case "read_file":
|
||||
// Type assertion is safe here because we're in the "read_file" case
|
||||
await readFileTool.handle(cline, block as ToolUse<"read_file">, {
|
||||
|
|
|
|||
|
|
@ -25,12 +25,6 @@ const EDIT_TOOL_VARIANT_MAP: Record<EditToolVariant, string> = {
|
|||
*/
|
||||
const ALL_EDIT_TOOL_VARIANTS = new Set(Object.values(EDIT_TOOL_VARIANT_MAP))
|
||||
|
||||
/**
|
||||
* Legacy edit tool names that are now aliases.
|
||||
* These should be excluded from the tool list since they're replaced by the variants.
|
||||
*/
|
||||
const LEGACY_EDIT_TOOL_NAMES = new Set(["apply_diff", "search_and_replace", "search_replace", "apply_patch"])
|
||||
|
||||
/**
|
||||
* Reverse lookup map - maps alias name to canonical tool name.
|
||||
* Built once at module load from the central TOOL_ALIASES constant.
|
||||
|
|
@ -326,12 +320,6 @@ export function filterNativeToolsForMode(
|
|||
}
|
||||
|
||||
// Handle edit tool variant selection:
|
||||
// 1. Remove legacy edit tool names (they're now aliases)
|
||||
// 2. Remove non-selected edit tool variants
|
||||
// 3. The selected variant will be renamed to "edit_file" below
|
||||
for (const legacyTool of LEGACY_EDIT_TOOL_NAMES) {
|
||||
allowedToolNames.delete(legacyTool)
|
||||
}
|
||||
for (const variantTool of ALL_EDIT_TOOL_VARIANTS) {
|
||||
allowedToolNames.delete(variantTool)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ interface SearchAndReplaceParams {
|
|||
edits: EditOperation[]
|
||||
}
|
||||
|
||||
export class SearchAndReplaceTool extends BaseTool<"search_and_replace"> {
|
||||
readonly name = "search_and_replace" as const
|
||||
export class SearchAndReplaceTool extends BaseTool<"edit_file_anthropic"> {
|
||||
readonly name = "edit_file_anthropic" as const
|
||||
|
||||
parseLegacy(params: Partial<Record<string, string>>): SearchAndReplaceParams {
|
||||
// Parse edits from JSON string if provided
|
||||
|
|
@ -52,14 +52,14 @@ export class SearchAndReplaceTool extends BaseTool<"search_and_replace"> {
|
|||
// Validate required parameters
|
||||
if (!relPath) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_and_replace")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("search_and_replace", "path"))
|
||||
task.recordToolError("edit_file_anthropic")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("edit_file_anthropic", "path"))
|
||||
return
|
||||
}
|
||||
|
||||
if (!edits || !Array.isArray(edits) || edits.length === 0) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_and_replace")
|
||||
task.recordToolError("edit_file_anthropic")
|
||||
pushToolResult(
|
||||
formatResponse.toolError(
|
||||
"Missing or empty 'edits' parameter. At least one edit operation is required.",
|
||||
|
|
@ -73,13 +73,13 @@ export class SearchAndReplaceTool extends BaseTool<"search_and_replace"> {
|
|||
const op = edits[i]
|
||||
if (!op.old_text) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_and_replace")
|
||||
task.recordToolError("edit_file_anthropic")
|
||||
pushToolResult(formatResponse.toolError(`Edit ${i + 1} is missing the 'old_text' field.`))
|
||||
return
|
||||
}
|
||||
if (op.new_text === undefined) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_and_replace")
|
||||
task.recordToolError("edit_file_anthropic")
|
||||
pushToolResult(formatResponse.toolError(`Edit ${i + 1} is missing the 'new_text' field.`))
|
||||
return
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ export class SearchAndReplaceTool extends BaseTool<"search_and_replace"> {
|
|||
const fileExists = await fileExistsAtPath(absolutePath)
|
||||
if (!fileExists) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_and_replace")
|
||||
task.recordToolError("edit_file_anthropic")
|
||||
const errorMessage = `File not found: ${relPath}. Cannot perform search and replace on a non-existent file.`
|
||||
await task.say("error", errorMessage)
|
||||
pushToolResult(formatResponse.toolError(errorMessage))
|
||||
|
|
@ -115,7 +115,7 @@ export class SearchAndReplaceTool extends BaseTool<"search_and_replace"> {
|
|||
fileContent = fileContent.replace(/\r\n/g, "\n")
|
||||
} catch (error) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_and_replace")
|
||||
task.recordToolError("edit_file_anthropic")
|
||||
const errorMessage = `Failed to read file '${relPath}'. Please verify file permissions and try again.`
|
||||
await task.say("error", errorMessage)
|
||||
pushToolResult(formatResponse.toolError(errorMessage))
|
||||
|
|
@ -152,7 +152,7 @@ export class SearchAndReplaceTool extends BaseTool<"search_and_replace"> {
|
|||
// If all edits failed, return error
|
||||
if (errors.length === edits.length) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_and_replace", "no_match")
|
||||
task.recordToolError("edit_file_anthropic", "no_match")
|
||||
pushToolResult(formatResponse.toolError(`All edits failed:\n${errors.join("\n")}`))
|
||||
return
|
||||
}
|
||||
|
|
@ -256,8 +256,6 @@ export class SearchAndReplaceTool extends BaseTool<"search_and_replace"> {
|
|||
pushToolResult(message)
|
||||
}
|
||||
|
||||
// Record successful tool usage and cleanup
|
||||
task.recordToolUsage("search_and_replace")
|
||||
await task.diffViewProvider.reset()
|
||||
|
||||
// Process any queued messages after file edit completes
|
||||
|
|
@ -268,7 +266,7 @@ export class SearchAndReplaceTool extends BaseTool<"search_and_replace"> {
|
|||
}
|
||||
}
|
||||
|
||||
override async handlePartial(task: Task, block: ToolUse<"search_and_replace">): Promise<void> {
|
||||
override async handlePartial(task: Task, block: ToolUse<"edit_file_anthropic">): Promise<void> {
|
||||
const relPath: string | undefined = block.params.path
|
||||
const editsStr: string | undefined = block.params.edits
|
||||
|
||||
|
|
@ -308,3 +306,5 @@ function escapeRegExp(input: string): string {
|
|||
}
|
||||
|
||||
export const searchAndReplaceTool = new SearchAndReplaceTool()
|
||||
// Alias for new naming convention
|
||||
export const editFileAnthropicTool = searchAndReplaceTool
|
||||
|
|
@ -20,8 +20,8 @@ interface ApplyPatchParams {
|
|||
patch: string
|
||||
}
|
||||
|
||||
export class ApplyPatchTool extends BaseTool<"apply_patch"> {
|
||||
readonly name = "apply_patch" as const
|
||||
export class ApplyPatchTool extends BaseTool<"edit_file_codex"> {
|
||||
readonly name = "edit_file_codex" as const
|
||||
|
||||
parseLegacy(params: Partial<Record<string, string>>): ApplyPatchParams {
|
||||
return {
|
||||
|
|
@ -37,8 +37,8 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
|
|||
// Validate required parameters
|
||||
if (!patch) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("apply_patch")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("apply_patch", "patch"))
|
||||
task.recordToolError("edit_file_codex")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("edit_file_codex", "patch"))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
|
|||
parsedPatch = parsePatch(patch)
|
||||
} catch (error) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("apply_patch")
|
||||
task.recordToolError("edit_file_codex")
|
||||
const errorMessage =
|
||||
error instanceof ParseError
|
||||
? `Invalid patch format: ${error.message}`
|
||||
|
|
@ -73,7 +73,7 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
|
|||
changes = await processAllHunks(parsedPatch.hunks, readFile)
|
||||
} catch (error) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("apply_patch")
|
||||
task.recordToolError("edit_file_codex")
|
||||
const errorMessage = `Failed to process patch: ${error instanceof Error ? error.message : String(error)}`
|
||||
pushToolResult(formatResponse.toolError(errorMessage))
|
||||
return
|
||||
|
|
@ -108,7 +108,6 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
|
|||
}
|
||||
|
||||
task.consecutiveMistakeCount = 0
|
||||
task.recordToolUsage("apply_patch")
|
||||
} catch (error) {
|
||||
await handleError("apply patch", error as Error)
|
||||
await task.diffViewProvider.reset()
|
||||
|
|
@ -129,7 +128,7 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
|
|||
const fileExists = await fileExistsAtPath(absolutePath)
|
||||
if (fileExists) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("apply_patch")
|
||||
task.recordToolError("edit_file_codex")
|
||||
const errorMessage = `File already exists: ${relPath}. Use Update File instead.`
|
||||
await task.say("error", errorMessage)
|
||||
pushToolResult(formatResponse.toolError(errorMessage))
|
||||
|
|
@ -220,7 +219,7 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
|
|||
const fileExists = await fileExistsAtPath(absolutePath)
|
||||
if (!fileExists) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("apply_patch")
|
||||
task.recordToolError("edit_file_codex")
|
||||
const errorMessage = `File not found: ${relPath}. Cannot delete a non-existent file.`
|
||||
await task.say("error", errorMessage)
|
||||
pushToolResult(formatResponse.toolError(errorMessage))
|
||||
|
|
@ -278,7 +277,7 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
|
|||
const fileExists = await fileExistsAtPath(absolutePath)
|
||||
if (!fileExists) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("apply_patch")
|
||||
task.recordToolError("edit_file_codex")
|
||||
const errorMessage = `File not found: ${relPath}. Cannot update a non-existent file.`
|
||||
await task.say("error", errorMessage)
|
||||
pushToolResult(formatResponse.toolError(errorMessage))
|
||||
|
|
@ -363,7 +362,7 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
|
|||
const isMovePathWriteProtected = task.rooProtectedController?.isWriteProtected(change.movePath) || false
|
||||
if (isMovePathWriteProtected) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("apply_patch")
|
||||
task.recordToolError("edit_file_codex")
|
||||
const errorMessage = `Cannot move file to write-protected path: ${change.movePath}`
|
||||
await task.say("error", errorMessage)
|
||||
pushToolResult(formatResponse.toolError(errorMessage))
|
||||
|
|
@ -375,7 +374,7 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
|
|||
const isMoveOutsideWorkspace = isPathOutsideWorkspace(moveAbsolutePath)
|
||||
if (isMoveOutsideWorkspace) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("apply_patch")
|
||||
task.recordToolError("edit_file_codex")
|
||||
const errorMessage = `Cannot move file to path outside workspace: ${change.movePath}`
|
||||
await task.say("error", errorMessage)
|
||||
pushToolResult(formatResponse.toolError(errorMessage))
|
||||
|
|
@ -426,7 +425,7 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
|
|||
task.processQueuedMessages()
|
||||
}
|
||||
|
||||
override async handlePartial(task: Task, block: ToolUse<"apply_patch">): Promise<void> {
|
||||
override async handlePartial(task: Task, block: ToolUse<"edit_file_codex">): Promise<void> {
|
||||
const patch: string | undefined = block.params.patch
|
||||
|
||||
let patchPreview: string | undefined
|
||||
|
|
@ -448,3 +447,5 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
|
|||
}
|
||||
|
||||
export const applyPatchTool = new ApplyPatchTool()
|
||||
// Alias for new naming convention
|
||||
export const editFileCodexTool = applyPatchTool
|
||||
|
|
@ -324,8 +324,6 @@ export class EditFileTool extends BaseTool<"edit_file"> {
|
|||
|
||||
pushToolResult(message + replacementInfo)
|
||||
|
||||
// Record successful tool usage and cleanup
|
||||
task.recordToolUsage("edit_file")
|
||||
await task.diffViewProvider.reset()
|
||||
|
||||
// Process any queued messages after file edit completes
|
||||
|
|
@ -371,3 +369,5 @@ export class EditFileTool extends BaseTool<"edit_file"> {
|
|||
}
|
||||
|
||||
export const editFileTool = new EditFileTool()
|
||||
// Alias for new naming convention
|
||||
export const editFileGeminiTool = editFileTool
|
||||
|
|
@ -20,8 +20,8 @@ interface SearchReplaceParams {
|
|||
new_string: string
|
||||
}
|
||||
|
||||
export class SearchReplaceTool extends BaseTool<"search_replace"> {
|
||||
readonly name = "search_replace" as const
|
||||
export class SearchReplaceTool extends BaseTool<"edit_file_grok"> {
|
||||
readonly name = "edit_file_grok" as const
|
||||
|
||||
parseLegacy(params: Partial<Record<string, string>>): SearchReplaceParams {
|
||||
return {
|
||||
|
|
@ -39,29 +39,29 @@ export class SearchReplaceTool extends BaseTool<"search_replace"> {
|
|||
// Validate required parameters
|
||||
if (!file_path) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_replace")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("search_replace", "file_path"))
|
||||
task.recordToolError("edit_file_grok")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("edit_file_grok", "file_path"))
|
||||
return
|
||||
}
|
||||
|
||||
if (!old_string) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_replace")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("search_replace", "old_string"))
|
||||
task.recordToolError("edit_file_grok")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("edit_file_grok", "old_string"))
|
||||
return
|
||||
}
|
||||
|
||||
if (new_string === undefined) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_replace")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("search_replace", "new_string"))
|
||||
task.recordToolError("edit_file_grok")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("edit_file_grok", "new_string"))
|
||||
return
|
||||
}
|
||||
|
||||
// Validate that old_string and new_string are different
|
||||
if (old_string === new_string) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_replace")
|
||||
task.recordToolError("edit_file_grok")
|
||||
pushToolResult(
|
||||
formatResponse.toolError(
|
||||
"The 'old_string' and 'new_string' parameters must be different.",
|
||||
|
|
@ -95,7 +95,7 @@ export class SearchReplaceTool extends BaseTool<"search_replace"> {
|
|||
const fileExists = await fileExistsAtPath(absolutePath)
|
||||
if (!fileExists) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_replace")
|
||||
task.recordToolError("edit_file_grok")
|
||||
const errorMessage = `File not found: ${relPath}. Cannot perform search and replace on a non-existent file.`
|
||||
await task.say("error", errorMessage)
|
||||
pushToolResult(formatResponse.toolError(errorMessage, toolProtocol))
|
||||
|
|
@ -109,7 +109,7 @@ export class SearchReplaceTool extends BaseTool<"search_replace"> {
|
|||
fileContent = fileContent.replace(/\r\n/g, "\n")
|
||||
} catch (error) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_replace")
|
||||
task.recordToolError("edit_file_grok")
|
||||
const errorMessage = `Failed to read file '${relPath}'. Please verify file permissions and try again.`
|
||||
await task.say("error", errorMessage)
|
||||
pushToolResult(formatResponse.toolError(errorMessage, toolProtocol))
|
||||
|
|
@ -125,7 +125,7 @@ export class SearchReplaceTool extends BaseTool<"search_replace"> {
|
|||
|
||||
if (matchCount === 0) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_replace", "no_match")
|
||||
task.recordToolError("edit_file_grok", "no_match")
|
||||
pushToolResult(
|
||||
formatResponse.toolError(
|
||||
`No match found for the specified 'old_string'. Please ensure it matches the file contents exactly, including whitespace and indentation.`,
|
||||
|
|
@ -137,7 +137,7 @@ export class SearchReplaceTool extends BaseTool<"search_replace"> {
|
|||
|
||||
if (matchCount > 1) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("search_replace", "multiple_matches")
|
||||
task.recordToolError("edit_file_grok", "multiple_matches")
|
||||
pushToolResult(
|
||||
formatResponse.toolError(
|
||||
`Found ${matchCount} matches for the specified 'old_string'. This tool can only replace ONE occurrence at a time. Please provide more context (3-5 lines before and after) to uniquely identify the specific instance you want to change.`,
|
||||
|
|
@ -237,8 +237,6 @@ export class SearchReplaceTool extends BaseTool<"search_replace"> {
|
|||
const message = await task.diffViewProvider.pushToolWriteResult(task, task.cwd, false)
|
||||
pushToolResult(message)
|
||||
|
||||
// Record successful tool usage and cleanup
|
||||
task.recordToolUsage("search_replace")
|
||||
await task.diffViewProvider.reset()
|
||||
|
||||
// Process any queued messages after file edit completes
|
||||
|
|
@ -249,7 +247,7 @@ export class SearchReplaceTool extends BaseTool<"search_replace"> {
|
|||
}
|
||||
}
|
||||
|
||||
override async handlePartial(task: Task, block: ToolUse<"search_replace">): Promise<void> {
|
||||
override async handlePartial(task: Task, block: ToolUse<"edit_file_grok">): Promise<void> {
|
||||
const filePath: string | undefined = block.params.file_path
|
||||
const oldString: string | undefined = block.params.old_string
|
||||
|
||||
|
|
@ -281,3 +279,5 @@ export class SearchReplaceTool extends BaseTool<"search_replace"> {
|
|||
}
|
||||
|
||||
export const searchReplaceTool = new SearchReplaceTool()
|
||||
// Alias for new naming convention
|
||||
export const editFileGrokTool = searchReplaceTool
|
||||
|
|
@ -16,22 +16,22 @@ import { computeDiffStats, sanitizeUnifiedDiff } from "../diff/stats"
|
|||
import { BaseTool, ToolCallbacks } from "./BaseTool"
|
||||
import type { ToolUse } from "../../shared/tools"
|
||||
|
||||
interface ApplyDiffParams {
|
||||
interface EditFileRooParams {
|
||||
path: string
|
||||
diff: string
|
||||
}
|
||||
|
||||
export class ApplyDiffTool extends BaseTool<"apply_diff"> {
|
||||
readonly name = "apply_diff" as const
|
||||
export class EditFileRooTool extends BaseTool<"edit_file_roo"> {
|
||||
readonly name = "edit_file_roo" as const
|
||||
|
||||
parseLegacy(params: Partial<Record<string, string>>): ApplyDiffParams {
|
||||
parseLegacy(params: Partial<Record<string, string>>): EditFileRooParams {
|
||||
return {
|
||||
path: params.path || "",
|
||||
diff: params.diff || "",
|
||||
}
|
||||
}
|
||||
|
||||
async execute(params: ApplyDiffParams, task: Task, callbacks: ToolCallbacks): Promise<void> {
|
||||
async execute(params: EditFileRooParams, task: Task, callbacks: ToolCallbacks): Promise<void> {
|
||||
const { askApproval, handleError, pushToolResult, toolProtocol } = callbacks
|
||||
let { path: relPath, diff: diffContent } = params
|
||||
|
||||
|
|
@ -42,15 +42,15 @@ export class ApplyDiffTool extends BaseTool<"apply_diff"> {
|
|||
try {
|
||||
if (!relPath) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("apply_diff")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("apply_diff", "path"))
|
||||
task.recordToolError("edit_file_roo")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("edit_file_roo", "path"))
|
||||
return
|
||||
}
|
||||
|
||||
if (!diffContent) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("apply_diff")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("apply_diff", "diff"))
|
||||
task.recordToolError("edit_file_roo")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("edit_file_roo", "diff"))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ export class ApplyDiffTool extends BaseTool<"apply_diff"> {
|
|||
|
||||
if (!fileExists) {
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("apply_diff")
|
||||
task.recordToolError("edit_file_roo")
|
||||
const formattedError = `File does not exist at path: ${absolutePath}\n\n<error_details>\nThe specified file could not be found. Please verify the file path and try again.\n</error_details>`
|
||||
await task.say("error", formattedError)
|
||||
task.didToolFailInCurrentTurn = true
|
||||
|
|
@ -118,7 +118,7 @@ export class ApplyDiffTool extends BaseTool<"apply_diff"> {
|
|||
await task.say("diff_error", formattedError)
|
||||
}
|
||||
|
||||
task.recordToolError("apply_diff", formattedError)
|
||||
task.recordToolError("edit_file_roo", formattedError)
|
||||
|
||||
pushToolResult(formattedError)
|
||||
return
|
||||
|
|
@ -164,9 +164,9 @@ export class ApplyDiffTool extends BaseTool<"apply_diff"> {
|
|||
let toolProgressStatus
|
||||
|
||||
if (task.diffStrategy && task.diffStrategy.getProgressStatus) {
|
||||
const block: ToolUse<"apply_diff"> = {
|
||||
const block: ToolUse<"edit_file_roo"> = {
|
||||
type: "tool_use",
|
||||
name: "apply_diff",
|
||||
name: "edit_file_roo",
|
||||
params: { path: relPath, diff: diffContent },
|
||||
partial: false,
|
||||
}
|
||||
|
|
@ -208,9 +208,9 @@ export class ApplyDiffTool extends BaseTool<"apply_diff"> {
|
|||
let toolProgressStatus
|
||||
|
||||
if (task.diffStrategy && task.diffStrategy.getProgressStatus) {
|
||||
const block: ToolUse<"apply_diff"> = {
|
||||
const block: ToolUse<"edit_file_roo"> = {
|
||||
type: "tool_use",
|
||||
name: "apply_diff",
|
||||
name: "edit_file_roo",
|
||||
params: { path: relPath, diff: diffContent },
|
||||
partial: false,
|
||||
}
|
||||
|
|
@ -272,7 +272,7 @@ export class ApplyDiffTool extends BaseTool<"apply_diff"> {
|
|||
}
|
||||
}
|
||||
|
||||
override async handlePartial(task: Task, block: ToolUse<"apply_diff">): Promise<void> {
|
||||
override async handlePartial(task: Task, block: ToolUse<"edit_file_roo">): Promise<void> {
|
||||
const relPath: string | undefined = block.params.path
|
||||
const diffContent: string | undefined = block.params.diff
|
||||
|
||||
|
|
@ -296,4 +296,6 @@ export class ApplyDiffTool extends BaseTool<"apply_diff"> {
|
|||
}
|
||||
}
|
||||
|
||||
export const applyDiffTool = new ApplyDiffTool()
|
||||
export const editFileRooTool = new EditFileRooTool()
|
||||
// Legacy alias for backward compatibility
|
||||
export const applyDiffTool = editFileRooTool
|
||||
|
|
@ -14,7 +14,7 @@ import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
|
|||
import { unescapeHtmlEntities } from "../../utils/text-normalization"
|
||||
import { parseXmlForDiff } from "../../utils/xml"
|
||||
import { EXPERIMENT_IDS, experiments } from "../../shared/experiments"
|
||||
import { applyDiffTool as applyDiffToolClass } from "./ApplyDiffTool"
|
||||
import { applyDiffTool as applyDiffToolClass } from "./EditFileRooTool"
|
||||
import { computeDiffStats, sanitizeUnifiedDiff } from "../diff/stats"
|
||||
import { isNativeProtocol } from "@roo-code/types"
|
||||
import { resolveToolProtocol } from "../../utils/resolveToolProtocol"
|
||||
|
|
@ -65,7 +65,7 @@ export async function applyDiffTool(
|
|||
// Use the task's locked protocol for consistency throughout the task lifetime
|
||||
const toolProtocol = resolveToolProtocol(cline.apiConfiguration, cline.api.getModel().info, cline.taskToolProtocol)
|
||||
if (isNativeProtocol(toolProtocol)) {
|
||||
return applyDiffToolClass.handle(cline, block as ToolUse<"apply_diff">, {
|
||||
return applyDiffToolClass.handle(cline, block as ToolUse<"edit_file_roo">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
|
|
@ -85,7 +85,7 @@ export async function applyDiffTool(
|
|||
|
||||
// If experiment is disabled, use single-file class-based tool
|
||||
if (!isMultiFileApplyDiffEnabled) {
|
||||
return applyDiffToolClass.handle(cline, block as ToolUse<"apply_diff">, {
|
||||
return applyDiffToolClass.handle(cline, block as ToolUse<"edit_file_roo">, {
|
||||
askApproval,
|
||||
handleError,
|
||||
pushToolResult,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { fileExistsAtPath } from "../../../utils/fs"
|
|||
import { isPathOutsideWorkspace } from "../../../utils/pathUtils"
|
||||
import { getReadablePath } from "../../../utils/path"
|
||||
import { ToolUse, ToolResponse } from "../../../shared/tools"
|
||||
import { searchReplaceTool } from "../SearchReplaceTool"
|
||||
import { searchReplaceTool } from "../EditFileGrokTool"
|
||||
|
||||
vi.mock("fs/promises", () => ({
|
||||
default: {
|
||||
|
|
@ -179,7 +179,7 @@ describe("searchReplaceTool", () => {
|
|||
|
||||
const toolUse: ToolUse = {
|
||||
type: "tool_use",
|
||||
name: "search_replace",
|
||||
name: "edit_file_grok",
|
||||
params: {
|
||||
file_path: testFilePath,
|
||||
old_string: testOldString,
|
||||
|
|
@ -193,7 +193,7 @@ describe("searchReplaceTool", () => {
|
|||
toolResult = result
|
||||
})
|
||||
|
||||
await searchReplaceTool.handle(mockCline, toolUse as ToolUse<"search_replace">, {
|
||||
await searchReplaceTool.handle(mockCline, toolUse as ToolUse<"edit_file_grok">, {
|
||||
askApproval: mockAskApproval,
|
||||
handleError: mockHandleError,
|
||||
pushToolResult: mockPushToolResult,
|
||||
|
|
@ -210,7 +210,7 @@ describe("searchReplaceTool", () => {
|
|||
|
||||
expect(result).toBe("Missing param error")
|
||||
expect(mockCline.consecutiveMistakeCount).toBe(1)
|
||||
expect(mockCline.recordToolError).toHaveBeenCalledWith("search_replace")
|
||||
expect(mockCline.recordToolError).toHaveBeenCalledWith("edit_file_grok")
|
||||
})
|
||||
|
||||
it("returns error when old_string is missing", async () => {
|
||||
|
|
@ -268,7 +268,7 @@ describe("searchReplaceTool", () => {
|
|||
expect(result).toContain("Error:")
|
||||
expect(result).toContain("No match found")
|
||||
expect(mockCline.consecutiveMistakeCount).toBe(1)
|
||||
expect(mockCline.recordToolError).toHaveBeenCalledWith("search_replace", "no_match")
|
||||
expect(mockCline.recordToolError).toHaveBeenCalledWith("edit_file_grok", "no_match")
|
||||
})
|
||||
|
||||
it("returns error when multiple matches are found", async () => {
|
||||
|
|
@ -280,7 +280,7 @@ describe("searchReplaceTool", () => {
|
|||
expect(result).toContain("Error:")
|
||||
expect(result).toContain("3 matches")
|
||||
expect(mockCline.consecutiveMistakeCount).toBe(1)
|
||||
expect(mockCline.recordToolError).toHaveBeenCalledWith("search_replace", "multiple_matches")
|
||||
expect(mockCline.recordToolError).toHaveBeenCalledWith("edit_file_grok", "multiple_matches")
|
||||
})
|
||||
|
||||
it("successfully replaces single unique match", async () => {
|
||||
|
|
@ -306,7 +306,7 @@ describe("searchReplaceTool", () => {
|
|||
|
||||
expect(mockCline.diffViewProvider.saveChanges).toHaveBeenCalled()
|
||||
expect(mockCline.didEditFile).toBe(true)
|
||||
expect(mockCline.recordToolUsage).toHaveBeenCalledWith("search_replace")
|
||||
expect(mockCline.recordToolUsage).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("reverts changes when user rejects", async () => {
|
||||
|
|
@ -335,7 +335,7 @@ describe("searchReplaceTool", () => {
|
|||
|
||||
const toolUse: ToolUse = {
|
||||
type: "tool_use",
|
||||
name: "search_replace",
|
||||
name: "edit_file_grok",
|
||||
params: {
|
||||
file_path: testFilePath,
|
||||
old_string: testOldString,
|
||||
|
|
@ -349,7 +349,7 @@ describe("searchReplaceTool", () => {
|
|||
capturedResult = result
|
||||
})
|
||||
|
||||
await searchReplaceTool.handle(mockCline, toolUse as ToolUse<"search_replace">, {
|
||||
await searchReplaceTool.handle(mockCline, toolUse as ToolUse<"edit_file_grok">, {
|
||||
askApproval: mockAskApproval,
|
||||
handleError: mockHandleError,
|
||||
pushToolResult: localPushToolResult,
|
||||
|
|
@ -8,8 +8,8 @@ vi.mock("vscode", () => ({
|
|||
},
|
||||
}))
|
||||
|
||||
// Mock the ApplyDiffTool module
|
||||
vi.mock("../ApplyDiffTool", () => ({
|
||||
// Mock the EditFileRooTool module
|
||||
vi.mock("../EditFileRooTool", () => ({
|
||||
applyDiffTool: {
|
||||
handle: vi.fn(),
|
||||
},
|
||||
|
|
@ -17,7 +17,7 @@ vi.mock("../ApplyDiffTool", () => ({
|
|||
|
||||
// Import after mocking to get the mocked version
|
||||
import { applyDiffTool as multiApplyDiffTool } from "../MultiApplyDiffTool"
|
||||
import { applyDiffTool as applyDiffToolClass } from "../ApplyDiffTool"
|
||||
import { applyDiffTool as applyDiffToolClass } from "../EditFileRooTool"
|
||||
|
||||
describe("applyDiffTool experiment routing", () => {
|
||||
let mockCline: any
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { fileExistsAtPath } from "../../../utils/fs"
|
|||
import { isPathOutsideWorkspace } from "../../../utils/pathUtils"
|
||||
import { getReadablePath } from "../../../utils/path"
|
||||
import { ToolUse, ToolResponse } from "../../../shared/tools"
|
||||
import { editFileTool } from "../EditFileTool"
|
||||
import { editFileTool } from "../EditFileGeminiTool"
|
||||
|
||||
vi.mock("fs/promises", () => ({
|
||||
default: {
|
||||
|
|
@ -348,7 +348,7 @@ describe("editFileTool", () => {
|
|||
|
||||
expect(mockTask.diffViewProvider.saveChanges).toHaveBeenCalled()
|
||||
expect(mockTask.didEditFile).toBe(true)
|
||||
expect(mockTask.recordToolUsage).toHaveBeenCalledWith("edit_file")
|
||||
expect(mockTask.recordToolUsage).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("reverts changes when user rejects", async () => {
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ describe("isToolAllowedForMode", () => {
|
|||
|
||||
it("disallows customTools by default (not in includedTools)", () => {
|
||||
// search_and_replace is a customTool in the edit group, should be disallowed by default
|
||||
expect(isToolAllowedForMode("search_and_replace", "test-custom-tools", customModesWithEditGroup)).toBe(
|
||||
expect(isToolAllowedForMode("edit_file_anthropic", "test-custom-tools", customModesWithEditGroup)).toBe(
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
|
@ -335,13 +335,13 @@ describe("isToolAllowedForMode", () => {
|
|||
// search_and_replace should be allowed when explicitly included
|
||||
expect(
|
||||
isToolAllowedForMode(
|
||||
"search_and_replace",
|
||||
"edit_file_anthropic",
|
||||
"test-custom-tools",
|
||||
customModesWithEditGroup,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
["search_and_replace"],
|
||||
["edit_file_anthropic"],
|
||||
),
|
||||
).toBe(true)
|
||||
})
|
||||
|
|
@ -359,13 +359,13 @@ describe("isToolAllowedForMode", () => {
|
|||
// Even if included, should be disallowed because the mode doesn't have edit group
|
||||
expect(
|
||||
isToolAllowedForMode(
|
||||
"search_and_replace",
|
||||
"edit_file_anthropic",
|
||||
"no-edit-mode",
|
||||
customModesWithoutEdit,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
["search_and_replace"],
|
||||
["edit_file_anthropic"],
|
||||
),
|
||||
).toBe(false)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -70,14 +70,14 @@ export const toolParamNames = [
|
|||
"prompt",
|
||||
"image",
|
||||
"files", // Native protocol parameter for read_file
|
||||
"edits", // edit_file_anthropic parameter for multiple edit operations
|
||||
"old_text", // edit_file_anthropic parameter for text to replace
|
||||
"new_text", // edit_file_anthropic parameter for replacement text
|
||||
"patch", // apply_patch parameter
|
||||
"file_path", // search_replace and edit_file parameter
|
||||
"old_string", // search_replace and edit_file parameter
|
||||
"new_string", // search_replace and edit_file parameter
|
||||
"expected_replacements", // edit_file parameter for multiple occurrences
|
||||
"edits", // edit_file (anthropic variant) parameter for multiple edit operations
|
||||
"old_text", // edit_file (anthropic variant) parameter for text to replace
|
||||
"new_text", // edit_file (anthropic variant) parameter for replacement text
|
||||
"patch", // edit_file (codex variant) parameter
|
||||
"file_path", // edit_file (grok/gemini variant) parameter
|
||||
"old_string", // edit_file (grok/gemini variant) parameter
|
||||
"new_string", // edit_file (grok/gemini variant) parameter
|
||||
"expected_replacements", // edit_file (gemini variant) parameter for multiple occurrences
|
||||
] as const
|
||||
|
||||
export type ToolParamName = (typeof toolParamNames)[number]
|
||||
|
|
@ -93,13 +93,22 @@ export type NativeToolArgs = {
|
|||
read_file: { files: FileEntry[] }
|
||||
attempt_completion: { result: string }
|
||||
execute_command: { command: string; cwd?: string }
|
||||
// Legacy edit tool names (deprecated, mapped to new names via aliases)
|
||||
// apply_diff is kept for XML protocol backward compatibility
|
||||
apply_diff: { path: string; diff: string }
|
||||
search_and_replace: { path: string; edits: Array<{ old_text: string; new_text: string }> }
|
||||
search_replace: { file_path: string; old_string: string; new_string: string }
|
||||
edit_file: { file_path: string; old_string: string; new_string: string; expected_replacements?: number }
|
||||
apply_patch: { patch: string }
|
||||
// New edit tool variant names (all present "edit_file" to LLM)
|
||||
// Unified edit_file for native protocol - variant-specific args based on modelInfo.editToolVariant
|
||||
// The actual arg structure depends on which variant is selected:
|
||||
// - roo: { path, diff }
|
||||
// - anthropic: { path, edits }
|
||||
// - grok: { file_path, old_string, new_string }
|
||||
// - gemini: { file_path, old_string, new_string, expected_replacements? }
|
||||
// - codex: { patch }
|
||||
edit_file:
|
||||
| { path: string; diff: string }
|
||||
| { path: string; edits: Array<{ old_text: string; new_text: string }> }
|
||||
| { file_path: string; old_string: string; new_string: string }
|
||||
| { file_path: string; old_string: string; new_string: string; expected_replacements?: number }
|
||||
| { patch: string }
|
||||
// Internal edit tool variant names (used by native protocol, presented to LLM as "edit_file")
|
||||
edit_file_roo: { path: string; diff: string }
|
||||
edit_file_anthropic: { path: string; edits: Array<{ old_text: string; new_text: string }> }
|
||||
edit_file_grok: { file_path: string; old_string: string; new_string: string }
|
||||
|
|
@ -257,13 +266,11 @@ export const TOOL_DISPLAY_NAMES: Record<ToolName, string> = {
|
|||
read_file: "read files",
|
||||
fetch_instructions: "fetch instructions",
|
||||
write_to_file: "write files",
|
||||
// Legacy edit tool names (deprecated)
|
||||
// apply_diff is kept for XML protocol backward compatibility
|
||||
apply_diff: "apply changes",
|
||||
search_and_replace: "apply changes using search and replace",
|
||||
search_replace: "apply single search and replace",
|
||||
edit_file: "edit files using search and replace",
|
||||
apply_patch: "apply patches using codex format",
|
||||
// New edit tool variant names
|
||||
// Unified edit tool for native protocol
|
||||
edit_file: "edit files",
|
||||
// Internal edit tool variant names (used by native protocol)
|
||||
edit_file_roo: "edit files (roo format)",
|
||||
edit_file_anthropic: "edit files (anthropic format)",
|
||||
edit_file_grok: "edit files (grok format)",
|
||||
|
|
@ -292,25 +299,12 @@ export const TOOL_GROUPS: Record<ToolGroup, ToolGroupConfig> = {
|
|||
tools: ["read_file", "fetch_instructions", "search_files", "list_files", "codebase_search"],
|
||||
},
|
||||
edit: {
|
||||
// apply_diff is included for XML protocol backward compatibility
|
||||
// For native protocol, filterNativeToolsForMode selects the appropriate edit_file_* variant
|
||||
// For XML protocol: apply_diff is included for backward compatibility
|
||||
// For native protocol: filterNativeToolsForMode selects the appropriate edit_file_* variant
|
||||
// and presents it as "edit_file" to the LLM
|
||||
tools: ["write_to_file", "apply_diff", "edit_file", "generate_image"],
|
||||
// All edit tool variants and legacy names - one is selected based on modelInfo.editToolVariant
|
||||
// "edit_file" is the unified name that LLMs see (for modelInfo.includedTools validation)
|
||||
customTools: [
|
||||
// Unified edit tool name (for includedTools validation)
|
||||
"edit_file",
|
||||
// Legacy names (for backward compatibility with existing includedTools configs)
|
||||
"search_and_replace",
|
||||
"search_replace",
|
||||
"apply_patch",
|
||||
// Variant names (for native protocol internal use)
|
||||
"edit_file_roo",
|
||||
"edit_file_anthropic",
|
||||
"edit_file_grok",
|
||||
"edit_file_gemini",
|
||||
"edit_file_codex",
|
||||
],
|
||||
// Variant names for native protocol internal use - one is selected based on modelInfo.editToolVariant
|
||||
customTools: ["edit_file_roo", "edit_file_anthropic", "edit_file_grok", "edit_file_gemini", "edit_file_codex"],
|
||||
},
|
||||
browser: {
|
||||
tools: ["browser_action"],
|
||||
|
|
@ -341,20 +335,16 @@ export const ALWAYS_AVAILABLE_TOOLS: ToolName[] = [
|
|||
* Central registry of tool aliases.
|
||||
* Maps alias name -> canonical tool name.
|
||||
*
|
||||
* This allows models to use alternative names for tools (e.g., "edit_file" instead of "apply_diff").
|
||||
* This allows models to use alternative names for tools.
|
||||
* When a model calls a tool by its alias, the system resolves it to the canonical name for execution,
|
||||
* but preserves the alias in API conversation history for consistency.
|
||||
*
|
||||
* To add a new alias, simply add an entry here. No other files need to be modified.
|
||||
* Note: Legacy edit tool aliases (apply_diff, search_and_replace, search_replace, apply_patch)
|
||||
* have been removed. Native protocol now uses editToolVariant to select the edit tool schema,
|
||||
* and all edit tools are presented to the LLM as "edit_file". XML protocol still uses apply_diff directly.
|
||||
*/
|
||||
export const TOOL_ALIASES: Record<string, ToolName> = {
|
||||
write_file: "write_to_file",
|
||||
// Backward compatibility: map old edit tool names to new variant names
|
||||
apply_diff: "edit_file_roo",
|
||||
search_and_replace: "edit_file_anthropic",
|
||||
search_replace: "edit_file_grok",
|
||||
// Note: edit_file is kept as a tool name (for gemini variant) but also serves as the unified LLM-facing name
|
||||
apply_patch: "edit_file_codex",
|
||||
} as const
|
||||
|
||||
export type DiffResult =
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue