Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
Copy Markdown
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,
)

Loading