Files
firebase-ios-sdk/GeminiLanguageModel/scripts/typegen
Andrew Heard 4a4d0fa518 feat(ai): add Gemini API Swift data model generator (#16879)
Add the Python pipeline under `GeminiLanguageModel/scripts/typegen` that
generates the Swift data models in `GeminiAPIDataModels/GenerateContent`
from the Firebase AI Logic Google Discovery Document, so the models can
be regenerated in-tree as the upstream API evolves.
- `upgrade_spec.py` fetches the `v1beta` Discovery Document, converts it
  to OpenAPI 3.1.0, extracts shared standalone enums per backend, infers
  required properties, and merges the schema overrides from
  `discovery_documents/firebasevertexai-overrides.yaml`.
- `generate_types.py` (the `swift_typegen` package) strips the Gemini
  Developer API and Gemini Enterprise Agent Platform prefixes, resolves
  the schemas reachable from the request/response roots, merges both
  backends with DocC availability callouts, checks for value-type
  cycles, renders Swift via Jinja2 templates, runs `swift-format`, and
  prunes stale generated files while preserving hand-written ones.
- Add 117 unit tests covering every pipeline stage, and `pyink` settings
  in `pyproject.toml`.
- Add a `check-data-models` CI job that runs the unit tests and warns
  when the committed data models are behind the Discovery Document.
- Add `Shared/Buildable.swift`, which the regenerated types depend on.
The `GenerateContent` sources are not regenerated here; that follows in
a separate PR.
2026-10-09 18:35:46 -04:00
..

Swift type generation (typegen)

This directory contains the OpenAPI 3.1.0 upgrade and Swift code generation pipeline used to generate the data models in GeminiLanguageModel/Sources/GeminiAPIDataModels/GenerateContent.


Architecture and code generation workflow

graph TD
    A["Google Discovery Document JSON"] -->|Upgraded by| B("upgrade_spec.py")
    E["firebasevertexai-overrides.yaml"] -->|Merged by| B
    B -->|Produces| F["firebasevertexai-openapi.yaml"]
    F -->|Parsed by| C("generate_types.py")
    E -->|Configures| C
    D["Jinja2 Swift Templates"] -->|Rendered by| C
    C -->|Generates Swift Models| G["Sources/GeminiAPIDataModels/GenerateContent"]

Setup

From GeminiLanguageModel/scripts/typegen:

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

1. Upgrading the specification (upgrade_spec.py)

Before generating types, convert the Google Discovery Document to an OpenAPI 3.1.0 specification and apply manual overrides:

python upgrade_spec.py

If discovery_documents/firebasevertexai_discovery_v1beta.json is not cached locally, upgrade_spec.py automatically downloads it from Google APIs. To force a fresh download of the latest Discovery Document even when cached:

python upgrade_spec.py --fetch

This script loads firebasevertexai_discovery_v1beta.json, normalizes schema references, extracts shared standalone enums (such as HarmCategory, Modality, and DataType), infers required fields, merges manual overrides from firebasevertexai-overrides.yaml, and writes discovery_documents/firebasevertexai-openapi.yaml (both the fetched .json and generated -openapi.yaml files are gitignored).


2. Generating Swift types (generate_types.py)

Use generate_types.py to parse the upgraded OpenAPI 3.1.0 specification and write Swift types directly into GeminiLanguageModel/Sources/GeminiAPIDataModels/GenerateContent:

python generate_types.py

Command-line arguments reference

Argument Default Description
--openapi-spec discovery_documents/firebasevertexai-openapi.yaml Upgraded spec YAML path.
--overrides-file discovery_documents/firebasevertexai-overrides.yaml YAML overrides file path.
--output-dir ../../Sources/GeminiAPIDataModels/GenerateContent Output directory.
--roots ["GenerateContentRequest", ...] Roots to resolve.
--access-level package Swift access control: public, package, or internal.
--strip-prefix all generatorConfig.backends Backend prefixes to strip and merge (pass with no values to disable).
--namespace "" Swift root namespace.
--shared-models-target "" Shared models target.
--templates-dir templates Jinja2 templates folder.
--doc-wrap-width 100 Maximum column width for DocC comments.
--verbose false Enable verbose output.

The overrides file is required: the generator exits with an error if it is missing, rather than generating a much smaller type set and pruning existing output. Each --strip-prefix value must be listed in generatorConfig.backends. If no backends are configured, the generator exits with an error unless --strip-prefix is passed with no values. Backends are always merged Developer API (gl-developer) first, regardless of argument or config order.

Code layout

generate_types.py is a thin entry point. The implementation lives in the swift_typegen package:

Module Responsibility
cli.py Argument parsing; builds PipelineOptions.
pipeline.py Orchestration: load → per-backend preprocess → merge → cycle check → process → write.
config.py GeneratorConfig, loaded from the overrides YAML generatorConfig block (including backends prefixes/tags and preservedFiles).
merge.py Backend prefix stripping, schema renaming, and cross-backend schema merging.
graph.py $ref traversal, reachability from roots, and cycle detection.
processor.py SchemaProcessor: OpenAPI schemas → SwiftType models.
models.py SwiftType, SwiftProperty, SwiftEnumCase.
naming.py Swift identifier casing, acronyms, and keyword escaping.
docc.py DocC comment extraction, cleanup, and wrapping.
render.py Jinja2 rendering to (filename, source) with no file I/O.
output.py Writing files, swift-format, and pruning stale outputs.

3. Running unit tests

From GeminiLanguageModel/scripts/typegen/:

python -m unittest discover -s tests -t .

Or from anywhere in the repository:

python -m unittest discover \
  -s GeminiLanguageModel/scripts/typegen/tests \
  -t GeminiLanguageModel/scripts/typegen

4. Formatting

Python sources are formatted with pyink using the settings in pyproject.toml. From GeminiLanguageModel/scripts/typegen/:

pip install pyink
pyink .