Skip to content

Commit

Permalink
fix: pass tool errors through the HTTP POST /tools requests with de…
Browse files Browse the repository at this point in the history
…tailed error messages (#2110)
  • Loading branch information
cpacker authored Nov 27, 2024
1 parent c2ee91c commit c2b41f7
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 14 deletions.
12 changes: 12 additions & 0 deletions letta/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ class LettaError(Exception):
"""Base class for all Letta related errors."""


class LettaToolCreateError(LettaError):
"""Error raised when a tool cannot be created."""

default_error_message = "Error creating tool."

def __init__(self, message=None):
if message is None:
message = self.default_error_message
self.message = message
super().__init__(self.message)


class LLMError(LettaError):
pass

Expand Down
10 changes: 4 additions & 6 deletions letta/functions/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,18 @@
import os
from textwrap import dedent # remove indentation
from types import ModuleType
from typing import Optional, List
from typing import Dict, List, Optional

from letta.constants import CLI_WARNING_PREFIX
from letta.errors import LettaToolCreateError
from letta.functions.schema_generator import generate_schema


def derive_openai_json_schema(source_code: str, name: Optional[str] = None) -> dict:
# auto-generate openai schema
try:
# Define a custom environment with necessary imports
env = {
"Optional": Optional, # Add any other required imports here
"List": List
}
env = {"Optional": Optional, "List": List, "Dict": Dict} # Add any other required imports here

env.update(globals())
exec(source_code, env)
Expand All @@ -29,7 +27,7 @@ def derive_openai_json_schema(source_code: str, name: Optional[str] = None) -> d
json_schema = generate_schema(func, name=name)
return json_schema
except Exception as e:
raise RuntimeError(f"Failed to execute source code: {e}")
raise LettaToolCreateError(f"Failed to derive JSON schema from source code: {e}")


def parse_source_code(func) -> str:
Expand Down
11 changes: 6 additions & 5 deletions letta/functions/schema_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,12 @@ def generate_schema(function, name: Optional[str] = None, description: Optional[
else:
# Add parameter details to the schema
param_doc = next((d for d in docstring.params if d.arg_name == param.name), None)
schema["parameters"]["properties"][param.name] = {
# "type": "string" if param.annotation == str else str(param.annotation),
"type": type_to_json_schema_type(param.annotation) if param.annotation != inspect.Parameter.empty else "string",
"description": param_doc.description,
}
if param_doc:
schema["parameters"]["properties"][param.name] = {
# "type": "string" if param.annotation == str else str(param.annotation),
"type": type_to_json_schema_type(param.annotation) if param.annotation != inspect.Parameter.empty else "string",
"description": param_doc.description,
}
if param.default == inspect.Parameter.empty:
schema["parameters"]["required"].append(param.name)

Expand Down
17 changes: 14 additions & 3 deletions letta/server/rest_api/routers/v1/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from fastapi import APIRouter, Body, Depends, Header, HTTPException

from letta.errors import LettaToolCreateError
from letta.orm.errors import UniqueConstraintViolationError
from letta.schemas.tool import Tool, ToolCreate, ToolUpdate
from letta.server.rest_api.utils import get_letta_server
Expand All @@ -14,12 +15,13 @@
def delete_tool(
tool_id: str,
server: SyncServer = Depends(get_letta_server),
user_id: Optional[str] = Header(None, alias="user_id"), # Extract user_id from header, default to None if not present
):
"""
Delete a tool by name
"""
# actor = server.get_user_or_default(user_id=user_id)
server.tool_manager.delete_tool(tool_id=tool_id)
actor = server.get_user_or_default(user_id=user_id)
server.tool_manager.delete_tool_by_id(tool_id=tool_id, actor=actor)


@router.get("/{tool_id}", response_model=Tool, operation_id="get_tool")
Expand Down Expand Up @@ -91,7 +93,16 @@ def create_tool(
except UniqueConstraintViolationError as e:
# Log or print the full exception here for debugging
print(f"Error occurred: {e}")
raise HTTPException(status_code=409, detail=str(e))
clean_error_message = f"Tool with name {request.name} already exists."
raise HTTPException(status_code=409, detail=clean_error_message)
except LettaToolCreateError as e:
# HTTP 400 == Bad Request
print(f"Error occurred during tool creation: {e}")
# print the full stack trace
import traceback

print(traceback.format_exc())
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
# Catch other unexpected errors and raise an internal server error
print(f"Unexpected error occurred: {e}")
Expand Down

0 comments on commit c2b41f7

Please sign in to comment.