metnos_http_server serve la chat web, l'API dei
turni e l'area Settings. Il valore predefinito è
127.0.0.1:8770; un'installazione può cambiare indirizzo e porta.
Il protocollo degli executor remoti su 8765 e il servizio browser
su 8771 sono componenti distinti, con autorità e rotte proprie.
Chiedi a Metnos con una richiesta come quella di questo esempio:
Mostrami dove posso verificare i turni recenti e cambiare la configurazione dei modelli.
La risposta deve iniziare dal percorso della chat:
Settings > Attività > Turni e
Settings > Sistema > Modelli. Se la domanda proviene da
Telegram, va precisato che Settings si apre nella chat web. Solo a chi chiede
un'integrazione tecnica servono poi i percorsi HTTP
/admin/turns e /admin/virt.
La factory make_app crea una sola applicazione
aiohttp con limite del corpo a 50 MiB e monta tre registri di
rotte:
| Modulo | Responsabilità |
|---|---|
http_routes_agent.py | Chat, discovery, turni, sessioni, dialoghi, allegati, associazione web e callback OAuth. |
http_routes_admin.py | Settings, utenti, modelli, servizi, dispositivi, scheduler, Safety ed evoluzione degli executor. |
http_routes_stack.py | Prontezza complessiva di server, catalogo e servizio browser. |
I middleware vengono applicati nello stesso ordine a tutte le rotte: prima classificano il chiamante, poi impostano nel contesto della richiesta la lingua del suo utente. Il contesto linguistico viene copiato anche nel pool che esegue i turni, così richieste concorrenti non condividono una variabile di lingua globale.
agent_server, normalmente su 127.0.0.1:8765, gestisce polling, heartbeat, bundle firmati e risultati degli executor remoti. Il daemon Telegram può ospitarlo in un proprio thread.playwright_sidecar, normalmente su 127.0.0.1:8771, gestisce sessioni browser e non è esposto come API utente.POST /agent/register esiste anche sulla porta della chat e riusa il gestore canonico di agent_server; non duplica la semantica dei token monouso.| Metodo e percorso | Funzione | Accesso |
|---|---|---|
GET / | Chat web; un anonimo viene rinviato all'accesso amministrativo. | Utente o amministratore; apertura iniziale ammessa per il rinvio. |
GET /agent/health | Vitalità, versione dell'API, versione del prodotto e tempo di attività. | Anonimo. |
GET /.well-known/metnos.json | Descrittore del nodo e URL di associazione; non pubblica chiavi o impronte amministrative. | Anonimo. |
POST /agent/register | Consuma il token monouso di un executor remoto. | Anonimo con token valido. |
GET /pair/{token} | Consuma un token web e imposta il cookie del dispositivo associato. | Anonimo con token valido. |
GET /oauth/callback | Completa un flusso OAuth usando lo stato breve emesso da Metnos. | Pubblica per necessità del reindirizzamento; lo stato è il vincolo. |
Manifesto PWA, service worker e file sotto /static/ sono
leggibili senza autenticazione. Le fotografie sotto
/agent/photos/ usano invece un URL firmato e a scadenza: l'URL
stesso è una capacità e va trattato come riservato.
| Gruppo | Percorsi | Contratto |
|---|---|---|
| Turno diretto | POST /agent/turn | JSON oppure flusso SSE sulla stessa connessione. |
| Turno riprendibile | POST /agent/turn/submit; GET /agent/turns/{id}/stream; GET /agent/turns/{id} | Accettazione immediata, eventi ricollegabili e ripiego tramite polling. |
| Cronologia e giudizio | GET /agent/turns/recent; POST /agent/turns/{id}/feedback; POST /agent/turns/{id}/retry | Cronologia della conversazione, riscontro esplicito e ripetizione. |
| Sessione di scrittura | /agent/session/register, takeover, ping, revoke, events | Un dispositivo scrivente per coppia utente-canale e trasferimento esplicito. |
| Dialoghi | /agent/dialog/{id}/form, submit, cancel, preview, context | Raccolta di input con proprietario e, quando serve, capacità delegabile a breve durata. |
| Allegati | /agent/gallery/{turn_id}, /agent/photos/{turn_id}/{idx}, /agent/photos/web | Galleria vincolata al proprietario; file locali con URL firmati; proxy web con difese SSRF e limiti di dimensione. |
Tutte le rotte sotto /admin, salvo il modulo di accesso,
richiedono il ruolo amministratore. Le aree principali sono:
/admin/virt e /admin/services per modelli e servizi;/admin/turns, /admin/runs, /admin/builds e /admin/timers per l'attività;/admin/changes, /admin/executors e /admin/praxis per ciclo di vita e motore cognitivo;/admin/safety, /admin/users e /admin/devices per firme, identità e dispositivi;/agent/stack/health per la prontezza complessiva, nonostante il prefisso /agent.Il registro completo delle rotte è nel codice e resta la fonte canonica. Questo raggruppamento spiega la superficie senza congelare un conteggio destinato a cambiare.
Il middleware assegna uno dei tre ruoli
anonymous, user o admin:
admin;user come compatibilità di installazione;Un Bearer errato non cade nel ripiego della rete locale. Gli header
CF-Connecting-IP e X-Forwarded-For sono considerati
soltanto quando il peer TCP appartiene a
METNOS_TRUSTED_PROXIES; un client ordinario non può dichiararsi
locale tramite un header.
La chiave amministrativa vive in PATH_USER_CONFIG/admin.key,
viene creata con permessi 0600 e serve anche a derivare firme e
chiavi di cifratura con domini separati. Il cookie amministrativo dura sette
giorni, è HttpOnly, Secure e
SameSite=Strict; quello utente dura novanta giorni ed è
HttpOnly, Secure e SameSite=Lax.
La sessione attiva è indicizzata dalla coppia
(user_id, channel). Host e guest possono quindi usare la chat
contemporaneamente senza condividere lease, conversazione o memoria locale del
browser. Il client separa anche token, buffer dei comandi e cronologia mediante
uno scope opaco derivato dall'utente.
Quando un secondo dispositivo trova una sessione attiva, il server emette un token monouso e lascia tre scelte all'interfaccia:
Il trasferimento ricontrolla atomicamente utente e vecchio scrivente. La
cronologia recente richiede una conversazione appartenente all'utente. Anche
stato, stream, galleria, feedback e ripetizione verificano il proprietario del
turno: conoscere un turn_id non concede accesso. I vecchi record
senza owner_user_id usano soltanto associazioni deterministiche di
conversazione o attore; un errore del registro identità viene negato, non
trasformato in permesso.
POST /agent/turn accetta JSON oppure multipart con una
richiesta e immagini di riferimento. Con
Accept: text/event-stream invia eventi
thinking, progress, tool_call e infine
final o error; commenti periodici mantengono viva la
connessione. Senza SSE restituisce un unico documento JSON.
POST /agent/turn/submit riserva prima una posizione nel pool e
risponde 202 con turn_id e
stream_url. Il turno continua anche se la pagina viene aggiornata
o la rete cade. Lo stream accetta Last-Event-ID e riproduce gli
eventi successivi; GET /agent/turns/{id} è il ripiego di
polling.
Gli eventi in memoria restano per un intervallo limitato dopo la chiusura. Quando non sono più presenti, lo stato cerca il record persistito nel registro giornaliero. La persistenza non sostituisce il controllo del proprietario.
I turni bloccanti passano da un pool dedicato con limite globale, coda
finita e limite per principal. Se la riserva non arriva entro il tempo
ammesso, il server risponde 503 turn_capacity_exhausted con
Retry-After: 1. Una disconnessione non libera prematuramente il
posto mentre il thread continua a lavorare.
Le collezioni amministrative che usano
negotiate_collection restituiscono HTML quando
Accept include text/html, altrimenti JSON. Il corpo
riceve un ETag derivato da SHA-256; un If-None-Match uguale produce
304. Non tutte le rotte usano questa negoziazione: alcune sono
solo HTML, solo JSON o SSE.
La chat imposta no-cache, no-store perché il client deve
ricevere il contratto aggiornato. Le risposte negoziate amministrative hanno
cache privata breve; configurazione dei modelli e servizi usano
no-store. Gli URL firmati degli allegati hanno una durata propria
e non vanno confusi con una sessione utente.
Settings usa template Jinja2, il registro
runtime/ui_surfaces.py per navigazione e descrizioni, htmx per
alcuni aggiornamenti e uPlot soltanto nella vista statistica degli executor.
Non esiste una fase di compilazione front-end.
Ogni testo visibile deve provenire dal catalogo i18n o da dati già
localizzati. La lingua è una preferenza del singolo utente e vive in un
ContextVar per richiesta; una nuova lingua richiede voci del
catalogo, lessico di riconoscimento e documentazione corrispondente, non
condizioni per singole frasi nel template.
Settings è l'interfaccia amministrativa interattiva. Il rendiconto HTML
generato da runtime.observability è invece un artefatto separato,
descritto nella guida all'osservabilità
operativa.
10.0.0.0/8 e 192.168.0.0/16; non equivale a «qualsiasi rete privata» e non sostituisce l'associazione di un dispositivo.PATH_USER_STATE impedisce due server della stessa installazione./agent/health dice che il processo risponde; /agent/stack/health, riservato all'amministratore, controlla anche catalogo, contratto browser e servizio adiacente.curl -fsS http://127.0.0.1:8770/agent/health curl -fsS http://127.0.0.1:8770/.well-known/metnos.json curl -fsS -H "Authorization: Bearer <chiave-amministrativa>" \ http://127.0.0.1:8770/agent/stack/health
La prima sonda prova soltanto la vitalità. La terza è l'evidenza
adatta prima di un riavvio o di un collaudo complessivo. Le suite sotto
tests/runtime/http/ verificano autenticazione, sessioni,
isolamento dei turni, SSE, cache, upload, rendering e pagine amministrative;
la guida non fissa un numero di prove.
runtime/metnos_http_server.py — factory, middleware, lifecycle e pool;runtime/http_auth.py — ruoli, cookie, Bearer, reti e proxy fidati;runtime/http_routes_agent.py — chat, turni, sessioni, dialoghi e allegati;runtime/http_routes_admin.py — Settings e azioni amministrative;runtime/http_routes_stack.py — prontezza complessiva;runtime/http_render.py — template, negoziazione ed ETag;runtime/turn_events.py — eventi riprendibili e loro proprietà.