I gave it a Dockerfile and an image, which mints another thing to build, deploy,
route and operate for one package. api.hanzo.ai is the AI surface and already
serves /v1/audio/*; the realtime socket belongs beside them, reached the one way
everything else is.
The gate stays. This repo had none, its suite opens no database, and a finished
service that nothing compiles on push is how it came to be complete and
unreachable at the same time.
Co-authored-by: Hanzo Dev <[email protected]>
Both dependencies are public and on the proxy. The private-module apparatus I
copied from a sibling — GOPRIVATE, a git rewrite, a build secret — was for a
problem this tree does not have, and it is the half of the build that cannot
explain itself when it fails.
Co-authored-by: Hanzo Dev <[email protected]>
The service was finished and measured — answer latency, chunking, the three
seams — and had no Dockerfile, no gate and no image. So it ran nowhere:
/v1/voice answers 404 in production while the code sits complete in main, and
nothing that wants a spoken conversation can have one.
The gate here runs the tests, not just a compile. Nothing in this tree opens a
database; the seams are interfaces and talk_test.go drives them with stand-ins,
so the suite is hermetic and belongs on every push rather than in a lane of its
own.
Everything it reaches is already ours and needs no argument: speech at
speech.hanzo.svc, the model through api.hanzo.ai, JWKS from hanzo.id. Audio is
billed to whoever spoke, never to a service account.
Co-authored-by: Hanzo Dev <[email protected]>
Audio in, audio out, on an IAM bearer, billed to whoever spoke. speech holds
the models; this holds the conversation.
The wire is the OpenAI realtime protocol so existing clients work unchanged.
hanzoai/go-openai-realtime already carries the event types but is a client, so
it can only unmarshal the server's half; Read supplies the other direction.
A browser cannot put a header on a WebSocket, so the bearer is spent on a POST
and the URL carries a single-use thirty-second ticket naming a principal
already verified here. It has no claims and cannot be verified elsewhere, so a
copy lifted from a log buys nothing.
Replies are synthesised a sentence at a time: 452 ms to first sound against
2267 ms for a whole reply, and every sentence after the first is free because
synthesis outruns speech. Measured end to end at 1.15-1.55 s from the speaker
stopping, of which 500 ms is the silence detector that Turn exists to replace.
Turn, Mind and Meter are the seams. Hush ends a turn on silence alone, which
cuts people off mid-thought and waits through gaps it should have taken; it is
there so the surface works while a detector that reads intent is built.
Co-authored-by: Hanzo Dev <[email protected]>