feat: pass in LETTA_TOOL_ID, LETTA_AGENT_ID, LETTA_PROJECT_ID into tool env (#6439)
This commit is contained in:
committed by
Caren Thomas
parent
0a0cf391fc
commit
c4d5c380d6
@@ -56,7 +56,7 @@ class SandboxToolExecutor(ToolExecutor):
|
||||
|
||||
# inject some extra env such as PROJECT_ID from agent_state
|
||||
if agent_state and agent_state.project_id:
|
||||
fetched_credentials["PROJECT_ID"] = agent_state.project_id
|
||||
fetched_credentials["PROJECT_ID"] = agent_state.project_id
|
||||
|
||||
sandbox_env_vars = {**fetched_credentials, **sandbox_env_vars}
|
||||
|
||||
@@ -83,15 +83,16 @@ class SandboxToolExecutor(ToolExecutor):
|
||||
function_name,
|
||||
function_args,
|
||||
actor,
|
||||
tool_id=tool.id,
|
||||
agent_id=agent_state.id if agent_state else None,
|
||||
project_id=agent_state.project_id if agent_state else None,
|
||||
tool_object=tool,
|
||||
sandbox_config=sandbox_config,
|
||||
sandbox_env_vars=sandbox_env_vars,
|
||||
organization_id=actor.organization_id,
|
||||
)
|
||||
# TODO: pass through letta api key
|
||||
tool_execution_result = await sandbox.run(
|
||||
agent_id=agent_state.id, agent_state=agent_state_copy, additional_env_vars=sandbox_env_vars
|
||||
)
|
||||
tool_execution_result = await sandbox.run(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}")
|
||||
@@ -106,6 +107,9 @@ class SandboxToolExecutor(ToolExecutor):
|
||||
function_name,
|
||||
function_args,
|
||||
actor,
|
||||
tool_id=tool.id,
|
||||
agent_id=agent_state.id if agent_state else None,
|
||||
project_id=agent_state.project_id if agent_state else None,
|
||||
tool_object=tool,
|
||||
sandbox_config=sandbox_config,
|
||||
sandbox_env_vars=sandbox_env_vars,
|
||||
@@ -115,6 +119,9 @@ class SandboxToolExecutor(ToolExecutor):
|
||||
function_name,
|
||||
function_args,
|
||||
actor,
|
||||
tool_id=tool.id,
|
||||
agent_id=agent_state.id if agent_state else None,
|
||||
project_id=agent_state.project_id if agent_state else None,
|
||||
tool_object=tool,
|
||||
sandbox_config=sandbox_config,
|
||||
sandbox_env_vars=sandbox_env_vars,
|
||||
|
||||
@@ -27,6 +27,9 @@ class AsyncToolSandboxBase(ABC):
|
||||
tool_name: str,
|
||||
args: JsonDict,
|
||||
user,
|
||||
tool_id: str,
|
||||
agent_id: Optional[str] = None,
|
||||
project_id: Optional[str] = None,
|
||||
tool_object: Optional[Tool] = None,
|
||||
sandbox_config: Optional[SandboxConfig] = None,
|
||||
sandbox_env_vars: Optional[Dict[str, Any]] = None,
|
||||
@@ -34,6 +37,9 @@ class AsyncToolSandboxBase(ABC):
|
||||
self.tool_name = tool_name
|
||||
self.args = args
|
||||
self.user = user
|
||||
self.agent_id = agent_id
|
||||
self.project_id = project_id
|
||||
self.tool_id = tool_id
|
||||
self.tool = tool_object
|
||||
|
||||
# Store provided values or create manager to fetch them later
|
||||
@@ -394,6 +400,13 @@ class AsyncToolSandboxBase(ABC):
|
||||
if additional_env_vars:
|
||||
env.update(additional_env_vars)
|
||||
|
||||
# Inject agent, project, and tool IDs as environment variables
|
||||
if self.agent_id:
|
||||
env["LETTA_AGENT_ID"] = self.agent_id
|
||||
if self.project_id:
|
||||
env["LETTA_PROJECT_ID"] = self.project_id
|
||||
env["LETTA_TOOL_ID"] = self.tool_id
|
||||
|
||||
# Filter out None values to prevent subprocess errors
|
||||
env = {k: v for k, v in env.items() if v is not None}
|
||||
|
||||
|
||||
@@ -31,12 +31,25 @@ class AsyncToolSandboxE2B(AsyncToolSandboxBase):
|
||||
tool_name: str,
|
||||
args: JsonDict,
|
||||
user,
|
||||
tool_id: str,
|
||||
agent_id: Optional[str] = None,
|
||||
project_id: Optional[str] = None,
|
||||
force_recreate: bool = True,
|
||||
tool_object: Optional[Tool] = None,
|
||||
sandbox_config: Optional[SandboxConfig] = None,
|
||||
sandbox_env_vars: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
super().__init__(tool_name, args, user, tool_object, sandbox_config=sandbox_config, sandbox_env_vars=sandbox_env_vars)
|
||||
super().__init__(
|
||||
tool_name,
|
||||
args,
|
||||
user,
|
||||
tool_id=tool_id,
|
||||
agent_id=agent_id,
|
||||
project_id=project_id,
|
||||
tool_object=tool_object,
|
||||
sandbox_config=sandbox_config,
|
||||
sandbox_env_vars=sandbox_env_vars,
|
||||
)
|
||||
self.force_recreate = force_recreate
|
||||
|
||||
@trace_method
|
||||
|
||||
@@ -37,12 +37,25 @@ class AsyncToolSandboxLocal(AsyncToolSandboxBase):
|
||||
tool_name: str,
|
||||
args: JsonDict,
|
||||
user,
|
||||
tool_id: str,
|
||||
agent_id: Optional[str] = None,
|
||||
project_id: Optional[str] = None,
|
||||
force_recreate_venv=False,
|
||||
tool_object: Optional[Tool] = None,
|
||||
sandbox_config: Optional[SandboxConfig] = None,
|
||||
sandbox_env_vars: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
super().__init__(tool_name, args, user, tool_object, sandbox_config=sandbox_config, sandbox_env_vars=sandbox_env_vars)
|
||||
super().__init__(
|
||||
tool_name,
|
||||
args,
|
||||
user,
|
||||
tool_id=tool_id,
|
||||
agent_id=agent_id,
|
||||
project_id=project_id,
|
||||
tool_object=tool_object,
|
||||
sandbox_config=sandbox_config,
|
||||
sandbox_env_vars=sandbox_env_vars,
|
||||
)
|
||||
self.force_recreate_venv = force_recreate_venv
|
||||
|
||||
@trace_method
|
||||
|
||||
@@ -36,18 +36,29 @@ class AsyncToolSandboxModal(AsyncToolSandboxBase):
|
||||
tool_name: str,
|
||||
args: JsonDict,
|
||||
user,
|
||||
tool_id: str,
|
||||
agent_id: Optional[str] = None,
|
||||
project_id: Optional[str] = None,
|
||||
force_recreate: bool = True,
|
||||
tool_object: Optional[Tool] = None,
|
||||
sandbox_config: Optional[SandboxConfig] = None,
|
||||
sandbox_env_vars: Optional[Dict[str, Any]] = None,
|
||||
organization_id: Optional[str] = None,
|
||||
project_id: str = "default",
|
||||
):
|
||||
super().__init__(tool_name, args, user, tool_object, sandbox_config=sandbox_config, sandbox_env_vars=sandbox_env_vars)
|
||||
super().__init__(
|
||||
tool_name,
|
||||
args,
|
||||
user,
|
||||
tool_id=tool_id,
|
||||
agent_id=agent_id,
|
||||
project_id=project_id,
|
||||
tool_object=tool_object,
|
||||
sandbox_config=sandbox_config,
|
||||
sandbox_env_vars=sandbox_env_vars,
|
||||
)
|
||||
self.force_recreate = force_recreate
|
||||
# Get organization_id from user if not explicitly provided
|
||||
self.organization_id = organization_id if organization_id is not None else user.organization_id
|
||||
self.project_id = project_id
|
||||
|
||||
# TODO: check to make sure modal app `App(tool.id)` exists
|
||||
|
||||
@@ -86,7 +97,6 @@ class AsyncToolSandboxModal(AsyncToolSandboxBase):
|
||||
@trace_method
|
||||
async def run(
|
||||
self,
|
||||
agent_id: Optional[str] = None,
|
||||
agent_state: Optional[AgentState] = None,
|
||||
additional_env_vars: Optional[Dict] = None,
|
||||
) -> ToolExecutionResult:
|
||||
@@ -149,7 +159,7 @@ class AsyncToolSandboxModal(AsyncToolSandboxBase):
|
||||
result = await func.remote.aio(
|
||||
tool_name=self.tool_name,
|
||||
agent_state=agent_state_dict,
|
||||
agent_id=agent_id,
|
||||
agent_id=self.agent_id,
|
||||
env_vars=env_vars,
|
||||
letta_api_key=letta_api_key,
|
||||
**self.args,
|
||||
|
||||
@@ -37,6 +37,9 @@ class AsyncToolSandboxModalV2(AsyncToolSandboxBase):
|
||||
tool_name: str,
|
||||
args: JsonDict,
|
||||
user,
|
||||
tool_id: str,
|
||||
agent_id: str | None = None,
|
||||
project_id: str | None = None,
|
||||
tool_object: Tool | None = None,
|
||||
sandbox_config: SandboxConfig | None = None,
|
||||
sandbox_env_vars: dict[str, Any] | None = None,
|
||||
@@ -51,6 +54,9 @@ class AsyncToolSandboxModalV2(AsyncToolSandboxBase):
|
||||
tool_name: Name of the tool to execute
|
||||
args: Arguments to pass to the tool
|
||||
user: User/actor for permissions
|
||||
tool_id: Tool ID for the tool being executed
|
||||
agent_id: Agent ID (optional)
|
||||
project_id: Project ID for the tool execution (optional)
|
||||
tool_object: Tool object (optional)
|
||||
sandbox_config: Sandbox configuration (optional)
|
||||
sandbox_env_vars: Environment variables (optional)
|
||||
@@ -58,7 +64,17 @@ class AsyncToolSandboxModalV2(AsyncToolSandboxBase):
|
||||
use_locking: Whether to use locking for deployment coordination (default: True)
|
||||
use_version_tracking: Whether to track and reuse deployments (default: True)
|
||||
"""
|
||||
super().__init__(tool_name, args, user, tool_object, sandbox_config=sandbox_config, sandbox_env_vars=sandbox_env_vars)
|
||||
super().__init__(
|
||||
tool_name,
|
||||
args,
|
||||
user,
|
||||
tool_id=tool_id,
|
||||
agent_id=agent_id,
|
||||
project_id=project_id,
|
||||
tool_object=tool_object,
|
||||
sandbox_config=sandbox_config,
|
||||
sandbox_env_vars=sandbox_env_vars,
|
||||
)
|
||||
|
||||
if not tool_settings.modal_token_id or not tool_settings.modal_token_secret:
|
||||
raise ValueError("MODAL_TOKEN_ID and MODAL_TOKEN_SECRET must be set.")
|
||||
|
||||
@@ -559,12 +559,12 @@ async def test_local_sandbox_default(disable_e2b_api_key, add_integers_tool, tes
|
||||
|
||||
# Mock and assert correct pathway was invoked
|
||||
with patch.object(AsyncToolSandboxLocal, "run") as mock_run:
|
||||
sandbox = AsyncToolSandboxLocal(add_integers_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(add_integers_tool.name, args, user=test_user, tool_id=add_integers_tool.id)
|
||||
await sandbox.run()
|
||||
mock_run.assert_called_once()
|
||||
|
||||
# Run again to get actual response
|
||||
sandbox = AsyncToolSandboxLocal(add_integers_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(add_integers_tool.name, args, user=test_user, tool_id=add_integers_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert result.func_return == args["x"] + args["y"]
|
||||
|
||||
@@ -573,7 +573,7 @@ async def test_local_sandbox_default(disable_e2b_api_key, add_integers_tool, tes
|
||||
@pytest.mark.local_sandbox
|
||||
async def test_local_sandbox_stateful_tool(disable_e2b_api_key, clear_core_memory_tool, test_user, agent_state):
|
||||
args = {}
|
||||
sandbox = AsyncToolSandboxLocal(clear_core_memory_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(clear_core_memory_tool.name, args, user=test_user, tool_id=clear_core_memory_tool.id)
|
||||
result = await sandbox.run(agent_state=agent_state)
|
||||
assert sandbox.inject_agent_state == True
|
||||
assert result.agent_state.memory.get_block("human").value == ""
|
||||
@@ -584,7 +584,7 @@ async def test_local_sandbox_stateful_tool(disable_e2b_api_key, clear_core_memor
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.local_sandbox
|
||||
async def test_local_sandbox_with_list_rv(disable_e2b_api_key, list_tool, test_user):
|
||||
sandbox = AsyncToolSandboxLocal(list_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(list_tool.name, {}, user=test_user, tool_id=list_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert len(result.func_return) == 5
|
||||
|
||||
@@ -603,7 +603,7 @@ async def test_local_sandbox_env(disable_e2b_api_key, get_env_tool, test_user):
|
||||
SandboxEnvironmentVariableCreate(key=key, value=long_random_string), sandbox_config_id=config.id, actor=test_user
|
||||
)
|
||||
|
||||
sandbox = AsyncToolSandboxLocal(get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(get_env_tool.name, {}, user=test_user, tool_id=get_env_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert long_random_string in result.func_return
|
||||
|
||||
@@ -625,7 +625,7 @@ async def test_local_sandbox_per_agent_env(disable_e2b_api_key, get_env_tool, ag
|
||||
correct_val = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(20))
|
||||
agent_state.secrets = [AgentEnvironmentVariable(key=key, value=correct_val, agent_id=agent_state.id)]
|
||||
|
||||
sandbox = AsyncToolSandboxLocal(get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(get_env_tool.name, {}, user=test_user, tool_id=get_env_tool.id)
|
||||
result = await sandbox.run(agent_state=agent_state)
|
||||
assert wrong_val not in result.func_return
|
||||
assert correct_val in result.func_return
|
||||
@@ -637,7 +637,7 @@ async def test_local_sandbox_external_codebase_with_venv(
|
||||
disable_e2b_api_key, custom_test_sandbox_config, external_codebase_tool, test_user
|
||||
):
|
||||
args = {"percentage": 10}
|
||||
sandbox = AsyncToolSandboxLocal(external_codebase_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(external_codebase_tool.name, args, user=test_user, tool_id=external_codebase_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert result.func_return == "Price Adjustments:\nBurger: $8.99 -> $9.89\nFries: $2.99 -> $3.29\nSoda: $1.99 -> $2.19"
|
||||
assert "Hello World" in result.stdout[0]
|
||||
@@ -648,7 +648,7 @@ async def test_local_sandbox_external_codebase_with_venv(
|
||||
async def test_local_sandbox_with_venv_and_warnings_does_not_error(
|
||||
disable_e2b_api_key, custom_test_sandbox_config, get_warning_tool, test_user
|
||||
):
|
||||
sandbox = AsyncToolSandboxLocal(get_warning_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(get_warning_tool.name, {}, user=test_user, tool_id=get_warning_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert result.func_return == "Hello World"
|
||||
|
||||
@@ -656,7 +656,7 @@ async def test_local_sandbox_with_venv_and_warnings_does_not_error(
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.e2b_sandbox
|
||||
async def test_local_sandbox_with_venv_errors(disable_e2b_api_key, custom_test_sandbox_config, always_err_tool, test_user):
|
||||
sandbox = AsyncToolSandboxLocal(always_err_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(always_err_tool.name, {}, user=test_user, tool_id=always_err_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert len(result.stdout) != 0
|
||||
assert "error" in result.stdout[0]
|
||||
@@ -679,7 +679,7 @@ async def test_local_sandbox_with_venv_pip_installs_basic(disable_e2b_api_key, c
|
||||
SandboxEnvironmentVariableCreate(key=key, value=long_random_string), sandbox_config_id=config.id, actor=test_user
|
||||
)
|
||||
|
||||
sandbox = AsyncToolSandboxLocal(cowsay_tool.name, {}, user=test_user, force_recreate_venv=True)
|
||||
sandbox = AsyncToolSandboxLocal(cowsay_tool.name, {}, user=test_user, tool_id=cowsay_tool.id, force_recreate_venv=True)
|
||||
result = await sandbox.run()
|
||||
assert long_random_string in result.stdout[0]
|
||||
|
||||
@@ -694,7 +694,12 @@ async def test_local_sandbox_with_tool_pip_requirements(disable_e2b_api_key, too
|
||||
await manager.create_or_update_sandbox_config_async(config_create, test_user)
|
||||
|
||||
sandbox = AsyncToolSandboxLocal(
|
||||
tool_with_pip_requirements.name, {}, user=test_user, tool_object=tool_with_pip_requirements, force_recreate_venv=True
|
||||
tool_with_pip_requirements.name,
|
||||
{},
|
||||
user=test_user,
|
||||
tool_id=tool_with_pip_requirements.id,
|
||||
tool_object=tool_with_pip_requirements,
|
||||
force_recreate_venv=True,
|
||||
)
|
||||
result = await sandbox.run()
|
||||
|
||||
@@ -718,7 +723,12 @@ async def test_local_sandbox_with_mixed_pip_requirements(disable_e2b_api_key, to
|
||||
await manager.create_or_update_sandbox_config_async(config_create, test_user)
|
||||
|
||||
sandbox = AsyncToolSandboxLocal(
|
||||
tool_with_pip_requirements.name, {}, user=test_user, tool_object=tool_with_pip_requirements, force_recreate_venv=True
|
||||
tool_with_pip_requirements.name,
|
||||
{},
|
||||
user=test_user,
|
||||
tool_id=tool_with_pip_requirements.id,
|
||||
tool_object=tool_with_pip_requirements,
|
||||
force_recreate_venv=True,
|
||||
)
|
||||
result = await sandbox.run()
|
||||
|
||||
@@ -741,7 +751,7 @@ async def test_local_sandbox_with_venv_pip_installs_with_update(disable_e2b_api_
|
||||
SandboxEnvironmentVariableCreate(key=key, value=long_random_string), sandbox_config_id=config.id, actor=test_user
|
||||
)
|
||||
|
||||
sandbox = AsyncToolSandboxLocal(cowsay_tool.name, {}, user=test_user, force_recreate_venv=True)
|
||||
sandbox = AsyncToolSandboxLocal(cowsay_tool.name, {}, user=test_user, tool_id=cowsay_tool.id, force_recreate_venv=True)
|
||||
result = await sandbox.run()
|
||||
assert len(result.stdout) == 0
|
||||
assert "No module named 'cowsay'" in result.stderr[0]
|
||||
@@ -751,7 +761,7 @@ async def test_local_sandbox_with_venv_pip_installs_with_update(disable_e2b_api_
|
||||
)
|
||||
await manager.create_or_update_sandbox_config_async(config_create, test_user)
|
||||
|
||||
sandbox = AsyncToolSandboxLocal(cowsay_tool.name, {}, user=test_user, force_recreate_venv=False)
|
||||
sandbox = AsyncToolSandboxLocal(cowsay_tool.name, {}, user=test_user, tool_id=cowsay_tool.id, force_recreate_venv=False)
|
||||
result = await sandbox.run()
|
||||
assert long_random_string in result.stdout[0]
|
||||
|
||||
@@ -766,12 +776,12 @@ async def test_e2b_sandbox_default(check_e2b_key_is_set, add_integers_tool, test
|
||||
|
||||
# Mock and assert correct pathway was invoked
|
||||
with patch.object(AsyncToolSandboxE2B, "run") as mock_run:
|
||||
sandbox = AsyncToolSandboxE2B(add_integers_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(add_integers_tool.name, args, user=test_user, tool_id=add_integers_tool.id)
|
||||
await sandbox.run()
|
||||
mock_run.assert_called_once()
|
||||
|
||||
# Run again to get actual response
|
||||
sandbox = AsyncToolSandboxE2B(add_integers_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(add_integers_tool.name, args, user=test_user, tool_id=add_integers_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert int(result.func_return) == args["x"] + args["y"]
|
||||
|
||||
@@ -791,7 +801,7 @@ async def test_e2b_sandbox_pip_installs(check_e2b_key_is_set, cowsay_tool, test_
|
||||
actor=test_user,
|
||||
)
|
||||
|
||||
sandbox = AsyncToolSandboxE2B(cowsay_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(cowsay_tool.name, {}, user=test_user, tool_id=cowsay_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert long_random_string in result.stdout[0]
|
||||
|
||||
@@ -799,7 +809,7 @@ async def test_e2b_sandbox_pip_installs(check_e2b_key_is_set, cowsay_tool, test_
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.e2b_sandbox
|
||||
async def test_e2b_sandbox_stateful_tool(check_e2b_key_is_set, clear_core_memory_tool, test_user, agent_state):
|
||||
sandbox = AsyncToolSandboxE2B(clear_core_memory_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(clear_core_memory_tool.name, {}, user=test_user, tool_id=clear_core_memory_tool.id)
|
||||
result = await sandbox.run(agent_state=agent_state)
|
||||
assert result.agent_state.memory.get_block("human").value == ""
|
||||
assert result.agent_state.memory.get_block("persona").value == ""
|
||||
@@ -813,7 +823,7 @@ async def test_e2b_sandbox_inject_env_var_existing_sandbox(check_e2b_key_is_set,
|
||||
config_create = SandboxConfigCreate(config=E2BSandboxConfig().model_dump())
|
||||
config = await manager.create_or_update_sandbox_config_async(config_create, test_user)
|
||||
|
||||
sandbox = AsyncToolSandboxE2B(get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(get_env_tool.name, {}, user=test_user, tool_id=get_env_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert result.func_return is None
|
||||
|
||||
@@ -825,7 +835,7 @@ async def test_e2b_sandbox_inject_env_var_existing_sandbox(check_e2b_key_is_set,
|
||||
actor=test_user,
|
||||
)
|
||||
|
||||
sandbox = AsyncToolSandboxE2B(get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(get_env_tool.name, {}, user=test_user, tool_id=get_env_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert long_random_string in result.func_return
|
||||
|
||||
@@ -848,7 +858,7 @@ async def test_e2b_sandbox_per_agent_env(check_e2b_key_is_set, get_env_tool, age
|
||||
|
||||
agent_state.secrets = [AgentEnvironmentVariable(key=key, value=correct_val, agent_id=agent_state.id)]
|
||||
|
||||
sandbox = AsyncToolSandboxE2B(get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(get_env_tool.name, {}, user=test_user, tool_id=get_env_tool.id)
|
||||
result = await sandbox.run(agent_state=agent_state)
|
||||
assert wrong_val not in result.func_return
|
||||
assert correct_val in result.func_return
|
||||
@@ -857,7 +867,7 @@ async def test_e2b_sandbox_per_agent_env(check_e2b_key_is_set, get_env_tool, age
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.e2b_sandbox
|
||||
async def test_e2b_sandbox_with_list_rv(check_e2b_key_is_set, list_tool, test_user):
|
||||
sandbox = AsyncToolSandboxE2B(list_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(list_tool.name, {}, user=test_user, tool_id=list_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert len(result.func_return) == 5
|
||||
|
||||
@@ -870,7 +880,9 @@ async def test_e2b_sandbox_with_tool_pip_requirements(check_e2b_key_is_set, tool
|
||||
config_create = SandboxConfigCreate(config=E2BSandboxConfig().model_dump())
|
||||
await manager.create_or_update_sandbox_config_async(config_create, test_user)
|
||||
|
||||
sandbox = AsyncToolSandboxE2B(tool_with_pip_requirements.name, {}, user=test_user, tool_object=tool_with_pip_requirements)
|
||||
sandbox = AsyncToolSandboxE2B(
|
||||
tool_with_pip_requirements.name, {}, user=test_user, tool_id=tool_with_pip_requirements.id, tool_object=tool_with_pip_requirements
|
||||
)
|
||||
result = await sandbox.run()
|
||||
|
||||
# Should succeed since tool pip requirements were installed
|
||||
@@ -889,7 +901,9 @@ async def test_e2b_sandbox_with_mixed_pip_requirements(check_e2b_key_is_set, too
|
||||
config_create = SandboxConfigCreate(config=E2BSandboxConfig(pip_requirements=["cowsay"]).model_dump())
|
||||
await manager.create_or_update_sandbox_config_async(config_create, test_user)
|
||||
|
||||
sandbox = AsyncToolSandboxE2B(tool_with_pip_requirements.name, {}, user=test_user, tool_object=tool_with_pip_requirements)
|
||||
sandbox = AsyncToolSandboxE2B(
|
||||
tool_with_pip_requirements.name, {}, user=test_user, tool_id=tool_with_pip_requirements.id, tool_object=tool_with_pip_requirements
|
||||
)
|
||||
result = await sandbox.run()
|
||||
|
||||
# Should succeed since both sandbox and tool pip requirements were installed
|
||||
@@ -908,7 +922,13 @@ async def test_e2b_sandbox_with_broken_tool_pip_requirements_error_handling(
|
||||
config_create = SandboxConfigCreate(config=E2BSandboxConfig().model_dump())
|
||||
await manager.create_or_update_sandbox_config_async(config_create, test_user)
|
||||
|
||||
sandbox = AsyncToolSandboxE2B(tool_with_broken_pip_requirements.name, {}, user=test_user, tool_object=tool_with_broken_pip_requirements)
|
||||
sandbox = AsyncToolSandboxE2B(
|
||||
tool_with_broken_pip_requirements.name,
|
||||
{},
|
||||
user=test_user,
|
||||
tool_id=tool_with_broken_pip_requirements.id,
|
||||
tool_object=tool_with_broken_pip_requirements,
|
||||
)
|
||||
|
||||
# Should raise a RuntimeError with informative message
|
||||
with pytest.raises(RuntimeError) as exc_info:
|
||||
@@ -935,12 +955,14 @@ async def test_e2b_sandbox_with_broken_tool_pip_requirements_error_handling(
|
||||
async def test_async_function_detection(add_integers_tool, async_add_integers_tool, test_user):
|
||||
"""Test that async function detection works correctly"""
|
||||
# Test sync function detection
|
||||
sync_sandbox = AsyncToolSandboxE2B(add_integers_tool.name, {}, test_user, tool_object=add_integers_tool)
|
||||
sync_sandbox = AsyncToolSandboxE2B(add_integers_tool.name, {}, test_user, tool_id=add_integers_tool.id, tool_object=add_integers_tool)
|
||||
await sync_sandbox._init_async()
|
||||
assert not sync_sandbox.is_async_function
|
||||
|
||||
# Test async function detection
|
||||
async_sandbox = AsyncToolSandboxE2B(async_add_integers_tool.name, {}, test_user, tool_object=async_add_integers_tool)
|
||||
async_sandbox = AsyncToolSandboxE2B(
|
||||
async_add_integers_tool.name, {}, test_user, tool_id=async_add_integers_tool.id, tool_object=async_add_integers_tool
|
||||
)
|
||||
await async_sandbox._init_async()
|
||||
assert async_sandbox.is_async_function
|
||||
|
||||
@@ -949,7 +971,7 @@ async def test_async_function_detection(add_integers_tool, async_add_integers_to
|
||||
async def test_async_template_selection(add_integers_tool, async_add_integers_tool, test_user):
|
||||
"""Test that correct templates are selected for sync vs async functions"""
|
||||
# Test sync function uses regular template
|
||||
sync_sandbox = AsyncToolSandboxE2B(add_integers_tool.name, {}, test_user, tool_object=add_integers_tool)
|
||||
sync_sandbox = AsyncToolSandboxE2B(add_integers_tool.name, {}, test_user, tool_id=add_integers_tool.id, tool_object=add_integers_tool)
|
||||
sync_script = await sync_sandbox.generate_execution_script(agent_state=None)
|
||||
print("=== SYNC SCRIPT ===")
|
||||
print(sync_script)
|
||||
@@ -958,7 +980,9 @@ async def test_async_template_selection(add_integers_tool, async_add_integers_to
|
||||
assert "asyncio.run" not in sync_script
|
||||
|
||||
# Test async function uses async template
|
||||
async_sandbox = AsyncToolSandboxE2B(async_add_integers_tool.name, {}, test_user, tool_object=async_add_integers_tool)
|
||||
async_sandbox = AsyncToolSandboxE2B(
|
||||
async_add_integers_tool.name, {}, test_user, tool_id=async_add_integers_tool.id, tool_object=async_add_integers_tool
|
||||
)
|
||||
async_script = await async_sandbox.generate_execution_script(agent_state=None)
|
||||
print("=== ASYNC SCRIPT ===")
|
||||
print(async_script)
|
||||
@@ -974,7 +998,7 @@ async def test_local_sandbox_async_function_execution(disable_e2b_api_key, async
|
||||
"""Test that async functions execute correctly in local sandbox"""
|
||||
args = {"x": 15, "y": 25}
|
||||
|
||||
sandbox = AsyncToolSandboxLocal(async_add_integers_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(async_add_integers_tool.name, args, user=test_user, tool_id=async_add_integers_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert result.func_return == args["x"] + args["y"]
|
||||
|
||||
@@ -985,7 +1009,7 @@ async def test_e2b_sandbox_async_function_execution(check_e2b_key_is_set, async_
|
||||
"""Test that async functions execute correctly in E2B sandbox"""
|
||||
args = {"x": 20, "y": 30}
|
||||
|
||||
sandbox = AsyncToolSandboxE2B(async_add_integers_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(async_add_integers_tool.name, args, user=test_user, tool_id=async_add_integers_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert int(result.func_return) == args["x"] + args["y"]
|
||||
|
||||
@@ -996,7 +1020,7 @@ async def test_local_sandbox_async_complex_computation(disable_e2b_api_key, asyn
|
||||
"""Test complex async computation with multiple awaits in local sandbox"""
|
||||
args = {"iterations": 2}
|
||||
|
||||
sandbox = AsyncToolSandboxLocal(async_complex_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(async_complex_tool.name, args, user=test_user, tool_id=async_complex_tool.id)
|
||||
result = await sandbox.run()
|
||||
|
||||
assert isinstance(result.func_return, dict)
|
||||
@@ -1012,7 +1036,7 @@ async def test_e2b_sandbox_async_complex_computation(check_e2b_key_is_set, async
|
||||
"""Test complex async computation with multiple awaits in E2B sandbox"""
|
||||
args = {"iterations": 2}
|
||||
|
||||
sandbox = AsyncToolSandboxE2B(async_complex_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(async_complex_tool.name, args, user=test_user, tool_id=async_complex_tool.id)
|
||||
result = await sandbox.run()
|
||||
|
||||
func_return = result.func_return
|
||||
@@ -1027,7 +1051,7 @@ async def test_e2b_sandbox_async_complex_computation(check_e2b_key_is_set, async
|
||||
@pytest.mark.local_sandbox
|
||||
async def test_local_sandbox_async_list_return(disable_e2b_api_key, async_list_tool, test_user):
|
||||
"""Test async function returning list in local sandbox"""
|
||||
sandbox = AsyncToolSandboxLocal(async_list_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(async_list_tool.name, {}, user=test_user, tool_id=async_list_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert result.func_return == [1, 2, 3, 4, 5]
|
||||
|
||||
@@ -1036,7 +1060,7 @@ async def test_local_sandbox_async_list_return(disable_e2b_api_key, async_list_t
|
||||
@pytest.mark.e2b_sandbox
|
||||
async def test_e2b_sandbox_async_list_return(check_e2b_key_is_set, async_list_tool, test_user):
|
||||
"""Test async function returning list in E2B sandbox"""
|
||||
sandbox = AsyncToolSandboxE2B(async_list_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(async_list_tool.name, {}, user=test_user, tool_id=async_list_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert result.func_return == [1, 2, 3, 4, 5]
|
||||
|
||||
@@ -1059,7 +1083,7 @@ async def test_local_sandbox_async_with_env_vars(disable_e2b_api_key, async_get_
|
||||
SandboxEnvironmentVariableCreate(key=key, value=test_value), sandbox_config_id=config.id, actor=test_user
|
||||
)
|
||||
|
||||
sandbox = AsyncToolSandboxLocal(async_get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(async_get_env_tool.name, {}, user=test_user, tool_id=async_get_env_tool.id)
|
||||
result = await sandbox.run()
|
||||
|
||||
assert test_value in result.func_return
|
||||
@@ -1080,7 +1104,7 @@ async def test_e2b_sandbox_async_with_env_vars(check_e2b_key_is_set, async_get_e
|
||||
SandboxEnvironmentVariableCreate(key=key, value=test_value), sandbox_config_id=config.id, actor=test_user
|
||||
)
|
||||
|
||||
sandbox = AsyncToolSandboxE2B(async_get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(async_get_env_tool.name, {}, user=test_user, tool_id=async_get_env_tool.id)
|
||||
result = await sandbox.run()
|
||||
|
||||
assert test_value in result.func_return
|
||||
@@ -1090,7 +1114,7 @@ async def test_e2b_sandbox_async_with_env_vars(check_e2b_key_is_set, async_get_e
|
||||
@pytest.mark.local_sandbox
|
||||
async def test_local_sandbox_async_with_agent_state(disable_e2b_api_key, async_stateful_tool, test_user, agent_state):
|
||||
"""Test async function with agent state in local sandbox"""
|
||||
sandbox = AsyncToolSandboxLocal(async_stateful_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(async_stateful_tool.name, {}, user=test_user, tool_id=async_stateful_tool.id)
|
||||
result = await sandbox.run(agent_state=agent_state)
|
||||
|
||||
assert result.agent_state is not None
|
||||
@@ -1103,7 +1127,7 @@ async def test_local_sandbox_async_with_agent_state(disable_e2b_api_key, async_s
|
||||
@pytest.mark.e2b_sandbox
|
||||
async def test_e2b_sandbox_async_with_agent_state(check_e2b_key_is_set, async_stateful_tool, test_user, agent_state):
|
||||
"""Test async function with agent state in E2B sandbox"""
|
||||
sandbox = AsyncToolSandboxE2B(async_stateful_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(async_stateful_tool.name, {}, user=test_user, tool_id=async_stateful_tool.id)
|
||||
result = await sandbox.run(agent_state=agent_state)
|
||||
|
||||
assert result.agent_state.memory.get_block("human").value == ""
|
||||
@@ -1115,7 +1139,7 @@ async def test_e2b_sandbox_async_with_agent_state(check_e2b_key_is_set, async_st
|
||||
@pytest.mark.local_sandbox
|
||||
async def test_local_sandbox_async_error_handling(disable_e2b_api_key, async_error_tool, test_user):
|
||||
"""Test async function error handling in local sandbox"""
|
||||
sandbox = AsyncToolSandboxLocal(async_error_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(async_error_tool.name, {}, user=test_user, tool_id=async_error_tool.id)
|
||||
result = await sandbox.run()
|
||||
|
||||
# Check that error was captured
|
||||
@@ -1129,7 +1153,7 @@ async def test_local_sandbox_async_error_handling(disable_e2b_api_key, async_err
|
||||
@pytest.mark.e2b_sandbox
|
||||
async def test_e2b_sandbox_async_error_handling(check_e2b_key_is_set, async_error_tool, test_user):
|
||||
"""Test async function error handling in E2B sandbox"""
|
||||
sandbox = AsyncToolSandboxE2B(async_error_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(async_error_tool.name, {}, user=test_user, tool_id=async_error_tool.id)
|
||||
result = await sandbox.run()
|
||||
|
||||
# Check that error was captured
|
||||
@@ -1157,7 +1181,7 @@ async def test_local_sandbox_async_per_agent_env(disable_e2b_api_key, async_get_
|
||||
correct_val = "correct_async_local_value"
|
||||
agent_state.secrets = [AgentEnvironmentVariable(key=key, value=correct_val, agent_id=agent_state.id)]
|
||||
|
||||
sandbox = AsyncToolSandboxLocal(async_get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxLocal(async_get_env_tool.name, {}, user=test_user, tool_id=async_get_env_tool.id)
|
||||
result = await sandbox.run(agent_state=agent_state)
|
||||
assert wrong_val not in result.func_return
|
||||
assert correct_val in result.func_return
|
||||
@@ -1182,7 +1206,7 @@ async def test_e2b_sandbox_async_per_agent_env(check_e2b_key_is_set, async_get_e
|
||||
|
||||
agent_state.secrets = [AgentEnvironmentVariable(key=key, value=correct_val, agent_id=agent_state.id)]
|
||||
|
||||
sandbox = AsyncToolSandboxE2B(async_get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxE2B(async_get_env_tool.name, {}, user=test_user, tool_id=async_get_env_tool.id)
|
||||
result = await sandbox.run(agent_state=agent_state)
|
||||
assert wrong_val not in result.func_return
|
||||
assert correct_val in result.func_return
|
||||
@@ -1265,6 +1289,7 @@ async def test_local_sandbox_with_client_injection(disable_e2b_api_key, list_too
|
||||
tool_name=list_tools_with_client_tool.name,
|
||||
args={},
|
||||
user=test_user,
|
||||
tool_id=list_tools_with_client_tool.id,
|
||||
tool_object=list_tools_with_client_tool,
|
||||
sandbox_env_vars=sandbox_env_vars,
|
||||
)
|
||||
@@ -1323,6 +1348,7 @@ async def test_e2b_sandbox_with_client_injection(check_e2b_key_is_set, list_tool
|
||||
tool_name=list_tools_with_client_tool.name,
|
||||
args={},
|
||||
user=test_user,
|
||||
tool_id=list_tools_with_client_tool.id,
|
||||
tool_object=list_tools_with_client_tool,
|
||||
sandbox_env_vars=sandbox_env_vars,
|
||||
)
|
||||
|
||||
@@ -485,12 +485,12 @@ async def test_modal_sandbox_default(check_modal_key_is_set, add_integers_tool,
|
||||
|
||||
# Mock and assert correct pathway was invoked
|
||||
with patch.object(AsyncToolSandboxModal, "run") as mock_run:
|
||||
sandbox = AsyncToolSandboxModal(add_integers_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(add_integers_tool.name, args, user=test_user, tool_id=add_integers_tool.id)
|
||||
await sandbox.run()
|
||||
mock_run.assert_called_once()
|
||||
|
||||
# Run again to get actual response
|
||||
sandbox = AsyncToolSandboxModal(add_integers_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(add_integers_tool.name, args, user=test_user, tool_id=add_integers_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert int(result.func_return) == args["x"] + args["y"]
|
||||
|
||||
@@ -511,7 +511,7 @@ async def test_modal_sandbox_pip_installs(check_modal_key_is_set, cowsay_tool, t
|
||||
actor=test_user,
|
||||
)
|
||||
|
||||
sandbox = AsyncToolSandboxModal(cowsay_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(cowsay_tool.name, {}, user=test_user, tool_id=cowsay_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert long_random_string in result.stdout[0]
|
||||
|
||||
@@ -519,7 +519,7 @@ async def test_modal_sandbox_pip_installs(check_modal_key_is_set, cowsay_tool, t
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.modal_sandbox
|
||||
async def test_modal_sandbox_stateful_tool(check_modal_key_is_set, clear_core_memory_tool, test_user, agent_state):
|
||||
sandbox = AsyncToolSandboxModal(clear_core_memory_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(clear_core_memory_tool.name, {}, user=test_user, tool_id=clear_core_memory_tool.id)
|
||||
result = await sandbox.run(agent_state=agent_state)
|
||||
assert result.agent_state.memory.get_block("human").value == ""
|
||||
assert result.agent_state.memory.get_block("persona").value == ""
|
||||
@@ -533,7 +533,7 @@ async def test_modal_sandbox_inject_env_var_existing_sandbox(check_modal_key_is_
|
||||
config_create = SandboxConfigCreate(config=ModalSandboxConfig().model_dump())
|
||||
config = await manager.create_or_update_sandbox_config_async(config_create, test_user)
|
||||
|
||||
sandbox = AsyncToolSandboxModal(get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(get_env_tool.name, {}, user=test_user, tool_id=get_env_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert result.func_return is None
|
||||
|
||||
@@ -545,7 +545,7 @@ async def test_modal_sandbox_inject_env_var_existing_sandbox(check_modal_key_is_
|
||||
actor=test_user,
|
||||
)
|
||||
|
||||
sandbox = AsyncToolSandboxModal(get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(get_env_tool.name, {}, user=test_user, tool_id=get_env_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert long_random_string in result.func_return
|
||||
|
||||
@@ -568,7 +568,7 @@ async def test_modal_sandbox_per_agent_env(check_modal_key_is_set, get_env_tool,
|
||||
|
||||
agent_state.secrets = [AgentEnvironmentVariable(key=key, value=correct_val, agent_id=agent_state.id)]
|
||||
|
||||
sandbox = AsyncToolSandboxModal(get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(get_env_tool.name, {}, user=test_user, tool_id=get_env_tool.id)
|
||||
result = await sandbox.run(agent_state=agent_state)
|
||||
assert wrong_val not in result.func_return
|
||||
assert correct_val in result.func_return
|
||||
@@ -577,7 +577,7 @@ async def test_modal_sandbox_per_agent_env(check_modal_key_is_set, get_env_tool,
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.modal_sandbox
|
||||
async def test_modal_sandbox_with_list_rv(check_modal_key_is_set, list_tool, test_user):
|
||||
sandbox = AsyncToolSandboxModal(list_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(list_tool.name, {}, user=test_user, tool_id=list_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert len(result.func_return) == 5
|
||||
|
||||
@@ -590,7 +590,9 @@ async def test_modal_sandbox_with_tool_pip_requirements(check_modal_key_is_set,
|
||||
config_create = SandboxConfigCreate(config=ModalSandboxConfig().model_dump())
|
||||
await manager.create_or_update_sandbox_config_async(config_create, test_user)
|
||||
|
||||
sandbox = AsyncToolSandboxModal(tool_with_pip_requirements.name, {}, user=test_user, tool_object=tool_with_pip_requirements)
|
||||
sandbox = AsyncToolSandboxModal(
|
||||
tool_with_pip_requirements.name, {}, user=test_user, tool_id=tool_with_pip_requirements.id, tool_object=tool_with_pip_requirements
|
||||
)
|
||||
result = await sandbox.run()
|
||||
|
||||
# Should succeed since tool pip requirements were installed
|
||||
@@ -611,7 +613,9 @@ async def test_modal_sandbox_with_mixed_pip_requirements(check_modal_key_is_set,
|
||||
config_create = SandboxConfigCreate(config=ModalSandboxConfig().model_dump())
|
||||
await manager.create_or_update_sandbox_config_async(config_create, test_user)
|
||||
|
||||
sandbox = AsyncToolSandboxModal(tool_with_pip_requirements.name, {}, user=test_user, tool_object=tool_with_pip_requirements)
|
||||
sandbox = AsyncToolSandboxModal(
|
||||
tool_with_pip_requirements.name, {}, user=test_user, tool_id=tool_with_pip_requirements.id, tool_object=tool_with_pip_requirements
|
||||
)
|
||||
result = await sandbox.run()
|
||||
|
||||
# Should succeed since tool pip requirements were installed
|
||||
@@ -651,12 +655,14 @@ async def test_modal_sandbox_with_broken_tool_pip_requirements_error_handling(ch
|
||||
async def test_async_function_detection(add_integers_tool, async_add_integers_tool, test_user):
|
||||
"""Test that async function detection works correctly"""
|
||||
# Test sync function detection
|
||||
sync_sandbox = AsyncToolSandboxModal(add_integers_tool.name, {}, test_user, tool_object=add_integers_tool)
|
||||
sync_sandbox = AsyncToolSandboxModal(add_integers_tool.name, {}, test_user, tool_id=add_integers_tool.id, tool_object=add_integers_tool)
|
||||
await sync_sandbox._init_async()
|
||||
assert not sync_sandbox.is_async_function
|
||||
|
||||
# Test async function detection
|
||||
async_sandbox = AsyncToolSandboxModal(async_add_integers_tool.name, {}, test_user, tool_object=async_add_integers_tool)
|
||||
async_sandbox = AsyncToolSandboxModal(
|
||||
async_add_integers_tool.name, {}, test_user, tool_id=async_add_integers_tool.id, tool_object=async_add_integers_tool
|
||||
)
|
||||
await async_sandbox._init_async()
|
||||
assert async_sandbox.is_async_function
|
||||
|
||||
@@ -667,7 +673,7 @@ async def test_modal_sandbox_async_function_execution(check_modal_key_is_set, as
|
||||
"""Test that async functions execute correctly in Modal sandbox"""
|
||||
args = {"x": 20, "y": 30}
|
||||
|
||||
sandbox = AsyncToolSandboxModal(async_add_integers_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(async_add_integers_tool.name, args, user=test_user, tool_id=async_add_integers_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert int(result.func_return) == args["x"] + args["y"]
|
||||
|
||||
@@ -678,7 +684,7 @@ async def test_modal_sandbox_async_complex_computation(check_modal_key_is_set, a
|
||||
"""Test complex async computation with multiple awaits in Modal sandbox"""
|
||||
args = {"iterations": 2}
|
||||
|
||||
sandbox = AsyncToolSandboxModal(async_complex_tool.name, args, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(async_complex_tool.name, args, user=test_user, tool_id=async_complex_tool.id)
|
||||
result = await sandbox.run()
|
||||
|
||||
func_return = result.func_return
|
||||
@@ -693,7 +699,7 @@ async def test_modal_sandbox_async_complex_computation(check_modal_key_is_set, a
|
||||
@pytest.mark.modal_sandbox
|
||||
async def test_modal_sandbox_async_list_return(check_modal_key_is_set, async_list_tool, test_user):
|
||||
"""Test async function returning list in Modal sandbox"""
|
||||
sandbox = AsyncToolSandboxModal(async_list_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(async_list_tool.name, {}, user=test_user, tool_id=async_list_tool.id)
|
||||
result = await sandbox.run()
|
||||
assert result.func_return == [1, 2, 3, 4, 5]
|
||||
|
||||
@@ -713,7 +719,7 @@ async def test_modal_sandbox_async_with_env_vars(check_modal_key_is_set, async_g
|
||||
SandboxEnvironmentVariableCreate(key=key, value=test_value), sandbox_config_id=config.id, actor=test_user
|
||||
)
|
||||
|
||||
sandbox = AsyncToolSandboxModal(async_get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(async_get_env_tool.name, {}, user=test_user, tool_id=async_get_env_tool.id)
|
||||
result = await sandbox.run()
|
||||
|
||||
assert test_value in result.func_return
|
||||
@@ -723,7 +729,7 @@ async def test_modal_sandbox_async_with_env_vars(check_modal_key_is_set, async_g
|
||||
@pytest.mark.modal_sandbox
|
||||
async def test_modal_sandbox_async_with_agent_state(check_modal_key_is_set, async_stateful_tool, test_user, agent_state):
|
||||
"""Test async function with agent state in Modal sandbox"""
|
||||
sandbox = AsyncToolSandboxModal(async_stateful_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(async_stateful_tool.name, {}, user=test_user, tool_id=async_stateful_tool.id)
|
||||
result = await sandbox.run(agent_state=agent_state)
|
||||
|
||||
assert result.agent_state.memory.get_block("human").value == ""
|
||||
@@ -735,7 +741,7 @@ async def test_modal_sandbox_async_with_agent_state(check_modal_key_is_set, asyn
|
||||
@pytest.mark.modal_sandbox
|
||||
async def test_modal_sandbox_async_error_handling(check_modal_key_is_set, async_error_tool, test_user):
|
||||
"""Test async function error handling in Modal sandbox"""
|
||||
sandbox = AsyncToolSandboxModal(async_error_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(async_error_tool.name, {}, user=test_user, tool_id=async_error_tool.id)
|
||||
result = await sandbox.run()
|
||||
|
||||
# Check that error was captured
|
||||
@@ -764,7 +770,7 @@ async def test_modal_sandbox_async_per_agent_env(check_modal_key_is_set, async_g
|
||||
|
||||
agent_state.secrets = [AgentEnvironmentVariable(key=key, value=correct_val, agent_id=agent_state.id)]
|
||||
|
||||
sandbox = AsyncToolSandboxModal(async_get_env_tool.name, {}, user=test_user)
|
||||
sandbox = AsyncToolSandboxModal(async_get_env_tool.name, {}, user=test_user, tool_id=async_get_env_tool.id)
|
||||
result = await sandbox.run(agent_state=agent_state)
|
||||
assert wrong_val not in result.func_return
|
||||
assert correct_val in result.func_return
|
||||
|
||||
@@ -269,6 +269,7 @@ class TestModalV2BasicExecution:
|
||||
tool_name="calculate",
|
||||
args={"operation": "add", "a": 5, "b": 3},
|
||||
user=test_user,
|
||||
tool_id=basic_tool.id,
|
||||
tool_object=basic_tool,
|
||||
)
|
||||
|
||||
@@ -281,6 +282,7 @@ class TestModalV2BasicExecution:
|
||||
tool_name="calculate",
|
||||
args={"operation": "divide", "a": 10, "b": 2},
|
||||
user=test_user,
|
||||
tool_id=basic_tool.id,
|
||||
tool_object=basic_tool,
|
||||
)
|
||||
|
||||
@@ -296,6 +298,7 @@ class TestModalV2BasicExecution:
|
||||
tool_name="calculate",
|
||||
args={"operation": "divide", "a": 10, "b": 0},
|
||||
user=test_user,
|
||||
tool_id=basic_tool.id,
|
||||
tool_object=basic_tool,
|
||||
)
|
||||
|
||||
@@ -308,6 +311,7 @@ class TestModalV2BasicExecution:
|
||||
tool_name="calculate",
|
||||
args={"operation": "unknown", "a": 1, "b": 2},
|
||||
user=test_user,
|
||||
tool_id=basic_tool.id,
|
||||
tool_object=basic_tool,
|
||||
)
|
||||
|
||||
@@ -322,6 +326,7 @@ class TestModalV2BasicExecution:
|
||||
tool_name="fetch_data",
|
||||
args={"url": "https://example.com", "delay": 0.01},
|
||||
user=test_user,
|
||||
tool_id=async_tool.id,
|
||||
tool_object=async_tool,
|
||||
)
|
||||
|
||||
@@ -344,6 +349,7 @@ class TestModalV2BasicExecution:
|
||||
tool_name="calculate",
|
||||
args={"operation": "add", "a": i, "b": i + 1},
|
||||
user=test_user,
|
||||
tool_id=basic_tool.id,
|
||||
tool_object=basic_tool,
|
||||
)
|
||||
for i in range(5)
|
||||
@@ -594,6 +600,7 @@ class TestModalV2Persistence:
|
||||
tool_name="calculate",
|
||||
args={"operation": "add", "a": 1, "b": 1},
|
||||
user=mock_user,
|
||||
tool_id=basic_tool.id,
|
||||
tool_object=basic_tool,
|
||||
sandbox_config=config1,
|
||||
)
|
||||
@@ -602,6 +609,7 @@ class TestModalV2Persistence:
|
||||
tool_name="calculate",
|
||||
args={"operation": "add", "a": 2, "b": 2},
|
||||
user=mock_user,
|
||||
tool_id=basic_tool.id,
|
||||
tool_object=basic_tool,
|
||||
sandbox_config=config2,
|
||||
)
|
||||
@@ -696,6 +704,7 @@ def calculate(operation: str, a: float, b: float) -> float:
|
||||
tool_name="integration_test",
|
||||
args={"operation": "add", "a": 5, "b": 3},
|
||||
user=mock_user,
|
||||
tool_id=tool.id,
|
||||
tool_object=tool,
|
||||
sandbox_config=sandbox_config,
|
||||
)
|
||||
@@ -791,6 +800,7 @@ class TestModalV2DeploymentStats:
|
||||
tool_name=tool.name,
|
||||
args={},
|
||||
user=test_user,
|
||||
tool_id=tool.id,
|
||||
tool_object=tool,
|
||||
)
|
||||
await sandbox.run()
|
||||
|
||||
@@ -497,7 +497,9 @@ def memory_clear(label: str, agent_id: str, client: "Letta"):
|
||||
# Simulate tool execution with the reserved keywords
|
||||
# This would normally happen during agent execution, but we'll test the tool directly
|
||||
# Create the sandbox for the tool
|
||||
sandbox = AsyncToolSandboxLocal(tool_name="memory_clear", args={"label": "test_block"}, user=test_user, tool_object=created_tool)
|
||||
sandbox = AsyncToolSandboxLocal(
|
||||
tool_name="memory_clear", args={"label": "test_block"}, user=test_user, tool_id=created_tool.id, tool_object=created_tool
|
||||
)
|
||||
|
||||
# Initialize the sandbox to detect reserved keywords
|
||||
await sandbox._init_async()
|
||||
|
||||
@@ -377,6 +377,7 @@ def test_function(x: int, y: int) -> int:
|
||||
tool_name="test_function",
|
||||
args={"x": 1, "y": 2},
|
||||
user=mock_user,
|
||||
tool_id=mock_tool.id,
|
||||
tool_object=mock_tool,
|
||||
sandbox_config=mock_sandbox_config,
|
||||
)
|
||||
@@ -396,6 +397,7 @@ def test_function(x: int, y: int) -> int:
|
||||
tool_name="test_function",
|
||||
args={"x": 1, "y": 2},
|
||||
user=mock_user,
|
||||
tool_id=mock_tool.id,
|
||||
tool_object=mock_tool,
|
||||
sandbox_config=mock_sandbox_config,
|
||||
)
|
||||
@@ -409,6 +411,7 @@ def test_function(x: int, y: int) -> int:
|
||||
tool_name="test_function",
|
||||
args={"x": 1, "y": 2},
|
||||
user=mock_user,
|
||||
tool_id=mock_tool.id,
|
||||
tool_object=mock_tool,
|
||||
sandbox_config=mock_sandbox_config,
|
||||
)
|
||||
@@ -434,6 +437,7 @@ def test_function(x: int, y: int) -> int:
|
||||
tool_name="test_function",
|
||||
args={"x": 1, "y": 2},
|
||||
user=mock_user,
|
||||
tool_id=mock_tool.id,
|
||||
tool_object=mock_tool,
|
||||
)
|
||||
|
||||
@@ -510,6 +514,7 @@ def test_function(x: int, y: int) -> int:
|
||||
tool_name="test_function",
|
||||
args={"x": 1, "y": 2},
|
||||
user=mock_user,
|
||||
tool_id=mock_tool.id,
|
||||
tool_object=mock_tool,
|
||||
sandbox_config=mock_sandbox_config,
|
||||
)
|
||||
@@ -543,6 +548,7 @@ def test_function(x: int, y: int) -> int:
|
||||
tool_name="sync_func",
|
||||
args={},
|
||||
user=mock_user,
|
||||
tool_id=sync_tool.id,
|
||||
tool_object=sync_tool,
|
||||
)
|
||||
|
||||
@@ -560,6 +566,7 @@ def test_function(x: int, y: int) -> int:
|
||||
tool_name="async_func",
|
||||
args={},
|
||||
user=mock_user,
|
||||
tool_id=async_tool.id,
|
||||
tool_object=async_tool,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user