Wraps RealtimeClient with reconnect-on-drop (ResilientRealtimeClient), adds
a MockRealtimeProvider so client/animation work doesn't need a live OpenAI
key, and introduces "optional package" as a third module-layering kind
alongside core/project — humanoid is the first instance, providing a
renderer-agnostic avatar-state reducer and ARKit blend-shape animation
compositor that future eye look-at/blink/lip-sync libraries can build on
without forcing that surface onto non-humanoid (e.g. 2D) projects.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Centralizes env parsing/validation into a single loadConfig() (config.ts),
replacing scattered process.env reads across server.js and dev-plugin.ts and
making dev fail fast on a missing OPENAI_API_KEY the same way prod already
did. Analytics gains a master on/off switch (a new NoopAnalyticsRecorder,
selected when ANALYTICS_ENABLED=false) plus independent category toggles for
messages/tool calls/events, so a deployment can control what gets logged
without writing a custom recorder. Session persona (model/instructions)
moves out of the core defaults.ts into project-owned persona.ts, mirroring
the existing tools.ts split and fixing a prior inconsistency where a
branched project was expected to hand-edit a core file. Client tool timeout,
token TTL, model override, and default voice are now env-configurable
instead of hardcoded constants.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Records session start/end, conversation messages, tool calls, and
errors via better-sqlite3, hooked into RealtimeSession's existing
choke points so no client-side changes are needed. Also fixes a
pre-existing gap where an upstream-initiated disconnect only forwarded
session.closed to the browser without ever calling close(), so no
session end time was ever recorded for that path.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Extends the realtime session protocol with tool.call/tool.result/response.trigger
so the model can invoke functions that run either on our server or, relayed
through the session, in the browser (e.g. DOM interaction) — a single
outstanding-call counter lets a turn mix both without racing the model's
continuation. createToolRegistry enforces at startup that a client-only tool
can never accidentally be backed by server logic.
Also introduces a project/ namespace alongside core/, server/core/, and
client/core/, for code specific to whichever client project branches from
this template. Core never imports project; the two composition roots
(server.js, vite.config.ts) do the merge instead, so template updates can
still be pulled into a branched project without touching core files.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Provider-agnostic session layer for the base project: a shared client/server
wire protocol, a RealtimeProvider adapter interface, and an OpenAI Realtime
implementation of it, wired through a WebSocket relay (browser <-> our
SvelteKit server <-> OpenAI) so the API key never reaches the browser and
future providers/pipelines can be added without touching client code.
Switches the adapter to adapter-node and adds a custom server.js + dev-mode
Vite plugin, since SvelteKit has no native WebSocket support yet.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>