Files
podman/docs/gemini.md
T
Ramis 12dbf69431 docs: reposition around team-coordination, sync specs to code, prune stale docs
Reframe README around the real bottleneck (human coordination, not
engineering ability) with the "five-minute meeting" cost story; rewrite the
demo script to match. Update gemini/livekit/mongodb/digitalocean specs to
reflect shipped code (Gemini Live agent, TTS, embeddings, Lyria via
Interactions API; current API routes; hermes_jobs collections). Add hermes.md.
Rename graph.md -> cont_learning.md. Remove outdated/dead docs (agent-learning
scaffolding, graph-discovery, handoffs, superpowers, idea/plan/demo-setup) and
the bundled LiveKit starter under examples/. Rewire CLAUDE.md doc-first gate
off the deleted PLAN.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LuV8W8oNYRsDWKoqK8Mkqc
2026-06-28 06:41:09 -07:00

119 lines
4.6 KiB
Markdown

# 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.