Lot 6 : la façade reçoit le chat du Go et ses événements

Une requête qui porte le jeton interne vient du Go, qui l'a déjà
authentifiée (tunnel du relais) : les routes du chat la servent sans
redemander la clé. L'API interne de la façade, réservée à ce jeton, reçoit
les événements d'affichage nés au Go (mode Code, critères) et le
rechargement après déverrouillage : une discussion chargée vide mémoire
verrouillée revient au déverrouillage, jamais par-dessus un fil rempli
(sinon le premier message aurait écrasé la discussion chiffrée).

Le relais par la façade de /api/chat/mode et /api/chat/criteria et les
critères rendus par l'outil disparaissent : le Go pousse ses événements
lui-même, une seule source quel que soit le chemin.

README : LOKI_CHAT=rust et ce qu'il ne prend pas encore en charge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
This commit is contained in:
Claude committed 2026-10-15 11:19:42 +00:00
1 parent 306c7a2f6c
commit ad46bb69a6
9 files changed
+175 -90

No files matched your search

+16 -10
View File
@@ -86,10 +86,11 @@ pub async fn serve(
backend: cfg.backend,
ctx: api::Ctx {
store: Store::new(cfg.backend, cfg.internal_token.clone()),
internal: InternalClient::new(cfg.backend, cfg.internal_token),
internal: InternalClient::new(cfg.backend, cfg.internal_token.clone()),
host_env: cfg.host_env,
engine: cfg.engine,
chat: cfg.chat,
internal_token: cfg.internal_token.clone(),
},
});
tokio::pin!(shutdown);
@@ -127,12 +128,22 @@ pub async fn serve(
impl Proxy {
async fn handle(&self, mut req: Request<Incoming>) -> Response<Body> {
// Le Go (et lui seul : jeton tiré à chaque démarrage) remet à la
// façade le trafic de chat qui lui arrive sans passer par elle.
let from_go = self.ctx.chat.is_some() && self.ctx.from_go(req.headers());
// Jamais de confiance accordée sur la foi d'un en-tête du client :
// ni « je viens du tunnel », ni « je suis la façade ».
req.headers_mut().remove(VIA_TUNNEL);
req.headers_mut().remove(INTERNAL_HEADER);
let path = req.uri().path();
// L'API interne de la façade : pour le Go seulement.
if from_go
&& let Some(chat) = &self.ctx.chat
&& chatapi::is_internal(path)
{
return chatapi::serve_internal(chat, req).await;
}
// L'API interne du Go n'est jamais joignable de l'extérieur.
if path.starts_with("/internal/") {
return plain(StatusCode::NOT_FOUND, "404 page not found");
@@ -147,15 +158,10 @@ impl Proxy {
if api::handles(req.method(), path) {
return api::serve(&self.ctx, req).await;
}
if let Some(chat) = &self.ctx.chat {
if chatapi::handles(path) {
return chatapi::serve(&self.ctx, chat, req).await;
}
if chatapi::relays_delta(path) {
let (method, path) = (req.method().clone(), path.to_string());
let resp = self.forward(req).await;
return chatapi::after_forward(chat, &method, &path, resp).await;
}
if let Some(chat) = &self.ctx.chat
&& chatapi::handles(path)
{
return chatapi::serve(&self.ctx, chat, req, from_go).await;
}
self.forward(req).await
}