# Next Session: Google Maps Tool for Annie

## What

Add a `google_maps` tool to Annie that handles directions (with ETA and live traffic), nearby place search, and trip planning. Returns clickable Google Maps links + advisory text. On voice, Annie reads the ETA aloud. Works on all channels (voice, text, Telegram, WhatsApp, phone). Uses Google Maps REST APIs via httpx.AsyncClient (NOT the sync `googlemaps` package). Cost: ~$2/month for personal use.

## Plan

`~/.claude/plans/glowing-soaring-parrot.md`

Read the plan first — it has the full implementation, all 25 adversarial review findings with resolutions, pre-mortem analysis, and handler design.

## Key Design Decisions (from adversarial review)

1. **httpx.AsyncClient, NOT `googlemaps` package** — The official package is sync-only (urllib). It would block Pipecat's entire event loop (STT, TTS, VAD all freeze). Use httpx like every other tool in the codebase (tools.py search_web pattern).

2. **Literal types for search_type and travel_mode** — Free strings cause Gemma 4 hallucination ("route", "navigation", "car"). `Literal["directions", "nearby"]` and `Literal["driving", "walking", "bicycling", "transit"]` constrain the LLM.

3. **Lazy home address loading** — NOT at import time. First call reads `~/.her-os/rajesh-contact.json`, caches result. If missing, returns user-friendly error instead of crashing annie-voice.

4. **departure_time only for driving/transit** — Google API errors on walking/bicycling with departure_time. Handler conditionally omits it.

5. **Privacy: generic area name in URLs** — Nearby search URLs use "HSR Layout Bangalore" not the resolved full home address "424, 23rd Cross, Sector 7...".

6. **400 char output cap** — Gemma 4 has limited tool result context. Responses truncated to prevent token budget exhaustion.

7. **Add to _TOOL_LEAK_RE** — `google_maps` must be added to bot.py's tool leak regex, or Gemma 4 will speak the raw JSON tool call aloud.

8. **Add to _SECRET_ENV_KEYS + _SECRET_PATTERNS** — GOOGLE_MAPS_API_KEY + `AIzaSy[a-zA-Z0-9_-]{33}` regex to prevent key appearing in logs or LLM context.

9. **Observability creature "compass"** — Maps tool activity must be visible on dashboard.

10. **Check OVER_QUERY_LIMIT in response body** — Google returns quota errors inside HTTP 200 JSON, not as HTTP 429.

## Files to Modify

1. `services/annie-voice/maps_tools.py` — **CREATE**: httpx-based Google Maps handler (~250 lines)
2. `services/annie-voice/tool_schemas.py` — **ADD**: `GoogleMapsInput` with Literal types
3. `services/annie-voice/text_llm.py` — **ADD**: ToolSpec in TOOL_SPECS + _SECRET_ENV_KEYS + _SECRET_PATTERNS
4. `services/annie-voice/tool_adapters.py` — **ADD**: `MapsAdapter` + ADAPTERS entry
5. `services/annie-voice/bot.py` — **EDIT**: _TOOL_LEAK_RE + _NARRATION_PHRASES
6. `services/annie-voice/observability.py` — **EDIT**: Add "compass" creature
7. `services/annie-voice/.env.example` — **EDIT**: Add GOOGLE_MAPS_API_KEY=
8. `services/annie-voice/tests/test_maps_tools.py` — **CREATE**: Unit tests (~200 lines)

## Start Command

```bash
# Read the reviewed plan first
cat ~/.claude/plans/glowing-soaring-parrot.md

# Then implement in order:
# Phase 1: Schema + URL builder + home address resolution + tests
# Phase 2: Directions API via httpx + departure_time handling + tests
# Phase 3: Nearby Places API via httpx + privacy-safe URLs + tests
# Phase 4: ToolSpec + adapter + bot.py wiring + observability + secrets
# Phase 5: Deploy (API key in .env on Titan) + E2E test
```

## Verification

1. `cd services/annie-voice && python3 -m pytest tests/test_maps_tools.py -v` — all tests pass
2. Unit tests: address resolution, URL encoding, directions mock, nearby mock, time parsing, error paths
3. E2E voice: "Annie, how long to get to Skandagiri from home?"
4. E2E Telegram: "Find coffee shops near HSR Layout"
5. E2E WhatsApp: "How far is the airport?" — clickable link
6. Verify voice reads ETA without URL
7. Verify `/v1/capabilities` lists google_maps in "maps" group
8. Verify API key not in logs (grep for AIzaSy)
