fix(tts): add error handling for accumulated block TTS

This commit is contained in:
Glucksberg 2026-01-25 19:52:56 +00:00 committed by Shadow
parent 938a9ab627
commit 145618d625
No known key found for this signature in database

View File

@ -346,42 +346,48 @@ export async function dispatchReplyFromConfig(params: {
// This handles the case where block streaming succeeds and drops final payloads, // This handles the case where block streaming succeeds and drops final payloads,
// but we still want TTS audio to be generated from the accumulated block content. // but we still want TTS audio to be generated from the accumulated block content.
if (replies.length === 0 && blockCount > 0 && accumulatedBlockText.trim()) { if (replies.length === 0 && blockCount > 0 && accumulatedBlockText.trim()) {
const ttsSyntheticReply = await maybeApplyTtsToPayload({ try {
payload: { text: accumulatedBlockText }, const ttsSyntheticReply = await maybeApplyTtsToPayload({
cfg, payload: { text: accumulatedBlockText },
channel: ttsChannel, cfg,
kind: "final", channel: ttsChannel,
inboundAudio, kind: "final",
ttsAuto: sessionTtsAuto, inboundAudio,
}); ttsAuto: sessionTtsAuto,
// Only send if TTS was actually applied (mediaUrl exists) });
if (ttsSyntheticReply.mediaUrl) { // Only send if TTS was actually applied (mediaUrl exists)
// Send TTS-only payload (no text, just audio) so it doesn't duplicate the block content if (ttsSyntheticReply.mediaUrl) {
const ttsOnlyPayload: ReplyPayload = { // Send TTS-only payload (no text, just audio) so it doesn't duplicate the block content
mediaUrl: ttsSyntheticReply.mediaUrl, const ttsOnlyPayload: ReplyPayload = {
audioAsVoice: ttsSyntheticReply.audioAsVoice, mediaUrl: ttsSyntheticReply.mediaUrl,
}; audioAsVoice: ttsSyntheticReply.audioAsVoice,
if (shouldRouteToOriginating && originatingChannel && originatingTo) { };
const result = await routeReply({ if (shouldRouteToOriginating && originatingChannel && originatingTo) {
payload: ttsOnlyPayload, const result = await routeReply({
channel: originatingChannel, payload: ttsOnlyPayload,
to: originatingTo, channel: originatingChannel,
sessionKey: ctx.SessionKey, to: originatingTo,
accountId: ctx.AccountId, sessionKey: ctx.SessionKey,
threadId: ctx.MessageThreadId, accountId: ctx.AccountId,
cfg, threadId: ctx.MessageThreadId,
}); cfg,
queuedFinal = result.ok || queuedFinal; });
if (result.ok) routedFinalCount += 1; queuedFinal = result.ok || queuedFinal;
if (!result.ok) { if (result.ok) routedFinalCount += 1;
logVerbose( if (!result.ok) {
`dispatch-from-config: route-reply (tts-only) failed: ${result.error ?? "unknown error"}`, logVerbose(
); `dispatch-from-config: route-reply (tts-only) failed: ${result.error ?? "unknown error"}`,
);
}
} else {
const didQueue = dispatcher.sendFinalReply(ttsOnlyPayload);
queuedFinal = didQueue || queuedFinal;
} }
} else {
const didQueue = dispatcher.sendFinalReply(ttsOnlyPayload);
queuedFinal = didQueue || queuedFinal;
} }
} catch (err) {
logVerbose(
`dispatch-from-config: accumulated block TTS failed: ${err instanceof Error ? err.message : String(err)}`,
);
} }
} }