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

+32 -55
View File
@@ -1,6 +1,16 @@
import { HUD_LAYOUTS } from '../hudLayoutPolicy.js';
// Canonical action arguments. Descriptive wording is supplied separately.
import {
VOICE_CONTEXT_LAYER_IDS,
VOICE_QUERY_LAYER_IDS,
VOICE_TOGGLE_LAYER_IDS,
} from './layerManifest.js';
// Layer enums come from the voice layer manifest so every shipped layer is
// reachable; the manifest test keeps it in step with the layer catalog.
const toggleLayerIds = () => [...VOICE_TOGGLE_LAYER_IDS];
const schemas = [
{
name: 'fly_to_location',
@@ -46,6 +56,9 @@ const schemas = [
waitForArrival: {
type: 'boolean',
},
referent: {
type: 'integer',
},
},
},
},
@@ -124,25 +137,7 @@ const schemas = [
properties: {
layerId: {
type: 'string',
enum: [
'flights',
'military',
'earthquakes',
'satellites',
'rocket-launches',
'traffic',
'cctv',
'radio',
'bikeshare',
'ais-live-vessels',
'local-datacenters',
'local-dams',
'telegeography-submarine-cables',
'local-firms',
'fire-perimeters',
'alpr-cameras',
'local-adsb',
],
enum: toggleLayerIds(),
},
enabled: {
type: 'boolean',
@@ -159,23 +154,7 @@ const schemas = [
properties: {
layerId: {
type: 'string',
enum: [
'flights',
'military',
'earthquakes',
'satellites',
'traffic',
'cctv',
'radio',
'bikeshare',
'ais-live-vessels',
'local-datacenters',
'local-dams',
'telegeography-submarine-cables',
'local-firms',
'fire-perimeters',
'alpr-cameras',
],
enum: toggleLayerIds(),
},
},
},
@@ -197,6 +176,8 @@ const schemas = [
'scene-panel',
'pp-toggles',
'global-context-panel',
'weather-panel',
'recent-imagery-panel',
],
},
open: {
@@ -276,16 +257,14 @@ const schemas = [
properties: {
scope: {
type: 'string',
enum: ['auto', 'selected', 'in_view'],
enum: ['auto', 'selected', 'in_view', 'pointer'],
},
referent: {
type: 'integer',
},
layerId: {
type: 'string',
enum: [
'local-datacenters',
'local-dams',
'telegeography-submarine-cables',
'local-firms',
],
enum: [...VOICE_CONTEXT_LAYER_IDS],
},
limit: {
type: 'number',
@@ -552,6 +531,9 @@ const schemas = [
layerId: {
type: 'string',
},
referent: {
type: 'integer',
},
},
required: ['query'],
},
@@ -785,17 +767,7 @@ const schemas = [
type: 'array',
items: {
type: 'string',
enum: [
'flights',
'military',
'ais-live-vessels',
'local-firms',
'earthquakes',
'satellites',
'local-datacenters',
'local-dams',
'fire-perimeters',
],
enum: [...VOICE_QUERY_LAYER_IDS],
},
},
scope: {
@@ -804,7 +776,7 @@ const schemas = [
properties: {
kind: {
type: 'string',
enum: ['view', 'region', 'radius', 'anywhere'],
enum: ['view', 'region', 'radius', 'anywhere', 'pointer'],
},
name: {
type: 'string',
@@ -818,11 +790,16 @@ const schemas = [
properties: {
lat: {
type: 'number',
minimum: -90,
maximum: 90,
},
lon: {
type: 'number',
minimum: -180,
maximum: 180,
},
},
required: ['lat', 'lon'],
},
},
},