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:
Bilawal Sidhu committed 2026-09-28 21:19:23 -05:00
1 parent e7707d9a0f
commit a19897ad15
97 files changed
+14343 -755

No files matched your search

+44
View File
@@ -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 }); }