Files
majordomo/docs/adr/0011-google-provider.md
T
steve 1ca607906d feat: Google (Gemini) provider on the official Gen AI SDK
Phase 4: provider/google on google.golang.org/genai v1.59.0 — lazy cached
client, FunctionResponse tool loop, raw-JSON-schema tools and structured
output, ThinkingLevel reasoning mapping, iter.Pull2 streaming, hermetic
httptest suite via HTTPOptions.BaseURL. Registry wires google + gemini
schemes to the real client; stub machinery deleted (all built-ins real).
ADR-0011; README matrix + CLAUDE.md synced.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 13:04:28 +02:00

2.2 KiB

ADR-0011: Google provider on the official Gen AI SDK

Status: Accepted — 2026-06-10

Context

ADR-0007 approves exactly one third-party dependency: Google's surface (auth modes, API versions, endpoint shapes) moves too much to hand-roll profitably. The deprecated github.com/google/generative-ai-go is not an option; google.golang.org/genai is the current official SDK.

Decision

  • Build provider/google on google.golang.org/genai v1.59.0, BackendGeminiAPI, API key from GOOGLE_API_KEY then GEMINI_API_KEY (the SDK's own precedence).
  • The SDK client is created lazily on first request and cached; construction of the Provider never fails (per ADR-0005). A missing key is a synthetic 401 APIError, so chains fail over past it.
  • Mappings (recorded in the package doc): assistant role → model; tool results → FunctionResponse parts in a user content ({"output": ...} / {"error": ...} payloads); tool schemas via FunctionDeclaration.ParametersJsonSchema (raw JSON schema — no lossy conversion to genai.Schema); structured output via ResponseJsonSchema
    • application/json MIME; ToolChoiceFunctionCallingConfig modes (required → ANY, named → ANY + AllowedFunctionNames, none → tools omitted); ReasoningEffortThinkingConfig.ThinkingLevel (LOW/MEDIUM/HIGH); usage output = candidates + thoughts tokens; thought parts are skipped in content.
  • Streaming adapts the SDK's iter.Seq2 to majordomo's pull-based Stream with iter.Pull2; Close releases the iterator via its stop function. Function calls arrive whole per chunk (no partial-args assembly needed).
  • Hermetic tests use the SDK's documented hooks: HTTPOptions.BaseURL + HTTPClient pointed at httptest servers (the same technique as the SDK's own test suite); streaming fixtures are SSE.
  • Errors: genai.APIError (value type; Code = HTTP status) maps to llm.APIError{Status: Code, Code: Status} so the standard classifier applies.

Consequences

  • go.mod gains genai and its transitive tree (auth, grpc, protobuf) — the one sanctioned dependency cost.
  • Vertex AI backend is NOT wired (API-key Gemini only); adding it later is an options-level change, not a redesign.