Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tools don´t work #2330

Open
2 tasks
quantumcthulhu opened this issue Jan 5, 2025 · 6 comments
Open
2 tasks

Tools don´t work #2330

quantumcthulhu opened this issue Jan 5, 2025 · 6 comments

Comments

@quantumcthulhu
Copy link

Describe the bug

I´m trying to create any tool, but it doesn´t work. I try this tool from the Deeplearning example:

def task_queue_push(self: "Agent", task_description: str):
    """
    Push to a task queue stored in core memory. 

    Args:
        task_description (str): A description of the next task you must accomplish. 

    Returns:
        Optional[str]: None is always returned as this function 
        does not produce a response.
    """
    import json
    tasks = json.loads(self.memory.get_block("tasks").value)
    tasks.append(task_description)
    self.memory.update_block_value("tasks", json.dumps(tasks))
    return None

When agent is working it always return me error like this:

Request

{
  "task_description": "Create project directory and necessary files for Calendar app.",
  "request_heartbeat": true
}

Response

{
  "status": "Failed",
  "message": "Error executing function task_queue_push: TypeError: task_queue_push() missing 1 required positional argument: 'self'",
  "time": "2025-01-05 03:49:44 PM WET+0000"
}

Whenever I add any other tool, it always has issues with ´self´:

def create_file(self: "Agent", relative_path: str, initial_content: str = "") -> str:
    """
    Creates a new file at '/Users/Shared/Projects/<project_name>/<relative_path>'
    and optionally writes initial content.
    If the file already exists, it will be overwritten.

    Args:
        relative_path (str): The path (relative to the project directory).
        initial_content (str): Optional string content to write into the newly created file.

    Returns:
        str: A success or error message.
    """
    import os

    # Retrieve the project name from memory (adapt if your memory system differs).
    project_name = self.memory.get_block("project_name").value
    base_dir = "/Users/Shared/Projects"
    full_path = os.path.join(base_dir, project_name, relative_path)

    try:
        os.makedirs(os.path.dirname(full_path), exist_ok=True)
        with open(full_path, "w", encoding="utf-8") as f:
            f.write(initial_content)
        return f"File created at '{full_path}' with initial content."
    except Exception as e:
        return f"Failed to create file '{full_path}': {str(e)}"

Request

{
  "relative_path": "Main.storyboard",
  "initial_content": "<storyboard version=\"3.0\"></storyboard>",
  "request_heartbeat": true
}

Response

{
  "status": "Failed",
  "message": "Error executing function create_file: TypeError: create_file() missing 1 required positional argument: 'self'",
  "time": "2025-01-05 03:49:49 PM WET+0000"
}

Please describe your setup

  • How did you install letta?
    • pip install letta
  • Describe your setup
    • What's your OS (Windows/MacOS/Linux)?
      MacOS

    • How are you running letta? (cmd.exe/Powershell/Anaconda Shell/Terminal)
      Terminal

Letta Config
[defaults]
preset = memgpt_chat
persona = sam_pov
human = basic

[archival_storage]
type = sqlite
path = /Users/user/.letta

[recall_storage]
type = sqlite
path = /Users/user/.letta

[metadata_storage]
type = sqlite
path = /Users/user/.letta

[version]
letta_version = 0.6.7

@lemorage
Copy link
Contributor

Sorry, lots of things changed. I think now for ver0.6.7, you don't need to include the param self: "Agent" anymore when defining the tool.

@quantumcthulhu
Copy link
Author

Sorry, lots of things changed. I think now for ver0.6.7, you don't need to include the param self: "Agent" anymore when defining the tool.

Can you please provide right format how to define tool

@sarahwooders
Copy link
Collaborator

sarahwooders commented Jan 11, 2025

You should be able to do this on the lates 0.6.9 version:

from letta import create_client

def create_file(relative_path: str, initial_content: str = "") -> str:
    """
    Creates a new file at '/Users/Shared/Projects/<project_name>/<relative_path>'
    and optionally writes initial content.
    If the file already exists, it will be overwritten.

    Args:
        relative_path (str): The path (relative to the project directory).
        initial_content (str): Optional string content to write into the newly created file.

    Returns:
        str: A success or error message.
    """
    import os

    # Retrieve the project name from memory (adapt if your memory system differs).
    project_name = self.memory.get_block("project_name").value
    base_dir = "/Users/Shared/Projects"
    full_path = os.path.join(base_dir, project_name, relative_path)

    try:
        os.makedirs(os.path.dirname(full_path), exist_ok=True)
        with open(full_path, "w", encoding="utf-8") as f:
            f.write(initial_content)
        return f"File created at '{full_path}' with initial content."
    except Exception as e:
        return f"Failed to create file '{full_path}': {str(e)}"

client = create_client() 
tool = client.create_tool(create_file)
print(tool)

Note that you'll need to attach the tool to the agent when you create it.

@RadeenXALNW
Copy link

Mine is showing name is not defined when I am executing my code as well as the above code also is showing same error.

  File "/home/zeus/miniconda3/envs/cloudspace/lib/python3.10/site-packages/letta/client/client.py", line 2999, in create_tool
    name=name,
NameError: name 'name' is not defined

@alaliaa
Copy link

alaliaa commented Feb 17, 2025

Mine is showing name is not defined when I am executing my code as well as the above code also is showing same error.

  File "/home/zeus/miniconda3/envs/cloudspace/lib/python3.10/site-packages/letta/client/client.py", line 2999, in create_tool
    name=name,
NameError: name 'name' is not defined

I am facing the same issue.
I believe it is a bug in the create_tool function. In the recent version, they removed the name argument.

Here is the old function (from the deeplearning.ai course)

    def create_tool(
        self,
        func,
        name: Optional[str] = None,
        update: Optional[bool] = True,  # TODO: actually use this
        tags: Optional[List[str]] = None,
    ) -> Tool:
        """
        Create a tool. This stores the source code of function on the server, so that the server can execute the function and generate an OpenAI JSON schemas for it when using with an agent.

        Args:
            func (callable): The function to create a tool for.
            name: (str): Name of the tool (must be unique per-user.)
            tags (Optional[List[str]], optional): Tags for the tool. Defaults to None.
            update (bool, optional): Update the tool if it already exists. Defaults to True.

        Returns:
            tool (Tool): The created tool.
        """
        # TODO: check if tool already exists
        # TODO: how to load modules?
        # parse source code/schema
        source_code = parse_source_code(func)
        source_type = "python"
        if not tags:
            tags = []

        # call server function
        return self.server.create_tool(
            # ToolCreate(source_type=source_type, source_code=source_code, name=tool_name, json_schema=json_schema, tags=tags),
            ToolCreate(source_type=source_type, source_code=source_code, name=name, tags=tags),
            user_id=self.user_id,
            update=update,
        )

and here is the function from Letta 0.6.27, which doesn't have the 'name' argument but it calls it in the body.

   def create_tool(
        self,
        func,
        tags: Optional[List[str]] = None,
        description: Optional[str] = None,
        return_char_limit: int = FUNCTION_RETURN_CHAR_LIMIT,
    ) -> Tool:
        """
        Create a tool. This stores the source code of function on the server, so that the server can execute the function and generate an OpenAI JSON schemas for it when using with an agent.

        Args:
            func (callable): The function to create a tool for.
            name: (str): Name of the tool (must be unique per-user.)
            tags (Optional[List[str]], optional): Tags for the tool. Defaults to None.
            description (str, optional): The description.
            return_char_limit (int): The character limit for the tool's return value. Defaults to FUNCTION_RETURN_CHAR_LIMIT.

        Returns:
            tool (Tool): The created tool.
        """
        # TODO: check if tool already exists
        # TODO: how to load modules?
        # parse source code/schema
        source_code = parse_source_code(func)
        source_type = "python"
        if not tags:
            tags = []

        # call server function
        return self.server.tool_manager.create_tool(
            Tool(
                source_type=source_type,
                source_code=source_code,
                name=name,
                tags=tags,
                description=description,
                return_char_limit=return_char_limit,
            ),
            actor=self.user,
        )

@lemorage
Copy link
Contributor

@alaliaa Yes, the create_tool method is implemented by LocalClient & RESTClient, and they are both deprecated as stated in the website:

Warning

The legacy Letta Python LocalClient/RestClient SDK is available under pip install letta (which also contains the server). This client is deprecated and will be replaced in a future release with the new letta-client. Please migrate any Python code using the old RESTClient or LocalClient to use letta-client to avoid breaking changes in the future.

Now the recommended way is to use the new letta-client, as follows:

client = Letta(base_url="http://localhost:8283")
# define a function with a docstring
def roll_d20() -> str:
"""
Simulate the roll of a 20-sided die (d20).
This function generates a random integer between 1 and 20, inclusive,
which represents the outcome of a single roll of a d20.
Returns:
int: A random integer between 1 and 20, representing the die roll.
Example:
>>> roll_d20()
15 # This is an example output and may vary each time the function is called.
"""
import random
dice_role_outcome = random.randint(1, 20)
output_string = f"You rolled a {dice_role_outcome}"
return output_string
# create a tool from the function
tool = client.tools.upsert_from_function(func=roll_d20)
print(f"Created tool with name {tool.name}")

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

No branches or pull requests

5 participants