Three issues prevented the Gemini OAuth path from working end-to-end:
1. Missing `project` field — the internal API returns 500 without it.
Added project field to InternalGenerateContentRequest and
resolve_oauth_project() to fetch it via loadCodeAssist endpoint.
2. No token refresh — stale access_token was read at construction time
and never refreshed. Google OAuth tokens expire after ~1 hour,
breaking long-lived daemon processes. Added runtime token refresh
with OAuthTokenState (Arc<Mutex>) that checks expiry before each
request and refreshes proactively (60s buffer).
3. Wrong response format — internal API nests candidates under a
`response` field. Added InternalGenerateContentResponse wrapper
and conditional deserialization in send_generate_content().
Also fixes OAuth warmup to call resolve_oauth_project() instead of
listing models on the public endpoint (which rejects OAuth tokens).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>