Skip to content

Commit ffbb0b3

Browse files
google-genai-botcopybara-github
authored andcommitted
feat: allow setting max_billed_bytes in BigQuery tools config
This will allow users to configure a limit to access in ADK tools on the charges for queries. PiperOrigin-RevId: 831921163
1 parent 22eb7e5 commit ffbb0b3

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

src/google/adk/tools/bigquery/config.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ class BigQueryToolConfig(BaseModel):
6161
change in future versions.
6262
"""
6363

64+
maximum_bytes_billed: Optional[int] = None
65+
"""Maximum number of bytes to bill for a query.
66+
67+
In BigQuery on-demand pricing, charges are rounded up to the nearest MB, with
68+
a minimum 10 MB data processed per table referenced by the query, and with a
69+
minimum 10 MB data processed per query. So this value must be set >=10485760.
70+
"""
71+
6472
max_query_result_rows: int = 50
6573
"""Maximum number of rows to return from a query.
6674
@@ -91,6 +99,19 @@ class BigQueryToolConfig(BaseModel):
9199
locations, see https://cloud.google.com/bigquery/docs/locations.
92100
"""
93101

102+
@field_validator('maximum_bytes_billed')
103+
@classmethod
104+
def validate_maximum_bytes_billed(cls, v):
105+
"""Validate the maximum bytes billed."""
106+
if v and v < 10_485_760:
107+
raise ValueError(
108+
'In BigQuery on-demand pricing, charges are rounded up to the nearest'
109+
' MB, with a minimum 10 MB data processed per table referenced by the'
110+
' query, and with a minimum 10 MB data processed per query. So'
111+
' max_bytes_billed must be set >=10485760.'
112+
)
113+
return v
114+
94115
@field_validator('application_name')
95116
@classmethod
96117
def validate_application_name(cls, v):

src/google/adk/tools/bigquery/query_tool.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,15 @@ def _execute_sql(
152152
return {"status": "SUCCESS", "dry_run_info": dry_run_job.to_api_repr()}
153153

154154
# Finally execute the query, fetch the result, and return it
155+
job_config = bigquery.QueryJobConfig(
156+
connection_properties=bq_connection_properties,
157+
labels=bq_job_labels,
158+
)
159+
if settings.maximum_bytes_billed:
160+
job_config.maximum_bytes_billed = settings.maximum_bytes_billed
155161
row_iterator = bq_client.query_and_wait(
156162
query,
157-
job_config=bigquery.QueryJobConfig(
158-
connection_properties=bq_connection_properties,
159-
labels=bq_job_labels,
160-
),
163+
job_config=job_config,
161164
project=project_id,
162165
max_results=settings.max_query_result_rows,
163166
)

tests/unittests/tools/bigquery/test_bigquery_query_tool.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,3 +1826,26 @@ def test_execute_sql_no_truncation():
18261826
# Check no truncation flag when fewer rows than limit
18271827
assert result["status"] == "SUCCESS"
18281828
assert "result_is_likely_truncated" not in result
1829+
1830+
1831+
def test_execute_sql_maximum_bytes_billed_config():
1832+
"""Test execute_sql tool respects maximum_bytes_billed from config."""
1833+
project = "my_project"
1834+
query = "SELECT 123 AS num"
1835+
statement_type = "SELECT"
1836+
credentials = mock.create_autospec(Credentials, instance=True)
1837+
tool_config = BigQueryToolConfig(maximum_bytes_billed=11_000_000)
1838+
tool_context = mock.create_autospec(ToolContext, instance=True)
1839+
1840+
with mock.patch("google.cloud.bigquery.Client", autospec=False) as Client:
1841+
bq_client = Client.return_value
1842+
query_job = mock.create_autospec(bigquery.QueryJob)
1843+
query_job.statement_type = statement_type
1844+
bq_client.query.return_value = query_job
1845+
1846+
execute_sql(project, query, credentials, tool_config, tool_context)
1847+
1848+
# Check that maximum_bytes_billed was called with config value
1849+
bq_client.query_and_wait.assert_called_once()
1850+
call_args = bq_client.query_and_wait.call_args
1851+
assert call_args.kwargs["job_config"].maximum_bytes_billed == 11_000_000

tests/unittests/tools/bigquery/test_bigquery_tool_config.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,24 @@ def test_bigquery_tool_config_max_query_result_rows_custom():
5656
with pytest.warns(UserWarning):
5757
config = BigQueryToolConfig(max_query_result_rows=100)
5858
assert config.max_query_result_rows == 100
59+
60+
61+
def test_bigquery_tool_config_valid_maximum_bytes_billed():
62+
"""Test BigQueryToolConfig raises exception with valid max bytes billed."""
63+
with pytest.warns(UserWarning):
64+
config = BigQueryToolConfig(maximum_bytes_billed=10_485_760)
65+
assert config.maximum_bytes_billed == 10_485_760
66+
67+
68+
def test_bigquery_tool_config_invalid_maximum_bytes_billed():
69+
"""Test BigQueryToolConfig raises exception with invalid max bytes billed."""
70+
with pytest.raises(
71+
ValueError,
72+
match=(
73+
"In BigQuery on-demand pricing, charges are rounded up to the nearest"
74+
" MB, with a minimum 10 MB data processed per table referenced by the"
75+
" query, and with a minimum 10 MB data processed per query. So"
76+
" max_bytes_billed must be set >=10485760."
77+
),
78+
):
79+
BigQueryToolConfig(maximum_bytes_billed=10_485_759)

0 commit comments

Comments
 (0)