Glasses-first runtime + Memory API + dataset spine#3
Draft
wdwd720 wants to merge 2 commits into
Draft
Conversation
Add a real (semi-real) audio pipeline alongside the existing simulator:
audio source → features → classifier → cooldown → signal mapper →
liveAudioDecision → existing priority/cue/action engines → HudOutputAdapter.
Audio layer (src/audio/):
- audioTypes.ts AudioFrame, AudioFeatures, AudioClassification,
AudioDetectionEvent, LiveContextOverride, snapshot
- audioSource.ts Web Audio mic + getDisplayMedia tab/system audio +
decodeAudioData file path with offline Goertzel
spectrum so file uploads use the same features
- audioFeatureExtractor RMS, peak, ZCR, dominant freq, energy bands,
tonality, beep/siren/speech/transient scores
- audioClassifier.ts Pluggable interface + RuleBasedAudioClassifier
(frequency-variation tracker for siren detection,
burst tracker for timer beeps) + PretrainedAudio
ClassifierStub hook for a future YAMNet swap
- audioSignalMapper.ts Per-label routing thresholds, maps to Hearer
AudioSignal (knock/speech_nearby added)
- audioController.ts Stateful orchestrator: source mgmt, cooldown,
debounce, auto-route toggle, manual route
- audioFixtures.ts Synthetic beeps/sirens/horn/knock/doorbell/
applause/speech-like buffers + WAV encoder so
fixtures run through the same decode pipeline
Glasses boundary (src/glasses/):
- hudOutputAdapter.ts interface
- simulatorHudAdapter.ts active in this build
- evenG2AdapterStub.ts wire-format only (no BLE/SDK in this build)
Engine extensions:
- types.ts: AudioEvent now includes "knock" and "speech_nearby"
- liveAudioDecision.ts: single-AudioSignal + override → DecisionResult
using the existing scenario engines; never
hallucinates a transcript from speech-like audio
- cueCompressor.ts: new live-audio compressors (timer-unknown, alarm,
loud-alert-unknown, doorbell-unknown, knock,
speech-nearby, applause, laughter)
- priorityEngine.ts: live_* scenario rules
- actionRouter.ts: live_* scenario routing (vibration sims for
physical alerts; awareness only for speech/crowd)
UI (src/components/audio/):
- AudioAwarenessPanel source controls, level meter, classifier status,
live context override, fixtures, last detection,
auto-route toggle, manual route button, log
- AudioLevelMeter, AudioFileDropzone, AudioClassifierStatus,
AudioDetectionLog
App wiring:
- App.tsx: refs for memory and override so the AudioController always sees
the latest state; subscribes to its decisions and routes them through
both the simulator HUD adapter and the Even G2 stub. Existing scenario
panel, auto-demo, and reset still work.
Tests (Vitest): 23 / 23 passing across cue compressor, priority engine,
action router, audio signal mapper, rule-based classifier, and the live
audio decision pipeline (kitchen vs unknown context, siren on street,
knock at home, speech_nearby never hallucinates a transcript).
Co-authored-by: wdwd720 <wdwd720@users.noreply.github.com>
Pivot Hearer to a glasses-first architecture: G2 mic -> Hearer brain ->
G2 HUD. Browser mic / file uploads / generated fixtures are now clearly
labelled DEV FALLBACKS, not the product surface.
Glasses-first runtime (src/glasses/):
- g2RuntimeTypes.ts WorldAudioInputAdapter + HudOutputAdapter
interfaces with isPrimaryTarget hierarchy.
- g2RuntimeController.ts Owns the active input/output adapter pair,
probes the Even Hub bridge once on boot,
routes G2 PCM frames through the same
feature/classifier/world-state/cue pipeline.
- evenHub/ Bridge probe (dynamic, SDK-optional, no hard
dependency on @evenrealities/even_hub_sdk),
Even G2 audio input adapter (audioControl +
onEvenHubEvent -> PCM16 LE -> AudioFrame),
Even G2 HUD output adapter (showText /
updateText / ensureCuePage+setCuePageText),
evenHubPcm.ts (PCM16 LE -> Float32 with
robust event-shape extraction).
- simulator/ Browser mic / display / file fallback +
simulator HUD that mirrors the same payload
the real glasses would receive.
World-state engine (src/engine/worldStateEngine.ts):
- Glasses-first inference: same beep -> different cue depending on
cooking routine, location, time of day. Stays honest about certainty
('Check stove', not 'Stove is on'). Used by liveAudioDecision to
bump priority when a saved cooking routine matches.
Memory API + Hearer brain integration:
- server/ Fastify + better-sqlite3 (SQLite) with JSON fallback. Routes
for profile/people/items/locations/routines/commitments/events/cues/
audio-detections/cue-feedback/memory-extract/memory-reset.
- shared/ types + rule-based memory extractor used by both server and
browser.
- src/api/hearerApi.ts + src/memory/{api,local,createMemory}Client.ts
-- frontend probes the API and falls back to localStorage.
- decide() and decideFromLiveAudio() now consume persistedRoutines and
surface 'Saved routine matched' in the reasoning trail. Leaving-home
scenario uses the saved routine action label when present (e.g.
'bring laptop' instead of 'keys + laptop').
- App.tsx wires the memory client, G2 controller, MemoryCommandBox,
cue feedback persistence, dataset/model status card, and the System
pipeline card.
UI:
- New G2RuntimePanel: input/output target rows, primary/fallback chips,
bridge-detected status, Start/Stop/Send-test-cue/Use-fallback buttons.
- New MemoryCommandBox: 'Tell Hearer what to remember…' with example
buttons; submit triggers /api/memory/extract and a tiny HUD
confirmation cue.
- SystemPipelineCard: 4-step glasses-first flow.
- DatasetModelCard: training/eval status; explicitly NOT the runtime.
- AudioAwarenessPanel re-labelled 'Audio fallback (dev)'; mic/tab
buttons now say '(fallback)' and the fixtures section is labelled
'Deterministic test inputs'. Direction selector added for simulated
360 awareness.
- MemoryPanel reads persisted summary (routines, commitments, items)
and falls back to in-engine demo memory.
- ActionPanel adds cue-feedback buttons (helpful/too_much/wrong/missed)
that POST to /api/cue-feedback.
ML / dataset spine (training/eval ONLY -- never the runtime):
- ml/hearer_labels.yaml: Hearer label taxonomy V1 with cueTemplates,
defaultPriority, actionType, minConfidenceForInterrupt, and
ESC-50/UrbanSound8K/FSD50K source mappings.
- ml/scripts/{prepare_esc50,prepare_urbansound8k,prepare_fsd50k,
build_hearer_manifest,validate_manifest,summarize_manifest,
export_label_map}.py: build a unified JSONL manifest, validate, and
generate src/audio/hearerLabelMap.generated.ts.
- ml/training/{train_audio_baseline,eval_audio_baseline,
export_model_stub}.py: CPU-friendly log-mel + sklearn baseline.
- ml/requirements.txt + ml/README.md cover setup. Datasets are NEVER
auto-downloaded.
Audio model adapter boundary:
- src/audio/modelAdapters/audioModelAdapter.ts:
RuleBasedModelAdapter + LocalTrainedModelAdapterStub +
PretrainedModelAdapterStub.
Tests (Vitest, 46/46 passing across 13 suites):
- evenHubPcm: PCM16 LE -> Float32, Int16Array passthrough, empty/odd
inputs, AudioFrame at 16 kHz with correct duration, event-shape
extraction across audioEvent / sysEvent.audioEvent / pcm / samples[].
- g2RuntimeController: simulator HUD active when bridge unavailable;
start/stop don't crash without a bridge.
- g2AudioDecision: G2 mic + cooking memory -> 'Kitchen timer beeping. /
Check stove.' (urgent, physical); same beep without context ->
softer cue; speech_nearby never hallucinates a transcript.
- worldStateEngine: cooking-routine match -> urgent + check-stove;
unknown context -> softer cue; never asserts 'stove is on'.
- hudOutputAdapter: payload is just text+priority+actionType+ttlMs;
simulator and Even G2 adapters agree on payload.
- memory extractor: routine, commitment, pharmacy routine,
ambiguous-input notes.
- hearerLabelMap.generated: core labels present; ESC-50/UrbanSound8K
source mappings round-trip.
Build + tests both pass. Server-bound components are not bundled into
the frontend; the frontend probes the API at runtime and falls back to
localStorage when offline.
Co-authored-by: wdwd720 <wdwd720@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Glasses-first
Pivots Hearer to a glasses-first architecture and lands the supporting layers:
Browser mic, tab/system audio, file uploads, and generated fixtures are now clearly dev fallbacks, not the product surface. The simulator HUD and the real Even G2 HUD adapter receive the same payload —
{ text, priority, actionType, ttlMs }— so the dashboard always reflects what the glasses would show.What's in here
Glasses-first runtime (
src/glasses/)g2RuntimeTypes.ts—WorldAudioInputAdapter(even_g2_micisisPrimaryTarget: true; browser mic / file / fixtures are fallbacks) andHudOutputAdapter(even_g2_hudprimary, simulator fallback).g2RuntimeController.ts— owns the active input/output adapters, probes the Even Hub bridge once on boot, routes G2 PCM frames through the same feature → classifier → world-state → cue pipeline as everything else.evenHub/— bridge probe (dynamic, SDK-optional, no hard dependency on@evenrealities/even_hub_sdk), Even G2 audio input adapter (audioControl + onEvenHubEvent → PCM16 LE → AudioFrame), Even G2 HUD output adapter (showText/updateText/ensureCuePage+setCuePageText), andevenHubPcm.ts(PCM16 LE → Float32, robust event-shape extraction).simulator/— browser-mic / display-audio / file fallback + simulator HUD that mirrors the same payload.World-state engine (
src/engine/worldStateEngine.ts)The actual intelligence. Same beep produces a different cue depending on:
Stays honest about certainty —
Check stove, neverStove is on. Plugs intodecideFromLiveAudioand bumps priority to urgent when a saved cooking routine matches.Memory API + brain integration
server/— Fastify +better-sqlite3(SQLite) with JSON fallback. Routes for profile / people / items / locations / routines / commitments / events / cues / audio-detections / cue-feedback / memory-extract / memory-reset.shared/— types and rule-based memory extractor used by both server and browser.src/api/hearerApi.ts+src/memory/{api,local,createMemory}Client.ts— frontend probes the API and falls back tolocalStoragecleanly.decide()anddecideFromLiveAudio()now consumepersistedRoutinesand surfaceSaved routine matchedin the reasoning trail. The leaving-home compressor uses the saved routine action label when present (e.g.bring laptopinstead ofkeys + laptop).UI
G2RuntimePanel— input/output target rows with primary/fallback chips, bridge-detected status, Start/Stop/Send-test-cue/Use-fallback buttons.MemoryCommandBox— "Tell Hearer what to remember…" with example one-click buttons; submit triggers/api/memory/extractand a tiny HUD confirmation cue.SystemPipelineCard— 4-step glasses-first flow.DatasetModelCard— training/eval status; explicitly not the runtime.AudioAwarenessPanelre-labelled Audio fallback (dev); mic/tab buttons say(fallback); fixtures labelled "Deterministic test inputs". Adds a direction selector for simulated 360 awareness.MemoryPanelreads the persisted summary (routines / commitments / items) and falls back to in-engine demo memory.ActionPaneladds cue-feedback buttons (helpful/too_much/wrong/missed) that POST to/api/cue-feedback.ML / dataset spine (training/eval ONLY — never the runtime)
ml/hearer_labels.yaml— Hearer label taxonomy V1 withcueTemplates,defaultPriority,actionType,minConfidenceForInterrupt, and ESC-50 / UrbanSound8K / FSD50K source mappings.ml/scripts/{prepare_esc50, prepare_urbansound8k, prepare_fsd50k, build_hearer_manifest, validate_manifest, summarize_manifest, export_label_map}.py— build a unified JSONL manifest, validate, and generatesrc/audio/hearerLabelMap.generated.ts.ml/training/{train_audio_baseline, eval_audio_baseline, export_model_stub}.py— CPU-friendly log-mel + sklearn baseline.ml/requirements.txtandml/README.mdcover setup. Datasets are never auto-downloaded.Audio model adapter boundary
src/audio/modelAdapters/audioModelAdapter.tsships:RuleBasedModelAdapter(active),LocalTrainedModelAdapterStub(waits forml/training/artifacts),PretrainedModelAdapterStub(YAMNet/TF.js plug point).Tests
npm test→ 46 / 46 passing across 13 suites:evenHubPcm— PCM16 LE → Float32,Int16Arraypassthrough, empty/odd inputs, AudioFrame at 16 kHz with the right duration, event-shape extraction acrossaudioEvent/sysEvent.audioEvent/pcm/samples[].g2RuntimeController— simulator HUD active when bridge unavailable; start/stop don't crash without a bridge.g2AudioDecision— G2 mic + cooking memory →Kitchen timer beeping. / Check stove.(urgent, physical); same beep without context → softer cue;speech_nearbynever hallucinates a transcript.worldStateEngine— cooking routine match → urgent + check-stove; unknown context → softer; never asserts hazard certainty.hudOutputAdapter— payload is justtext + priority + actionType + ttlMs; simulator and Even G2 adapters agree on payload.hearerLabelMap.generated— core labels present; ESC-50 / UrbanSound8K source mappings round-trip.npm run build→ success (~249 kB JS gzipped to ~75 kB).What is not in here
unavailablewhen the SDK isn't present. The boundary is in place; a real SDK swap is a single-file change.Check stove), never asserts hazards (Stove is on).How to run
Killer demo
Cooking timer safety cueroutine.Kitchen timer beeping. / Check stove.— URGENT / PHYSICAL — because the world-state engine matched the saved cooking routine.Timer beeping. / Check nearby..