HTTP channel
- Package
@mercury-fw/channel-http- Role
- Channel
- Version
- 0.13.2
bun add @mercury-fw/channel-http| Variable | What it is |
|---|---|
HTTP_SURFACE_PORT | Port of the HTTP surface (default 4100) |
HTTP_SURFACE_CORS_ORIGIN | Origin allowed to call the HTTP surface from a browser, if any |
HTTP_SURFACE_PUBLIC_URL | Address people's browsers reach the HTTP surface at, for logging in to the services plugins act on as them |
HTTP_SURFACE_RESUME_MAX_CHARS | Characters of a reopened conversation that come back to the model (empty: the core's SESSION_RESUME_MAX_CHARS, 0: off) |
The HTTP channel lets any program talk to the agent: a web page you build, a mobile app, a script. Each message is one request, and the answer comes back as it’s written, as a stream of Server-Sent Events (a standard way for a server to send a sequence of messages over one HTTP response). Next to it there are routes to confirm actions and to read what the agent holds: conversations, the wiki, the memory, its plugins.
It needs an auth provider to tell who is calling, and doesn’t start without one: OpenID Connect for real people, static tokens to try it on your machine.
Trying it on your machine
Section titled “Trying it on your machine”Create an app with the channel and static tokens:
bun create mercury-agent http-agent --channels http --auth static --yescd http-agentcp .env.example .envIn .env, fill in OLLAMA_MODEL as in Your first agent, and give a test
user a token:
AUTH_STATIC_TOKENS={"alice-token": {"id": "alice", "displayName": "Alice"}}Start it, and the log says the channel is up:
bunx mfw startbunx mfw logs mercurymercury-1 | [channel] http startedNow send a message as Alice. -N makes curl print the events as they arrive:
curl -N -X POST localhost:4100/turn \ -H 'Authorization: Bearer alice-token' \ -H 'Content-Type: application/json' \ -d '{"text": "Hi! In one sentence, who are you?", "conversationId": "first"}'The answer arrives in pieces (text events), then whole (final):
event: textdata: {"chunk":" documents"}
event: textdata: {"chunk":"."}
event: finaldata: {"text":"I am Mercury, an internal assistant with access to the team's wiki documents."}Send the same conversationId again to continue the conversation. A wrong token gets 401 before anything runs.
Adding it by hand
Section titled “Adding it by hand”An app created with --channels http has all of this already. In an existing app, bun add @mercury-fw/channel-http and an auth provider (here @mercury-fw/auth-static), and declare both:
import { httpChannel } from "@mercury-fw/channel-http";import { staticAuth } from "@mercury-fw/auth-static";
channels: [httpChannel],auth: staticAuth,The channel listens inside the container, so the compose file has to publish its port on your machine. Under the
mercury service in docker-compose.yml:
ports: - "${HTTP_SURFACE_PORT:-4100}:${HTTP_SURFACE_PORT:-4100}"What a chat interface needs to know
Section titled “What a chat interface needs to know”- Every conversation belongs to whoever opened it. The same
conversationIdsent by someone else is a conversation of their own. - Confirmations arrive as a
pendingevent with a token for each choice; send the token back as the next message’stext, or toPOST /confirm. See Confirmations. - Logins to the services plugins act on as the person arrive as a
loginevent with a link. They needHTTP_SURFACE_PUBLIC_URL, the address people’s browsers reach the channel at, because the service sends them back to<HTTP_SURFACE_PUBLIC_URL>/login/callback. - Browsers on another origin can call it: set
HTTP_SURFACE_CORS_ORIGINto your interface’s origin. - Languages. The texts the person reads that aren’t the model’s (a status line, a choice’s label, a
confirmation’s reply) come in their language: the one they asked the agent for, else the one the request’s
Accept-Languageheader asks for, which browsers send on their own. A plain confirmation has one choice with an empty label, which your interface words itself (a “Confirm” button), and when the model wrote nothing because the turn is waiting for a confirmation, thefinalevent says so withpendingNote, so your interface can hide that sentence next to its own confirmation. See Languages. - The time. The model reads each message with the time the person wrote it, in their time zone: send the
browser’s in an
X-Time-Zoneheader (Intl.DateTimeFormat().resolvedOptions().timeZonegives it), and offer it in your settings withPATCH /me, which saves it for the person. A zone they saved wins over the header. See The time where the person is. - Which Mercury it is.
GET /versionanswers the framework’s version ({ "ok": true, "version": "0.59.0" }) with no token, so your interface can show it anywhere, the login page included.
The HTTP API reference describes every route and event.