Skip to content

Commit 472e463

Browse files
GWealecopybara-github
authored andcommitted
fix: reject base_url and extra_body in generate_content_config
An agent-level `generate_content_config.http_options.base_url` is copied into every LlmRequest and overrides the client transport, so the configured API key and the full prompt/response traffic are sent to that host. Nothing rejected it, so a supplied agent config (including a YAML one) could redirect a credentialed model call to an arbitrary endpoint. `http_options.extra_body` is recursively merged into the serialized request body just before it is sent, and the merge aligns the incoming key case to the target, so it can overwrite `systemInstruction`, `tools` and `generationConfig` — the exact fields the other three checks in this validator exist to reject. It bypassed all of them. Reject both in the field validator. Request-time `http_options` such as headers, timeout, and retry options are unaffected; `base_url` belongs on the model or its client, which is already why `RunConfig.http_options` deliberately does not merge it. Co-authored-by: George Weale <gweale@google.com> PiperOrigin-RevId: 953629510
1 parent 65d8ea7 commit 472e463

2 files changed

Lines changed: 48 additions & 0 deletions

File tree

src/google/adk/agents/llm_agent.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,18 @@ def validate_generate_content_config(
10891089
raise ValueError(
10901090
'Response schema must be set via LlmAgent.output_schema.'
10911091
)
1092+
if generate_content_config.http_options:
1093+
if generate_content_config.http_options.base_url:
1094+
raise ValueError(
1095+
'Base URL is a transport setting and must be set on the model or'
1096+
' its client, not via LlmAgent.generate_content_config.'
1097+
)
1098+
if generate_content_config.http_options.extra_body:
1099+
raise ValueError(
1100+
'Extra body is merged into the request body and can overwrite the'
1101+
' tools, system instruction and response schema rejected above.'
1102+
' Set it on the model or its client.'
1103+
)
10921104
return generate_content_config
10931105

10941106
@override

tests/unittests/agents/test_llm_agent_fields.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,42 @@ class Schema(BaseModel):
329329
)
330330

331331

332+
def test_validate_generate_content_config_http_options_base_url_throw():
333+
"""Tests that a transport base URL cannot be set directly in config."""
334+
with pytest.raises(ValueError):
335+
_ = LlmAgent(
336+
name='test_agent',
337+
generate_content_config=types.GenerateContentConfig(
338+
http_options=types.HttpOptions(base_url='http://example.invalid')
339+
),
340+
)
341+
342+
343+
def test_validate_generate_content_config_http_options_extra_body_throw():
344+
"""Tests that an extra request body cannot be set directly in config."""
345+
with pytest.raises(ValueError):
346+
_ = LlmAgent(
347+
name='test_agent',
348+
generate_content_config=types.GenerateContentConfig(
349+
http_options=types.HttpOptions(
350+
extra_body={'systemInstruction': {'parts': [{'text': 'hi'}]}}
351+
)
352+
),
353+
)
354+
355+
356+
def test_validate_generate_content_config_http_options_allowed():
357+
"""Tests that request-time http options remain settable in config."""
358+
agent = LlmAgent(
359+
name='test_agent',
360+
generate_content_config=types.GenerateContentConfig(
361+
http_options=types.HttpOptions(timeout=1000)
362+
),
363+
)
364+
365+
assert agent.generate_content_config.http_options.timeout == 1000
366+
367+
332368
def test_allow_transfer_by_default():
333369
sub_agent = LlmAgent(name='sub_agent')
334370
agent = LlmAgent(name='test_agent', sub_agents=[sub_agent])

0 commit comments

Comments
 (0)