mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
feat(voice): voice core — honest layer reach, spoken summary with on-screen card, narration, point-and-ask
- Voice layer manifest (src/voice/layerManifest.js) generates the layer enums, aliases and analyst field hints; a test fails when a catalog layer has no entry. - analyst_query validates fields, operators, units, values and scopes, counts up to 250,000 loaded records per layer, reports complete/partial/unanswered, tells LAYER_OFF / NOT_READY / FEED_UNAVAILABLE apart from zero, refuses mismatched follow-ups and never lets a superseded query replace follow-up memory. Seven more layers expose analyst records. - Tool results carry a code-built say line and a display card; the voice card in the mic control shows captions, plan steps and the result (src/voice/resultDisplay.js is the one adapter). Slow tools narrate their current step out of band; holding Space while the assistant talks cuts it off. Turn spans go to the debug log; caption transcription is metered; the log omits what was said unless GEV_VOICE_LOG_CONTENT=1. - Point and ask: the Space-down pointer snapshot resolves "this", "that one" and "around here" through 'pointer' targets, and "the second one" through referent:n from the last numbered list. - Prompt states each policy once (instructions + tools 48.5k -> 46.7k chars). - Voice benchmark harness (scripts/qa-voice-bench.mjs, scripts/voice-bench/) shares its phrase table and grading with scripts/qa-voice-routing.mjs.
This commit is contained in:
1 parent
e7707d9a0f
commit
a19897ad15
97 files changed
+14343
-755
No files matched your search
@@ -3678,6 +3678,50 @@ test('a genuinely different refused call still gets its own output', async () =>
|
||||
assert.deepEqual(outputs, ['call_one', 'call_two'], 'each distinct call is answered');
|
||||
});
|
||||
|
||||
test('a claimed Space hold barges in on the assistant; a short tap never does', (t) => {
|
||||
const f = createPushToTalkFixture(t);
|
||||
const canvas = pushToTalkTarget({ tagName: 'CANVAS', id: 'world-overlay-canvas', tabIndex: 0 });
|
||||
let bargeIns = 0;
|
||||
f.controller._turns.bargeIn = () => {
|
||||
bargeIns += 1;
|
||||
return true;
|
||||
};
|
||||
// First hold starts the push-to-talk session; nothing to interrupt yet.
|
||||
f.key('keydown', canvas);
|
||||
f.advance(PUSH_TO_TALK_HOLD_DELAY_MS);
|
||||
f.key('keyup', canvas);
|
||||
assert.equal(bargeIns, 0);
|
||||
// A short tap during the reply stays a tap.
|
||||
f.key('keydown', canvas);
|
||||
f.advance(PUSH_TO_TALK_HOLD_DELAY_MS - 1);
|
||||
f.key('keyup', canvas);
|
||||
assert.equal(bargeIns, 0);
|
||||
// Only the 500 ms claim interrupts, and the microphone opens as before.
|
||||
f.key('keydown', canvas);
|
||||
f.advance(PUSH_TO_TALK_HOLD_DELAY_MS);
|
||||
assert.equal(bargeIns, 1);
|
||||
assert.equal(f.microphone.enabled, true);
|
||||
f.key('keyup', canvas);
|
||||
// Radio's claim is read before Radio is paused, and a held handoff is
|
||||
// never interrupted.
|
||||
const order = [];
|
||||
const input = f.controller._input;
|
||||
input.mayClaimSpeaker = () => {
|
||||
order.push('claim');
|
||||
return false;
|
||||
};
|
||||
const pause = input.pauseRadioForVoice;
|
||||
input.pauseRadioForVoice = (...args) => {
|
||||
order.push('pause');
|
||||
return pause(...args);
|
||||
};
|
||||
f.key('keydown', canvas);
|
||||
f.advance(PUSH_TO_TALK_HOLD_DELAY_MS);
|
||||
assert.deepEqual(order.slice(0, 2), ['claim', 'pause']);
|
||||
assert.equal(bargeIns, 1, 'no barge-in while Radio holds the speaker');
|
||||
f.key('keyup', canvas);
|
||||
});
|
||||
|
||||
const testPlaceSearch = () => createStandalonePlaceSearch({ resolveApiKey: () => globalThis.window?.__GOOGLE_MAPS_API_KEY__ });
|
||||
function createGevActionRunner(options) { return createActionRunner({ placeSearch: testPlaceSearch(), ...options }); }
|
||||
function controlRadio(viewer, manager, args, options) { return runControlRadio(viewer, manager, args, { placeSearch: testPlaceSearch(), ...options }); }
|
||||
Reference in new issue
Block a user