feat: harden voice reliability with tts fallback and talk controls

This commit is contained in:
William Valentin
2026-02-26 17:29:23 -08:00
parent 2a9bed8c91
commit 163b1a0139
13 changed files with 781 additions and 17 deletions
+30 -1
View File
@@ -139,6 +139,8 @@ function escapeHtml(str) {
function getAssistantStateSnapshot(configData) {
const automation = configData?.automation ?? {};
const memory = configData?.memory ?? {};
const audio = configData?.audio ?? {};
const talkMode = audio.talk_mode ?? {};
const tts = configData?.tts ?? {};
const queue = configData?.server?.queue ?? {};
return {
@@ -147,6 +149,10 @@ function getAssistantStateSnapshot(configData) {
memoryDaily: Boolean(memory.daily_log?.enabled),
memoryProactive: Boolean(memory.proactive_extract?.enabled),
memoryMinToolCalls: Number(memory.proactive_extract?.min_tool_calls ?? 1),
talkModeEnabled: Boolean(talkMode.enabled),
talkWakePhrase: typeof talkMode.wake_phrase === 'string' ? talkMode.wake_phrase : 'hey flynn',
talkTimeoutMs: Number(talkMode.timeout_ms ?? 120000),
talkManualToggle: talkMode.allow_manual_toggle !== false,
ttsEnabled: Boolean(tts.enabled),
ttsChannels: Array.isArray(tts.enabled_channels) ? tts.enabled_channels : [],
queueMode: queue.mode ?? 'collect',
@@ -161,6 +167,7 @@ function buildPlaybookPatches(playbook) {
'memory.daily_log.enabled': true,
'memory.proactive_extract.enabled': true,
'memory.proactive_extract.min_tool_calls': 1,
'audio.talk_mode.enabled': true,
'tts.enabled': true,
'tts.enabled_channels': [],
'server.queue.mode': 'interrupt',
@@ -177,6 +184,7 @@ function buildPlaybookPatches(playbook) {
'memory.daily_log.enabled': true,
'memory.proactive_extract.enabled': true,
'memory.proactive_extract.min_tool_calls': 2,
'audio.talk_mode.enabled': false,
'tts.enabled': false,
'server.queue.mode': 'steer_backlog',
};
@@ -191,6 +199,7 @@ function buildPlaybookPatches(playbook) {
'memory.daily_log.enabled': false,
'memory.proactive_extract.enabled': false,
'memory.proactive_extract.min_tool_calls': 3,
'audio.talk_mode.enabled': false,
'tts.enabled': false,
'server.queue.mode': 'collect',
};
@@ -207,6 +216,10 @@ function buildRollbackPatchesFromSnapshot(snapshot) {
'memory.daily_log.enabled': snapshot.memoryDaily,
'memory.proactive_extract.enabled': snapshot.memoryProactive,
'memory.proactive_extract.min_tool_calls': Number.isFinite(snapshot.memoryMinToolCalls) ? snapshot.memoryMinToolCalls : 1,
'audio.talk_mode.enabled': snapshot.talkModeEnabled,
'audio.talk_mode.wake_phrase': snapshot.talkWakePhrase,
'audio.talk_mode.timeout_ms': Number.isFinite(snapshot.talkTimeoutMs) ? snapshot.talkTimeoutMs : 120000,
'audio.talk_mode.allow_manual_toggle': snapshot.talkManualToggle,
'tts.enabled': snapshot.ttsEnabled,
'tts.enabled_channels': snapshot.ttsChannels,
'server.queue.mode': snapshot.queueMode,
@@ -936,6 +949,8 @@ function updateAssistantHealth(configData) {
const automation = configData?.automation ?? {};
const memory = configData?.memory ?? {};
const audio = configData?.audio ?? {};
const talkMode = audio.talk_mode ?? {};
const tts = configData?.tts ?? {};
const deliveryMode = automation.delivery_mode ?? 'shared_session';
@@ -944,6 +959,9 @@ function updateAssistantHealth(configData) {
const memoryDaily = Boolean(memory.daily_log?.enabled);
const memoryProactive = Boolean(memory.proactive_extract?.enabled);
const proactiveThreshold = Number(memory.proactive_extract?.min_tool_calls ?? 1);
const talkModeEnabled = Boolean(talkMode.enabled);
const talkWakePhrase = typeof talkMode.wake_phrase === 'string' ? talkMode.wake_phrase : 'hey flynn';
const talkTimeoutMs = Number(talkMode.timeout_ms ?? 120000);
const ttsEnabled = Boolean(tts.enabled);
const briefing = automation.daily_briefing ?? {};
const briefingName = briefing.name ?? 'daily-briefing';
@@ -1011,17 +1029,22 @@ function updateAssistantHealth(configData) {
: (_lastCouncilError ? `Last run failed: ${_lastCouncilError}` : 'No council run yet in this dashboard session.');
el.innerHTML = `
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-2 mb-4">
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-7 gap-2 mb-4">
${chip('Announce Mode', announce)}
${chip('Daily Briefing', dailyBriefing)}
${chip('Memory Daily Log', memoryDaily)}
${chip('Proactive Extract', memoryProactive)}
${chip('Talk Mode', talkModeEnabled)}
${chip('TTS Replies', ttsEnabled)}
<div class="flex justify-between items-center px-3 py-2.5 bg-zinc-900 border border-zinc-800 rounded-lg text-sm">
<span class="text-zinc-400">Extract Threshold</span>
<span class="font-bold">${Number.isFinite(proactiveThreshold) ? proactiveThreshold : 1}</span>
</div>
</div>
<div class="mb-3 text-sm text-zinc-500">
Talk controls: wake phrase <code class="text-zinc-300">${escapeHtml(talkWakePhrase)}</code>,
timeout ${Number.isFinite(talkTimeoutMs) ? Math.round(talkTimeoutMs / 1000) : 120}s.
</div>
<div class="flex flex-wrap gap-2 mb-4">
<button class="px-3 py-1.5 text-sm font-medium rounded-md border border-zinc-700 bg-zinc-800 text-zinc-200 hover:bg-zinc-700 transition-colors assistant-action-btn" data-action="toggle-announce">
${announce ? 'Disable Announce Mode' : 'Enable Announce Mode'}
@@ -1035,6 +1058,9 @@ function updateAssistantHealth(configData) {
<button class="px-3 py-1.5 text-sm font-medium rounded-md border border-zinc-700 bg-zinc-800 text-zinc-200 hover:bg-zinc-700 transition-colors assistant-action-btn" data-action="toggle-memory-proactive">
${memoryProactive ? 'Disable Proactive Extract' : 'Enable Proactive Extract'}
</button>
<button class="px-3 py-1.5 text-sm font-medium rounded-md border border-zinc-700 bg-zinc-800 text-zinc-200 hover:bg-zinc-700 transition-colors assistant-action-btn" data-action="toggle-talk-mode">
${talkModeEnabled ? 'Disable Talk Mode' : 'Enable Talk Mode'}
</button>
<button class="px-3 py-1.5 text-sm font-medium rounded-md border border-zinc-700 bg-zinc-800 text-zinc-200 hover:bg-zinc-700 transition-colors assistant-action-btn" data-action="toggle-tts">
${ttsEnabled ? 'Disable TTS' : 'Enable TTS'}
</button>
@@ -1341,6 +1367,9 @@ function updateAssistantHealth(configData) {
} else if (action === 'toggle-memory-proactive') {
patches = { 'memory.proactive_extract.enabled': !memoryProactive };
_assistantManualOverrides.add('memory.proactive_extract.enabled');
} else if (action === 'toggle-talk-mode') {
patches = { 'audio.talk_mode.enabled': !talkModeEnabled };
_assistantManualOverrides.add('audio.talk_mode.enabled');
} else if (action === 'toggle-tts') {
patches = { 'tts.enabled': !ttsEnabled };
_assistantManualOverrides.add('tts.enabled');