@xlaunch/llm-gemini
v0.3.0-beta.4
Published
The native Gemini generateContent LLM adapter: the gemini wire protocol to one Gemini-compatible endpoint, behind the Xlaunch LLM seam
Readme
description: "The native Gemini LLM adapter: the gemini wire protocol to one Gemini-compatible endpoint, behind the Xlaunch LLM seam." kind: "package-reference"
@xlaunch/llm-gemini
Summary
xlaunch-llm-gemini carries the harness's gemini wire protocol: request serialization (system instruction, tool calls, images), server-sent-event stream translation (text, thought, and function-call parts; finish reasons; usage metadata), and refusal mapping, plus GeminiAdapter, a full LLM adapter any composition can register routes with. The gateway adapter serves routes that declare api: gemini through the same translation, so a route can point directly at a Gemini-compatible endpoint without an OpenAI-compatible shim. Wire facts — the streamGenerateContent?alt=sse endpoint shape, the x-goog-api-key header, part vocabulary, finish reasons, and usage metadata semantics — are pinned to the Gemini generateContent API reference.
Table of Contents
Use this package
Declare a route under llm-gateway.providers in $XLAUNCH_HOME/settings.yaml with api: gemini, an endpoint base address ending at the version segment, and a credential reference; the Models page offers the protocol because the gateway's route schema enumerates it:
llm-gateway:
providers:
gemini-direct:
api: gemini
displayName: Gemini (direct)
baseURL: https://generativelanguage.googleapis.com/v1beta
apiKeyEnv: GEMINI_API_KEY
models:
- id: gemini-2.5-flash
contextWindow: 1000000
maxTokens: 8192Compositions that register adapters themselves can construct GeminiAdapter with the same dependency shape the gateway adapter takes — a route resolver, a credential resolver, and the attachment store — and register it with ctx.llm.registerAdapter(). The package is a library, not a plugin: it owns no settings section, and routes are declared where the gateway owns them.
Model Experience
Gemini generateContent dispatch
What the model sees
The adapter changes no model-visible text: it projects the assembled harness request onto the generateContent wire — the system prompt and system-role history into the systemInstruction content, tool results into functionResponse parts inside user turns, assistant tool calls into functionCall parts, and images into inline base64 data parts read under the adapter's request-image policy — and streams response parts back into harness chunks. Consecutive same-role turns are combined into one content, because the contents array is one flat conversation history. Stored tool-call arguments are re-parsed into functionCall args objects, and a stored call whose arguments do not parse is refused rather than rewritten. A functionResponse is a text part, so an image a tool result carries cannot ride it natively; the response's output text names the omission ([image omitted]) instead of dropping it silently, while the same image at the top level of a message goes out inline. A streamed functionCall part's thoughtSignature is stored on the harness tool call and replayed verbatim as a sibling of the outbound functionCall on the part — the position the generateContent schema defines it at — as the API requires a replayed signed call to carry it.
Token effect
None of the request's tokens are added or removed here; the assembled request reaches the endpoint verbatim up to wire encoding. Gemini reports promptTokenCount including cached tokens — the opposite of the harness convention, where input excludes cache reads — so the cached count is subtracted before mapping, the cached count becomes the harness cache-read field, and thoughtsTokenCount becomes the harness reasoning-token count.
KV Cache effect
Dispatch does not rewrite request prefixes, so an unchanged conversation prefix stays byte-stable across requests to the same route: system-role history folds deterministically, and adjacent same-role turns combine by position, not by content. Changing the route's baseURL, credential, or model id in settings directs later requests to a different endpoint and forfeits that provider's cache reuse.
Known Limitations and Deferred Work
These limits define when this adapter is a poor fit. They are current package constraints, not a task backlog.
- No reasoning-effort mapping — the generateContent request carries no effort field, so routes served through this wire declare no reasoning efforts and an effort-bearing request is refused before dispatch. Thinking is never enabled on requests, while
thoughtparts a gateway-enabled endpoint streams back are still translated into harness reasoning chunks. - Thought signatures replay on calls, not on thoughts — a
functionCallpart'sthoughtSignatureis stored with the harness tool call and resent beside the replayed call on the part, which keeps a signed call valid across turns. The thought text itself is not replayed, so a stateless multi-turn conversation still starts each turn without the model's prior-turn reasoning state; on Gemini 3 the signature keeps the call chain verifiable, and on 2.5 it preserves what the API retains of the reasoning state for the call itself. - No model discovery — model interrogation on the gateway's settings namespace speaks the OpenAI listing shape; a Gemini endpoint answers it with model ids but not display names.
- Text and image output only — assistant-side image generation is not mapped; responses carry text, thought, and function-call parts.
- Tool results must name a declared call — a
functionResponsecarries the function name, which the harness stores only as the call id; a tool result whose call is not elsewhere in the same request is refused rather than sent unnamed.
Dev Note
Runtime invariant: No companion is published. The wire translation is exercised directly by behavior specs (tests/stream.spec.ts, tests/request.spec.ts) against recorded server-sent-event transcripts; the adapter owns no durable package-local event stream.
