# Next Session: Fix Places API + Expand Google Maps to Weather, AQI & More

**Priority:** MEDIUM — directions work, nearby search needs fix, new APIs are additive
**Parallel session:** Can run independently of Audio Pipeline and WhatsApp sessions
**Estimated effort:** 2-3 hours (fix + research + implement 2-3 new tools + tests)

## Problem

The `google_maps` tool was deployed in session 13. **Directions API works E2E** ("How long to Skandagiri?" → 10h 23m). But **nearby search returns `REQUEST_DENIED`** because `maps_tools.py` uses the legacy Places API endpoint, and Google is pushing the new Places API.

Rajesh has enabled **all 33 Google Maps APIs**. This session should fix nearby search and add the most valuable new capabilities.

## All 33 Enabled APIs (Categorized)

```
Core (already using):
  ✓ Directions API          — get_directions() WORKING E2E
  ? Geocoding API           — search_nearby() REQUEST_DENIED in session 13 (now enabled)
  ? Places API (legacy)     — search_nearby() REQUEST_DENIED (now enabled)
  ✓ Places API (New)        — enabled, preferred over legacy

Navigation & Routes:
  • Routes API              — next-gen Directions (compute routes, route matrices, toll info)
  • Distance Matrix API     — multiple origin/destination pairs, batch ETA
  • Route Optimization API  — optimal ordering for multi-stop trips
  • Navigation SDK          — turn-by-turn (mobile only, not useful for Annie)

Location Intelligence:
  • Places Aggregate API    — aggregate stats about places
  • Places UI Kit           — pre-built widgets (not useful for backend)
  • Address Validation API  — verify addresses are real/deliverable
  • Geolocation API         — locate device by WiFi/cell tower

Environment:
  • Air Quality API         — real-time AQI, pollutants, health recommendations
  • Weather API             — current + forecast weather for any location
  • Pollen API              — pollen counts and allergen info
  • Solar API               — solar potential for rooftops
  • Time Zone API           — time zone for any lat/lng

Visual & Mapping:
  • Maps Static API         — generate map images (embed in Telegram/WhatsApp!)
  • Street View Static API  — street-level imagery
  • Maps Embed API          — embed maps in web pages
  • Maps JavaScript API     — interactive web maps
  • Map Tiles API           — raw map tiles
  • Maps Elevation API      — elevation data for any point

Advanced:
  • Roads API               — snap GPS to roads
  • Street View Publish API — publish photospheres
  • Maps Grounding Lite API — ground LLM outputs to real places (!!)
  • Maps 3D SDK             — 3D map views (mobile)
  • Maps Platform Datasets  — custom data layers
  • Map Management API      — map styles
```

## Step 1: Fix Nearby Search (MUST DO)

### First: Test if legacy endpoints work now
Rajesh enabled all 33 APIs since session 13. Test before migrating:
```bash
ssh titan
KEY=$(grep GOOGLE_MAPS_API_KEY ~/workplace/her/her-os/services/annie-voice/.env | cut -d= -f2)

# Test Geocoding (legacy)
curl -s "https://maps.googleapis.com/maps/api/geocode/json?address=HSR+Layout+Bangalore&key=$KEY" | python3 -c "import json,sys; print(json.load(sys.stdin)['status'])"

# Test Places Nearby (legacy)
curl -s "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=12.91,77.64&radius=5000&keyword=coffee&key=$KEY" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['status'], len(d.get('results',[])))"
```

**If both return OK → no code changes needed, nearby search just works now.**

### If legacy still fails → Migrate to Places API (New)
The new endpoint is different:
```bash
# Places API (New) — Nearby Search
curl -s -X POST "https://places.googleapis.com/v1/places:searchNearby" \
  -H "Content-Type: application/json" \
  -H "X-Goog-Api-Key: $KEY" \
  -H "X-Goog-FieldMask: places.displayName,places.rating,places.formattedAddress,places.location" \
  -d '{
    "locationRestriction": {
      "circle": {"center": {"latitude": 12.91, "longitude": 77.64}, "radius": 5000.0}
    },
    "includedTypes": ["coffee_shop"]
  }'
```

Changes needed in `maps_tools.py`:
- `_PLACES_URL` → `https://places.googleapis.com/v1/places:searchNearby`
- HTTP method: GET → POST with JSON body
- Auth: query param → `X-Goog-Api-Key` header
- Field selection: via `X-Goog-FieldMask` header
- Response parsing: different JSON structure (`places[].displayName.text`, not `results[].name`)
- Update `_maps_request()` to support POST + headers

## Step 2: Add Weather Tool (HIGH VALUE)

**"What's the weather like?"** — one of the most natural things to ask an assistant.

```bash
# Weather API — Current Conditions
curl -s -X POST "https://weather.googleapis.com/v1/currentConditions:lookup" \
  -H "Content-Type: application/json" \
  -H "X-Goog-Api-Key: $KEY" \
  -d '{
    "location": {"latitude": 12.91, "longitude": 77.64}
  }'
```

### Implementation
- Add `get_weather()` function to `maps_tools.py` (or create `weather_tools.py`)
- Add `WeatherInput` schema to `tool_schemas.py` (location field, default "home")
- Add ToolSpec in `text_llm.py`
- Response: temperature, humidity, description, wind, UV index
- Proactive use: Annie checks weather before suggesting outdoor activities

## Step 3: Add Air Quality Tool (HIGH VALUE)

**"Is it safe to go for a run?"** — health-critical, especially in Bangalore.

```bash
# Air Quality API — Current Conditions
curl -s -X POST "https://airquality.googleapis.com/v1/currentConditions:lookup" \
  -H "Content-Type: application/json" \
  -H "X-Goog-Api-Key: $KEY" \
  -d '{
    "location": {"latitude": 12.91, "longitude": 77.64},
    "extraComputations": ["HEALTH_RECOMMENDATIONS"]
  }'
```

### Implementation
- Add `get_air_quality()` function
- Add `AirQualityInput` schema (location, default "home")
- Response: AQI index, dominant pollutant, health recommendation, category (good/moderate/unhealthy)
- Proactive: "AQI is 180, skip the outdoor walk today"

## Step 4: Add Static Map Image (NICE TO HAVE)

When Annie gives directions, also send a visual map via Telegram/WhatsApp:
```
GET https://maps.googleapis.com/maps/api/staticmap?
  center=12.91,77.64&zoom=13&size=400x300
  &markers=color:red|label:A|12.91,77.64
  &markers=color:green|label:B|13.35,77.57
  &key=$KEY
```
Returns a PNG image → save to temp file → send via existing image pipeline.

## Step 5: Explore Maps Grounding Lite (RESEARCH ONLY)

**Maps Grounding Lite API** can verify that places Gemma 4 mentions actually exist on Google Maps. This could prevent hallucinated restaurant names or addresses. Research the API format and feasibility — don't implement yet.

## Files to Modify

| File | Change |
|------|--------|
| `maps_tools.py` | Fix `search_nearby()` (legacy or new API), add `get_weather()`, `get_air_quality()` |
| `tool_schemas.py` | Add `WeatherInput`, `AirQualityInput` |
| `text_llm.py` | Add ToolSpecs for `weather`, `air_quality` |
| `tool_adapters.py` | Add adapters for new tools (or reuse `MapsAdapter`) |
| `bot.py` | Add `weather`, `air_quality` to `_TOOL_LEAK_RE` + narration phrases |
| `observability.py` | Potentially add new creatures or reuse "compass" |
| `tests/test_maps_tools.py` | Update nearby mocks, add weather + AQI tests |

## Verification

```bash
# 1. Nearby search works
ssh titan
curl -s -N -X POST http://localhost:7860/v1/chat \
  -H "X-Internal-Token: $CE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message": "Find coffee shops near HSR Layout"}'
# Should return 3 places with ratings

# 2. Weather works
curl -s -N -X POST http://localhost:7860/v1/chat \
  -H "X-Internal-Token: $CE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message": "What is the weather like right now?"}'
# Should return temperature, conditions

# 3. Air quality works
curl -s -N -X POST http://localhost:7860/v1/chat \
  -H "X-Internal-Token: $CE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message": "Is it safe to go for a run outside?"}'
# Should return AQI + recommendation

# 4. Tests pass
cd ~/workplace/her/her-os/services/annie-voice
python3 -m pytest tests/test_maps_tools.py -v

# 5. API key not in logs
grep "AIzaSy" /tmp/annie-voice.log  # Should return 0 matches
```
