# Gemini Provider Support — Design

**Date:** 2026-03-01
**Scope:** Add Google Gemini as a third supported provider in agentbudget v0.1

---

## Problem

agentbudget currently supports OpenAI and Anthropic only. Users of Google Gemini (via `google-generativeai` or `google-genai`) cannot track costs.

**Key challenge:** Unlike OpenAI/Anthropic, the Gemini SDK response object does not always include the model name. The newer `google-genai` SDK exposes `response.model_version`; the older `google-generativeai` does not.

---

## Decision

**Approach B+C:** Add optional `model=` parameter to `session.track()` + helpful warning when model is unknown.

- Zero-config for users of `google-genai` (newer SDK, has `model_version`)
- Optional `model="gemini-2.0-flash"` param for users of `google-generativeai` (older SDK)
- Warning message guides the user when model cannot be detected

---

## Files to Create/Modify

### New
- `agentbudget/providers/gemini.py` — GeminiProvider extracting `usage_metadata.prompt_token_count` / `candidates_token_count`

### Modified
- `agentbudget/providers/base.py` — add Gemini to detection chain (isinstance + fingerprint + prefix)
- `agentbudget/session.py` — add `model: Optional[str] = None` to `track()`, override after extraction
- `agentbudget/pricing.py` — add 5 Gemini models
- `agentbudget/providers/__init__.py` — no change needed
- `pyproject.toml` — add `gemini = ["google-genai>=0.8.0"]`, update `all`
- `tests/test_providers.py` — add Gemini detection and extraction tests
- `README.md` — add Gemini example, update Features and Installation
- `CHANGELOG.md` — document addition

---

## Detection Chain (updated `detect_provider`)

```
1. isinstance openai.types.chat.ChatCompletion    → OpenAIProvider
2. isinstance google.generativeai.GenerateContentResponse → GeminiProvider
3. isinstance google.genai.types.GenerateContentResponse  → GeminiProvider
4. hasattr(response.usage, "input_tokens")        → AnthropicProvider
5. hasattr(response.usage_metadata, "prompt_token_count") → GeminiProvider
6. model prefix: gpt-/o1/o3 → OpenAI, claude- → Anthropic, gemini- → Gemini
7. raise ValueError
```

## GeminiProvider.extract_usage logic

```python
model = (
    getattr(response, "model", None)
    or getattr(response, "model_version", None)
    or "gemini"  # triggers $0.00 warning + hint to pass model= to track()
)
input_tokens  = response.usage_metadata.prompt_token_count
output_tokens = response.usage_metadata.candidates_token_count
```

## track() signature change

```python
def track(self, response: Any, label: str = "", model: Optional[str] = None) -> None:
```

`model` overrides the model extracted from the response. Used when the response doesn't include model info (older Gemini SDK).

## Pricing (USD per million tokens)

| Model | Input | Output |
|---|---|---|
| gemini-2.0-flash | $0.10 | $0.40 |
| gemini-2.0-flash-lite | $0.075 | $0.30 |
| gemini-1.5-pro | $1.25 | $5.00 |
| gemini-1.5-flash | $0.075 | $0.30 |
| gemini-1.5-flash-8b | $0.0375 | $0.15 |

---

## Success Criteria

- `session.track(gemini_response)` works zero-config with `google-genai` new SDK
- `session.track(gemini_response, model="gemini-2.0-flash")` works with old SDK
- All existing tests still pass
- New Gemini tests added to `test_providers.py`
- README updated with Gemini example
