From 442b916fa9e8be3664131dba5fd1c040c853bc4d Mon Sep 17 00:00:00 2001 From: jnjpng Date: Fri, 21 Nov 2025 15:26:03 -0800 Subject: [PATCH] feat: connect generated letta api key with modal function wrapper (#6329) base Co-authored-by: Letta Bot --- .../tool_executor/sandbox_tool_executor.py | 4 +++- letta/services/tool_manager.py | 15 ++++++++------- letta/services/tool_sandbox/modal_sandbox.py | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/letta/services/tool_executor/sandbox_tool_executor.py b/letta/services/tool_executor/sandbox_tool_executor.py index 366d0542..656d4dc7 100644 --- a/letta/services/tool_executor/sandbox_tool_executor.py +++ b/letta/services/tool_executor/sandbox_tool_executor.py @@ -84,7 +84,9 @@ class SandboxToolExecutor(ToolExecutor): organization_id=actor.organization_id, ) # TODO: pass through letta api key - tool_execution_result = await sandbox.run(agent_state=agent_state_copy, additional_env_vars=sandbox_env_vars) + tool_execution_result = await sandbox.run( + agent_id=agent_state.id, agent_state=agent_state_copy, additional_env_vars=sandbox_env_vars + ) except Exception as e: # Modal execution failed, log and fall back to E2B/LOCAL logger.warning(f"Modal execution failed for tool {tool.name}: {e}. Falling back to {tool_settings.sandbox_type.value}") diff --git a/letta/services/tool_manager.py b/letta/services/tool_manager.py index 245f8ea7..aa576453 100644 --- a/letta/services/tool_manager.py +++ b/letta/services/tool_manager.py @@ -61,7 +61,7 @@ def modal_tool_wrapper(tool: PydanticTool, actor: PydanticUser, sandbox_env_vars packages = [str(req) for req in tool.pip_requirements] if tool.pip_requirements else [] for package in MODAL_SAFE_IMPORT_MODULES: packages.append(package) - packages.append("letta_client") + packages.append("letta_client>=1.1.1") packages.append("letta") # Base letta without extras packages.append("asyncpg>=0.30.0") # Fixes asyncpg import error packages.append("psycopg2-binary>=2.9.10") # PostgreSQL adapter (pre-compiled, no build required) @@ -116,22 +116,23 @@ def modal_tool_wrapper(tool: PydanticTool, actor: PydanticUser, sandbox_env_vars print("Passing agent_state as dict to tool", file=sys.stderr) reconstructed_agent_state = agent_state - # Set environment variables if env_vars: for key, value in env_vars.items(): os.environ[key] = str(value) + # TODO: directly instantiate the letta client once we upgrade to 1.0.0+ in core # Initialize the Letta client - if letta_api_key: - letta_client = Letta(token=letta_api_key, base_url=os.environ.get("LETTA_API_URL", "https://api.letta.com")) - else: - letta_client = None + # if letta_api_key: + # letta_client = Letta(token=letta_api_key, base_url=os.environ.get("LETTA_API_URL", "https://api.letta.com")) + # else: + # letta_client = None tool_namespace = { "__builtins__": __builtins__, # Include built-in functions - "_letta_client": letta_client, # Make letta_client available + # "_letta_client": letta_client, # Make letta_client available "os": os, # Include os module for env vars access "agent_id": agent_id, + "_LETTA_API_KEY": letta_api_key, # Add any other modules/variables the tool might need } diff --git a/letta/services/tool_sandbox/modal_sandbox.py b/letta/services/tool_sandbox/modal_sandbox.py index 1c2acd33..eaa94a77 100644 --- a/letta/services/tool_sandbox/modal_sandbox.py +++ b/letta/services/tool_sandbox/modal_sandbox.py @@ -103,7 +103,7 @@ class AsyncToolSandboxModal(AsyncToolSandboxBase): if additional_env_vars is None: letta_api_key = None else: - letta_api_key = additional_env_vars.get("LETTA_API_KEY", None) + letta_api_key = additional_env_vars.get("LETTA_SECRET_API_KEY", None) # Construct dynamic env vars # Priority order (later overrides earlier):