
























@@ -45,6 +45,7 @@ const DISCORD_REALTIME_RECENT_AGENT_PROXY_CONSULT_TTL_MS = 15_000;
4545const DISCORD_REALTIME_LOG_PREVIEW_CHARS = 500;
4646const DISCORD_REALTIME_DEFAULT_MIN_BARGE_IN_AUDIO_END_MS = 250;
4747const DISCORD_REALTIME_FORCED_CONSULT_FALLBACK_DELAY_MS = 200;
48+const DISCORD_REALTIME_DUPLICATE_ERROR_SUPPRESS_MS = 60_000;
4849const REALTIME_PCM16_BYTES_PER_SAMPLE = 2;
4950const DISCORD_REALTIME_FORCED_CONSULT_TRAILING_FRAGMENT_WORDS = new Set([
5051"a",
@@ -332,6 +333,9 @@ export class DiscordRealtimeVoiceSession implements VoiceRealtimeSession {
332333private queuedExactSpeechMessages: string[] = [];
333334private exactSpeechResponseActive = false;
334335private exactSpeechAudioStarted = false;
336+private lastRealtimeError:
337+| { message: string; suppressed: number; lastLoggedAt: number }
338+| undefined;
335339private readonly playerIdleHandler = () => {
336340this.resetOutputStream("player-idle");
337341this.completeExactSpeechResponse("player-idle");
@@ -453,9 +457,11 @@ export class DiscordRealtimeVoiceSession implements VoiceRealtimeSession {
453457logger.info(interruptionLog);
454458}
455459},
456-onError: (error) =>
457-logger.warn(`discord voice: realtime error: ${formatErrorMessage(error)}`),
458-onClose: (reason) => logVoiceVerbose(`realtime closed: ${reason}`),
460+onError: (error) => this.logRealtimeError(formatErrorMessage(error)),
461+onClose: (reason) => {
462+this.flushSuppressedRealtimeErrors();
463+logVoiceVerbose(`realtime closed: ${reason}`);
464+},
459465});
460466const resolvedModel =
461467readProviderConfigString(resolved.providerConfig, "model") ?? resolved.provider.defaultModel;
@@ -478,6 +484,7 @@ export class DiscordRealtimeVoiceSession implements VoiceRealtimeSession {
478484479485close(): void {
480486this.stopped = true;
487+this.flushSuppressedRealtimeErrors();
481488this.talkback.close();
482489this.clearForcedConsultTimers();
483490this.pendingAgentProxyConsultContexts = [];
@@ -493,6 +500,30 @@ export class DiscordRealtimeVoiceSession implements VoiceRealtimeSession {
493500this.params.entry.player.off(voiceSdk.AudioPlayerStatus.Idle, this.playerIdleHandler);
494501}
495502503+private logRealtimeError(message: string): void {
504+const now = Date.now();
505+if (
506+this.lastRealtimeError?.message === message &&
507+now - this.lastRealtimeError.lastLoggedAt < DISCORD_REALTIME_DUPLICATE_ERROR_SUPPRESS_MS
508+) {
509+this.lastRealtimeError.suppressed += 1;
510+return;
511+}
512+this.flushSuppressedRealtimeErrors();
513+this.lastRealtimeError = { message, suppressed: 0, lastLoggedAt: now };
514+logger.warn(`discord voice: realtime error: ${message}`);
515+}
516+517+private flushSuppressedRealtimeErrors(): void {
518+if (!this.lastRealtimeError || this.lastRealtimeError.suppressed === 0) {
519+return;
520+}
521+logger.warn(
522+`discord voice: suppressed ${this.lastRealtimeError.suppressed} duplicate realtime errors: ${this.lastRealtimeError.message}`,
523+);
524+this.lastRealtimeError.suppressed = 0;
525+}
526+496527beginSpeakerTurn(context: VoiceRealtimeSpeakerContext, userId: string): VoiceRealtimeSpeakerTurn {
497528const turn: PendingSpeakerTurn = {
498529context: { ...context, userId },
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。