Skip to content

Commit af3a58c

Browse files
committed
fix(adk): wrap tool execution errors and align CI tests
1 parent 3bf4b1c commit af3a58c

4 files changed

Lines changed: 32 additions & 37 deletions

File tree

packages/toolbox-adk/integration.cloudbuild.yaml

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,6 @@
1313
# limitations under the License.
1414

1515
steps:
16-
- id: Build toolbox
17-
name: 'golang:1.26'
18-
entrypoint: /bin/bash
19-
args:
20-
- '-c'
21-
- |
22-
cd packages/toolbox-adk/genai-toolbox
23-
go build -o ../toolbox main.go
2416
- id: Install requirements
2517
name: 'python:${_VERSION}'
2618
dir: 'packages/toolbox-adk'
@@ -47,20 +39,16 @@ steps:
4739
- TOOLBOX_VERSION=$_TOOLBOX_VERSION
4840
- GOOGLE_CLOUD_PROJECT=$PROJECT_ID
4941
- TOOLBOX_MANIFEST_VERSION=${_TOOLBOX_MANIFEST_VERSION}
50-
- TEST_MOCK_GCP=false
5142
args:
5243
- '-c'
5344
- |
54-
chmod +x toolbox
5545
source /workspace/venv/bin/activate
56-
python -m pytest -s --cov=src/toolbox_adk --cov-report=term --cov-fail-under=90 tests/
46+
python -m pytest --cov=src/toolbox_adk --cov-report=term --cov-fail-under=90 tests/
5747
entrypoint: /bin/bash
5848
options:
59-
machineType: 'E2_HIGHCPU_8'
6049
logging: CLOUD_LOGGING_ONLY
6150
substitutions:
6251
_VERSION: '3.13'
6352
# Default values (can be overridden by triggers)
6453
_TOOLBOX_VERSION: '1.1.0'
6554
_TOOLBOX_MANIFEST_VERSION: '34'
66-
_TOOLBOX_URL: 'http://localhost:5000'

packages/toolbox-adk/src/toolbox_adk/tool.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,12 @@ def __init__(
4949
auth_config: Optional[CredentialConfig] = None,
5050
adk_token_getters: Optional[Mapping[str, Any]] = None,
5151
):
52-
"""Args:
53-
core_tool: The underlying toolbox_core.py tool instance.
54-
auth_config: Credential configuration to handle interactive flows.
55-
adk_token_getters: Tool-specific auth token getters.
52+
"""Initialize a toolbox-adk wrapper around a toolbox-core tool.
53+
54+
Args:
55+
core_tool: The underlying `toolbox_core.tool.ToolboxTool` instance.
56+
auth_config: Credential configuration to handle interactive flows.
57+
adk_token_getters: Tool-specific auth token getters.
5658
"""
5759
name = getattr(core_tool, "__name__", None)
5860
if not name:
@@ -220,6 +222,8 @@ async def run_async(
220222
)
221223
try:
222224
if tool_context._invocation_context.credential_service:
225+
# Persist the exchanged credential so future runs can load
226+
# from ADK credential storage instead of re-requesting consent.
223227
auth_config_adk.exchanged_auth_credential = creds
224228
await tool_context._invocation_context.credential_service.save_credential(
225229
auth_config=auth_config_adk,

packages/toolbox-adk/tests/integration/test_integration.py

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
from google.adk.sessions.in_memory_session_service import InMemorySessionService
2929
from google.adk.tools.base_tool import BaseTool
3030
from google.genai import types
31-
from pydantic import ValidationError
3231
from toolbox_core.protocol import Protocol
3332

3433
from toolbox_adk import CredentialStrategy, ToolboxTool, ToolboxToolset
@@ -479,11 +478,11 @@ async def test_run_tool_wrong_param_type(self):
479478
tool = tools[0]
480479

481480
ctx = MagicMock()
482-
with pytest.raises(
483-
ValidationError,
484-
match=r"num_rows\s+Input should be a valid string\s+\[type=string_type,\s+input_value=2,\s+input_type=int\]",
485-
):
486-
await tool.run_async({"num_rows": 2}, ctx)
481+
response = await tool.run_async({"num_rows": 2}, ctx)
482+
assert isinstance(response, dict)
483+
assert response.get("is_error") is True
484+
assert "ValidationError" in response.get("error", "")
485+
assert "Input should be a valid string" in response.get("error", "")
487486
finally:
488487
await toolset.close()
489488

@@ -631,11 +630,11 @@ async def test_run_tool_wrong_auth(self, auth_token2: str):
631630
tool = tools[0]
632631
ctx = MagicMock()
633632

634-
with pytest.raises(
635-
Exception,
636-
match=r"401 \(Unauthorized\)",
637-
):
638-
await tool.run_async({"id": "2"}, ctx)
633+
response = await tool.run_async({"id": "2"}, ctx)
634+
assert isinstance(response, dict)
635+
assert response.get("is_error") is True
636+
assert "RuntimeError" in response.get("error", "")
637+
assert "401 (Unauthorized)" in response.get("error", "")
639638
finally:
640639
await toolset.close()
641640

@@ -794,14 +793,17 @@ async def test_run_tool_with_wrong_map_value_type(self):
794793
tool = tools[0]
795794
ctx = MagicMock()
796795

797-
with pytest.raises(ValidationError):
798-
await tool.run_async(
799-
{
800-
"execution_context": {"env": "staging"},
801-
"user_scores": {"user4": "not-an-integer"},
802-
},
803-
ctx,
804-
)
796+
response = await tool.run_async(
797+
{
798+
"execution_context": {"env": "staging"},
799+
"user_scores": {"user4": "not-an-integer"},
800+
},
801+
ctx,
802+
)
803+
assert isinstance(response, dict)
804+
assert response.get("is_error") is True
805+
assert "ValidationError" in response.get("error", "")
806+
assert "Input should be a valid integer" in response.get("error", "")
805807
finally:
806808
await toolset.close()
807809

packages/toolbox-adk/tests/unit/test_tool.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import pytest
1818
from google.genai.types import Type
19+
from pydantic import ValidationError
1920

2021
from toolbox_adk.credentials import CredentialConfig, CredentialType
2122
from toolbox_adk.tool import ToolboxTool
@@ -99,7 +100,7 @@ async def test_run_async_returns_error_on_validation_error(self):
99100
assert isinstance(result, dict) and "error" in result
100101
assert result.get("is_error") is True
101102
assert "ValidationError" in result["error"]
102-
assert "field required" in result["error"]
103+
assert "Field required" in result["error"]
103104

104105
@pytest.mark.asyncio
105106
async def test_bind_params(self):

0 commit comments

Comments
 (0)