feat: add error handling for approval response attempt (#4326)

* feat: add error handling for approval response attempt

* add one more error case

* improve error messages
This commit is contained in:
cthomas
2025-08-29 20:39:28 -07:00
committed by GitHub
parent 4face1530d
commit 484d2a4e93
2 changed files with 50 additions and 2 deletions

View File

@@ -148,6 +148,27 @@ async def _prepare_in_context_messages_no_persist_async(
# Otherwise, include the full list of messages by ID for context
current_in_context_messages = await message_manager.get_messages_by_ids_async(message_ids=agent_state.message_ids, actor=actor)
# Check for approval-related message validation
if len(input_messages) == 1 and input_messages[0].type == "approval":
# User is trying to send an approval response
if current_in_context_messages[-1].role != "approval":
raise ValueError(
"Cannot process approval response: No tool call is currently awaiting approval. "
"Please send a regular message to interact with the agent."
)
if input_messages[0].approval_request_id != current_in_context_messages[-1].id:
raise ValueError(
f"Invalid approval request ID. Expected '{current_in_context_messages[-1].id}' "
f"but received '{input_messages[0].approval_request_id}'."
)
else:
# User is trying to send a regular message
if current_in_context_messages[-1].role == "approval":
raise ValueError(
"Cannot send a new message: The agent is waiting for approval on a tool call. "
"Please approve or deny the pending request before continuing."
)
# Create a new user message from the input but dont store it yet
new_in_context_messages = create_input_messages(
input_messages=input_messages, agent_id=agent_state.id, timezone=agent_state.timezone, actor=actor

View File

@@ -7,7 +7,8 @@ from typing import Any, List
import pytest
import requests
from dotenv import load_dotenv
from letta_client import Letta, MessageCreate
from letta_client import ApprovalCreate, Letta, MessageCreate
from letta_client.core.api_error import ApiError
from letta.log import get_logger
from letta.schemas.agent import AgentState
@@ -98,7 +99,7 @@ def approval_tool_fixture(client: Letta):
client.tools.upsert_base_tools()
approval_tool = client.tools.upsert_from_function(
func=requires_approval_tool,
# default_requires_approval=True,
# default_requires_approval=True, switch to this once it is supported in sdk
)
yield approval_tool
@@ -118,6 +119,11 @@ def agent(client: Letta, approval_tool_fixture) -> AgentState:
embedding="openai/text-embedding-3-small",
tags=["approval_test"],
)
client.agents.tools.modify_approval(
agent_id=agent_state.id,
tool_name=approval_tool_fixture.name,
requires_approval=True,
)
yield agent_state
@@ -136,6 +142,13 @@ def test_send_message_with_approval_tool(
This test just verifies that the agent can send a message successfully.
The actual approval logic testing will be filled out by the user.
"""
# Attempt to send approval without pending request
with pytest.raises(ApiError, match="No tool call is currently awaiting approval"):
client.agents.messages.create(
agent_id=agent.id,
messages=[ApprovalCreate(approve=True, approval_request_id="fake_id")],
)
# Send a simple greeting message to test basic functionality
response = client.agents.messages.create(
agent_id=agent.id,
@@ -147,3 +160,17 @@ def test_send_message_with_approval_tool(
assert len(response.messages) == 2
assert response.messages[0].message_type == "reasoning_message"
assert response.messages[1].message_type == "approval_request_message"
# Attempt to send user message - should fail
with pytest.raises(ApiError, match="Please approve or deny the pending request before continuing"):
client.agents.messages.create(
agent_id=agent.id,
messages=[MessageCreate(role="user", content="hi")],
)
# Attempt to send approval with incorrect id
with pytest.raises(ApiError, match="Invalid approval request ID"):
client.agents.messages.create(
agent_id=agent.id,
messages=[ApprovalCreate(approve=True, approval_request_id="fake_id")],
)