Skip to content

Commit 74e52d9

Browse files
vertex-sdk-botcopybara-github
authored andcommitted
feat: GenAI SDK client - Add sandbox code execution SDK support
PiperOrigin-RevId: 801031399
1 parent d946e95 commit 74e52d9

9 files changed

+2161
-2
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# pylint: disable=protected-access,bad-continuation,missing-function-docstring
16+
17+
from tests.unit.vertexai.genai.replays import pytest_helper
18+
from vertexai._genai import types
19+
20+
21+
def test_create_sandbox(client):
22+
agent_engine = client.agent_engines.create()
23+
assert isinstance(agent_engine, types.AgentEngine)
24+
assert isinstance(agent_engine.api_resource, types.ReasoningEngine)
25+
26+
operation = client.agent_engines.sandboxes.create(
27+
name=agent_engine.api_resource.name,
28+
spec={
29+
"code_execution_environment": {
30+
"machineConfig": "MACHINE_CONFIG_VCPU4_RAM4GIB"
31+
}
32+
},
33+
config=types.CreateAgentEngineSandboxConfig(display_name="test_sandbox"),
34+
)
35+
assert isinstance(operation, types.AgentEngineSandboxOperation)
36+
assert operation.response.display_name == "test_sandbox"
37+
assert (
38+
operation.response.spec.code_execution_environment.machine_config
39+
== "MACHINE_CONFIG_VCPU4_RAM4GIB"
40+
)
41+
assert operation.response.name.startswith(agent_engine.api_resource.name)
42+
43+
44+
pytestmark = pytest_helper.setup(
45+
file=__file__,
46+
globals_for_file=globals(),
47+
test_method="agent_engines.sandboxes.create",
48+
)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# pylint: disable=protected-access,bad-continuation,missing-function-docstring
16+
from tests.unit.vertexai.genai.replays import pytest_helper
17+
from vertexai._genai import types
18+
19+
20+
def test_delete_sandbox(client):
21+
agent_engine = client.agent_engines.create()
22+
assert isinstance(agent_engine, types.AgentEngine)
23+
assert isinstance(agent_engine.api_resource, types.ReasoningEngine)
24+
25+
operation = client.agent_engines.sandboxes.create(
26+
name=agent_engine.api_resource.name,
27+
spec={
28+
"code_execution_environment": {
29+
"machineConfig": "MACHINE_CONFIG_VCPU4_RAM4GIB"
30+
}
31+
},
32+
config=types.CreateAgentEngineSandboxConfig(display_name="test_sandbox"),
33+
)
34+
assert isinstance(operation, types.AgentEngineSandboxOperation)
35+
delete_operation = client.agent_engines.sandboxes.delete(
36+
name=operation.response.name,
37+
)
38+
assert isinstance(delete_operation, types.DeleteAgentEngineSandboxOperation)
39+
assert "/operations/" in delete_operation.name
40+
41+
42+
pytestmark = pytest_helper.setup(
43+
file=__file__,
44+
globals_for_file=globals(),
45+
test_method="agent_engines.sandboxes.delete",
46+
)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# pylint: disable=protected-access,bad-continuation,missing-function-docstring
16+
17+
from tests.unit.vertexai.genai.replays import pytest_helper
18+
from vertexai._genai import types
19+
20+
21+
def test_execute_code_sandbox(client):
22+
agent_engine = client.agent_engines.create()
23+
assert isinstance(agent_engine, types.AgentEngine)
24+
assert isinstance(agent_engine.api_resource, types.ReasoningEngine)
25+
26+
operation = client.agent_engines.sandboxes.create(
27+
name=agent_engine.api_resource.name,
28+
spec={
29+
"code_execution_environment": {
30+
"machineConfig": "MACHINE_CONFIG_VCPU4_RAM4GIB"
31+
}
32+
},
33+
config=types.CreateAgentEngineSandboxConfig(display_name="test_sandbox"),
34+
)
35+
assert isinstance(operation, types.AgentEngineSandboxOperation)
36+
input_data = {
37+
"language": "python",
38+
"code": 'with open("hello.txt","w") as file:\n file.write("Hello, world!")',
39+
}
40+
response = client.agent_engines.sandboxes.execute_code(
41+
name=operation.response.name,
42+
input_data=input_data,
43+
)
44+
assert response.outputs[0].mime_type == "application/json"
45+
46+
47+
pytestmark = pytest_helper.setup(
48+
file=__file__,
49+
globals_for_file=globals(),
50+
test_method="agent_engines.sandboxes.execute_code",
51+
)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# pylint: disable=protected-access,bad-continuation,missing-function-docstring
16+
17+
from tests.unit.vertexai.genai.replays import pytest_helper
18+
from vertexai._genai import types
19+
20+
21+
def test_get_sandbox(client):
22+
agent_engine = client.agent_engines.create()
23+
assert isinstance(agent_engine, types.AgentEngine)
24+
assert isinstance(agent_engine.api_resource, types.ReasoningEngine)
25+
26+
operation = client.agent_engines.sandboxes.create(
27+
name=agent_engine.api_resource.name,
28+
spec={
29+
"code_execution_environment": {
30+
"machineConfig": "MACHINE_CONFIG_VCPU4_RAM4GIB"
31+
}
32+
},
33+
config=types.CreateAgentEngineSandboxConfig(display_name="test_sandbox"),
34+
)
35+
assert isinstance(operation, types.AgentEngineSandboxOperation)
36+
sandbox = client.agent_engines.sandboxes.get(
37+
name=operation.response.name,
38+
)
39+
assert isinstance(sandbox, types.SandboxEnvironment)
40+
assert sandbox.name == operation.response.name
41+
42+
43+
pytestmark = pytest_helper.setup(
44+
file=__file__,
45+
globals_for_file=globals(),
46+
test_method="agent_engines.sandboxes.get",
47+
)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# pylint: disable=protected-access,bad-continuation,missing-function-docstring
16+
17+
from tests.unit.vertexai.genai.replays import pytest_helper
18+
from vertexai._genai import types
19+
20+
21+
def test_list_sandboxes(client):
22+
agent_engine = client.agent_engines.create()
23+
assert not list(
24+
client.agent_engines.sandboxes.list(
25+
name=agent_engine.api_resource.name,
26+
)
27+
)
28+
29+
operation = client.agent_engines.sandboxes.create(
30+
name=agent_engine.api_resource.name,
31+
spec={
32+
"code_execution_environment": {
33+
"machineConfig": "MACHINE_CONFIG_VCPU4_RAM4GIB"
34+
}
35+
},
36+
config=types.CreateAgentEngineSandboxConfig(display_name="test_sandbox"),
37+
)
38+
assert isinstance(operation, types.AgentEngineSandboxOperation)
39+
40+
sandbox_list = client.agent_engines.sandboxes.list(
41+
name=agent_engine.api_resource.name,
42+
)
43+
assert len(sandbox_list) == 1
44+
assert isinstance(sandbox_list[0], types.SandboxEnvironment)
45+
assert sandbox_list[0].name == operation.response.name
46+
47+
48+
pytestmark = pytest_helper.setup(
49+
file=__file__,
50+
globals_for_file=globals(),
51+
test_method="agent_engines.sandboxes.list",
52+
)

vertexai/_genai/_agent_engines_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,14 +367,14 @@ def _await_operation(
367367
*,
368368
operation_name: str,
369369
get_operation_fn: GetOperationFunction,
370-
poll_interval_seconds: int = 10,
370+
poll_interval_seconds: float = 10,
371371
) -> Any:
372372
"""Waits for the operation for creating an agent engine to complete.
373373
374374
Args:
375375
operation_name (str):
376376
Required. The name of the operation for creating the Agent Engine.
377-
poll_interval_seconds (int):
377+
poll_interval_seconds (float):
378378
The number of seconds to wait between each poll.
379379
get_operation_fn (Callable[[str], Any]):
380380
Optional. The function to use for getting the operation. If not

vertexai/_genai/agent_engines.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,7 @@ def _update(
845845
return return_value
846846

847847
_memories = None
848+
_sandboxes = None
848849
_sessions = None
849850

850851
@property
@@ -862,6 +863,25 @@ def memories(self):
862863
) from e
863864
return self._memories.Memories(self._api_client)
864865

866+
@property
867+
@_common.experimental_warning(
868+
"The Vertex SDK GenAI agent_engines.sandboxes module is experimental, "
869+
"and may change in future versions."
870+
)
871+
def sandboxes(self):
872+
if self._sandboxes is None:
873+
try:
874+
# We need to lazy load the sandboxes module to handle the
875+
# possibility of ImportError when dependencies are not installed.
876+
self._sandboxes = importlib.import_module(".sandboxes", __package__)
877+
except ImportError as e:
878+
raise ImportError(
879+
"The agent_engines.sandboxes module requires additional packages. "
880+
"Please install them using pip install "
881+
"google-cloud-aiplatform[agent_engines]"
882+
) from e
883+
return self._sandboxes.Sandboxes(self._api_client)
884+
865885
@property
866886
def sessions(self):
867887
if self._sessions is None:

0 commit comments

Comments
 (0)