Fix: honour ADK_DISABLE_GEMINI_MODEL_ID_CHECK in GoogleSearchTool - #614
Open
AmaadMartin wants to merge 2 commits into
Open
Fix: honour ADK_DISABLE_GEMINI_MODEL_ID_CHECK in GoogleSearchTool#614AmaadMartin wants to merge 2 commits into
AmaadMartin wants to merge 2 commits into
Conversation
added 2 commits
August 3, 2026 21:17
GoogleSearchTool.processLlmRequest gated purely on isGeminiModel(), so the ADK_DISABLE_GEMINI_MODEL_ID_CHECK escape hatch had no effect on it even though VertexAiSearchTool, EnterpriseWebSearchTool and GoogleMapsGroundingTool all honour it. Users pointing ADK at a Gemini-backed endpoint with a non-standard model id could not attach the built-in Google Search tool. OR the flag into the Gemini-family gate, matching adk-python src/google/adk/tools/google_search_tool.py. Gemini 1.x precedence and the un-bypassed error text are unchanged.
The two new bypass cases originally copied this file's `{} as never`
toolContext convention and hand-rolled env save/restore. Build a real
Context (real InvocationContext, LlmAgent, Session, PluginManager) instead,
so the new tests introduce no unchecked cast and run against genuine ADK
plumbing, and use vi.stubEnv/vi.unstubAllEnvs (already used elsewhere in
core/test) instead of duplicating the restore block.
Also pins that a falsy flag value does not bypass the model check. The six
pre-existing tests are untouched.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Please ensure you have read the contribution guide before creating a pull request.
Link to Issue or Description of Change
Closes: #issue_number
Related: #issue_number
Problem: ADK ships an escape hatch,
ADK_DISABLE_GEMINI_MODEL_ID_CHECK, for users pointing ADK at a Gemini-backed endpoint whose model id does not start withgemini-(a proxied, aliased or internally-named deployment such asinternal-model-v1).GoogleSearchTool.processLlmRequestnever consulted it: it gated purely onisGeminiModel(llmRequest.model)and otherwise threwGoogle search tool is not supported for model <model>, so the built-in Google Search tool could not be attached to such a model at all.This is both a cross-language parity gap and an internal inconsistency:
src/google/adk/tools/google_search_tool.py,process_llm_request, reads the flag intomodel_check_disabledand ORs it into the model-family gate.core/src/tools/vertex_ai_search_tool.ts,core/src/tools/enterprise_web_search_tool.ts,core/src/tools/google_maps_grounding_tool.ts.Solution: Read the flag through the existing
isGeminiModelIdCheckDisabled()helper and OR it into the Gemini-family gate, exactly as the three sibling tools do:Deliberately in scope / out of scope:
isGemini1Modelbranch, matching adk-python whereis_gemini_1_modelis theifand the disjunct lives in theelif. A Gemini 1.x request still getsgoogleSearchRetrievaland still raises "can not be used with other tools in Gemini 1.x." whether or not the flag is set._is_managed_agent(llm_request)is deliberately NOT ported. adk-js has noisManagedAgentequivalent anywhere incore/src, and inventing one is out of scope for a bug fix. Parity here is limited to themodel_check_disabledterm.applyGoogleSearch()free function was extracted "to match" the maps/enterprise tools; that is a refactor, not this fix.url_context_tool.tsandbuilt_in_code_executor.tsare handled separately; this PR changes exactly two files.core/src/utils/model_name.ts,core/src/utils/env_aware_utils.ts) are unchanged, noprocess.envis read directly insrc/, no export changes, no new error types. The change is strictly permissive and opt-in, so it is not a breaking change: with the variable unset, behaviour and error text are byte-identical to before.Collision check (required before implementation):
gh pr list --repo <fork> --state open --limit 1000returned 513 open PRs; filtering byfiles[].pathforgoogle_search_toolreturned #178, #293, #332, #413, #487, #514. All six are repo-wide typecheck/lint cleanups, none implements this behaviour: only #332 touchescore/src/tools/google_search_tool.ts, and it merely drops a now-redundantas GenerateContentConfigcast on a different line. #470 (honour ADK_DISABLE_GEMINI_MODEL_ID_CHECK in BuiltInCodeExecutor and UrlContextTool) is the closest sibling and touches only the four files for those two components — no overlap. This branch is therefore based directly onmain, not stacked.Testing Plan
Please describe the tests that you ran to verify your changes. This is required for all PRs that are not small documentation or typo fixes.
Unit Tests:
[x] I have added or updated unit tests for my change.
[x] All unit tests pass locally.
Three new cases were added to
core/test/tools/google_search_tool_test.tsinside a nesteddescribe('ADK_DISABLE_GEMINI_MODEL_ID_CHECK'). No existing test was edited, weakened, skipped or deleted — in particular'throws for unsupported (non-Gemini) model'is untouched and remains the regression guard for the un-bypassed path.adds googleSearch for a non-Gemini model when the check is disabled— flag'true', modelinternal-model-v1, asserts[{googleSearch: {}}]. Mirrors adk-python'stest_process_llm_request_with_non_gemini_model_and_disabled_check.keeps Gemini 1.x handling when the check is disabled— flag'true', modelgemini-1.5-pro, asserts[{googleSearchRetrieval: {}}]. Pins the precedence invariant, which no existing test covered.still throws for a non-Gemini model when the value is falsy— flag'false', asserts the original error still throws. This exercises the error path under the flag, proving the bypass is truthiness-gated rather than presence-gated.Two deliberate deviations from the surrounding file style, both in the safer direction and both confined to the new tests:
Context(realInvocationContext,LlmAgent,Session,PluginManager) via a localmakeToolContext()helper rather than copying this file'stoolContext: {} as neverconvention.as neveris an unchecked cast, so the new code introduces none; the six pre-existing call sites were left alone (a repo-wide cleanup of those casts is already in flight in a separate PR).vi.stubEnv+afterEach(vi.unstubAllEnvs)— already used incore/test/telemetry/setup_test.tsandcore/test/code_executors/agent_engine_sandbox_code_executor_test.ts— instead of duplicating a ten-line manual save/restore block in each test. It gives the same leak-proof restore guarantee (including on assertion failure) without the duplication.Command:
npx vitest run --project unit:core core/test/tools/google_search_tool_test.ts→ 10 passed (7 pre-existing + 3 new).Coverage. Measured with
--coverage.include='core/src/tools/google_search_tool.ts': 100% branch, 95.23% line/statement. The only uncovered lines are 31–32, the body of the pre-existingrunAsync()built-in stub, which this PR does not touch and which had no test before this change. Both lines added by this PR — theconst modelCheckDisabled = ...and the modified gate — are at 100% line and 100% branch coverage, including the newly reachabletruevalue of the new disjunct.Proof the new tests can fail (mutation testing). Each mutation was applied to
core/src/tools/google_search_tool.ts, the targeted suite re-run, then the source restored. Every mutation is killed, and each is killed by a different new test:if (isGeminiModel(llmRequest.model)) {Error: Google search tool is not supported for model internal-model-v1. Tests 2 and 3 still pass (that is the point of test 2: it pins behaviour the fix must not change).if (isGemini1Model(llmRequest.model) || modelCheckDisabled) {AssertionError: expected [ { googleSearchRetrieval: {} } ] to deeply equal [ { googleSearch: {} } ].if (isGemini1Model(llmRequest.model) && !modelCheckDisabled) {AssertionError: expected [ { googleSearch: {} } ] to deeply equal [ { googleSearchRetrieval: {} } ].const modelCheckDisabled = process.env.ADK_DISABLE_GEMINI_MODEL_ID_CHECK !== undefined;promise resolved "undefined" instead of rejecting.Manual End-to-End (E2E) Tests:
Please provide instructions on how to manually test your changes, including any necessary setup or configuration.
No integration-test fixture was added: this is an in-process gate change on a built-in tool that only mutates a request object — there is no transport, service or cross-component wiring to exercise, so a fixture would cost CI time for no signal.
Instead, the reproduction from the bug report was run against the built package (
npm run build, importing@google/adkfromdist, no mocks, no test framework), which confirms every row of the expected behaviour table:Observed (this branch):
On
mainthe first two rows throw instead. To reproduce:export ADK_DISABLE_GEMINI_MODEL_ID_CHECK=true, then run the snippet above.Other checks run on the pushed commit:
npm run build(clean),npx eslinton both touched files (clean),npx prettier --checkon both touched files (clean).npm run ts:checkis red repo-wide onmaintoday; the count forcore/test/tools/google_search_tool_test.tsis unchanged by this PR at exactly 1 — the pre-existingType '{ functionDeclarations: never[]; }' is not assignable to type 'never'on the untouched Gemini 1.x multi-tool test, caused by thetools = []default in the file'smakeRequesthelper. This PR adds zero new type errors and no suppressions of any kind.Checklist
[x] I have read the CONTRIBUTING.md document.
[x] I have performed a self-review of my own code.
[x] I have commented my code, particularly in hard-to-understand areas.
[x] I have added tests that prove my fix is effective or that my feature works.
[x] New and existing unit tests pass locally with my changes.
CI status on this PR
All checks pass on the reviewed commit:
run-tests,run-tests (ubuntu-latest),run-tests (macos-latest),run-tests (windows-latest),check-licenseand the Cross-Language Tests job.run-tests (windows-latest)was intermittently red on earlier runs of this same, unchanged commit, always on a pre-existing Windows flake unrelated to this diff: twice oncore/test/code_executors/unsafe_local_code_executor_test.ts > UnsafeLocalCodeExecutor > should execute shell code and return stdout(Test timed out in 5000ms) and once ontests/integration/app_loader/app_loader_test.ts > should discover apps vs agents across directories and standalone files(~41s timeout) — two different unrelated files, both real-subprocess timeouts, 223/244 test files passing each time. Both are already tracked by open PRs (#498 gives the real-subprocess cases inunsafe_local_code_executor_test.tsan explicit 60s timeout; #254 and #246 harden the same Windows shell cases), and both files pass locally on this commit. The job going green on a rerun with no code change confirms the flake rather than a regression; the fix belongs to those PRs, not here.