fix(voice): stop thinking continuation on silence

This commit is contained in:
Yera All
2026-04-16 23:56:10 +05:00
parent f14aeb39df
commit 52b2edfcd3
2 changed files with 85 additions and 2 deletions
+75
View File
@@ -1694,6 +1694,81 @@ def test_media_runtime_merges_thinking_continuation_into_current_utterance():
assert merged.endswith(continuation_pcm + continuation_pcm)
def test_media_runtime_thinking_continuation_is_not_kept_alive_by_silence():
runtime = AudioSocketMediaRuntime(
enabled=True,
host="127.0.0.1",
port=0,
frame_ms=20,
idle_timeout_seconds=2.0,
registration_wait_timeout_seconds=0.5,
min_speech_ms=40,
trailing_silence_ms=40,
max_turn_ms=2000,
asr_provider=_StubASRProvider(),
streaming_asr_provider=StreamingASRProvider(),
tts_provider=_StubTTSProvider(),
load_registration_by_media_uuid=lambda value: None,
mark_media_connected=lambda session_id, value: None,
mark_media_ended=lambda session_id, reason: None,
touch_media_frame=lambda session_id: None,
set_state=lambda session_id, state, handoff_reason, metadata: None,
get_pending_greeting=lambda session_id: None,
mark_reply_delivered=lambda session_id, text, is_greeting: None,
plan_reply=lambda session_id, text, metadata, kind: None,
process_turn=lambda session_id, transcript_text, language, barge_in, metadata: VoiceAITurnDecisionOut(
language=language or "ru",
intent="clarification",
reply_text="Подскажите подробнее, пожалуйста.",
confidence=0.8,
needs_handoff=False,
handoff_reason=None,
case_action="keep_open",
kb_refs=[],
summary_text="reply ready",
model="stub-voice",
latency_ms=1,
status="active",
),
request_handoff=lambda session_id, customer_request_text, decision: None,
handle_media_error=lambda session_id, message, metadata: None,
)
base_pcm = (1000).to_bytes(2, "little", signed=True) * 160
continuation_pcm = (900).to_bytes(2, "little", signed=True) * 160
silence_frame = b"\x00\x00" * 160
async def _scenario() -> bytes:
actor = MediaActor(
registration=MediaRegistration(
voice_session_id="avs_media_runtime_thinking_silence_tail",
call_id="call_media_runtime_thinking_silence_tail",
interaction_id="int_media_runtime_thinking_silence_tail",
ai_session_id="ais_media_runtime_thinking_silence_tail",
language="ru",
media_uuid=str(uuid.uuid4()),
),
reader=asyncio.StreamReader(),
writer=None, # type: ignore[arg-type]
vad=EnergyVAD(frame_ms=20, min_speech_ms=40, trailing_silence_ms=40, max_turn_ms=2000),
frame_ms=20,
frame_bytes=320,
state="thinking",
)
merge_task = asyncio.create_task(runtime._extend_with_thinking_continuation(actor, base_pcm))
await runtime._handle_pcm(actor, continuation_pcm)
for _ in range(40):
await runtime._handle_pcm(actor, silence_frame)
await asyncio.sleep(0.02)
merged = await asyncio.wait_for(merge_task, timeout=0.2)
assert actor.thinking_continuation_pcm == bytearray()
return merged
merged = asyncio.run(_scenario())
assert len(merged) > len(base_pcm)
assert continuation_pcm in merged
def _legacy_test_media_runtime_voice_v2_uses_streaming_sidecar_for_partial_and_final_asr():
registrations: dict[str, MediaRegistration] = {}
reply_starts: list[tuple[str, str | None, float]] = []