Files
Loki/internal/loki/facade_perf.go
T
Claude 35886da9b1 Lot 39 : anneau de télémétrie et /api/perf/summary tenus par la façade
L'anneau des complétions (perf_log.go) est porté en Rust (src/perfring.rs) :
perte de cache contre la complétion précédente de la même discussion et de
la même nature, ce qui s'est intercalé, seuil d'alerte du preset (dans
l'ordre du lancement, 2048 sur un modèle hybride), ligne [perf], résumé de
/api/perf/summary. ChatShared le porte : tours, vérifications, résumés de
compaction et préchauffage de la façade y rangent leurs complétions sans
aller-retour au Go.

Côté Go, quand la façade tient la conversation, perfRecord range chez elle
(/internal/facade/v1/perf/record) et perfSnapshot relit son anneau
(optimiseur) ; /api/perf/summary lui est remis. Façade injoignable : l'anneau
du Go prend le relais. La route /internal/v1/turn/perf, plus appelée, est
retirée.

Parité : journal tiré du Go (parity_perf_test.go → tests/parity_perf/
perf.json : 14 complétions, résumé, onze seuils), rejoué par
src/perfring/tests.rs ; deux tours qui perdent le cache (tests/lot6.rs),
l'API de l'anneau pour le Go, et TestFacadePerfAnneau côté Go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
2026-10-16 04:17:04 +00:00

75 lines
2.3 KiB
Go

package loki
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
// facade_perf.go — l'anneau de télémétrie tenu par la façade (lot 39 de la
// migration Rust). Quand elle tient la conversation, toutes les complétions y
// sont rangées :
//
// - celles de ses tours, directement ;
// - celles que le Go fait encore (sous-agents, tâches IA, bench, compaction
// et préchauffage de ses tours, clients externes de /v1), par
// /internal/facade/v1/perf/record.
//
// /api/perf/summary est servi par elle (facadeChatRoutes) et l'optimiseur lit
// l'anneau par perfSnapshot. Façade injoignable : la complétion est rangée
// ici, comme sans façade — la télémétrie ne fait jamais échouer un tour.
// facadePerfJSON appelle l'API de télémétrie de la façade et décode sa
// réponse.
func facadePerfJSON(path string, body, out any) error {
b, err := json.Marshal(body)
if err != nil {
return err
}
req, err := http.NewRequest(http.MethodPost, "http://"+facadeAddr()+path, bytes.NewReader(b))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set(internalTokenHeader, internalToken())
resp, err := facadeClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("façade : %s", resp.Status)
}
return json.NewDecoder(resp.Body).Decode(out)
}
// facadePerfRecord range une complétion dans l'anneau de la façade et la rend
// telle que rangée (numéro, perte de cache, ce qui s'est intercalé).
func facadePerfRecord(r perfRec, prefix []uint64) (perfRec, bool) {
var out struct {
Rec perfRec `json:"rec"`
}
err := facadePerfJSON("/internal/facade/v1/perf/record", map[string]any{"rec": r, "prefix": prefix}, &out)
if err != nil {
fmt.Fprintf(os.Stderr, "[perf] complétion non transmise à la façade : %v\n", err)
return perfRec{}, false
}
return out.Rec, true
}
// perfSnapshot : l'anneau, de la plus ancienne complétion à la plus récente —
// celui de la façade quand elle le tient.
func perfSnapshot() []perfRec {
if facadeChat() {
var out struct {
Recs []perfRec `json:"recs"`
}
if err := facadePerfJSON("/internal/facade/v1/perf/snapshot", map[string]any{}, &out); err == nil {
return out.Recs
}
}
return perfLog.snapshot()
}