Commit Graph
5 Commits
Author SHA1 Message Date
Bilawal Sidhu a19897ad15 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.
2026-09-28 21:19:23 -05:00
Sameh Khamis dd627891f8 fix: complete debug-log request bounds 2026-09-20 19:21:22 -07:00
Pedro Lobato 44817e1286 fix(realtime): bound the debug-log sink and stop blocking on its writes
Ported onto the split provider layout: the route now lives in
server/providers/openai/debug-log.js and its state belongs to the handler
the factory returns rather than to module scope.

/api/realtime/debug-log is the one route in its family left unhardened.
Both siblings enforce a limiter through openai/rate-limit.js, and this was
the only handler still writing with fs.appendFileSync on the request path.

- Always-on per-IP limiter (120/min, 400 global). Deliberately not the
  opt-in openAiRateLimiter(): that one defaults to unlimited so throttling
  cannot silently change what a user spends, and this sink spends disk and
  event-loop time rather than provider quota.
- Serialized async appends with a 32 MB rotation ceiling and one retained
  generation. REALTIME_DEBUG_LOG_MAX_BYTES caps a single request body; it
  never bounded the file those bodies accumulate into, so any local page
  could grow .gev-logs/realtime-conversations.jsonl for as long as the dev
  server ran. Serializing also closes a read-then-write race on the size
  check, where concurrent callers all stat under the ceiling and none
  rotates.
- Generic 400/500 answers separating a malformed record or oversized body
  from a failed write, instead of echoing error.message — an errno and an
  absolute path for an fs failure.
- readRequestBody marks an oversized body with code 'BODY_TOO_LARGE', the
  marker its sibling readRequestBodyCapped already sets, so the two cases
  are distinguishable without matching on text.

Coverage extends src/tooling/localServices.test.mjs, which already drives
the real handler over a temporary sourceRoot. Both new tests fail on the
previous implementation and pass with this one.

Refs #23. Does not add authentication: these proxies have no auth
mechanism today, so introducing one is a maintainer design decision.
2026-09-14 21:24:12 -05:00
Sameh Khamis 5223b6df5b style: format extracted local services 2026-09-12 13:01:49 -07:00
Sameh Khamis 638902296a refactor: separate local voice handlers and instructions 2026-09-12 12:59:39 -07:00