From 04f2cb68c4cd108b7f3658b3faa9ec5f629a4906 Mon Sep 17 00:00:00 2001 From: bhaktatejas922 Date: Wed, 16 Jul 2025 19:44:52 -0700 Subject: [PATCH 1/6] add instruction --- .../src/developer/editor_models/mod.rs | 9 ++++++--- .../editor_models/morphllm_editor.rs | 20 +++++++++++++++---- .../editor_models/openai_compatible_editor.rs | 1 + .../developer/editor_models/relace_editor.rs | 1 + crates/goose-mcp/src/developer/mod.rs | 13 ++++++++++-- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/crates/goose-mcp/src/developer/editor_models/mod.rs b/crates/goose-mcp/src/developer/editor_models/mod.rs index d442aa56c32b..563885b692e8 100644 --- a/crates/goose-mcp/src/developer/editor_models/mod.rs +++ b/crates/goose-mcp/src/developer/editor_models/mod.rs @@ -23,21 +23,23 @@ impl EditorModel { original_code: &str, old_str: &str, update_snippet: &str, + instruction: &str, ) -> Result { match self { EditorModel::MorphLLM(editor) => { + // Only MorphLLM uses the instruction parameter editor - .edit_code(original_code, old_str, update_snippet) + .edit_code(original_code, old_str, update_snippet, instruction) .await } EditorModel::OpenAICompatible(editor) => { editor - .edit_code(original_code, old_str, update_snippet) + .edit_code(original_code, old_str, update_snippet, instruction) .await } EditorModel::Relace(editor) => { editor - .edit_code(original_code, old_str, update_snippet) + .edit_code(original_code, old_str, update_snippet, instruction) .await } } @@ -61,6 +63,7 @@ pub trait EditorModelImpl { original_code: &str, old_str: &str, update_snippet: &str, + instruction: &str, ) -> Result; /// Get the description for the str_replace command when this editor is active diff --git a/crates/goose-mcp/src/developer/editor_models/morphllm_editor.rs b/crates/goose-mcp/src/developer/editor_models/morphllm_editor.rs index 8c5d60f8f813..b31bb1920cd8 100644 --- a/crates/goose-mcp/src/developer/editor_models/morphllm_editor.rs +++ b/crates/goose-mcp/src/developer/editor_models/morphllm_editor.rs @@ -27,6 +27,7 @@ impl EditorModelImpl for MorphLLMEditor { original_code: &str, _old_str: &str, update_snippet: &str, + instruction: &str, ) -> Result { eprintln!("Calling MorphLLM Editor API"); @@ -42,10 +43,10 @@ impl EditorModelImpl for MorphLLMEditor { // Create the client let client = Client::new(); - // Format the prompt as specified in the Python example + // Format the prompt according to MorphLLM's new format with instruction let user_prompt = format!( - "{}\n{}", - original_code, update_snippet + "{}\n{}\n{}", + instruction, original_code, update_snippet ); // Prepare the request body for OpenAI-compatible API @@ -98,6 +99,7 @@ impl EditorModelImpl for MorphLLMEditor { fn get_str_replace_description(&self) -> &'static str { "Use the edit_file to propose an edit to an existing file. + This will be read by a less intelligent model, which will quickly apply the edit. You should make it clear what the edit is, while also minimizing the unchanged code you write. When writing the edit, you should specify each edit in sequence, with the special comment // ... existing code ... to represent unchanged code in between edited lines. @@ -113,7 +115,17 @@ impl EditorModelImpl for MorphLLMEditor { You should bias towards repeating as few lines of the original file as possible to convey the change. Each edit should contain sufficient context of unchanged lines around the code you're editing to resolve ambiguity. If you plan on deleting a section, you must provide surrounding context to indicate the deletion. - DO NOT omit spans of pre-existing code without using the // ... existing code ... comment to indicate its absence. + DO NOT omit spans of pre-existing code without using the // ... existing code ... comment to indicate its absence. + + **IMPORTANT**: You must also provide an `instruction` parameter - a single sentence written in the first person describing what you are going to do for the sketched edit. This instruction helps the less intelligent model understand and apply your edit correctly. + + Examples of good instructions: + - \"I am adding error handling to the user authentication function and removing the old authentication method\" + - \"I am refactoring the database connection logic to use async/await\" + - \"I am fixing the bug in the validation logic by updating the regex pattern\" + - \"I am adding a new method to handle user preferences and updating the constructor\" + + The instruction should be specific enough to disambiguate any uncertainty in your edit. " } } diff --git a/crates/goose-mcp/src/developer/editor_models/openai_compatible_editor.rs b/crates/goose-mcp/src/developer/editor_models/openai_compatible_editor.rs index 313b7a873d97..4fe64ac7abfa 100644 --- a/crates/goose-mcp/src/developer/editor_models/openai_compatible_editor.rs +++ b/crates/goose-mcp/src/developer/editor_models/openai_compatible_editor.rs @@ -27,6 +27,7 @@ impl EditorModelImpl for OpenAICompatibleEditor { original_code: &str, _old_str: &str, update_snippet: &str, + _instruction: &str, // Not used by OpenAI compatible editor ) -> Result { eprintln!("Calling OpenAI-compatible Editor API"); diff --git a/crates/goose-mcp/src/developer/editor_models/relace_editor.rs b/crates/goose-mcp/src/developer/editor_models/relace_editor.rs index 3cc40bfb13a3..5d017ead1a3a 100644 --- a/crates/goose-mcp/src/developer/editor_models/relace_editor.rs +++ b/crates/goose-mcp/src/developer/editor_models/relace_editor.rs @@ -27,6 +27,7 @@ impl EditorModelImpl for RelaceEditor { original_code: &str, _old_str: &str, update_snippet: &str, + _instruction: &str, // Not used by Relace editor ) -> Result { eprintln!("Calling Relace Editor API"); diff --git a/crates/goose-mcp/src/developer/mod.rs b/crates/goose-mcp/src/developer/mod.rs index ddc81831cda6..c11e0b535667 100644 --- a/crates/goose-mcp/src/developer/mod.rs +++ b/crates/goose-mcp/src/developer/mod.rs @@ -334,6 +334,10 @@ impl DeveloperRouter { }, "old_str": {"type": "string"}, "new_str": {"type": "string"}, + "instruction": { + "type": "string", + "description": "Optional: A single sentence written in the first person describing what you are going to do for the sketched edit. Use it to disambiguate uncertainty in the edit." + }, "file_text": {"type": "string"} } }), @@ -880,8 +884,12 @@ impl DeveloperRouter { .ok_or_else(|| { ToolError::InvalidParameters("Missing 'new_str' parameter".into()) })?; + let instruction = params + .get("instruction") + .and_then(|v| v.as_str()) + .unwrap_or(""); // Empty string for backward compatibility - self.text_editor_replace(&path, old_str, new_str).await + self.text_editor_replace(&path, old_str, new_str, instruction).await } "insert" => { let insert_line = params @@ -1082,6 +1090,7 @@ impl DeveloperRouter { path: &PathBuf, old_str: &str, new_str: &str, + instruction: &str, ) -> Result, ToolError> { // Check if file exists and is active if !path.exists() { @@ -1100,7 +1109,7 @@ impl DeveloperRouter { // Editor API path - save history then call API directly self.save_file_history(path)?; - match editor.edit_code(&content, old_str, new_str).await { + match editor.edit_code(&content, old_str, new_str, instruction).await { Ok(updated_content) => { // Write the updated content directly let normalized_content = normalize_line_endings(&updated_content); From db2bff3973d5e013331bca98493479aa63e5f81e Mon Sep 17 00:00:00 2001 From: bhaktatejas922 Date: Wed, 16 Jul 2025 19:46:40 -0700 Subject: [PATCH 2/6] bump morph --- .../goose-mcp/src/developer/editor_models/EDITOR_API_EXAMPLE.md | 2 +- documentation/docs/guides/enhanced-code-editing.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/goose-mcp/src/developer/editor_models/EDITOR_API_EXAMPLE.md b/crates/goose-mcp/src/developer/editor_models/EDITOR_API_EXAMPLE.md index 073e34683dcf..9099eaff1747 100644 --- a/crates/goose-mcp/src/developer/editor_models/EDITOR_API_EXAMPLE.md +++ b/crates/goose-mcp/src/developer/editor_models/EDITOR_API_EXAMPLE.md @@ -36,7 +36,7 @@ export GOOSE_EDITOR_MODEL="claude-3-5-sonnet-20241022" ```bash export GOOSE_EDITOR_API_KEY="sk-..." export GOOSE_EDITOR_HOST="https://api.morphllm.com/v1" -export GOOSE_EDITOR_MODEL="morph-v0" +export GOOSE_EDITOR_MODEL="morph-v3-large" ``` **Relace** diff --git a/documentation/docs/guides/enhanced-code-editing.md b/documentation/docs/guides/enhanced-code-editing.md index 6c894f688b6a..900dfc52cab4 100644 --- a/documentation/docs/guides/enhanced-code-editing.md +++ b/documentation/docs/guides/enhanced-code-editing.md @@ -50,7 +50,7 @@ export GOOSE_EDITOR_MODEL="claude-3-5-sonnet-20241022" ```bash export GOOSE_EDITOR_API_KEY="sk-..." export GOOSE_EDITOR_HOST="https://api.morphllm.com/v1" -export GOOSE_EDITOR_MODEL="morph-v0" +export GOOSE_EDITOR_MODEL="morph-v3-large" ``` **Relace:** From 839eca91dd164feb61969e8dc6249c32f580b2e3 Mon Sep 17 00:00:00 2001 From: bhaktatejas922 Date: Sun, 20 Jul 2025 16:36:16 -0700 Subject: [PATCH 3/6] run cargo fmt --- crates/goose-mcp/src/developer/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/goose-mcp/src/developer/mod.rs b/crates/goose-mcp/src/developer/mod.rs index c11e0b535667..43137470eadb 100644 --- a/crates/goose-mcp/src/developer/mod.rs +++ b/crates/goose-mcp/src/developer/mod.rs @@ -889,7 +889,8 @@ impl DeveloperRouter { .and_then(|v| v.as_str()) .unwrap_or(""); // Empty string for backward compatibility - self.text_editor_replace(&path, old_str, new_str, instruction).await + self.text_editor_replace(&path, old_str, new_str, instruction) + .await } "insert" => { let insert_line = params @@ -1109,7 +1110,10 @@ impl DeveloperRouter { // Editor API path - save history then call API directly self.save_file_history(path)?; - match editor.edit_code(&content, old_str, new_str, instruction).await { + match editor + .edit_code(&content, old_str, new_str, instruction) + .await + { Ok(updated_content) => { // Write the updated content directly let normalized_content = normalize_line_endings(&updated_content); From 88aa940a2be108e6458a44f48ef894ccf6fea4ee Mon Sep 17 00:00:00 2001 From: bhaktatejas922 Date: Sun, 20 Jul 2025 16:39:20 -0700 Subject: [PATCH 4/6] minor prompt --- crates/goose-mcp/src/developer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/goose-mcp/src/developer/mod.rs b/crates/goose-mcp/src/developer/mod.rs index 43137470eadb..8fd07a4850c8 100644 --- a/crates/goose-mcp/src/developer/mod.rs +++ b/crates/goose-mcp/src/developer/mod.rs @@ -336,7 +336,7 @@ impl DeveloperRouter { "new_str": {"type": "string"}, "instruction": { "type": "string", - "description": "Optional: A single sentence written in the first person describing what you are going to do for the sketched edit. Use it to disambiguate uncertainty in the edit." + "description": "A single sentence written in the first person describing what you are going to do for the sketched edit. Use it to disambiguate uncertainty in the edit." }, "file_text": {"type": "string"} } From 3f668ae7ab90f25b869ba193a6ff8a9acc68ed19 Mon Sep 17 00:00:00 2001 From: bhaktatejas922 Date: Tue, 22 Jul 2025 14:04:27 -0700 Subject: [PATCH 5/6] conditional morph format --- .../editor_models/morphllm_editor.rs | 5 +- crates/goose-mcp/src/developer/mod.rs | 249 ++++++++++++------ 2 files changed, 171 insertions(+), 83 deletions(-) diff --git a/crates/goose-mcp/src/developer/editor_models/morphllm_editor.rs b/crates/goose-mcp/src/developer/editor_models/morphllm_editor.rs index b31bb1920cd8..e6b26b783b20 100644 --- a/crates/goose-mcp/src/developer/editor_models/morphllm_editor.rs +++ b/crates/goose-mcp/src/developer/editor_models/morphllm_editor.rs @@ -115,15 +115,12 @@ impl EditorModelImpl for MorphLLMEditor { You should bias towards repeating as few lines of the original file as possible to convey the change. Each edit should contain sufficient context of unchanged lines around the code you're editing to resolve ambiguity. If you plan on deleting a section, you must provide surrounding context to indicate the deletion. - DO NOT omit spans of pre-existing code without using the // ... existing code ... comment to indicate its absence. + DO NOT omit spans of pre-existing code without using the // ... existing code ... comment to indicate its absence. **IMPORTANT**: You must also provide an `instruction` parameter - a single sentence written in the first person describing what you are going to do for the sketched edit. This instruction helps the less intelligent model understand and apply your edit correctly. Examples of good instructions: - \"I am adding error handling to the user authentication function and removing the old authentication method\" - - \"I am refactoring the database connection logic to use async/await\" - - \"I am fixing the bug in the validation logic by updating the regex pattern\" - - \"I am adding a new method to handle user preferences and updating the constructor\" The instruction should be specific enough to disambiguate any uncertainty in your edit. " diff --git a/crates/goose-mcp/src/developer/mod.rs b/crates/goose-mcp/src/developer/mod.rs index 8fd07a4850c8..9644d24cc98a 100644 --- a/crates/goose-mcp/src/developer/mod.rs +++ b/crates/goose-mcp/src/developer/mod.rs @@ -38,7 +38,7 @@ use mcp_server::Router; use mcp_core::role::Role; -use self::editor_models::{create_editor_model, EditorModel}; +use self::editor_models::{create_editor_model, EditorModel, EditorModelImpl}; use self::shell::{expand_path, get_shell_config, is_absolute_path, normalize_line_endings}; use indoc::indoc; use std::process::Stdio; @@ -259,87 +259,168 @@ impl DeveloperRouter { }), ); - // Create text editor tool with different descriptions based on editor API configuration - let (text_editor_desc, str_replace_command) = if let Some(ref editor) = editor_model { - ( - formatdoc! {r#" - Perform text editing operations on files. - - The `command` parameter specifies the operation to perform. Allowed options are: - - `view`: View the content of a file. - - `write`: Create or overwrite a file with the given content - - `edit_file`: Edit the file with the new content. - - `insert`: Insert text at a specific line location in the file. - - `undo_edit`: Undo the last edit made to a file. - - To use the write command, you must specify `file_text` which will become the new content of the file. Be careful with - existing files! This is a full overwrite, so you must include everything - not just sections you are modifying. - - To use the edit_file command, you must specify both `old_str` and `new_str` - {}. - - To use the insert command, you must specify both `insert_line` (the line number after which to insert, 0 for beginning) - and `new_str` (the text to insert). - "#, editor.get_str_replace_description()}, - "edit_file", - ) - } else { - (indoc! {r#" - Perform text editing operations on files. - - The `command` parameter specifies the operation to perform. Allowed options are: - - `view`: View the content of a file. - - `write`: Create or overwrite a file with the given content - - `str_replace`: Replace a string in a file with a new string. - - `insert`: Insert text at a specific line location in the file. - - `undo_edit`: Undo the last edit made to a file. - - To use the write command, you must specify `file_text` which will become the new content of the file. Be careful with - existing files! This is a full overwrite, so you must include everything - not just sections you are modifying. - - To use the str_replace command, you must specify both `old_str` and `new_str` - the `old_str` needs to exactly match one - unique section of the original file, including any whitespace. Make sure to include enough context that the match is not - ambiguous. The entire original string will be replaced with `new_str`. - - To use the insert command, you must specify both `insert_line` (the line number after which to insert, 0 for beginning) - and `new_str` (the text to insert). - "#}.to_string(), "str_replace") + // Create text editor tool with different descriptions and schemas based on editor API configuration + let (text_editor_desc, schema_properties) = match &editor_model { + Some(EditorModel::MorphLLM(editor)) => { + // MorphLLM-specific configuration with instruction parameter + ( + formatdoc! {r#" + Perform text editing operations on files. + + The `command` parameter specifies the operation to perform. Allowed options are: + - `view`: View the content of a file. + - `write`: Create or overwrite a file with the given content + - `edit_file`: Edit the file with the new content. + - `insert`: Insert text at a specific line location in the file. + - `undo_edit`: Undo the last edit made to a file. + + To use the write command, you must specify `file_text` which will become the new content of the file. Be careful with + existing files! This is a full overwrite, so you must include everything - not just sections you are modifying. + + To use the edit_file command, you must specify both `old_str` and `new_str` - {}. + **IMPORTANT**: You must also provide an `instruction` parameter with your edit_file command. + + To use the insert command, you must specify both `insert_line` (the line number after which to insert, 0 for beginning) + and `new_str` (the text to insert). + "#, editor.get_str_replace_description()}, + json!({ + "path": { + "description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`.", + "type": "string" + }, + "command": { + "type": "string", + "enum": ["view", "write", "edit_file", "insert", "undo_edit"], + "description": "Allowed options are: `view`, `write`, `edit_file`, `insert`, `undo_edit`." + }, + "view_range": { + "type": "array", + "items": {"type": "integer"}, + "minItems": 2, + "maxItems": 2, + "description": "Optional array of two integers specifying the start and end line numbers to view. Line numbers are 1-indexed, and -1 for the end line means read to the end of the file. This parameter only applies when viewing files, not directories." + }, + "insert_line": { + "type": "integer", + "description": "The line number after which to insert the text (0 for beginning of file). This parameter is required when using the insert command." + }, + "old_str": {"type": "string"}, + "new_str": {"type": "string"}, + "instruction": { + "type": "string", + "description": "A single sentence written in the first person describing what you are going to do for the sketched edit. This helps the apply model understand and apply your edit correctly. Use it to disambiguate uncertainty in the edit." + }, + "file_text": {"type": "string"} + }), + ) + } + Some(editor) => { + // Other editors (OpenAI, etc...) - no instruction parameter + ( + formatdoc! {r#" + Perform text editing operations on files. + + The `command` parameter specifies the operation to perform. Allowed options are: + - `view`: View the content of a file. + - `write`: Create or overwrite a file with the given content + - `edit_file`: Edit the file with the new content. + - `insert`: Insert text at a specific line location in the file. + - `undo_edit`: Undo the last edit made to a file. + + To use the write command, you must specify `file_text` which will become the new content of the file. Be careful with + existing files! This is a full overwrite, so you must include everything - not just sections you are modifying. + + To use the edit_file command, you must specify both `old_str` and `new_str` - {}. + + To use the insert command, you must specify both `insert_line` (the line number after which to insert, 0 for beginning) + and `new_str` (the text to insert). + "#, editor.get_str_replace_description()}, + json!({ + "path": { + "description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`.", + "type": "string" + }, + "command": { + "type": "string", + "enum": ["view", "write", "edit_file", "insert", "undo_edit"], + "description": "Allowed options are: `view`, `write`, `edit_file`, `insert`, `undo_edit`." + }, + "view_range": { + "type": "array", + "items": {"type": "integer"}, + "minItems": 2, + "maxItems": 2, + "description": "Optional array of two integers specifying the start and end line numbers to view. Line numbers are 1-indexed, and -1 for the end line means read to the end of the file. This parameter only applies when viewing files, not directories." + }, + "insert_line": { + "type": "integer", + "description": "The line number after which to insert the text (0 for beginning of file). This parameter is required when using the insert command." + }, + "old_str": {"type": "string"}, + "new_str": {"type": "string"}, + "file_text": {"type": "string"} + }), + ) + } + None => { + // No editor - traditional str_replace + ( + indoc! {r#" + Perform text editing operations on files. + + The `command` parameter specifies the operation to perform. Allowed options are: + - `view`: View the content of a file. + - `write`: Create or overwrite a file with the given content + - `str_replace`: Replace a string in a file with a new string. + - `insert`: Insert text at a specific line location in the file. + - `undo_edit`: Undo the last edit made to a file. + + To use the write command, you must specify `file_text` which will become the new content of the file. Be careful with + existing files! This is a full overwrite, so you must include everything - not just sections you are modifying. + + To use the str_replace command, you must specify both `old_str` and `new_str` - the `old_str` needs to exactly match one + unique section of the original file, including any whitespace. Make sure to include enough context that the match is not + ambiguous. The entire original string will be replaced with `new_str`. + + To use the insert command, you must specify both `insert_line` (the line number after which to insert, 0 for beginning) + and `new_str` (the text to insert). + "#}.to_string(), + json!({ + "path": { + "description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`.", + "type": "string" + }, + "command": { + "type": "string", + "enum": ["view", "write", "str_replace", "insert", "undo_edit"], + "description": "Allowed options are: `view`, `write`, `str_replace`, `insert`, `undo_edit`." + }, + "view_range": { + "type": "array", + "items": {"type": "integer"}, + "minItems": 2, + "maxItems": 2, + "description": "Optional array of two integers specifying the start and end line numbers to view. Line numbers are 1-indexed, and -1 for the end line means read to the end of the file. This parameter only applies when viewing files, not directories." + }, + "insert_line": { + "type": "integer", + "description": "The line number after which to insert the text (0 for beginning of file). This parameter is required when using the insert command." + }, + "old_str": {"type": "string"}, + "new_str": {"type": "string"}, + "file_text": {"type": "string"} + }) + ) + } }; let text_editor_tool = Tool::new( "text_editor".to_string(), - text_editor_desc.to_string(), + text_editor_desc, json!({ "type": "object", "required": ["command", "path"], - "properties": { - "path": { - "description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`.", - "type": "string" - }, - "command": { - "type": "string", - "enum": ["view", "write", str_replace_command, "insert", "undo_edit"], - "description": format!("Allowed options are: `view`, `write`, `{}`, `insert`, `undo_edit`.", str_replace_command) - }, - "view_range": { - "type": "array", - "items": {"type": "integer"}, - "minItems": 2, - "maxItems": 2, - "description": "Optional array of two integers specifying the start and end line numbers to view. Line numbers are 1-indexed, and -1 for the end line means read to the end of the file. This parameter only applies when viewing files, not directories." - }, - "insert_line": { - "type": "integer", - "description": "The line number after which to insert the text (0 for beginning of file). This parameter is required when using the insert command." - }, - "old_str": {"type": "string"}, - "new_str": {"type": "string"}, - "instruction": { - "type": "string", - "description": "A single sentence written in the first person describing what you are going to do for the sketched edit. Use it to disambiguate uncertainty in the edit." - }, - "file_text": {"type": "string"} - } + "properties": schema_properties }), None, ); @@ -884,10 +965,20 @@ impl DeveloperRouter { .ok_or_else(|| { ToolError::InvalidParameters("Missing 'new_str' parameter".into()) })?; - let instruction = params - .get("instruction") - .and_then(|v| v.as_str()) - .unwrap_or(""); // Empty string for backward compatibility + + // Only extract instruction parameter when MorphLLM is being used + let instruction = match &self.editor_model { + Some(EditorModel::MorphLLM(_)) => params + .get("instruction") + .and_then(|v| v.as_str()) + .ok_or_else(|| { + ToolError::InvalidParameters( + "Missing 'instruction' parameter required for MorphLLM editor" + .into(), + ) + })?, + _ => "", // Empty instruction for other editors or no editor + }; self.text_editor_replace(&path, old_str, new_str, instruction) .await From 5033407c7c8e1f5c5c471806cce1d7f426af1204 Mon Sep 17 00:00:00 2001 From: bhaktatejas922 Date: Wed, 23 Jul 2025 17:55:38 -0700 Subject: [PATCH 6/6] refactor per mic comments --- crates/goose-mcp/src/developer/editor_models/mod.rs | 9 +++++++++ crates/goose-mcp/src/developer/mod.rs | 13 ++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/crates/goose-mcp/src/developer/editor_models/mod.rs b/crates/goose-mcp/src/developer/editor_models/mod.rs index 563885b692e8..0a91e1f41df5 100644 --- a/crates/goose-mcp/src/developer/editor_models/mod.rs +++ b/crates/goose-mcp/src/developer/editor_models/mod.rs @@ -53,6 +53,15 @@ impl EditorModel { EditorModel::Relace(editor) => editor.get_str_replace_description(), } } + + /// Check if this editor supports/requires the instruction parameter + pub fn supports_instruction_parameter(&self) -> bool { + match self { + EditorModel::MorphLLM(_) => true, + EditorModel::OpenAICompatible(_) => false, + EditorModel::Relace(_) => false, + } + } } /// Trait for individual editor implementations diff --git a/crates/goose-mcp/src/developer/mod.rs b/crates/goose-mcp/src/developer/mod.rs index 9644d24cc98a..0752d1120361 100644 --- a/crates/goose-mcp/src/developer/mod.rs +++ b/crates/goose-mcp/src/developer/mod.rs @@ -38,7 +38,7 @@ use mcp_server::Router; use mcp_core::role::Role; -use self::editor_models::{create_editor_model, EditorModel, EditorModelImpl}; +use self::editor_models::{create_editor_model, EditorModel}; use self::shell::{expand_path, get_shell_config, is_absolute_path, normalize_line_endings}; use indoc::indoc; use std::process::Stdio; @@ -261,8 +261,8 @@ impl DeveloperRouter { // Create text editor tool with different descriptions and schemas based on editor API configuration let (text_editor_desc, schema_properties) = match &editor_model { - Some(EditorModel::MorphLLM(editor)) => { - // MorphLLM-specific configuration with instruction parameter + Some(editor) if editor.supports_instruction_parameter() => { + // Editors that support/require instruction parameter (like MorphLLM) ( formatdoc! {r#" Perform text editing operations on files. @@ -966,15 +966,14 @@ impl DeveloperRouter { ToolError::InvalidParameters("Missing 'new_str' parameter".into()) })?; - // Only extract instruction parameter when MorphLLM is being used + // Only extract instruction parameter when editors that support it are being used let instruction = match &self.editor_model { - Some(EditorModel::MorphLLM(_)) => params + Some(editor) if editor.supports_instruction_parameter() => params .get("instruction") .and_then(|v| v.as_str()) .ok_or_else(|| { ToolError::InvalidParameters( - "Missing 'instruction' parameter required for MorphLLM editor" - .into(), + "Missing 'instruction' parameter required for this editor".into(), ) })?, _ => "", // Empty instruction for other editors or no editor