mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
refactor(voice): isolate gemini live provider core
This commit is contained in:
commit
10916227cb
655 files changed
+45946
-26483
No files matched your search
+18
-39
@@ -1,18 +1,11 @@
|
||||
/**
|
||||
* Protocol-independent voice lifetime and action dispatch.
|
||||
* An adapter receives { emit, runAction, signal, providerDropdown } and supplies start, stop,
|
||||
* An adapter receives { emit, runAction, signal } and supplies start, stop,
|
||||
* sendText and sendMapEvent. It owns its microphone/connection and wire messages.
|
||||
* Events: state, stop, transcript, action-call, progress, action-result,
|
||||
* interruption, completion, turn-metrics. A stop event also
|
||||
* covers teardown that preserves the adapter’s displayed status.
|
||||
* providerDropdown() reads current trusted host capability for local refusals.
|
||||
* Events: state, transcript, action-call, progress, action-result, interruption,
|
||||
* completion, turn-metrics.
|
||||
*/
|
||||
export function createVoiceSession({
|
||||
createAdapter,
|
||||
runner,
|
||||
signal,
|
||||
providerDropdown = () => false,
|
||||
}) {
|
||||
export function createVoiceSession({ createAdapter, runner, signal }) {
|
||||
if (typeof createAdapter !== 'function' || typeof runner !== 'function')
|
||||
throw new TypeError('Voice requires an adapter factory and action runner');
|
||||
const lifetime = new AbortController();
|
||||
@@ -69,14 +62,6 @@ export function createVoiceSession({
|
||||
!actionSignal.aborted &&
|
||||
epoch === generation &&
|
||||
(!options.isCurrent || options.isCurrent());
|
||||
// Provider intent can revoke cooperative resources without erasing a
|
||||
// result that committed before recognition. Session/turn revocation still
|
||||
// owns the outer result and always suppresses stale completion.
|
||||
const resourceSignal = options.providerPolicySignal
|
||||
? AbortSignal.any([actionSignal, options.providerPolicySignal])
|
||||
: actionSignal;
|
||||
const resourceIsCurrent = () =>
|
||||
isCurrent() && !options.providerPolicySignal?.aborted;
|
||||
const callId = options.callId ?? null;
|
||||
try {
|
||||
if (!isCurrent()) throw abortError();
|
||||
@@ -87,7 +72,7 @@ export function createVoiceSession({
|
||||
// Step reports reach observers only while the action is current, so a
|
||||
// cancelled tool cannot update the plan or start narration.
|
||||
const progress = (update) => {
|
||||
if (!resourceIsCurrent() || !update?.step) return;
|
||||
if (!isCurrent() || !update?.step) return;
|
||||
emit({
|
||||
type: 'progress',
|
||||
name,
|
||||
@@ -99,9 +84,8 @@ export function createVoiceSession({
|
||||
};
|
||||
const result = await runner(name, args, {
|
||||
...options,
|
||||
providerDropdown: providerDropdown() === true,
|
||||
signal: resourceSignal,
|
||||
isCurrent: resourceIsCurrent,
|
||||
signal: actionSignal,
|
||||
isCurrent,
|
||||
progress,
|
||||
});
|
||||
if (!isCurrent()) throw abortError();
|
||||
@@ -134,12 +118,7 @@ export function createVoiceSession({
|
||||
}
|
||||
const abort = () => dispose();
|
||||
try {
|
||||
adapter = createAdapter({
|
||||
emit,
|
||||
runAction,
|
||||
signal: lifetime.signal,
|
||||
providerDropdown: () => !disposed && providerDropdown() === true,
|
||||
});
|
||||
adapter = createAdapter({ emit, runAction, signal: lifetime.signal });
|
||||
for (const method of ['start', 'stop', 'sendText', 'sendMapEvent']) {
|
||||
if (typeof adapter?.[method] !== 'function')
|
||||
throw new TypeError('Voice adapter must implement ' + method);
|
||||
@@ -168,8 +147,9 @@ export function createVoiceSession({
|
||||
},
|
||||
async start(options) {
|
||||
if (disposed || !['idle', 'error'].includes(state)) return;
|
||||
emit({ type: 'state', state: 'connecting' });
|
||||
const attempt = ++startAttempt;
|
||||
emit({ type: 'state', state: 'connecting' });
|
||||
if (disposed || attempt !== startAttempt) return;
|
||||
try {
|
||||
await adapter.start(options);
|
||||
} catch (error) {
|
||||
@@ -185,19 +165,18 @@ export function createVoiceSession({
|
||||
stop(options = {}) {
|
||||
if (options.removeUi) return dispose();
|
||||
if (disposed) return;
|
||||
startAttempt++;
|
||||
const attempt = ++startAttempt;
|
||||
cancelActions();
|
||||
try {
|
||||
adapter.stop(options);
|
||||
} finally {
|
||||
if (options.preserveStatus)
|
||||
emit({ type: 'stop', preserveStatus: true });
|
||||
else
|
||||
emit({
|
||||
type: 'state',
|
||||
state: 'idle',
|
||||
detail: 'Voice off',
|
||||
});
|
||||
if (
|
||||
!options.preserveStatus &&
|
||||
!disposed &&
|
||||
attempt === startAttempt &&
|
||||
state !== 'idle'
|
||||
)
|
||||
emit({ type: 'state', state: 'idle', detail: 'Voice off' });
|
||||
}
|
||||
},
|
||||
sendText: (text) => !disposed && adapter.sendText(text),
|
||||
|
||||
Reference in new issue
Block a user