Repository: letta-ai/letta
Pull request: fix: include missing function arguments in error handling
**Please describe the purpose of this pull request.**
This pr changes `letta/agent.py` file by adding `function_args` as a parameter to several methods, so to ensure that function arguments are correctly passed and logged during error handling process.

**Related issues or PRs**
resolves #2422


Problem statement:
name 'function_args' is not defined
**Describe the bug**
When chatting with the Letta-created agents, I got the following error:

```sh
error = name 'function_args' is not defined
Letta.letta.agent - ERROR - step() failed with an unrecognized exception: 'name 'function_args' is not defined'
Letta.letta.server.server - ERROR - Error in server._step: name 'function_args' is not defined
Traceback (most recent call last):
  File "/Users/clannad/Library/Caches/pypoetry/virtualenvs/yanara-BBYGsHMK-py3.12/lib/python3.12/site-packages/letta/server/server.py", line 458, in _step
    usage_stats = letta_agent.step(
                  ^^^^^^^^^^^^^^^^^
  File "/Users/clannad/Library/Caches/pypoetry/virtualenvs/yanara-BBYGsHMK-py3.12/lib/python3.12/site-packages/letta/agent.py", line 616, in step
    step_response = self.inner_step(
                    ^^^^^^^^^^^^^^^^
  File "/Users/clannad/Library/Caches/pypoetry/virtualenvs/yanara-BBYGsHMK-py3.12/lib/python3.12/site-packages/letta/agent.py", line 869, in inner_step
    raise e
  File "/Users/clannad/Library/Caches/pypoetry/virtualenvs/yanara-BBYGsHMK-py3.12/lib/python3.12/site-packages/letta/agent.py", line 748, in inner_step
    all_response_messages, heartbeat_request, function_failed = self._handle_ai_response(
                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/clannad/Library/Caches/pypoetry/virtualenvs/yanara-BBYGsHMK-py3.12/lib/python3.12/site-packages/letta/agent.py", line 545, in _handle_ai_response
    messages = self._handle_function_error_response(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/clannad/Library/Caches/pypoetry/virtualenvs/yanara-BBYGsHMK-py3.12/lib/python3.12/site-packages/letta/agent.py", line 290, in _handle_function_error_response
    self.interface.function_message(f"Ran {function_name}({function_args})", msg_obj=new_message)
                                                           ^^^^^^^^^^^^^
NameError: name 'function_args' is not defined. Did you mean: 'function_name'?
```

**Please describe your setup**
- [X] How did you install letta?
  - `pip install letta`
- [X] Describe your setup
  - What's your OS? **MacOS**
  - How are you running `letta`? **Terminal**

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

[archival_storage]
type = chroma
path = /Users/clannad/.letta/chroma

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

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

[version]
letta_version = 0.6.23
```

Hints from issue discussion:

Commit message: fix: include missing function arguments in error handling

Patch to review:
diff --git a/letta/agent.py b/letta/agent.py
index bb082fbf7f..ce36173ab6 100644
--- a/letta/agent.py
+++ b/letta/agent.py
@@ -260,6 +260,7 @@ def _handle_function_error_response(
         error_msg: str,
         tool_call_id: str,
         function_name: str,
+        function_args: str,
         function_response: str,
         messages: List[Message],
         include_function_failed_message: bool = False,
@@ -394,6 +395,7 @@ def _handle_ai_response(
 
         messages = []  # append these to the history when done
         function_name = None
+        function_args = {}
 
         # Step 2: check if LLM wanted to call a function
         if response_message.function_call or (response_message.tool_calls is not None and len(response_message.tool_calls) > 0):
@@ -459,7 +461,7 @@ def _handle_ai_response(
             if not target_letta_tool:
                 error_msg = f"No function named {function_name}"
                 function_response = "None"  # more like "never ran?"
-                messages = self._handle_function_error_response(error_msg, tool_call_id, function_name, function_response, messages)
+                messages = self._handle_function_error_response(error_msg, tool_call_id, function_name, function_args, function_response, messages)
                 return messages, False, True  # force a heartbeat to allow agent to handle error
 
             # Failure case 2: function name is OK, but function args are bad JSON
@@ -469,7 +471,7 @@ def _handle_ai_response(
             except Exception:
                 error_msg = f"Error parsing JSON for function '{function_name}' arguments: {function_call.arguments}"
                 function_response = "None"  # more like "never ran?"
-                messages = self._handle_function_error_response(error_msg, tool_call_id, function_name, function_response, messages)
+                messages = self._handle_function_error_response(error_msg, tool_call_id, function_name, function_args, function_response, messages)
                 return messages, False, True  # force a heartbeat to allow agent to handle error
 
             # Check if inner thoughts is in the function call arguments (possible apparently if you are using Azure)
@@ -506,7 +508,7 @@ def _handle_ai_response(
 
                 if sandbox_run_result and sandbox_run_result.status == "error":
                     messages = self._handle_function_error_response(
-                        function_response, tool_call_id, function_name, function_response, messages
+                        function_response, tool_call_id, function_name, function_args, function_response, messages
                     )
                     return messages, False, True  # force a heartbeat to allow agent to handle error
 
@@ -535,7 +537,7 @@ def _handle_ai_response(
                 error_msg_user = f"{error_msg}\n{traceback.format_exc()}"
                 self.logger.error(error_msg_user)
                 messages = self._handle_function_error_response(
-                    error_msg, tool_call_id, function_name, function_response, messages, include_function_failed_message=True
+                    error_msg, tool_call_id, function_name, function_args, function_response, messages, include_function_failed_message=True
                 )
                 return messages, False, True  # force a heartbeat to allow agent to handle error
 
@@ -543,7 +545,7 @@ def _handle_ai_response(
             if function_response_string.startswith(ERROR_MESSAGE_PREFIX):
                 error_msg = function_response_string
                 messages = self._handle_function_error_response(
-                    error_msg, tool_call_id, function_name, function_response, messages, include_function_failed_message=True
+                    error_msg, tool_call_id, function_name, function_args, function_response, messages, include_function_failed_message=True
                 )
                 return messages, False, True  # force a heartbeat to allow agent to handle error
 


Code review comments:
diff_hunk: @@ -260,6 +260,7 @@ def _handle_function_error_response(
         error_msg: str,
         tool_call_id: str,
         function_name: str,
+        function_args: str,
path: letta/agent.py
text: @user1:
I think you meant  `function_args: dict`? 

@author:
yesssss!