fix: add summary fallback and stabilize recording sink

This commit is contained in:
2026-06-10 12:01:13 +00:00
parent 53889da8f6
commit 5e51535693
4 changed files with 153 additions and 10 deletions
+40
View File
@@ -9,6 +9,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
import discord
import bot
import voice
class FakeChannel:
@@ -66,3 +67,42 @@ def test_build_retry_notice_mentions_reason_and_path():
assert "OpenRouter 502" in message
assert "meeting.wav" in message
assert "`/retry`" in message
def test_meeting_recorder_wraps_wave_sink_with_silence_generator(tmp_path, monkeypatch):
created = {}
class FakeWaveSink:
def __init__(self, output_path):
self.output_path = output_path
created["wave"] = self
class FakeSilenceGeneratorSink:
def __init__(self, destination):
self.destination = destination
created["silence"] = self
class FakeVoiceClient:
def __init__(self):
self.listened_sink = None
def is_listening(self):
return False
def listen(self, sink, after):
self.listened_sink = sink
created["after"] = after
monkeypatch.setattr(voice.voice_recv, "WaveSink", FakeWaveSink)
monkeypatch.setattr(voice.voice_recv, "SilenceGeneratorSink", FakeSilenceGeneratorSink)
vc = FakeVoiceClient()
output_path = tmp_path / "meeting.wav"
recorder = voice.MeetingRecorder(vc, str(output_path))
asyncio.run(recorder.start(lambda error: None))
assert created["wave"].output_path == str(output_path)
assert created["silence"].destination is created["wave"]
assert vc.listened_sink is created["silence"]
assert recorder.recording is True
+44
View File
@@ -13,6 +13,7 @@ from openrouter_client import (
TRANSCRIPTION_MODELS,
_audio_format,
_build_transcription_payload,
_chat_completion,
_chunk_text,
_combined_summary_prompt,
_summary_prompt,
@@ -182,3 +183,46 @@ def test_transcribe_chunk_reports_provider_fallback_when_all_providers_fail(tmp_
assert "Transcription failed across providers" in message
assert "OpenRouter transcription failed" in message
assert "direct OpenAI fallback skipped" in message
def test_chat_completion_falls_back_to_direct_openai_when_openrouter_returns_empty(monkeypatch):
calls = []
async def fake_openrouter(prompt: str, *, timeout: int = 180) -> str:
calls.append(("openrouter", prompt, timeout))
raise RuntimeError("OpenRouter summarization returned empty content")
async def fake_openai(prompt: str, *, timeout: int = 180) -> str:
calls.append(("openai", prompt, timeout))
return "direct summary"
monkeypatch.setattr(openrouter_client, "_chat_completion_openrouter", fake_openrouter)
monkeypatch.setattr(openrouter_client, "_chat_completion_openai", fake_openai)
monkeypatch.setattr(openrouter_client, "_openai_api_key", lambda: "sk-test")
result = asyncio.run(_chat_completion("summarize this", timeout=42))
assert result == "direct summary"
assert calls == [
("openrouter", "summarize this", 42),
("openai", "summarize this", 42),
]
def test_chat_completion_reports_provider_fallback_when_all_summarizers_fail(monkeypatch):
async def fake_openrouter(_prompt: str, *, timeout: int = 180) -> str:
raise RuntimeError("OpenRouter summarization returned empty content")
monkeypatch.setattr(openrouter_client, "_chat_completion_openrouter", fake_openrouter)
monkeypatch.setattr(openrouter_client, "_openai_api_key", lambda: "")
try:
asyncio.run(_chat_completion("summarize this"))
except RuntimeError as exc:
message = str(exc)
else:
raise AssertionError("Expected summarization failure")
assert "Summarization failed across providers" in message
assert "OpenRouter summarization returned empty content" in message
assert "direct OpenAI summarization fallback skipped" in message