Skip to content

Commit

Permalink
patch anthropic parsing and improve error logging
Browse files Browse the repository at this point in the history
  • Loading branch information
mattzh72 committed Dec 12, 2024
1 parent 6ab7577 commit a0333e2
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 33 deletions.
33 changes: 27 additions & 6 deletions letta/llm_api/anthropic.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,9 @@ def convert_anthropic_response_to_chatcompletion(
if isinstance(response_json["content"], list):
if len(response_json["content"]) > 1:
# inner mono + function call
assert len(response_json["content"]) == 2, response_json
assert response_json["content"][0]["type"] == "text", response_json
assert response_json["content"][1]["type"] == "tool_use", response_json
assert len(response_json["content"]) == 2, f"Unexpected content length: {response_json}"
assert response_json["content"][0]["type"] == "text", f"Expected text, got: {response_json['content'][0]}"
assert response_json["content"][1]["type"] == "tool_use", f"Expected tool_use, got: {response_json['content'][1]}"
content = strip_xml_tags(string=response_json["content"][0]["text"], tag=inner_thoughts_xml_tag)
tool_calls = [
ToolCall(
Expand All @@ -258,10 +258,31 @@ def convert_anthropic_response_to_chatcompletion(
),
)
]
elif len(response_json["content"]) == 1:
# Only tool call or just inner mono
first_item = response_json["content"][0]
if first_item["type"] == "text":
# Just inner mono
content = strip_xml_tags(string=first_item["text"], tag=inner_thoughts_xml_tag)
tool_calls = None
elif first_item["type"] == "tool_use":
# Only tool call, no inner mono
content = None # No inner mono to extract
tool_calls = [
ToolCall(
id=first_item["id"],
type="function",
function=FunctionCall(
name=first_item["name"],
arguments=json.dumps(first_item["input"], indent=2),
),
)
]
else:
raise ValueError(f"Unexpected type in content: {first_item}")
else:
# Just inner mono
content = strip_xml_tags(string=response_json["content"][0]["text"], tag=inner_thoughts_xml_tag)
tool_calls = None
# Empty content list
raise ValueError(f"Empty content in response: {response_json}")
else:
raise RuntimeError("Unexpected type for content in response_json.")

Expand Down
12 changes: 11 additions & 1 deletion letta/offline_memory_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,18 @@ def trigger_rethink_memory(agent_state: "AgentState", message: Optional[str]) ->
"""
from letta import create_client
from letta.schemas.embedding_config import EmbeddingConfig
from letta.schemas.llm_config import LLMConfig

client = create_client()
ANTHROPIC_CONFIG = LLMConfig(
model_endpoint_type="anthropic",
model_endpoint="https://api.anthropic.com/v1",
model="claude-3-5-haiku-20241022",
context_window=32000,
)
client.set_default_llm_config(ANTHROPIC_CONFIG)
client.set_default_embedding_config(EmbeddingConfig.default_config(model_name="letta"))
agents = client.list_agents()
for agent in agents:
if agent.agent_type == "offline_memory_agent":
Expand Down Expand Up @@ -130,7 +140,7 @@ def __init__(
# extras
first_message_verify_mono: bool = False,
max_memory_rethinks: int = 10,
initial_message_sequence: Optional[List[Message]] = None,
initial_message_sequence: Optional[List[Message]] = None,
):
super().__init__(interface, agent_state, user, initial_message_sequence=initial_message_sequence)
self.first_message_verify_mono = first_message_verify_mono
Expand Down
5 changes: 2 additions & 3 deletions letta/server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,9 +521,8 @@ def _step(
# save agent after step
save_agent(letta_agent, self.ms)

except Exception as e:
logger.error(f"Error in server._step: {e}")
print(traceback.print_exc())
except Exception:
logger.exception("Error in server._step")
raise
finally:
logger.debug("Calling step_yield()")
Expand Down
4 changes: 2 additions & 2 deletions letta/services/tool_execution_sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def run_local_dir_sandbox_venv(self, sbx_config: SandboxConfig, env: Dict[str, s
func_result, stdout = self.parse_out_function_results_markers(result.stdout)
func_return, agent_state = self.parse_best_effort(func_result)
return SandboxRunResult(
func_return=func_return,
func_return=func_return,
agent_state=agent_state,
stdout=[stdout],
stderr=[result.stderr],
Expand All @@ -229,7 +229,7 @@ def run_local_dir_sandbox_runpy(

# Execute the temp file
with self.temporary_env_vars(env_vars):
result = runpy.run_path(temp_file_path, init_globals=env_vars)
result = runpy.run_path(temp_file_path, init_globals=env_vars, run_name="__main__")

# Fetch the result
func_result = result.get(self.LOCAL_SANDBOX_RESULT_VAR_NAME)
Expand Down
47 changes: 26 additions & 21 deletions tests/test_offline_memory_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,16 @@
@pytest.fixture(scope="module")
def client():
client = create_client()
client.set_default_llm_config(LLMConfig.default_config("gpt-4o-mini"))
client.set_default_embedding_config(EmbeddingConfig.default_config(provider="openai"))
ANTHROPIC_CONFIG = LLMConfig(
model_endpoint_type="anthropic",
model_endpoint="https://api.anthropic.com/v1",
model="claude-3-5-haiku-20241022",
context_window=32000,
)
# client.set_default_llm_config(LLMConfig.default_config("gpt-4o-mini"))
# client.set_default_embedding_config(EmbeddingConfig.default_config(provider="openai"))
client.set_default_llm_config(ANTHROPIC_CONFIG)
client.set_default_embedding_config(EmbeddingConfig.default_config(model_name="letta"))

yield client

Expand All @@ -32,6 +40,7 @@ def clear_agents(client):
for agent in client.list_agents():
client.delete_agent(agent.id)


def test_ripple_edit_anthropic(client, mock_e2b_api_key_none):
trigger_rethink_memory_tool = client.create_or_update_tool(trigger_rethink_memory)

Expand All @@ -57,19 +66,19 @@ def test_ripple_edit_anthropic(client, mock_e2b_api_key_none):
new_memory = Block(name="rethink_memory_block", label="rethink_memory_block", value="[empty]", limit=2000)
conversation_memory = BasicBlockMemory(blocks=[conversation_persona_block, conversation_human_block, fact_block, new_memory])
offline_memory = BasicBlockMemory(blocks=[offline_persona_block, offline_human_block, fact_block, new_memory])

ANTHROPIC_CONFIG = LLMConfig(
model_endpoint_type="anthropic",
model_endpoint="https://api.anthropic.com/v1",
model="claude-3-5-haiku-20241022",
context_window=32000,
)
#
# ANTHROPIC_CONFIG = LLMConfig(
# model_endpoint_type="anthropic",
# model_endpoint="https://api.anthropic.com/v1",
# model="claude-3-5-haiku-20241022",
# context_window=32000,
# )
conversation_agent = client.create_agent(
name="conversation_agent",
agent_type=AgentType.memgpt_agent,
system=gpt_system.get_system_text("memgpt_convo_only"),
llm_config=ANTHROPIC_CONFIG,
embedding_config=EmbeddingConfig.default_config("text-embedding-ada-002"),
# llm_config=ANTHROPIC_CONFIG,
# embedding_config=EmbeddingConfig.default_config("text-embedding-ada-002"),
tools=["send_message", trigger_rethink_memory_tool.name],
memory=conversation_memory,
include_base_tools=False,
Expand All @@ -85,8 +94,8 @@ def test_ripple_edit_anthropic(client, mock_e2b_api_key_none):
agent_type=AgentType.offline_memory_agent,
system=gpt_system.get_system_text("memgpt_offline_memory"),
memory=offline_memory,
llm_config=ANTHROPIC_CONFIG,
embedding_config=EmbeddingConfig.default_config("text-embedding-ada-002"),
# llm_config=ANTHROPIC_CONFIG,
# embedding_config=EmbeddingConfig.default_config("text-embedding-ada-002"),
tools=[rethink_memory_tool.name, finish_rethinking_memory_tool.name],
tool_rules=[TerminalToolRule(tool_name=finish_rethinking_memory_tool.name)],
include_base_tools=False,
Expand All @@ -97,18 +106,15 @@ def test_ripple_edit_anthropic(client, mock_e2b_api_key_none):
agent_id=conversation_agent.id, message="[trigger_rethink_memory]: Messi has now moved to playing for Inter Miami"
)
offline_memory_agent = client.get_agent(agent_id=offline_memory_agent.id)

import pdb; pdb.set_trace()
assert offline_memory_agent.memory.get_block("rethink_memory_block").value != "[empty]"
conversation_agent = client.get_agent(agent_id=conversation_agent.id)
assert conversation_agent.memory.get_block("rethink_memory_block").value != "[empty]"

# Clean up agent
'''
"""
client.delete_agent(conversation_agent.id)
client.delete_agent(offline_memory_agent.id)
'''

"""


def test_ripple_edit(client, mock_e2b_api_key_none):
Expand Down Expand Up @@ -214,6 +220,7 @@ def test_chat_only_agent(client, mock_e2b_api_key_none):
# Clean up agent
client.delete_agent(chat_only_agent.id)


def test_initial_message_sequence(client, mock_e2b_api_key_none):
"""
Test that when we set the initial sequence to an empty list,
Expand All @@ -229,8 +236,6 @@ def test_initial_message_sequence(client, mock_e2b_api_key_none):
initial_message_sequence=[],
)
assert offline_memory_agent is not None
assert len(offline_memory_agent.message_ids) == 1 # There should just the system message
assert len(offline_memory_agent.message_ids) == 1 # There should just the system message

client.delete_agent(offline_memory_agent.id)


0 comments on commit a0333e2

Please sign in to comment.