Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions contributing/samples/agent_engine_code_execution/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,8 @@ def base_system_instruction():
# Replace with agent engine resource name used for creating sandbox if
# sandbox_resource_name is not set.
agent_engine_resource_name="AGENT_ENGINE_RESOURCE_NAME",
# Optional: Set a TTL for the sandbox to automatically clean up resources.
# Format: duration string like "3600s" for 1 hour.
# sandbox_ttl="3600s",
),
)
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,20 @@ class AgentEngineSandboxCodeExecutor(BaseCodeExecutor):
sandbox_resource_name: If set, load the existing resource name of the code
interpreter extension instead of creating a new one. Format:
projects/123/locations/us-central1/reasoningEngines/456/sandboxEnvironments/789
sandbox_ttl: The time-to-live for the sandbox. The expiration time is
computed as: now + TTL. Format should be a duration string like "3600s"
for 1 hour. Only used when creating a new sandbox with
agent_engine_resource_name.
"""

sandbox_resource_name: str = None
sandbox_ttl: Optional[str] = None

def __init__(
self,
sandbox_resource_name: Optional[str] = None,
agent_engine_resource_name: Optional[str] = None,
sandbox_ttl: Optional[str] = None,
**data,
):
"""Initializes the AgentEngineSandboxCodeExecutor.
Expand All @@ -60,6 +66,9 @@ def __init__(
projects/123/locations/us-central1/reasoningEngines/456, when both
sandbox_resource_name and agent_engine_resource_name are set,
agent_engine_resource_name will be ignored.
sandbox_ttl: The time-to-live for the sandbox. The expiration time is
computed as: now + TTL. Format should be a duration string like "3600s"
for 1 hour. Only used when creating a new sandbox.
**data: Additional keyword arguments to be passed to the base class.
"""
super().__init__(**data)
Expand All @@ -81,13 +90,13 @@ def __init__(
agent_engine_resource_name, agent_engine_resource_name_pattern
)
)
# @TODO - Add TTL for sandbox creation after it is available
# in SDK.
self.sandbox_ttl = sandbox_ttl
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The sandbox_ttl attribute is only set when a new sandbox is created (i.e., when agent_engine_resource_name is provided). If an executor is initialized with an existing sandbox_resource_name, the sandbox_ttl parameter is ignored and self.sandbox_ttl remains None. This could be confusing for a user who provides the sandbox_ttl parameter in that case.

To improve consistency and predictability, consider setting self.sandbox_ttl = sandbox_ttl unconditionally at the beginning of the __init__ method. This would ensure the attribute always reflects the value passed to the constructor, even though it's only used during creation.

operation = self._get_api_client().agent_engines.sandboxes.create(
spec={'code_execution_environment': {}},
name=agent_engine_resource_name,
config=types.CreateAgentEngineSandboxConfig(
display_name='default_sandbox'
display_name='default_sandbox',
ttl=sandbox_ttl,
),
)
self.sandbox_resource_name = operation.response.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,69 @@ def test_execute_code_success(
name="projects/123/locations/us-central1/reasoningEngines/456/sandboxEnvironments/789",
input_data={"code": 'print("hello world")'},
)

@patch("vertexai.types.CreateAgentEngineSandboxConfig")
@patch("vertexai.Client")
def test_init_with_agent_engine_resource_name_and_ttl(
self,
mock_vertexai_client,
mock_sandbox_config,
):
"""Tests sandbox creation with agent_engine_resource_name and TTL."""
# Setup Mocks
mock_api_client = MagicMock()
mock_vertexai_client.return_value = mock_api_client
mock_operation = MagicMock()
mock_operation.response.name = (
"projects/123/locations/us-central1/reasoningEngines/456/sandboxEnvironments/789"
)
mock_api_client.agent_engines.sandboxes.create.return_value = mock_operation

# Execute
executor = AgentEngineSandboxCodeExecutor(
agent_engine_resource_name="projects/123/locations/us-central1/reasoningEngines/456",
sandbox_ttl="3600s",
)

# Assert
assert executor.sandbox_resource_name == (
"projects/123/locations/us-central1/reasoningEngines/456/sandboxEnvironments/789"
)
assert executor.sandbox_ttl == "3600s"
mock_sandbox_config.assert_called_once_with(
display_name="default_sandbox",
ttl="3600s",
)

@patch("vertexai.types.CreateAgentEngineSandboxConfig")
@patch("vertexai.Client")
def test_init_with_agent_engine_resource_name_without_ttl(
self,
mock_vertexai_client,
mock_sandbox_config,
):
"""Tests sandbox creation with agent_engine_resource_name and no TTL."""
# Setup Mocks
mock_api_client = MagicMock()
mock_vertexai_client.return_value = mock_api_client
mock_operation = MagicMock()
mock_operation.response.name = (
"projects/123/locations/us-central1/reasoningEngines/456/sandboxEnvironments/789"
)
mock_api_client.agent_engines.sandboxes.create.return_value = mock_operation

# Execute
executor = AgentEngineSandboxCodeExecutor(
agent_engine_resource_name="projects/123/locations/us-central1/reasoningEngines/456",
)

# Assert
assert executor.sandbox_resource_name == (
"projects/123/locations/us-central1/reasoningEngines/456/sandboxEnvironments/789"
)
assert executor.sandbox_ttl is None
mock_sandbox_config.assert_called_once_with(
display_name="default_sandbox",
ttl=None,
)