Skip to Content
ExamplesGemini

Gemini

These scripts show the wire: plain httpx against a proxy provisioned Format=Gemini (for example ddk-gemini-inbound) with the same client_id / client_secret pair. For an agent, ADK’s native Gemini model is bound to the same proxy by donkey.adk.gemini("gemini-2.5-flash") — see Native Gemini. The route is <proxy URL>/models/<model>:generateContent. DonkeyConfig still resolves and validates the credentials, and classify() still types the errors.

Both scripts need a live Format=Gemini proxy; there is no offline Gemini script.

#ScriptShowsNeeds
01native-generate-content.pyA Gemini-shaped contents body, usage and routingProxy credentials, Format=Gemini
02openai-shape-rejected.pyAn OpenAI-shaped request typed as UpstreamRequestErrorProxy credentials, Format=Gemini

Install

Follow the examples setup first, then:

python -m pip install -e "../donkey-development-kit/python[llm]" # httpx + classify() set -a; source .env.local; set +a export DONKEY_LLM_PROXY_URL=https://<host>/ddk-gemini-inbound/ # overrides the file

The model is gemini-2.5-flash (the MODEL constant).

01 — Native generateContent

python "demos/human-made/gemini/01 - native-generate-content.py"
cfg = DonkeyConfig.from_env().validated(need="llm") headers = {"client_id": cfg.llm_proxy_client_id, "client_secret": cfg.llm_proxy_client_secret} ok = httpx.post( f"{cfg.llm_proxy_url}/models/{MODEL}:generateContent", headers=headers, json={"contents": [{"role": "user", "parts": [{"text": "Say hello in exactly three words."}]}]}, timeout=60, ) ok.raise_for_status() body = ok.json() print(body["candidates"][0]["content"]["parts"][0]["text"]) print("total tokens ", body["usageMetadata"]["totalTokenCount"]) print("routing ", ok.headers.get("x-llm-proxy-model-based-routing-success"))

You should see: the reply, total tokens from usageMetadata, and the proxy’s model-based routing header. A KeyError: 'candidates' means the proxy refused; print ok.text to see why. A 404 means the URL points at a Format=OpenAI proxy.

02 — The wrong shape, typed

python "demos/human-made/gemini/02 - openai-shape-rejected.py"

An OpenAI-shaped /chat/completions request sent to the Gemini proxy comes back as Gemini’s error envelope. classify() types it as a bad request, not a policy refusal.

bad = httpx.post( f"{cfg.llm_proxy_url}/chat/completions", headers=headers, json={"model": "gemini-2.5-flash", "messages": [{"role": "user", "content": "hello"}]}, timeout=60, ) error = classify(bad) print(type(error).__name__, bad.status_code, getattr(error, "code", None), getattr(error, "error_type", None)) print(error)

You should see: UpstreamRequestError, the HTTP status, the upstream code and error type, and the message. Typing Gemini’s list envelope needs donkey-kit 0.1.0.dev9 or later.

Learn more: Typed refusals · Model access

Source: demos/human-made/gemini/

Last updated on