Skip to content

Commit

Permalink
Merge branch 'main' of github.com:letta-ai/letta into granch
Browse files Browse the repository at this point in the history
  • Loading branch information
Shubham Naik committed Dec 23, 2024
2 parents 097b30e + ea2a739 commit 16de9f6
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 12 deletions.
3 changes: 1 addition & 2 deletions letta/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,6 @@ def _get_ai_reply(
# Force a tool call if exactly one tool is specified
elif step_count is not None and step_count > 0 and len(allowed_tool_names) == 1:
force_tool_call = allowed_tool_names[0]

for attempt in range(1, empty_response_retry_limit + 1):
try:
response = create(
Expand Down Expand Up @@ -314,7 +313,7 @@ def _get_ai_reply(
except ValueError as ve:
if attempt >= empty_response_retry_limit:
warnings.warn(f"Retry limit reached. Final error: {ve}")
break
raise Exception(f"Retries exhausted and no valid response received. Final error: {ve}")
else:
delay = min(backoff_factor * (2 ** (attempt - 1)), max_delay)
warnings.warn(f"Attempt {attempt} failed: {ve}. Retrying in {delay} seconds...")
Expand Down
2 changes: 1 addition & 1 deletion letta/server/rest_api/routers/v1/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def add_tool_to_agent(
):
"""Add tools to an existing agent"""
actor = server.user_manager.get_user_or_default(user_id=user_id)
return server.agent_manager.attach_tool(agent_id=agent_id, tool_id=tool_id, user_id=actor)
return server.agent_manager.attach_tool(agent_id=agent_id, tool_id=tool_id, actor=actor)


@router.patch("/{agent_id}/remove-tool/{tool_id}", response_model=AgentState, operation_id="remove_tool_from_agent")
Expand Down
57 changes: 52 additions & 5 deletions letta/server/rest_api/routers/v1/tools.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from typing import List, Optional

from composio.client import ComposioClientError, HTTPError, NoItemsFound
from composio.client.collections import ActionModel, AppModel
from composio.client.enums.base import EnumStringNotFound
from composio.exceptions import ComposioSDKError
from composio.exceptions import ApiKeyNotProvidedError, ComposioSDKError
from composio.tools.base.abs import InvalidClassDefinition
from fastapi import APIRouter, Body, Depends, Header, HTTPException

from letta.errors import LettaToolCreateError
Expand Down Expand Up @@ -239,21 +241,66 @@ def add_composio_tool(
try:
tool_create = ToolCreate.from_composio(action_name=composio_action_name, api_key=composio_api_key)
return server.tool_manager.create_or_update_tool(pydantic_tool=Tool(**tool_create.model_dump()), actor=actor)
except EnumStringNotFound:
except EnumStringNotFound as e:
raise HTTPException(
status_code=400, # Bad Request
detail={
"code": "EnumStringNotFound",
"message": f"Cannot find composio action with name `{composio_action_name}`.",
"message": str(e),
"composio_action_name": composio_action_name,
},
)
except ComposioSDKError:
except HTTPError as e:
raise HTTPException(
status_code=400, # Bad Request
detail={
"code": "HTTPError",
"message": str(e),
"composio_action_name": composio_action_name,
},
)
except NoItemsFound as e:
raise HTTPException(
status_code=400, # Bad Request
detail={
"code": "NoItemsFound",
"message": str(e),
"composio_action_name": composio_action_name,
},
)
except ComposioClientError as e:
raise HTTPException(
status_code=400, # Bad Request
detail={
"code": "ComposioClientError",
"message": str(e),
"composio_action_name": composio_action_name,
},
)
except ApiKeyNotProvidedError as e:
raise HTTPException(
status_code=400, # Bad Request
detail={
"code": "ApiKeyNotProvidedError",
"message": str(e),
"composio_action_name": composio_action_name,
},
)
except InvalidClassDefinition as e:
raise HTTPException(
status_code=400, # Bad Request
detail={
"code": "InvalidClassDefinition",
"message": str(e),
"composio_action_name": composio_action_name,
},
)
except ComposioSDKError as e:
raise HTTPException(
status_code=400, # Bad Request
detail={
"code": "ComposioSDKError",
"message": f"No connected account found for tool `{composio_action_name}`. You need to connect the relevant app in Composio order to use the tool.",
"message": str(e),
"composio_action_name": composio_action_name,
},
)
Expand Down
8 changes: 4 additions & 4 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,16 +400,16 @@ def always_error():

response_message = None
for message in response.messages:
if isinstance(message, FunctionReturn):
if isinstance(message, ToolReturnMessage):
response_message = message
break

assert response_message, "FunctionReturn message not found in response"
assert response_message, "ToolReturnMessage message not found in response"
assert response_message.status == "error"
if isinstance(client, RESTClient):
assert response_message.function_return == "Error executing function always_error: ZeroDivisionError: division by zero"
assert response_message.tool_return == "Error executing function always_error: ZeroDivisionError: division by zero"
else:
response_json = json.loads(response_message.function_return)
response_json = json.loads(response_message.tool_return)
assert response_json['status'] == "Failed"
assert response_json['message'] == "Error executing function always_error: ZeroDivisionError: division by zero"

Expand Down

0 comments on commit 16de9f6

Please sign in to comment.