Skip to content

Update Gemini API spec from Discovery, regenerate bindings, and add live (multimodal) integration tests#1

Draft
o1lo01ol1o wants to merge 4 commits intosonowz:masterfrom
o1lo01ol1o:bump-google-spec
Draft

Update Gemini API spec from Discovery, regenerate bindings, and add live (multimodal) integration tests#1
o1lo01ol1o wants to merge 4 commits intosonowz:masterfrom
o1lo01ol1o:bump-google-spec

Conversation

@o1lo01ol1o
Copy link

PR Description (Detailed)

Context / Motivation

This repo is an auto-generated low-level Haskell client for the Gemini (Generative Language) API. The
upstream OpenAPI spec link from the public docs was unavailable/404, and the repo’s existing spec had
fallen behind the latest API revision. We needed a repeatable way to:

  • fetch the most current API description,
  • convert it into an OpenAPI document that openapi-generator can consume, and
  • regenerate the Haskell client reliably.

What Changed

1) Update the API spec source of truth

  • Added the latest Google Discovery document to the repo: discovery-v1beta.json (added in commit 857cf98).
  • Updated openapi.yaml to reflect the newer Discovery revision (commit 857cf98).

Why

  • openapi-generator cannot consume Google Discovery format directly.
  • The “official OpenAPI download URL” referenced via ai.google.dev was returning 404, so Discovery became
    the stable upstream artifact.

2) Add a reproducible Discovery → OpenAPI generation workflow

  • Added flake input: flake.nix now pulls github:stackql/google-discovery-to-openapi (commit f8a9f56).
  • Added Nix devshell tooling in nix/modules/flake/devshell.nix:
    • google-discovery-to-openapi: runs the upstream StackQL converter.
    • genai-generate-openapi: fetches https://generativelanguage.googleapis.com/$discovery/rest?
      version=v1beta and writes ./openapi.yaml for this repo.
    • Includes nodejs + python3 in the dev environment (commit f8a9f56), plus later additions (zlib, pkg-
      config) to build native deps required by Haskell packages.
    • Adds devShells.codegen to avoid pulling the full Haskell toolchain when you only need spec/codegen.

Why

  • Keeps regeneration deterministic and “one command”.
  • Avoids depending on ad-hoc manual spec downloads.
  • Avoids disk-heavy nix develop paths for codegen-only flows.

3) Sanitize the converted OpenAPI so generators don’t choke

Inside genai-generate-openapi (embedded Node script in nix/modules/flake/devshell.nix), we sanitize schemas
to remove Discovery-only / invalid OpenAPI keywords and prevent codegen collisions.

Key fixes:

  • Remove Discovery schema keywords like id, enumDescriptions, enumDeprecated.
  • Convert Discovery type: any into an OpenAPI-friendly “free-form object”.
  • Drop underscore-collision aliases (e.g. both _responseJsonSchema and responseJsonSchema) which otherwise
    cause duplicate record fields in Haskell.

Why

  • openapi-generator validates the spec and rejects unknown fields.
  • The Haskell generator normalizes names and can create duplicate record fields, which GHC rejects (your
    generationConfigResponseJsonSchema collision).

4) Regenerate the Haskell client from the updated spec

  • Updated generator script to use the repo spec: run-generator.sh uses --input-spec openapi.yaml (commit
    f8a9f56).
  • Regenerated outputs (commit 51c054a), including:
    • new lib/GenAI/Client/API/ApiDefault.hs
    • removed stale lib/GenAI/Client/API/Generativelanguage.hs
    • updated generated lib/GenAI/Client/Model.hs, Client.hs, etc.
  • Updated .openapi-generator/* metadata files accordingly.

Why

  • Ensures the generated Haskell bindings match the new API surface and revision.

5) Add live integration tests that hit the real API using generated client code

  • Added tests/Live.hs (commit 240dade, plus follow-ups) and a Cabal test-suite entry test-suite live in
    haskell-google-genai-client.cabal.
  • Live tests cover:
    • listModels (prints models when GEMINI_PRINT_MODELS=1)
    • generateContent (text-only)
    • multimodal image+text test that downloads a Haskell-logo image and asks the model to identify the
      language.

Live-test environment variables:

  • GEMINI_API_KEY (required)
  • GEMINI_MODEL (optional; defaults to a flash model)
  • GEMINI_IMAGE_MODEL (optional; defaults to gemini-3-pro-image-preview)
  • HASKELL_LOGO_URL (optional; defaults to GitHub avatar PNG)
  • GEMINI_HTTP_TIMEOUT_SECONDS (optional; defaults to 120)
  • GEMINI_PRINT_MODELS=1 to print available model names
  • GEMINI_PRINT_MULTIMODAL_RESPONSE=1 to print multimodal response text parts

Why

  • We want to validate that the generated library can successfully talk to the live API (not just compile).
  • Multimodal specifically validates inlineData (base64 bytes) support and multipart content structure.

6) Improve developer ergonomics / documentation

  • Updated README.md with:
    • spec refresh command using .#codegen
    • live test commands
    • model listing commands

Why

  • Keeps the regeneration workflow discoverable and consistent for contributors.

How to Reproduce / Regenerate

Update spec and regenerate bindings

  • nix develop .#codegen -c bash -c 'genai-generate-openapi && ./run-generator.sh'

Run live tests

  • List models:
    GEMINI_API_KEY='...' GEMINI_PRINT_MODELS=1 cabal test live --test-options='--match listModels'
  • Text gen test:
    GEMINI_API_KEY='...' GEMINI_MODEL='models/gemini-3-pro-preview' cabal test live --test-options='--match
    generateContent'
  • Multimodal test:
    GEMINI_API_KEY='...' GEMINI_IMAGE_MODEL='models/gemini-3-pro-image-preview'
    GEMINI_HTTP_TIMEOUT_SECONDS=180 cabal test live --test-options='--match multimodal'

Notes / Known Tradeoffs

  • The StackQL converter repo brings in Node dependencies; npm ci may report upstream vulnerabilities. This
    doesn’t ship in the Haskell library artifact, but it’s worth tracking if you want to vendor/pin/fork
    the converter.
  • Live tests depend on external network + an API key and can be flaky due to model latency, rate limits, or
    transient image decoding errors. Timeouts are now configurable.

@o1lo01ol1o o1lo01ol1o marked this pull request as draft December 26, 2025 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant