Files
jpmschweitzerandClaude Opus 4.6 9f34d030d7 feat(voice): complete Spike 2 voice pipeline with quality-tested prompt engine
Spike 2 delivers the full voice pipeline: queue → worker pool → sr-voice
child process (stdio JSONL) → cache → disk. Three rounds of quality testing
with Paula, Mellanie, and Gestalt produced iterative prompt improvements.

Prompt engine (prompt_builder.rs):
- Example-based epistemic marker integration (not keyword lists)
- Length-aware Angry tell variant (preserves facts on long content)
- Double-prompt technique: REMEMBER block repeats constraints near OUTPUT:
- Imperative injection framing (composition engine controls frequency)
- Anti-invention constraint ("do not add information not in the input")
- Universal RULES cleaned: worldbuilding moved to culture personas

Worker pool (worker.rs):
- Output post-processor strips after first newline (prevents prompt leakage)
- Watchdog poll loop (1s ticks) replaces blocking sleep for cancel
- Child health check before writing (try_wait)

Test infrastructure:
- voice_pipeline.rs: end-to-end test, auto-detects real sr-voice or mock
- voice_quality_batch.rs: 39 edge-case prompts for quality review
- mock-stdio.sh: Python JSONL mock for CI (no model needed)
- Makefile targets: test-voice-mock, test-voice-real

Quality results (Gemma 2B Q4_K_M, CPU ~13 t/s):
- Epistemic markers: naturally integrated (round 1 comma-lists fixed)
- Tell differentiation: 3/5 working (Nervous, Guarded, Angry)
- Information preservation: ~90% (up from ~70%)
- Prompt leakage: eliminated
- Open: Friendly/RoutineDeviation tells inert (#651), Factual bypass (#650)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 19:20:06 +01:00

56 lines
1.6 KiB
Bash
Executable File

#!/usr/bin/env python3
"""Mock sr-voice stdio mode for pipeline testing (D-138).
Reads JSONL from stdin, writes JSONL to stdout. Simulates inference
by uppercasing the base text portion of the prompt as the "voiced" output.
Usage: echo '{"prompt":"Re-voice this.","seed":42}' | ./mock-stdio.sh serve --stdio
"""
import json
import sys
print("mock-sr-voice: stdio mode (no model loaded)", file=sys.stderr, flush=True)
# Use readline() loop — Python's `for line in sys.stdin` has an internal
# read-ahead buffer that blocks on piped stdin until 8KB is available.
while True:
line = sys.stdin.readline()
if not line:
break
line = line.strip()
if not line:
continue
try:
req = json.loads(line)
except json.JSONDecodeError as e:
print(json.dumps({"error": f"invalid JSON: {e}"}), flush=True)
continue
prompt = req.get("prompt", "")
if not prompt:
print(json.dumps({"error": "missing prompt field"}), flush=True)
continue
# Extract the INPUT line from the prompt (last INPUT: before OUTPUT:)
input_text = ""
for pline in prompt.split("\n"):
if pline.startswith("INPUT: "):
input_text = pline[7:]
if not input_text:
input_text = prompt[:80]
voiced = f"[VOICED] {input_text.upper()}"
result = {
"text": voiced,
"tokens_generated": len(voiced.split()),
"generation_time_ms": 50,
"tokens_per_sec": 240.0,
"prefill_time_ms": 10,
}
print(json.dumps(result), flush=True)
print("mock-sr-voice: stdin closed, exiting", file=sys.stderr, flush=True)