fix(conversation): 修复实时会话 TTS/回复被离屏 WS 抢占

- 列表预热仅预取消息缓存,避免后台 WebSocket 覆盖服务端连接
- RealtimeSession UI 回调按 owner 独占,防止 offscreen 覆盖聊天页
- 列表页聚焦时再 prewarm,会话页 TTS 入队优先 base64
- 管线下发 TTS 同时带 audio_base64 与 audio_url;协议说明同步
- 移除 TTS 排查用前后端调试日志,保留错误/告警
- 补充 WS / RealtimeSession / entry-warmup / 播放器相关单测

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Kevin
2026-05-12 10:42:44 +08:00
parent 93be60f74c
commit 3d01085442
18 changed files with 643 additions and 261 deletions

View File

@@ -118,6 +118,45 @@ describe('WsClient', () => {
client.dispose();
});
test('maps tts audio with base64 and url playback channels', async () => {
const client = new WsClient('conv-123');
const events: WsEvent[] = [];
client.onEvent((e) => events.push(e));
await client.connect();
await new Promise((r) => setTimeout(r, 10));
const ws = (client as unknown as { ws: MockWebSocket }).ws;
ws.simulateMessage({
type: 'tts_audio',
conversation_id: 'conv-123',
data: {
audio_base64: 'ZmFrZS1tcDM=',
audio_url: 'https://example.com/tts.mp3',
index: 0,
total: 1,
assistant_message_id: 'aa11aa11-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
manual: true,
},
timestamp: '2026-01-01T00:00:00Z',
});
expect(events).toEqual([
{
kind: 'tts_audio_received',
conversationId: 'conv-123',
audioBase64: 'ZmFrZS1tcDM=',
audioUrl: 'https://example.com/tts.mp3',
index: 0,
total: 1,
assistantMessageId: 'aa11aa11-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
manual: true,
},
]);
client.dispose();
});
test('sends text messages', async () => {
const client = new WsClient('conv-123');