src/ante/static/ ships the conversation app's full interface — talk, personality
picker, tool access, settings — as ES modules already wired to the JSON-RPC methods
console.py registers. None of it was reachable: the scaffolder's OpenAI key page held
index.html, so the views had no shell to mount into, and style.css defined none of
their 95 classes.
Adds the shell those modules expect (#view-outlet, the header's data-action controls,
the personality badge hooks) and the stylesheet for every class, in both themes so the
host's ?theme= parameter works either way. The header spans the viewport rather than
the shell's column, so content no longer scrolls past it on both sides.
The displaced page's 0G remediation moves into the settings view's current state,
shown only while the backend is disconnected, and main.js goes with the page it drove.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QvUxqcAivGZmgnMKiGMa4B
Replace the stale OpenAI key form in the settings UI
The settings page was scaffolder output for a backend this app does not use. It
asked for an OpenAI API key and posted it to /validate_api_key and
/openai_api_key, neither of which exists in the current template, so every save
failed with 'Failed to validate/save key'. Ante has no API key at all: 0G
requests are paid per call from the user's own wallet.
The page now reports the state of the 0G realtime backend, tells the user how to
start it when it is not running, and points at sub-account funding as the usual
cause of a server that runs but will not answer.
Surface 0G provider refusals instead of failing silently
0G providers report refusals such as an unfunded sub-account in the body of an
HTTP 200, so raise_for_status() passes and the transcript came back empty. A
robot that has no funds and a robot that heard nothing were indistinguishable:
both produced silence with no explanation.
Both the transcription and chat clients now inspect the response body and raise
ZeroGRequestError, which the realtime layer forwards to the app as an error
event carrying the provider's own remediation command.
Verified against the live unfunded whisper provider: the insufficient-balance
message now reaches the client as a provider_refused error event.
Ante answers questions out loud with its language model running on the 0G
Compute Network instead of a hosted provider.
The conversation app is an OpenAI Realtime API client, so rather than rewrite
its conversation loop, this adds a local server that speaks the realtime
protocol and is backed by 0G. The app reaches it through two lines of .env;
its tool system, movement manager, personality system and web UI are unchanged.
The realtime API is speech-to-speech over one socket while 0G exposes ordinary
request/response models, so the server reassembles the stages behind that
interface: 0G Whisper for hearing, 0G glm-5.2 for thinking, and Piper on the
robot for speaking. Speech synthesis is local because the network has no
synthesis provider; transcription is remote because the Wireless robot's CM4
cannot run Whisper.
Signing and settlement are delegated to `0g-compute-cli inference serve`, so no
private key or single-use request header is handled here.
Reasoning is stripped before sy…