refactor(voice): isolate gemini live provider core

This commit is contained in:
manjunath committed 2026-10-19 21:40:40 +05:30
commit 10916227cb
655 files changed
+45946 -26483

No files matched your search

-349
View File
@@ -2,7 +2,6 @@ import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import vm from 'node:vm';
import { harness as sessionHarness, tick } from './geminiNativeHarness.mjs';
import {
createGeminiAudio,
decodeGeminiPcm,
@@ -1133,351 +1132,3 @@ test('PTT admission leaves open-mic start, silence, PCM and end unchanged', asyn
);
assert.deepEqual(emittedPcm(h.events), new Array(1024).fill(0));
});
async function realAdapterSession(t, overrides = {}) {
const a = admissionHarness();
await a.audio.close(); // Only the controller-owned adapter remains live below.
const h = sessionHarness({ createAudio: a.createAudio, ...overrides });
t.after(() => h.c.stop());
await h.c.start({ pushToTalk: true });
return { ...h, worklet: a.worklets[0] };
}
test('silent PTT actual-controller integration sends no activity/context/PCM and releases pending state', async (t) => {
const h = await realAdapterSession(t);
const ws = h.sockets[0];
const before = ws.sent.length;
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(new Float32Array(1024));
h.c.input.pushToTalkKeyHeld = false;
h.c.input.setMicrophoneEnabled(false);
assert.equal(ws.sent.length, before);
assert.equal(h.c.userTurnPending, false);
assert.equal(h.c.replyPending, false);
assert.equal(h.c.forwardedActivityOpen, false);
assert.equal(h.c.audio.diagnostics().suppressedPttCaptures, 1);
assert.equal(h.c.status, 'listening');
});
test('silent PTT during native playback retains local interruption without creating a successor', async (t) => {
const h = await realAdapterSession(t);
const ws = h.sockets[0];
ws.message({
serverContent: {
modelTurn: {
parts: [
{ inlineData: { data: 'AAA=', mimeType: 'audio/pcm;rate=24000' } },
],
},
},
});
assert.equal(h.c.audio.pending, true);
const before = ws.sent.length;
assert.equal(h.c.input.bargeIn(), true);
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(new Float32Array(1024));
h.c.input.pushToTalkKeyHeld = false;
h.c.input.setMicrophoneEnabled(false);
assert.equal(ws.sent.length, before);
assert.equal(h.c.audio.pending, false);
assert.equal(h.c.userTurnPending, false);
ws.message({ serverContent: { turnComplete: true } });
h.advance(5001);
await tick();
assert.equal(h.c.retiredReplyPending, false);
assert.equal(h.c.status, 'listening');
assert.equal(h.timers.size, 0);
});
test('voiced PTT actual-controller integration submits one ordered activity and recovers after silence', async (t) => {
const h = await realAdapterSession(t);
const ws = h.sockets[0];
for (const [samples, admitted] of [
[new Float32Array(640), false],
[tone(640, 0.005), true],
]) {
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(samples);
h.c.input.pushToTalkKeyHeld = false;
h.c.input.setMicrophoneEnabled(false);
if (!admitted) assert.equal(h.c.userTurnPending, false);
}
const frames = ws.sent
.filter((m) => m.realtimeInput)
.map((m) => Object.keys(m.realtimeInput)[0]);
assert.deepEqual(frames, ['activityStart', 'audio', 'activityEnd']);
assert.equal(h.c.replyPending, true);
ws.message({
toolCall: {
functionCalls: [
{
id: 'after-silent',
name: 'adjust_camera_zoom',
args: { direction: 'out', amount: 'little' },
},
],
},
});
await h.c.toolQueue;
assert.equal(h.calls.length, 1);
ws.message({ serverContent: { turnComplete: true } });
assert.equal(h.c.userTurnPending, false);
});
test('silent PTT discard cannot clear a newer typed request', async (t) => {
const h = await realAdapterSession(t);
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(new Float32Array(1024));
h.c.sendTextCommand('zoom out a little');
const typed = h.c.readTypedTurnInput();
h.c.input.pushToTalkKeyHeld = false;
h.c.input.setMicrophoneEnabled(false);
assert.equal(h.c.userTurnPending, true);
assert.equal(h.c.readTypedTurnInput(), typed);
assert.equal(h.c.replyPending, true);
});
// A physical hold alone cannot retire a provider tool request: without admitted
// speech there is no native activity boundary to cancel that request.
test('silent physical PTT preserves old tool completion without a retired-boundary timeout', async (t) => {
const h = await realAdapterSession(t),
ws = h.sockets[0];
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(tone(640, 0.005));
h.c.input.pushToTalkKeyHeld = false;
h.c.input.setMicrophoneEnabled(false);
const before = ws.sent.length,
turn = h.c.turn;
assert.equal(h.c.input.bargeIn(), true);
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(new Float32Array(1024));
h.c.input.pushToTalkKeyHeld = false;
h.c.input.setMicrophoneEnabled(false);
ws.message({
toolCall: {
functionCalls: [
{
id: 'after-empty-hold',
name: 'adjust_camera_zoom',
args: { direction: 'out', amount: 'little' },
},
],
},
});
await h.c.toolQueue;
assert.equal(h.c.turn, turn);
assert.equal(h.calls.length, 1);
assert.equal(ws.sent.slice(before).filter((m) => m.toolResponse).length, 1);
assert.equal(
ws.sent.slice(before).some((m) => m.realtimeInput || m.clientContent),
false,
);
h.advance(5001);
await tick();
assert.equal(h.c.status, 'listening');
assert.equal(h.c.retiredReplyPending, false);
ws.message({ serverContent: { turnComplete: true } });
assert.equal(h.c.replyPending, false);
assert.equal(h.timers.size, 0);
});
test('silent physical PTT does not supersede an earlier typed request', async (t) => {
const h = await realAdapterSession(t);
h.c.sendTextCommand('zoom out a little');
const typed = h.c.readTypedTurnInput(),
turn = h.c.turn;
h.c.input.bargeIn();
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(new Float32Array(640));
h.c.input.pushToTalkKeyHeld = false;
h.c.input.setMicrophoneEnabled(false);
assert.equal(h.c.turn, turn);
assert.equal(h.c.readTypedTurnInput(), typed);
assert.equal(h.c.userTurnPending, true);
assert.equal(h.c.replyPending, true);
h.advance(5001);
await tick();
assert.equal(h.c.status, 'listening');
});
test('admitted physical PTT retires older input only at sustained energy', async (t) => {
const h = await realAdapterSession(t),
ws = h.sockets[0];
h.c.sendTextCommand('zoom out a little');
const turn = h.c.turn;
h.c.input.bargeIn();
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(new Float32Array(1024));
assert.equal(h.c.turn, turn);
h.worklet.feed(tone(1024, 0.005));
assert.equal(h.c.turn, turn + 1);
assert.equal(h.c.readTypedTurnInput(), undefined);
assert.equal(h.c.retiredReplyPending, true);
h.c.input.pushToTalkKeyHeld = false;
h.c.input.setMicrophoneEnabled(false);
assert.equal(ws.sent.filter((m) => m.realtimeInput?.activityStart).length, 1);
ws.message({ serverContent: { interrupted: true, turnComplete: true } });
assert.equal(h.c.retiredReplyPending, false);
});
test('rejected admitted PTT start fails closed instead of stranding a pending turn', async (t) => {
const h = await realAdapterSession(t),
ws = h.sockets[0];
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
ws.readyState = 0;
h.worklet.feed(tone(1024, 0.005));
await tick();
assert.equal(h.c.status, 'error');
assert.equal(h.c.userTurnPending, false);
assert.equal(h.c.replyPending, false);
assert.equal(ws.closed, true);
});
test('a silent physical hold cannot replace the current tool pointer; admitted released speech uses its owned snapshot', async (t) => {
const { createPointerTracker } = await import('./pointerContext.js');
let clock = 0;
const pointer = createPointerTracker({
element: { clientWidth: 1000, clientHeight: 500, addEventListener() {} },
pick: (x, y) => ({ ground: { lat: x / 10, lon: y / 10, heightM: 0 } }),
now: () => clock,
setTimer: () => 0,
clearTimer() {},
});
const h = await realAdapterSession(t, { pointer });
pointer.moveTo(100, 100);
const old = pointer.beginTurn('text');
pointer.moveTo(200, 200);
h.c.input.holdPointer();
h.c.input.beginPointerTurn('keydown');
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
assert.equal(pointer.activeSnapshot(), old);
h.worklet.feed(new Float32Array(640));
h.c.input.pushToTalkKeyHeld = false;
h.c.input.setMicrophoneEnabled(false);
h.c.input.releasePointerHold();
assert.equal(pointer.activeSnapshot(), old);
pointer.moveTo(300, 250);
h.c.input.holdPointer();
h.c.input.beginPointerTurn('keydown');
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(tone(640, 0.005));
h.c.input.pushToTalkKeyHeld = false;
h.c.input.releasePointerHold();
h.c.input.setMicrophoneEnabled(false);
assert.deepEqual(pointer.activeSnapshot().screenPx, { x: 300, y: 250 });
const contexts = h.sockets[0].sent.filter((m) => m.clientContent);
assert.equal(contexts.length, 1);
assert.match(contexts[0].clientContent.turns[0].parts[0].text, /30/);
});
test('a typed reply completes while its superseded silent PTT hold is still open', async (t) => {
const h = await realAdapterSession(t),
ws = h.sockets[0];
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(new Float32Array(640));
h.c.sendTextCommand('zoom out a little');
ws.message({ serverContent: { turnComplete: true } });
assert.equal(h.events.filter((e) => e.type === 'completion').length, 1);
h.c.input.pushToTalkKeyHeld = false;
h.c.input.setMicrophoneEnabled(false);
assert.equal(h.events.filter((e) => e.type === 'completion').length, 1);
assert.equal(h.c.pendingCompletionStatus, null);
});
test('typed voice-off completion is not held behind a superseded silent capture', async (t) => {
const h = await realAdapterSession(t),
ws = h.sockets[0];
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(new Float32Array(640));
h.c.sendTextCommand('turn voice off');
h.c.stopAfterReply = true;
h.c.postToolOutput = true;
ws.message({ serverContent: { turnComplete: true } });
assert.equal(h.c.status, 'idle');
assert.equal(ws.closed, true);
});
test('silent PTT release waits for asynchronous discard before presentation or Radio handoff', async (t) => {
const h = await realAdapterSession(t),
ws = h.sockets[0];
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(new Float32Array(640));
const deliver = h.worklet.port.onmessage,
queued = [];
h.worklet.port.onmessage = (e) => queued.push(e);
h.c.input.pushToTalkKeyHeld = false;
h.c.input.setMicrophoneEnabled(false);
let handoffs = 0;
h.c.radio.startPendingRadioHandoff = async () => {
handoffs++;
};
h.c.radio.pendingRadioPlaybackResult = {
ok: true,
radioPlaybackRequested: true,
};
h.c.postToolOutput = true;
ws.message({ serverContent: { turnComplete: true } });
assert.equal(h.events.filter((e) => e.type === 'completion').length, 0);
assert.equal(handoffs, 0);
for (const e of queued) deliver(e);
assert.equal(h.events.filter((e) => e.type === 'completion').length, 1);
assert.equal(handoffs, 0);
assert.equal(h.c.radio.pendingRadioPlaybackResult, null);
});
test('expiry cannot admit a voiced partial worklet tail or replace its pointer', async (t) => {
const h = await realAdapterSession(t),
ws = h.sockets[0];
h.c.sendTextCommand('zoom out a little');
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(tone(320, 0.005));
const before = ws.sent.length;
ws.message({ goAway: { timeLeft: '10s' } });
assert.equal(ws.sent.length, before);
assert.equal(h.c.forwardedActivityOpen, false);
assert.equal(h.c.captureOwner.settled, true);
assert.equal(h.c.captureOwner.admitted, false);
});
test('suppressed old native PCM is not reported as spoken after a silent claim', async (t) => {
const h = await realAdapterSession(t),
ws = h.sockets[0];
h.c.sendTextCommand('zoom out a little');
h.c.input.bargeIn();
h.c.input.pushToTalkKeyHeld = true;
h.c.input.setMicrophoneEnabled(true);
h.worklet.feed(new Float32Array(640));
h.c.input.pushToTalkKeyHeld = false;
h.c.input.setMicrophoneEnabled(false);
ws.message({
serverContent: {
modelTurn: {
parts: [
{ inlineData: { data: 'AAA=', mimeType: 'audio/pcm;rate=24000' } },
],
},
},
});
assert.equal(h.c.audio.diagnostics().outputChunks, 0);
assert.equal(h.c.modelSpoke, false);
ws.message({ serverContent: { turnComplete: true } });
assert.equal(
h.events.filter((e) => e.type === 'completion').at(-1).spoken,
false,
);
});