Skip to content

feat: wire VoiceDNA VoiceAdapter into live OpenClaw per-agent voice pipeline - #7

Open
lukejmorrison wants to merge 3 commits into
mainfrom
feature/voicedna-openclaw-integration
Open

feat: wire VoiceDNA VoiceAdapter into live OpenClaw per-agent voice pipeline#7
lukejmorrison wants to merge 3 commits into
mainfrom
feature/voicedna-openclaw-integration

Conversation

@lukejmorrison

Copy link
Copy Markdown
Owner

Summary

Wires VoiceAdapter preset routing into the live OpenClaw agent voice pipeline via a new render_agent_voice() entry point.

What's new

File Role
voicedna/openclaw_live_voice.py render_agent_voice() — per-agent voice entry point. Lazy singleton VoiceAdapter with env override via VOICEDNA_OPENCLAW_PRESETS_MAP.
tests/test_openclaw_live_voice.py 12 integration tests: preset map, singleton, env override, file write, per-agent routing.
DEPLOY_NOTES.md Full deploy/rollback/wiring guide.
demo/ Validation-run WAVs + log.

Default agent preset mapping

Agent Preset
agent:namshub neutral
agent:david-hardman friendly
agent:dr-voss-thorne flair

Test results (local)

pytest tests/test_voice_adapter.py tests/test_openclaw_live_voice.py -v
→ 30 passed in 1.93s

pytest (full suite)
→ 46 passed in 1.88s

Wiring options

See DEPLOY_NOTES.md for three integration options (programmatic, env-driven, full skill hook).

Rollback

Remove voicedna/openclaw_live_voice.py and tests/test_openclaw_live_voice.py. All existing code paths are unaffected.

- voicedna/openclaw_live_voice.py: render_agent_voice() entry point
  wires VoiceAdapter preset routing into the live OpenClaw agent voice
  pipeline. Default map covers agent:namshub (neutral), agent:david-hardman
  (friendly), agent:dr-voss-thorne (flair). Env override via
  VOICEDNA_OPENCLAW_PRESETS_MAP. Singleton adapter, lazy init, reset_adapter()
  for tests.
- tests/test_openclaw_live_voice.py: 12 tests, all pass.
- Existing code paths untouched. Opt-in only.

30/30 tests pass. ruff clean. py_compile clean.
- DEPLOY_NOTES.md: full deploy/rollback/wiring guide
- demo/: validation run outputs — namshub.wav, david-hardman.wav, dr-voss-thorne.wav, validation_log_20260418.txt
- demos/: updated demo WAVs (mirrors examples/openclaw/output/)
- research/: integration plan, preflight, logs, packet artifacts
- All 46 tests pass locally (30 adapter+live-voice, 16 core suite)

Signed-off-by: Dr Voss Thorne <subagent>
Copilot AI review requested due to automatic review settings April 18, 2026 17:12

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an opt-in, per-agent VoiceDNA preset routing entry point intended to be called from OpenClaw’s live TTS seam, plus tests and rollout docs to validate and deploy the integration.

Changes:

  • Introduces render_agent_voice() (lazy singleton VoiceAdapter) with default agent→preset routing and env override support.
  • Adds integration tests for routing, singleton/reset behavior, env override behavior, and WAV file writing.
  • Adds/updates deployment + integration planning docs and captures validation logs/artifacts.

Reviewed changes

Copilot reviewed 18 out of 27 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
voicedna/openclaw_live_voice.py New live entry point render_agent_voice() with default mapping + env override merge and adapter singleton/reset.
tests/test_openclaw_live_voice.py New integration tests for the live entry point and mapping behavior.
DEPLOY_NOTES.md Deployment/wiring/rollback guidance for enabling the OpenClaw integration.
IMPLEMENTATION_NOTE.md Implementation notes, reproduction commands, and rollout/rollback guidance.
demo/validation_log_20260418.txt Captured manual validation run output for the live voice entry point.
research/voicedna_openclaw_integration_plan.md Integration plan outlining OpenClaw seam wiring and rollout expectations.
research/pr_description.md Draft PR description content for the target OpenClaw-side PR.
research/merge_ready_report.md Merge readiness report and verification notes.
research/logs/test_voice_adapter_20260418.txt Captured adapter test run output.
research/logs/test_full_suite_20260418.txt Captured full-suite pytest output.
research/logs/demo_voicedemo_validation_20260418.txt Captured WAV validation (sizes/format) for demo outputs.
research/logs/demo_voicedemo_20260418.txt Captured demo script console output.
research/integration_preflight.md Preflight checklist and exact rollout steps for the OpenClaw wiring.
research/integration_checklist.md Go/no-go checklist for integration and rollout verification.
research/integration-packet/local_run_commands.txt Local command sequence used for validation.
research/integration-packet/implementation_checklist.md Implementation checklist for wiring and validation steps.
research/integration-packet/blockers.txt Notes on potential blockers/approvals for pushing/wiring.
research/integration-packet/DESIGN_DOC.md Design overview for the per-agent voice pilot approach.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +66 to +69
# Also clear the module-level AGENT_PRESETS dict from adapter
import voicedna.openclaw_adapter as adp
adp.AGENT_PRESETS.clear()
adapter = _get_adapter()

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test has to reach into voicedna.openclaw_adapter.AGENT_PRESETS and clear it to make env overrides deterministic. That’s a sign the live-voice module’s reset path doesn’t fully reset the underlying preset cache. Prefer moving this reset into reset_adapter() (or a public reset helper in openclaw_adapter) so tests don’t depend on another module’s mutable globals.

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +11
import sys

import pytest

# Ensure the project root is importable
sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parents[1]))

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The repo already inserts the project root onto sys.path in the root conftest.py, so this per-test sys.path.insert(...) is redundant and makes import order harder to reason about. Consider removing it (or at least using the consistent from pathlib import Path pattern used elsewhere) and rely on conftest.py for path setup.

Suggested change
import sys
import pytest
# Ensure the project root is importable
sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parents[1]))
import pytest

Copilot uses AI. Check for mistakes.
Comment thread DEPLOY_NOTES.md
Comment on lines +144 to +149
If push/auth is required for new commits, set the remote with a PAT:

```bash
git remote set-url origin https://<YOUR_PAT>@github.com/lukejmorrison/VoiceDNA.git
git push origin feature/voicedna-openclaw-integration
```

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs suggest embedding a PAT directly in the remote URL (https://<YOUR_PAT>@github.com/...). This is easy to leak via shell history, git remote -v, logs, or screenshots. Prefer recommending gh auth login, GITHUB_TOKEN with gh, or git push https://github.com/... and let Git prompt/credential-manager handle auth (or use a one-off HTTPS URL without saving it to origin).

Copilot uses AI. Check for mistakes.
Comment thread IMPLEMENTATION_NOTE.md
Comment on lines +118 to +127
## Pushing to origin (PAT required)

4. **Preset names**: `neutral`, `friendly`, `flair` match the design doc verbatim.
Push is blocked without a PAT (HTTPS remote, no stored credential).

5. **No new packaging deps**: The adapter imports only from `voicedna.*` and stdlib.
**If you provide a PAT:**
```bash
cd /home/namshub/dev/VoiceDNA
git remote set-url origin https://<YOUR_PAT>@github.com/lukejmorrison/VoiceDNA.git
git push origin feature/voicedna-openclaw-integration
```

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This guidance recommends putting a PAT into the origin URL. That pattern frequently results in accidental token disclosure (git config, terminal history, logs) and can persist beyond the intended short-lived use. Prefer documenting gh auth login --with-token, Git credential manager, or a one-time git push https://github.com/... without permanently changing the remote URL.

Copilot uses AI. Check for mistakes.
Comment thread DEPLOY_NOTES.md
Comment on lines +85 to +93
### Option B — Env-driven (zero-code)

```bash
export VOICEDNA_OPENCLAW_PRESETS=1
export VOICEDNA_OPENCLAW_PRESETS_MAP='{"agent:namshub":"neutral","agent:dr-voss-thorne":"flair"}'
```

Set these in the OpenClaw agent's environment before starting the gateway.

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“Option B — Env-driven (zero-code)” reads as if setting env vars alone enables the OpenClaw routing. In this repo, VOICEDNA_OPENCLAW_PRESETS is only a convention (the library doesn’t gate/auto-hook on it), and VOICEDNA_OPENCLAW_PRESETS_MAP is only configuration for code that already calls render_agent_voice(). Consider clarifying that an OpenClaw-side seam/shim still needs to invoke render_agent_voice() (Option A/C), and the env vars only control whether that seam is enabled and how routing is configured.

Copilot uses AI. Check for mistakes.
Comment on lines +98 to +101
def reset_adapter() -> None:
"""Reset the shared adapter (useful in tests or after env changes)."""
global _adapter
_adapter = None

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reset_adapter() claims it’s useful “after env changes”, but resetting only _adapter is not enough because _get_adapter() pulls env overrides via load_presets_from_env(), which populates/returns the global voicedna.openclaw_adapter.AGENT_PRESETS and does not clear it when the env var is removed/changed. This can cause stale agent→preset mappings to persist across resets. Consider having reset_adapter() also clear AGENT_PRESETS (or add a dedicated reset in openclaw_adapter and call it here), or change _get_adapter() to parse the env JSON without using the cached module global.

Copilot uses AI. Check for mistakes.
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