# Gemini Integration Spec Status: active / matches code. PodMan uses Gemini for five jobs, all through the `@google/genai` SDK (`GoogleGenAI`) with a single `GEMINI_API_KEY` (`GOOGLE_API_KEY` / `GOOGLE_GENERATIVE_AI_API_KEY` also accepted): 1. **Vision** — turn screen frames into structured work context. 2. **Embeddings** — vector recall over past coordination events. 3. **TTS voice** — spoken urgent escalations over LiveKit. 4. **Live conversation** — a real-time voice agent teammates talk to. 5. **GenMedia (Lyria)** — a per-pod background score. Collision detection and intervention text are **deterministic in code**, not Gemini calls. PodMan does not ask Gemini "is this a conflict?" — that is decided by `backend/src/collision/detector.ts` from fused vision + git truth. This is a deliberate reliability choice for the live demo. --- ## 1. Vision — screen understanding **Model:** `GEMINI_VISION_MODEL` (default `gemini-2.0-flash`) **Code:** `backend/src/vision/gemini.ts` → `analyzeFrame()` **Trigger:** the LiveKit agent samples a JPEG frame from each engineer's screen-share track (not an HTTP upload — frames arrive over LiveKit). **Input:** a single base64 JPEG, sampled at low media resolution. **Output:** structured JSON via `responseJsonSchema` (no markdown parsing): ```ts { currentFile: string, // open file path, e.g. src/auth/session.ts currentSymbol: string, // function/class under the cursor activity: string, // editing | reading | debugging | terminal | PR review hasUnpushedChanges: boolean, // dirty git gutter / modified markers visible confidence: number // 0..1 } ``` **Latency/cost levers (in code):** - `thinkingConfig: { thinkingBudget: 0 }` — minimal thinking for the ambient loop. - `mediaResolution: MEDIA_RESOLUTION_LOW` — smaller image tokens. - Missing `confidence` defaults to `0.5`. **Demo reliability:** large editor font, single window, visible file tab. This is the primary lever for clean reads. --- ## 2. Embeddings — semantic recall **Model:** `GEMINI_EMBEDDING_MODEL` (default `gemini-embedding-001`, 768 dims) **Code:** `backend/src/memory/vectors.ts` Each collision is embedded into a short memory text (`file`, `symbol`, `engineers`, `severity`, unpushed flag) and stored on the `collisions` document. On a new collision PodMan embeds the query and runs MongoDB Atlas `$vectorSearch` (index `collision_embedding`) to recall similar past events and their outcomes. **Provider order:** Voyage (`VOYAGE_API_KEY`, `voyage-4-lite`) is tried first when present; Gemini embeddings are the fallback. Without either, recall degrades to exact signature/file matching — the demo still works. --- ## 3. TTS voice — urgent escalation over LiveKit **Model:** `GEMINI_LIVE_MODEL` (default `gemini-3.1-flash-tts-preview`) **Default voice:** `GEMINI_TTS_VOICE` (default `Charon`) **Code:** `backend/src/voice/live.ts` → `speak()` / `speakInRoom()` Flow: a short, natural voice line is generated for a critical collision, returned as audio, and published as a LiveKit microphone-source audio track. The track is held for the audio duration plus tail/hold so browsers do not cut playout short. Browser audio must be unlocked by a user gesture first. The frontend always renders the `VOICE_CUE` text as a fallback. See `docs/livekit.md` for delivery. --- ## 4. Live conversation — real-time voice agent **Model:** `GEMINI_CONVERSATION_MODEL` (default `gemini-3.1-flash-live-preview`) **Code:** `agents/podman-live-conversation/agent.py` (Python LiveKit Agents, `google.realtime.RealtimeModel`) A teammate can start a live, streaming speech-to-speech session with PodMan. The agent answers using **function tools** rather than guessing, including: - `get_active_pod_context`, `get_recent_changes`, `search_team_memory` - `search_repo`, `repo_recent_commits`, `repo_find_commits` (repo + git history) - `record_conversation_note` - `delegate_to_hermes`, `abort_active_hermes_job` (hands work to the async Hermes job runner — see `docs/hermes.md`) Started/stopped via `POST /api/pods/:id/live-conversation/start` and `.../stop`. --- ## 5. GenMedia — Lyria background score **Model:** `lyria-3-clip-preview` (override with `GEMINI_MUSIC_MODEL`) **Endpoint:** Gemini **Interactions API** (`/v1beta/interactions`) **Code:** `backend/src/voice/music.ts` A pod-specific ~30s clip is generated through the Interactions API, cached in MongoDB, and served via `GET /api/pods/:id/music` to play as ambient room audio. --- ## Cooldown Per-pod cooldown (`NUDGE_COOLDOWN_MS`, default 180000 ms / 3 min) gates repeated interventions. Implemented in `backend/src/memory/policy.ts`, not in Gemini.