The web console is the app
nanomuse serveserves at/— the front door of the desktop app and of a self-hosted runtime (app.md). This page is about one part of it: how it picks the model that answers, and what it offers when the model lacks something. The guide for making a key is own-key.md.
The console reads the same list of providers as the phones, the desktop and the
relay: nanomuse/llm/providers.json (contract
C11). Each provider says what one key there covers — chat, vision (the
hands read screenshots), image (the avatar studio's pictures), video (its
clips) — and which sign-ins it has besides a key. The console asks the runtime
first (GET /api/providers, which also says which slots are configured today
and what that covers) and falls back to the copy bundled at build time on an
older runtime, with nothing known about what is configured. web/src/providers.ts
is the module; web/src/providers.test.ts checks the ordering, the mapping
and the sentences.
Connections → Chat model. The provider tiles are the runtime's presets, the
region's first pick first (Alibaba Cloud Bailian on the mainland, OpenRouter
elsewhere — region.ts). Under the tiles the chosen
provider's line from the catalogue says what its key covers and what to know
about it (the Kimi editions, the OpenRouter Image API, the ChatGPT caveat). The
Hands model picker lists models that see; a provider without vision gets
the one sentence instead of a blind hands model. Under Pictures and clips,
a provider without image or video shows the sentence in place of the
picker; one with them shows Automatic — the catalogue's default so you know
what Automatic will draw with. A Proxy (optional) field under them takes an
http://host:port, https:// or socks5:// address for this provider's
requests only ([llm] proxy; nanoMuse Cloud never goes through it, a SOCKS
address needs httpx[socks] on the runtime); a saved password comes back as
dots, and an emptied field clears it.
Connections → Or sign in with a ChatGPT plan. The card asks the runtime to
start the Codex sign-in (POST /api/chatgpt/login → {url}), opens the page
in a new tab, polls GET /api/chatgpt/status every two seconds for up to ten
minutes, and when the tokens are in the runtime's store offers Use it for the
chat ([llm] provider = "chatgpt") and Sign out of ChatGPT
(POST /api/chatgpt/logout). The card says what the sign-in covers — chat and
the hands, not pictures or clips — and carries the honest line about OpenAI's
terms. A runtime without these routes answers 404; the card then names the
command to run in a terminal, nanomuse chatgpt login, instead of pretending.
The sign-in's callback lands on port 1455 of the machine the runtime runs on.
When the browser cannot reach it (a runtime on another computer, or the port
taken — port_bound: false in the login's answer), the browser ends on an
address that will not load; the card has a box for that address and hands it
to the runtime (POST /api/chatgpt/callback {url}; a stale link is 400
state_mismatch, a login older than ten minutes 409 no_login). The box is
there in every case, with a sentence saying why when the port could not be
bound (configuration.md).
The allowance card (Account, and in the chat on allowance_exhausted) has
three ways on: Use your own model key with the region's first pick, a Set it
up that opens Connections on that provider, Get a key from …, the guide, and
under Other providers and what each key covers the rest of the region's list
(the relay's guidance.providers when the relay sends it, relay 0.21; else the
catalogue's) each with its covers line, its own Set it up and key link;
Sign in with a plan you already pay for with the ChatGPT card inline; and
the invitation. The 80 % heads-up and the first-sign-in sheet point the same
way.
Avatar studio. Without an image model the Draw button is off and the line under it is the one sentence — Pictures need a provider with image models — Alibaba Cloud Bailian, Zhipu GLM, SiliconFlow or Volcengine Ark on the mainland, OpenRouter, OpenAI, Google Gemini or xAI Grok elsewhere — with Change model beside it. Settings → Image & video models shows the same sentence as its value when the runtime says pictures or clips are not covered.
The first-run list is Add a model → Connect mail, calendar, contacts
(optional) → Start. There is no naming page: Start asks the runtime to begin
the first conversation (POST /api/firstrun/start {lang}, which also marks the
first run done) and opens the chat, where the opening happens the way it does
on the phones and the desktop (contract C4 in parity.md):
- The app speaks first, as the agent, three lines in the console's
language — hello, I am a personal agent on this computer, free and open
source, from a small non-profit, and what should I call you? They cost no
tokens and the model never sees them as messages; the chat draws them where
the history begins (
GET /api/firstrun?lang=returns them asintro). - The model asks your name and, when you give it (or decline), reports it
in a
```nanomuse-namingblock at the end of its reply — the same JSON the desktop and the phones read (addressGiven,userAddress,suggestions,agentName). The runtime owns the phases (none → ask_user_name → ask_agent_name → named → done,nanomuse/server/firstrun.py, saved asfirstrun.jsonnext to the profile), writes your address to the profile and to memory as Call them: …, and tells the page over the socket (firstrunframe). The block itself is never shown, not even half-streamed. - The chooser appears under the reply: the model's two or three name
suggestions, or two from the built-in pool when it gave none, and
Something else for a name of your own. A chip saves the name at once
(
POST /api/firstrun/pick {name}) and sends it as your message, so the model's next reply is its first as itself; a typed name reaches the model and comes back in the block. A card the app answers itself (the avatar options) dismisses the chooser (POST /api/firstrun/dismiss).
While the first conversation runs, its turns are never tasks for the star asks. The addendum that tells the model about the ritual goes only into the chat the conversation is bound to, never into a routine, a feed post or another chat. Skip setup keeps the plain "onboarded" without the conversation; the identity form stays under Settings for changing the name, face and tone later. An older runtime without these routes gets the plain greeting and the form-free list as before.
Every unavailable feature is one sentence, never a raw error, built by
unavailableLine(cap, region, locale) from the region's providers with that
capability (four at most, in the catalogue's order):
| Capability | English | 中文 |
|---|---|---|
image |
Pictures need a provider with image models — {providers}. | 画图需要一个有图像模型的服务商——{providers}。 |
video |
Clips need a provider with video models — {providers}. | 生成视频需要一个有视频模型的服务商——{providers}。 |
vision |
The hands need a model that sees pictures — {providers}. | 动手需要一个能看图的模型——{providers}。 |
chat |
Chat needs a model — {providers}. | 对话需要一个模型——{providers}。 |
A How link beside each goes to own-key.md. The provider names
come from the catalogue in the console's language (name / name_zh).
A turn the relay refused is one sentence too, by the relay's code
(nanomuse/server/failures.py; the sentence is the key in web/src/i18n/zh-CN.ts,
so the Chinese is looked up from the English): the allowance used up (with the
ways card under it), the daily cap, a rate limit, a bad key, a disabled account,
a model the relay does not offer, the provider behind the relay in trouble —
and since 0.1.40 the four that fell through to The model provider answered
with an error: … and the five the operator's switches send
(cloud.md):
| The relay said | The chat says |
|---|---|
413 too_large |
That message is too large for the model's window. Shorten it, leave out some attachments, or start a new chat. |
403 not_invited |
This relay takes new accounts by invitation only; sign in with an invite code under Account. |
429 too_many_in_flight |
Too many turns are running on this account at once; wait for one to finish and try again. |
429 provider_busy |
The model provider is busy; try again in a moment. |
429 allowance_exhausted with paused: true |
The free allowance is paused on this relay for now, not used up. Your own model key under Connections keeps you going; your sign-in, your devices and what is left stay as they are. — the same ways card as a spent pool, the notice carries paused |
403 signup_closed |
New sign-ups are paused on this relay for now; existing accounts keep working. Try again later. |
503 service_paused |
nanoMuse Cloud is paused by its operator for now; your sign-in and your data are kept. Try again later. |
503 sync_paused |
Conversation sync is paused on this relay for now; what is stored is kept and your devices keep working on their own. |
503 hub_paused |
The device hub is paused on this relay for now; each device keeps working on its own. |
The raw reply stays under Details for a bug report, never as the only thing shown.
cd web && npm run lint && LANG=en_US.UTF-8 npx vitest run && npm run buildThe build writes nanomuse/server/static/, which is committed with the change;
web/tsconfig.tsbuildinfo is a by-product and is not.