···1+"""Defensive memory operations that handle missing blocks gracefully."""
2+import os
3+from typing import Optional
4+from letta_client import Letta
5+6+7+def safe_memory_insert(agent_state: "AgentState", label: str, content: str, insert_line: int = -1) -> str:
8+ """
9+ Safe version of memory_insert that handles missing blocks by fetching them from API.
10+11+ This is a stopgap solution for the dynamic block loading issue where agent_state.memory
12+ doesn't reflect blocks that were attached via API during the same message processing cycle.
13+ """
14+ try:
15+ # Try the normal memory_insert first
16+ from letta.functions.function_sets.base import memory_insert
17+ return memory_insert(agent_state, label, content, insert_line)
18+19+ except KeyError as e:
20+ if "does not exist" in str(e):
21+ print(f"[SAFE_MEMORY] Block {label} not found in agent_state.memory, fetching from API...")
22+ # Try to fetch the block from the API and add it to agent_state.memory
23+ try:
24+ client = Letta(token=os.environ["LETTA_API_KEY"])
25+26+ # Get all blocks attached to this agent
27+ api_blocks = client.agents.blocks.list(agent_id=str(agent_state.id))
28+29+ # Find the block we're looking for
30+ target_block = None
31+ for block in api_blocks:
32+ if block.label == label:
33+ target_block = block
34+ break
35+36+ if target_block:
37+ # Add it to agent_state.memory
38+ agent_state.memory.set_block(target_block)
39+ print(f"[SAFE_MEMORY] Successfully fetched and added block {label} to agent_state.memory")
40+41+ # Now try the memory_insert again
42+ from letta.functions.function_sets.base import memory_insert
43+ return memory_insert(agent_state, label, content, insert_line)
44+ else:
45+ # Block truly doesn't exist
46+ raise Exception(f"Block {label} not found in API - it may not be attached to this agent")
47+48+ except Exception as api_error:
49+ raise Exception(f"Failed to fetch block {label} from API: {str(api_error)}")
50+ else:
51+ raise e # Re-raise if it's a different KeyError
52+53+54+def safe_core_memory_replace(agent_state: "AgentState", label: str, old_content: str, new_content: str) -> Optional[str]:
55+ """
56+ Safe version of core_memory_replace that handles missing blocks.
57+ """
58+ try:
59+ # Try the normal core_memory_replace first
60+ from letta.functions.function_sets.base import core_memory_replace
61+ return core_memory_replace(agent_state, label, old_content, new_content)
62+63+ except KeyError as e:
64+ if "does not exist" in str(e):
65+ print(f"[SAFE_MEMORY] Block {label} not found in agent_state.memory, fetching from API...")
66+ try:
67+ client = Letta(token=os.environ["LETTA_API_KEY"])
68+ api_blocks = client.agents.blocks.list(agent_id=str(agent_state.id))
69+70+ target_block = None
71+ for block in api_blocks:
72+ if block.label == label:
73+ target_block = block
74+ break
75+76+ if target_block:
77+ agent_state.memory.set_block(target_block)
78+ print(f"[SAFE_MEMORY] Successfully fetched and added block {label} to agent_state.memory")
79+80+ from letta.functions.function_sets.base import core_memory_replace
81+ return core_memory_replace(agent_state, label, old_content, new_content)
82+ else:
83+ raise Exception(f"Block {label} not found in API - it may not be attached to this agent")
84+85+ except Exception as api_error:
86+ raise Exception(f"Failed to fetch block {label} from API: {str(api_error)}")
87+ else:
88+ raise e