Skip to content

feat(voip): per-agent VoIP config panel + persisted voice (abilityai/trinity-enterprise#28)#1323

Merged
AndriiPasternak31 merged 2 commits into
devfrom
feature/28-voip-config-panel
Jun 24, 2026
Merged

feat(voip): per-agent VoIP config panel + persisted voice (abilityai/trinity-enterprise#28)#1323
AndriiPasternak31 merged 2 commits into
devfrom
feature/28-voip-config-panel

Conversation

@vybe

@vybe vybe commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds the missing per-agent VoIP config UI (agent Settings/Sharing tab) over the existing OSS GET/PUT/DELETE /api/agents/{name}/voip endpoints — no new binding CRUD.
  • Adds a persisted per-agent Gemini voice (agent_ownership.voice_name, default Kore), replacing two hardcoded "Kore" sites; applies to the voice overlay/workspace and outbound VoIP calls.
  • Ships as plain OSS gated on the existing voip_available platform flag — not entitlement-gated. The issue's original "entitlement-gated" framing was deliberately dropped: a UI gate over a money-spending OSS backend would be cosmetic, and both autoplan reviewers flagged it. (No trinity-enterprise submodule change; one public PR.)

Changes

Backend

  • agent_ownership.voice_name — dual-track migration: SQLite db/migrations.py + Alembic 0004_agent_ownership_voice_name + db/schema.py/db/tables.py. db.get/set_voice_name with read-path fallback to Kore for unset/invalid values.
  • GET/PUT /api/agents/{name}/voice/name (PUT owner-only, validated vs GEMINI_VOICE_NAMES). routers/voice.py::_get_voice_name + services/voip_service.py now read the persisted voice.
  • PUT /api/agents/{name}/voip/enabled toggle (owner-only, 404 when no binding). create_binding upsert no longer forces enabled=1, so re-saving credentials preserves a disabled state (call path already refuses disabled bindings).

Frontend

  • components/VoipChannelPanel.vue (modeled on WhatsAppChannelPanel.vue), mounted in SharingPanel.vue under v-if="sessionsStore.voipAvailable"; stores/sessions.js surfaces voip_available.
  • Shared src/constants/voices.js (drift-guarded against the backend list); AgentWorkspace.vue picker defaults to the persisted voice.

Docs/tests: architecture.md, requirements.md §39.2, feature-flows (voip-telephony.md, voice-chat.md); tests/unit/test_28_voip_voice_config.py.

Test Plan

  • New unit tests pass: cd tests && python -m pytest unit/test_28_voip_voice_config.py -v
  • Regression guards green: test_schema_parity.py, test_voip_db.py, test_migrations*.py, test_1076_voice_model_config.py, test_1069/1073_voip* (64 tests total)
  • Backend imports + route registration smoke-tested (/voice/name, /voip/enabled)
  • Manual: configure a binding in the UI, toggle enable/disable, pick a voice, verify outbound call uses it (needs a live Twilio voice number — VoIP is flag-OFF by default)

Refs abilityai/trinity-enterprise#28

🤖 Generated with Claude Code

Eugene Vyborov and others added 2 commits June 23, 2026 19:34
…trinity-enterprise#28)

Add the missing per-agent VoIP config UI (agent Settings/Sharing tab) and a
persisted per-agent Gemini voice. Shipped as plain OSS gated on the existing
voip_available platform flag — NOT entitlement-gated (a UI gate over a
money-spending OSS backend would be cosmetic; deliberate simplification of the
issue's original "entitlement-gated" framing).

Backend:
- agent_ownership.voice_name (default Kore) via dual-track migration
  (SQLite db/migrations.py + Alembic 0004 + schema.py/tables.py). db
  get/set_voice_name with read-path fallback to Kore for unset/invalid values.
- GET/PUT /api/agents/{name}/voice/name (PUT owner-only, validated against
  GEMINI_VOICE_NAMES). _get_voice_name and voip_service now read the persisted
  voice instead of the two hardcoded "Kore" sites.
- PUT /api/agents/{name}/voip/enabled toggle (owner-only, 404 when no binding);
  create_binding upsert no longer forces enabled=1 so re-saving credentials
  preserves a disabled state (call path already refuses disabled bindings).

Frontend:
- VoipChannelPanel.vue (modeled on WhatsAppChannelPanel) mounted in SharingPanel
  under voip_available; shared src/constants/voices.js (drift-guarded vs backend);
  AgentWorkspace picker defaults to the persisted voice; sessions store surfaces
  voip_available.

Tests: tests/unit/test_28_voip_voice_config.py — voice fallback/roundtrip/
invalid->default, enable toggle + re-PUT-preserves-disabled (H3), and the
frontend/backend voice-list drift guard. Schema-parity + voip-db guards green.

Refs abilityai/trinity-enterprise#28

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#28 review I1)

Pre-landing /review flagged that the new endpoints were covered only at the DB
layer. Add FastAPI TestClient tests (mount real routers, override auth deps, stub
db/voip_service) asserting:
- PUT /voice/name: owner-gated (403), 400 on unknown voice, empty clears to
  default, valid voice persists; GET returns voice_name + available_voices.
- PUT /voip/enabled: owner-gated (403), 404 when no binding / when voip flag off,
  200 reflecting state with no auth_token leaked.

Also capture a durable learning (docs/memory/learnings.md): the schema-parity
test is blind to db/tables.py drift — a missing Column there passes parity but
breaks at runtime; guard it with a db-accessor unit test that executes a live
select on the new column.

Refs abilityai/trinity-enterprise#28

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

⚠️ Nightly unit-suite check skipped — merge conflict against dev.

Resolve by running git merge dev locally and pushing the result. The next nightly run will re-test once the conflict is gone.

@AndriiPasternak31 AndriiPasternak31 merged commit 550920e into dev Jun 24, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants