Skip to content

Comments

feat: create a text editor tool with multiple commands#186

Closed
salman1993 wants to merge 6 commits intomainfrom
sm/anthropic-text-editor-tool
Closed

feat: create a text editor tool with multiple commands#186
salman1993 wants to merge 6 commits intomainfrom
sm/anthropic-text-editor-tool

Conversation

@salman1993
Copy link
Contributor

@salman1993 salman1993 commented Oct 23, 2024

Changes:

Anthropic is using this text editor tool for Computer Use. It might be useful to try this in goose - docs, code. It seems like they prefer to have fewer tools, but each tool has more optional args which are used for specific actions. For example, in goose we have separate tools for read_file, write_file, patch_file but in this case, its a single EditorTool with command as an Enum that routes to the editor action (view, create, insert).

Test:

tool descriptions are correctly passed
tool-descriptions

@salman1993 salman1993 requested a review from baxen October 23, 2024 17:28
@salman1993 salman1993 changed the title Create a text editor tool with multiple commands feat: create a text editor tool with multiple commands Oct 23, 2024
import uuid
from importlib.metadata import entry_points
from typing import get_args, get_origin
from typing import Literal, get_args, get_origin, Any, List, Tuple, Dict, Union
Copy link
Contributor

@lamchau lamchau Oct 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:nit: we can use list, tuple, and dict directly now

@michaelneale
Copy link
Collaborator

interesting, will try this out, could be promising. I did notice that tool calling seemed to work well with parameters in the past, and even with richer CLIs - ie able to use the one "tool" different ways seems to suit it more so than choosing between tools (intuitively that makes sense, as a human, to some limited extent, you don't have the cognitive overload of choosing the tool)

@michaelneale
Copy link
Collaborator

@salman1993 any tips on how to try it out to A/B test?

@michaelneale
Copy link
Collaborator

tried it out with editing just one spot in a yaml file... just FYI:

The phrase "Found packages with disallowed licenses" occurs multiple times in the .github/workflows/license-check.yml file, making it necessary to be more      
specific in the string replace operation. I'll view more of the file to identify the different locations and modify them accordingly. Let's check the           
occurrences separately.                                                                                                                                         

─── .github/workflows/license-check.yml ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                                                                                                                                                                
         uses: actions/setup-python@v5                                                                                                                          
         with:                                                                                                                                                  
           python-version: '3.10'                                                                                                                               
                                                                                                                                                                
       - name: Install dependencies                                                                                                                             
         run: |                                                                                                                                                 
           python -m pip install --upgrade pip                                                                                                                  
           pip install tomli requests urllib3                                                                                                                   
                                                                                                                                                                
       - name: Check licenses                                                                                                                                   
         run: |                                                                                                                                                 
           python .github/workflows/scripts/check_licenses.py \                                                                                                 
             pyproject.toml || exit_code=$?                                                                                                                     
           if [ "${exit_code:-0}" -ne 0 ]; then                                                                                                                 
             echo "::error::Found packages with disallowed licenses"                                                                                            
             exit 1                                                                                                                                             
           fi                                                                                                                                                   
                                                                                                                                                                
       - name: Check Exchange licenses                                                                                                                          
         run: |                                                                                                                                                 
           python .github/workflows/scripts/check_licenses.py \                                                                                                 
             packages/exchange/pyproject.toml || exit_code=$?                                                                                                   
           if [ "${exit_code:-0}" -ne 0 ]; then                                                                                                                 
             echo "::error::Found packages with disallowed licenses in exchange"                                                                                
             exit 1                                                                                                                                             
           fi                                                                                                                                                   
                                                                                                                                                                


─── .github/workflows/license-check.yml ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                


─── .github/workflows/license-check.yml ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                

Let's specify the contexts where we succeed the operations, starting with the first one.                                                                        

─── .github/workflows/license-check.yml ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                                                                                                                                                                
 echo "::error::Found packages with disallowed licenses"                                                                                                        
                                                                                                                                                                

->                                                                                                                                                              

                                                                                                                                                                
 echo "::error::Found packages with disallowed licenses, it was in the goose package."                                                                          
                                                                                                                                                                


─── .github/workflows/license-check.yml ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                                                                                                                                                                
 echo "::error::Found packages with disallowed licenses in exchange"                                                                                            
                                                                                                                                                                

->                                                                                                                                                              

                                                                                                                                                                
 echo "::error::Found packages with disallowed licenses, it was in the goose package."

some odd artifacts like:

image

@michaelneale
Copy link
Collaborator

so far seems to do a good job - but not pushed too hard today

print(f"We are warning the LLM to view before write in write_file, with path={path} and patho={str(patho)}")
raise ValueError(f"You must view {path} using read_file before you overwrite it")

self._save_file_history(patho) # Save current content to history
Copy link
Contributor

@lamchau lamchau Oct 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:nit: i see a lot of erroneous comments like these in this pr and most of the time they're already self documenting. maybe remove?

return f"Successfully undid the last edit on {path}"

@tool
def text_editor(
Copy link
Contributor

@lamchau lamchau Oct 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a lot of conflated concerns/responsibilities in a single method. it's a little tough to read and would even harder to test. how about trying out a dispatch pattern?

command_dispatch: dict[str, callable] = {
    "create": self._create_file,
    "insert": self._insert_string,
    "undo_edit": self._undo_edit,
     ...
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should possibly consider creating a text editor abstraction given the complex interactions we have here. maybe these things would play well with the editor integrations people have made plugins for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like the suggestion for dispatcher pattern. i opened another PR cause i also batched up the changes for bash and process manager: #191

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lamchau I think this is the approach that claude took and it seems to work well - a smaller number of tools I think is cognitively more pleasant vs LLM needing to decide which tool to use (also lets us put more smarts in the tool vs relying on LLM always to choose the right way) - so I think this general approach feels right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@michaelneale not sure i follow? i think the logic itself is sound just tidying it up

@salman1993
Copy link
Contributor Author

changes from this PR are in this one: #191

@salman1993 salman1993 closed this Oct 25, 2024
@yingjiehe-xyz yingjiehe-xyz deleted the sm/anthropic-text-editor-tool branch February 5, 2025 21:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants