Fix: accept GOOGLE_API_KEY in geminiInitParams so adk create .env files work - #313
Open
AmaadMartin wants to merge 1 commit into
Open
Fix: accept GOOGLE_API_KEY in geminiInitParams so adk create .env files work#313AmaadMartin wants to merge 1 commit into
adk create .env files work#313AmaadMartin wants to merge 1 commit into
Conversation
geminiInitParams() only consulted GOOGLE_GENAI_API_KEY and GEMINI_API_KEY on the non-Vertex branch, so the .env that `adk create` generates -- which writes GOOGLE_API_KEY -- could not construct a Gemini model. GOOGLE_API_KEY is the name @google/genai reads itself and the name adk-python's CLI writes. Insert it between the two existing names: GOOGLE_GENAI_API_KEY keeps top env priority so no current setup changes meaning, and GOOGLE_API_KEY precedes GEMINI_API_KEY to match getApiKeyFromEnv() in the SDK.
This was referenced Jul 31, 2026
Fix: gitignore the .env that adk create writes so scaffolded agents cannot commit their API key
#364
Open
Open
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: An agent scaffolded by the officially supported on-ramp cannot construct its own model.
generateEnvFile()indev/src/cli/cli_create.tswrites the Gemini-API credentials as:But
geminiInitParams()incore/src/models/google_llm.tsonly consultedGOOGLE_GENAI_API_KEYandGEMINI_API_KEYon the non-Vertex branch.GOOGLE_API_KEY— the name the CLI had just written — was not among them, soparams.apiKeystayedundefinedand theGeminiconstructor threw:Reproduced end to end against a local build (see the E2E section below):
adk create demo --api_key <KEY> --yes, then loading the generated.envand doingnew Gemini({model: 'gemini-2.5-flash'})throws.The underlying SDK would have accepted the key on its own — ADK's own pre-flight validation is what rejected the CLI-generated
.env.@google/genai@1.52.0(the version in this repo's lockfile) resolves it ingetApiKeyFromEnv():Solution: Accept
GOOGLE_API_KEYas an additional fallback insidegeminiInitParams(), rather than changing whatgenerateEnvFile()emits.Why fix the resolver and not the CLI:
GOOGLE_API_KEYis the name@google/genaireads, the nameadk-python's CLI writes, and a name already used elsewhere in this repo for Vertex Express mode (core/src/utils/vertex_ai_utils.ts). Renaming the CLI output would make adk-js the odd one out in its own ecosystem..env, and every hand-written.envfollowing the SDK/python convention, still broken. Fixing the resolver repairs both populations.Resulting precedence (non-Vertex branch,
!isBrowser()only):params.apiKey(explicit constructor argument) — always wins.GOOGLE_GENAI_API_KEY— keeps top env priority, so no current setup changes meaning.GOOGLE_API_KEY— new.GEMINI_API_KEY.GOOGLE_API_KEYis placed ahead ofGEMINI_API_KEYdeliberately, mirroring the SDK ordering quoted above.The throw message at
core/src/models/google_llm.tsenumerated the accepted names and would have become wrong, so it now reads... GOOGLE_GENAI_API_KEY, GOOGLE_API_KEY or GEMINI_API_KEY .... Doc comments onGeminiParams.apiKeyandApigeeLlmParams.apiKey, which enumerate the same names, were updated to match. No key value is ever interpolated into a message or log.Scope and invariants held
else, so Vertex Express mode still resolvesGOOGLE_API_KEYonly throughgetExpressModeApiKey(). Pinned by a test (see mutation M6).!isBrowser()guard still wraps everyprocess.envread —coreships a browser bundle and must not touchprocess.envthere.generateEnvFile()writes, and no change toGOOGLE_GENAI_USE_VERTEXAIhandling (the..._USE_ENTERPRISErename is a separate, in-flight change).package.json/lockfile churn.Cross-language parity:
adk-pythonhas no such gap — its CLI writesGOOGLE_API_KEYand itsGemini.api_clientconstructsgoogle.genai.Client(**kwargs)without an explicitapi_key, so the SDK's own resolution applies. This change makes adk-js match on the observable behaviour (which env var names are accepted, and in what order), which is the side that parity governs.Two behaviour deltas, both intended
GOOGLE_API_KEYandGEMINI_API_KEYare set to different values, ADK previously usedGEMINI_API_KEYand now usesGOOGLE_API_KEY— which is what@google/genaiitself would have done. Deliberate alignment, not a regression.ApigeeLlm:apigeeToGeminiInitParams()substitutes the fake key'-'when no key resolves. WithGOOGLE_API_KEYset in the environment, the gemini-provider path now uses that real key instead of'-'— the same treatmentGOOGLE_GENAI_API_KEYalready got. Consistent and intended.Collision check (required before implementation): scanned all 221 open PRs on the fork for any that touch
core/src/models/{google_llm,apigee_llm}.tsordev/src/cli/cli_create.ts, then grepped each candidate diff forGOOGLE_API_KEY/geminiInitParams. No open PR lands this change. Adjacent-but-distinct work exists and this PR is branched frommainrather than stacked, because it depends on none of it:params.vertexaigate a few lines above, not the non-Vertex api-keyelse; different hunk, different concern.generateEnvFile()emits (GOOGLE_GENAI_USE_VERTEXAI→GOOGLE_GENAI_USE_ENTERPRISE). This is why thedevtest here was not tightened into an exact whole-.env-body pin: doing so would pin the very line Feat: Emit GOOGLE_GENAI_USE_ENTERPRISE from adk create and adk deploy #286 is changing. Only the API-key name is pinned, which is the contract this fix actually depends on and which is orthogonal to that rename.clearEnv()addition here; that line is still required onmaintoday.Deviations from the elaborated plan, both narrowing:
core/test/models/apigee_llm_test.tswas not modified. The plan proposed addingGOOGLE_API_KEY/GEMINI_API_KEYdeletions to itsafterEachfor hermeticity, but this was tested rather than assumed: running that suite withGOOGLE_API_KEY=ambient-keyexported passes 43/43 both before and after this change, because no assertion in the file observes the resolved key. The addition would have been dead code.devtest tightening was reduced to a contract comment over the existingGOOGLE_API_KEY=my-api-keyassertion, for the Feat: Emit GOOGLE_GENAI_USE_ENTERPRISE from adk create and adk deploy #286 reason above. That assertion already fails on a rename (verified — mutation M7).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.
Commands run (targeted, on the exact pushed commit):
Added to
core/test/models/google_llm_test.ts:GOOGLE_API_KEYalone;GOOGLE_GENAI_API_KEYoverGOOGLE_API_KEY;GOOGLE_API_KEYoverGEMINI_API_KEY;GEMINI_API_KEYalone.'should prefer the constructor apiKey over GOOGLE_API_KEY'.'should not use GOOGLE_API_KEY on the Vertex AI path'— pins the invariant that the fallback stays inside the non-Vertex branch.'should construct from the .env written byadk create'— sets exactly the two lines the CLI emits and asserts the model constructs and the client receivescli-key. This is the bug's contract, expressed hermetically./API key must be provided/to the full updated message includingGOOGLE_API_KEY.delete process.env['GOOGLE_API_KEY']added toclearEnv(). This is required, not cosmetic: without it the pre-existing tests'should throw error if apiKey is missing in constructor'and'should return undefined apiKey if missing'start failing on any machine that exportsGOOGLE_API_KEY.No existing test was deleted, skipped, or weakened.
Coverage: 100% of the changed regions. Measured with
@vitest/coverage-v8scoped tocore/src/models/google_llm.ts, then inspected per-line from the JSON report: zero uncovered statements and zero uncovered branches in both changed regions (the throw at lines 118–122 and the fallback chain at lines 396–404).Proof each test can fail. Every new test was run against mutated source and confirmed to FAIL. Recorded mutations and their failure messages:
process.env['GOOGLE_API_KEY'] ||termshould construct from the .env written by \adk create`;should resolve GOOGLE_API_KEY when it is the only key set;should resolve GOOGLE_API_KEY over GEMINI_API_KEY`API key must be provided via constructor or GOOGLE_GENAI_API_KEY, GOOGLE_API_KEY or GEMINI_API_KEY environment variable./expected undefined to be 'google-api-key'/expected 'gemini-api-key' to be 'google-api-key'should throw error if apiKey is missing in constructorexpected [Function] to throw error matching /API key must be provided via construc…/ but got 'API key must be provided via construc…'GOOGLE_API_KEYafterGEMINI_API_KEYshould resolve GOOGLE_API_KEY over GEMINI_API_KEYexpected 'gemini-api-key' to be 'google-api-key'GOOGLE_API_KEYbeforeGOOGLE_GENAI_API_KEYshould resolve GOOGLE_GENAI_API_KEY over GOOGLE_API_KEYexpected 'google-api-key' to be 'genai-api-key'!params.apiKeyguard (env would beat the constructor arg)should prefer the constructor apiKey over GOOGLE_API_KEY(+9 pre-existing)expected 'google-api-key' to be 'explicit-key'elsebranchshould not use GOOGLE_API_KEY on the Vertex AI pathexpected 'google-api-key' to be undefinedGOOGLE_GENAI_API_KEY=insteadshould set Google AI env vars if api key provided(dev)expected "spy" to be called with arguments: [ StringContaining ".env", …(1) ]GOOGLE_API_KEYfromclearEnv(), with it exported ambientlyshould throw error if apiKey is missing in constructor;should return undefined apiKey if missing;should resolve GEMINI_API_KEY when it is the only key setexpected [Function] to throw an error/expected 'cli-key' to be undefined/expected 'google-api-key' to be 'gemini-api-key'|| process.env['GEMINI_API_KEY']termshould resolve GEMINI_API_KEY when it is the only key setexpected undefined to be 'gemini-api-key'Manual End-to-End (E2E) Tests:
Please provide instructions on how to manually test your changes, including any necessary setup or configuration.
Run with no mocks, against the real built package and a real
adk createscaffold. Both directions were verified.npm install && npm run buildat the repo root.demo/.envcontainsGOOGLE_API_KEY=<PLACEHOLDER>andGOOGLE_GENAI_USE_VERTEXAI=0— unchanged by this PR. (Constructing a model does not call the API, so a placeholder key is sufficient; do not paste a real key anywhere.)demo/, run a script that mirrors what the generatedagent.tsdoes —dotenv.config(), thennew Gemini({model: 'gemini-2.5-flash'})— resolving@google/adkto the local build:Results:
constructed ok.corefrom the pre-fixgoogle_llm.tsand re-ran the identical script:Error: API key must be provided via constructor or GOOGLE_GENAI_API_KEY or GEMINI_API_KEY environment variable.Restoring the fix and rebuilding returns it toconstructed ok.No new integration or
tests/e2etest was added: the behaviour is fully determined byprocess.envand is covered hermetically by the unit tests, and a live-credential test would be skipped in CI. Confirmed no existingtests/**case asserts the old error string.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.
Notes for the reviewer:
@ts-expect-error,@ts-ignore,eslint-disable,as any,as never, coverage ignores): zero hits.dev/test/cli/cli_create_test.tsshows 1 pre-existing failure on this developer machine (should handle Vertex AI selection with gcloud defaults) caused by an ambientGOOGLE_CLOUD_PROJECT. It fails identically on unmodifiedmainand passes with that variable unset, as on a CI runner. Unrelated to this change; Fix: make the adk create gcloud-defaults unit test hermetic #203 / Fix: make cli_create_test hermetic against ambient GOOGLE_CLOUD_* env vars #259 address it.