Bug
_get_usage() in APIMixin (client.py:262) calls _parse_usage() expecting a RawUsage dict, then wraps it with self._usage_class(**raw).
Three modality-level overrides return typed ImageUsage objects instead of dicts:
GeminiImagesClient._parse_usage() → ImageUsage(**usage, num_images=...)
GoogleImagesClient._parse_usage() → delegates to Gemini strategy, returns ImageUsage
OllamaImagesClient._parse_usage() → ImageUsage()
This causes a crash on Gemini image generation:
ImageUsage() argument after ** must be a mapping, not ImageUsage
Root cause
PR #151 ("centralize usage/finish_reason type conversion") introduced _get_usage() but these 3 overrides were never updated to return dicts.
The modality template also generates this same contract-violating pattern.
Fix
- Align the 3
_parse_usage overrides to return dict[str, int | float | None]
- Remove redundant
_parse_usage and _parse_finish_reason from the modality template (_get_usage/_get_finish_reason already handle type conversion)
Bug
_get_usage()inAPIMixin(client.py:262) calls_parse_usage()expecting aRawUsagedict, then wraps it withself._usage_class(**raw).Three modality-level overrides return typed
ImageUsageobjects instead of dicts:GeminiImagesClient._parse_usage()→ImageUsage(**usage, num_images=...)GoogleImagesClient._parse_usage()→ delegates to Gemini strategy, returnsImageUsageOllamaImagesClient._parse_usage()→ImageUsage()This causes a crash on Gemini image generation:
Root cause
PR #151 ("centralize usage/finish_reason type conversion") introduced
_get_usage()but these 3 overrides were never updated to return dicts.The modality template also generates this same contract-violating pattern.
Fix
_parse_usageoverrides to returndict[str, int | float | None]_parse_usageand_parse_finish_reasonfrom the modality template (_get_usage/_get_finish_reasonalready handle type conversion)