Sky-Kim's picture
Initial commit
2e7837a
Raw
History Blame Contribute Delete
4.21 kB
using System;
using System.Threading;
using OnDeviceAgent.AgentCore;
namespace OnDeviceAgent.VoiceManager
{
public sealed class VoiceEventRelay
{
readonly IAgentRuntime m_Runtime;
readonly AgentInterruptController m_Interrupt;
readonly AgentEventBus m_EventBus;
readonly AgentTraceStore m_TraceStore;
readonly Action<string> m_Log;
readonly Func<bool> m_StreamingPreferred;
public bool EnableVoiceEvents { get; set; } = true;
public bool EnableInterrupts { get; set; } = true;
public bool EnableBargeIn { get; set; } = true;
public bool EnableEventBus { get; set; } = true;
public VoiceEventRelay(
IAgentRuntime runtime,
AgentInterruptController interrupt,
AgentEventBus eventBus,
AgentTraceStore traceStore,
Action<string> log,
Func<bool> streamingPreferred)
{
if (runtime == null) throw new ArgumentNullException(nameof(runtime));
if (interrupt == null) throw new ArgumentNullException(nameof(interrupt));
if (eventBus == null) throw new ArgumentNullException(nameof(eventBus));
if (traceStore == null) throw new ArgumentNullException(nameof(traceStore));
m_Runtime = runtime;
m_Interrupt = interrupt;
m_EventBus = eventBus;
m_TraceStore = traceStore;
m_Log = log ?? (_ => { });
m_StreamingPreferred = streamingPreferred ?? (() => true);
}
public void OnFinalTranscript(string text)
{
if (!EnableVoiceEvents || string.IsNullOrWhiteSpace(text))
return;
if (m_Runtime.IsRunning && TryHandleInterruptPrompt(text, "Voice"))
return;
if (EnableBargeIn && m_Runtime.IsRunning)
{
m_Log("Voice barge-in: cancelling current run.");
m_Runtime.TryInterrupt("voice barge-in");
}
PublishAgentEvent("Voice", text, AgentEventPriority.High);
}
public void ProcessQueuedEvents()
{
if (m_Runtime.IsRunning)
return;
AgentEvent agentEvent;
if (!m_EventBus.TryDequeue(out agentEvent))
return;
StartRunWithPrompt(agentEvent.Prompt, agentEvent.Source);
}
void PublishAgentEvent(string source, string prompt, AgentEventPriority priority)
{
if (EnableEventBus)
{
m_EventBus.Publish(source, prompt, priority);
m_TraceStore.RecordEvent("event", source + " queued.");
return;
}
if (m_Runtime.IsRunning)
{
m_EventBus.Publish(source, prompt, priority);
return;
}
StartRunWithPrompt(prompt, source);
}
bool TryHandleInterruptPrompt(string prompt, string origin)
{
if (!EnableInterrupts || !m_Runtime.IsRunning)
return false;
AgentInterruptRequest request;
if (!m_Interrupt.TryCreateInterrupt(prompt, out request))
return false;
var originText = string.IsNullOrWhiteSpace(origin) ? "User" : origin.Trim();
m_Log(originText + " interrupt: " + request.Reason);
m_Runtime.TryInterrupt(request.Reason);
if (!string.IsNullOrWhiteSpace(request.FollowUpPrompt))
PublishAgentEvent(origin, request.FollowUpPrompt, AgentEventPriority.High);
return true;
}
void StartRunWithPrompt(string prompt, string origin)
{
var label = string.IsNullOrWhiteSpace(origin) ? "Voice" : origin.Trim();
m_Log(label + ": " + (prompt ?? string.Empty));
var request = new AgentRunRequest(prompt, origin, m_StreamingPreferred(), null);
m_Runtime.RunAsync(request, CancellationToken.None).ContinueWith(
t => m_Log("RunAsync fault: " + t.Exception),
System.Threading.Tasks.TaskContinuationOptions.OnlyOnFaulted);
}
}
}