<svg width="100%" viewBox="0 0 760 760" role="img" xmlns="http://www.w3.org/2000/svg">
  <title>Voice turn — end-to-end hop trace</title>
  <desc>Pi publishes mic to LiveKit room; voice-bridge STTs, calls hermes, TTSs the reply, publishes back; Pi plays.</desc>
  <style>
    text{font-family:"Anthropic Sans",-apple-system,system-ui,"Segoe UI",sans-serif}
    .t{font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:central}
    .s{font-size:12px;text-anchor:middle;dominant-baseline:central}
    .stp{font-size:12px;fill:#c2c0b6}
    rect{stroke-width:.5}
    .green{fill:#27500a;stroke:#97c459}   .gt{fill:#c0dd97} .gs{fill:#97c459}
    .blue{fill:#1f3b7a;stroke:#8aaef0}    .bt{fill:#cfdcf4} .bs{fill:#8aaef0}
    .orange{fill:#712b13;stroke:#f0997b}  .ot{fill:#f5c4b3} .os{fill:#f0997b}
    .purple{fill:#3c3489;stroke:#afa9ec}  .pt{fill:#ceccf6} .ps{fill:#afa9ec}
    .arrow{fill:none;stroke:#9c9a92;stroke-width:1.5}
    .arrow-ok{fill:none;stroke:#1d9e75;stroke-width:1.5}
  </style>
  <defs>
    <marker id="a" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
    </marker>
  </defs>

  <text class="stp" x="40" y="64">1</text>
  <text class="stp" x="40" y="164">2</text>
  <text class="stp" x="40" y="264">3</text>
  <text class="stp" x="40" y="364">4</text>
  <text class="stp" x="40" y="464">5</text>
  <text class="stp" x="40" y="564">6</text>
  <text class="stp" x="40" y="664">7</text>
  <text class="stp" x="40" y="744">8</text>

  <rect class="green" x="120" y="40" width="560" height="60" rx="8"/>
  <text class="t gt" x="400" y="64">Pi publishes mic frames into room_&lt;user_id&gt;</text>
  <text class="s gs" x="400" y="84">WebRTC · sudoedge LiveKit client</text>

  <rect class="blue" x="120" y="140" width="560" height="60" rx="8"/>
  <text class="t bt" x="400" y="164">voice-bridge receives frames · runs STT</text>
  <text class="s bs" x="400" y="184">Deepgram (Sarvam in prod)</text>

  <rect class="blue" x="120" y="240" width="560" height="60" rx="8"/>
  <text class="t bt" x="400" y="264">voice-bridge → sudo-api · ensure_runtime(uid)</text>
  <text class="s bs" x="400" y="284">make sure the family's hermes is up</text>

  <rect class="blue" x="120" y="340" width="560" height="60" rx="8"/>
  <text class="t bt" x="400" y="364">sudo-api spawns hermes if needed · waits healthy</text>
  <text class="s bs" x="400" y="384">docker run + _SEED_AND_EXEC + GET /health</text>

  <rect class="orange" x="120" y="440" width="560" height="60" rx="8"/>
  <text class="t ot" x="400" y="464">voice-bridge → hermes  ·  POST :8642/v1/chat/completions</text>
  <text class="s os" x="400" y="484">Bearer API_SERVER_KEY · X-Hermes-Session-Key</text>

  <rect class="purple" x="120" y="540" width="560" height="60" rx="8"/>
  <text class="t pt" x="400" y="564">hermes calls OpenRouter · streams reply (SSE)</text>
  <text class="s ps" x="400" y="584">LLM key from global_settings.llm_provider</text>

  <rect class="blue" x="120" y="640" width="560" height="60" rx="8"/>
  <text class="t bt" x="400" y="664">voice-bridge runs TTS · publishes audio to room</text>
  <text class="s bs" x="400" y="684">ElevenLabs / OpenAI (Sarvam bulbul in prod)</text>

  <rect class="green" x="120" y="720" width="560" height="40" rx="8"/>
  <text class="t gt" x="400" y="740">Pi plays the reply on the speaker</text>

  <path class="arrow"    d="M 400 100 L 400 138" marker-end="url(#a)"/>
  <path class="arrow"    d="M 400 200 L 400 238" marker-end="url(#a)"/>
  <path class="arrow"    d="M 400 300 L 400 338" marker-end="url(#a)"/>
  <path class="arrow"    d="M 400 400 L 400 438" marker-end="url(#a)"/>
  <path class="arrow"    d="M 400 500 L 400 538" marker-end="url(#a)"/>
  <path class="arrow-ok" d="M 400 600 L 400 638" marker-end="url(#a)"/>
  <path class="arrow-ok" d="M 400 700 L 400 718" marker-end="url(#a)"/>
</svg>
