Files
Loki/internal/loki/chat_prompt_size_test.go
T
Loki de6551a153 Rebaptise AJEAN en Loki (fork, lignée conservée)
- module github.com/R0m1k3/Loki, cmd/loki, internal/loki (package loki)
- LOKI_HOME, LOKI_MODEL_DIRS, LOKI_SERVICE, LOKI_DL_CONNS ; /etc/loki ;
  units loki-engine / loki-ui ; binaire et aide CLI
- updateRepo pointe sur R0m1k3/Loki (l'auto-update ne tirera plus les
  binaires AJEAN amont)

Conservé à l'identique : le domaine ajean.link (service de tunnel amont),
les littéraux de migration 0.7.x (migrate_07.go), RELEASE_NOTES.md et
LICENSE (historique et licence de l'amont).

go build/vet/test : verts.
2026-08-14 21:33:15 +00:00

66 lines
2.4 KiB
Go

package loki
import (
"encoding/json"
"strings"
"testing"
)
// Budget du préambule envoyé À CHAQUE TOUR : prompt système + schémas des outils.
// Il est payé sur toute la conversation et sort du contexte utile.
//
// Ce test existe pour empêcher le regonflement. Le prompt a déjà été raccourci
// une fois pour une raison de comportement (un préambule verbeux fait
// sur-raisonner les modèles à reasoning, qui finissent leur tour sans appeler
// d'outil), puis une seconde fois pour le coût. Les deux fois, il avait
// regrossi ligne par ligne, chacune paraissant anodine.
//
// Approximation 1 tok ≈ 4 caractères : suffisante pour une alerte, et sans
// dépendance à un tokenizer.
const promptCharBudget = 7500 // ~1875 tokens, tout allumé
func TestSystemPromptStaysLean(t *testing.T) {
caps := Caps{Agent: true, Internet: true, Mem: MemAlways}
sp := baseSystemPrompt(caps)
tb, err := json.Marshal(EnabledTools(caps))
if err != nil {
t.Fatal(err)
}
total := len(sp) + len(tb)
t.Logf("prompt %d car (~%d tok) + outils %d car (~%d tok) = ~%d tok",
len(sp), len(sp)/4, len(tb), len(tb)/4, total/4)
if total > promptCharBudget {
t.Fatalf("préambule à %d car (~%d tok), budget %d car (~%d tok).\n"+
"Avant de relever le budget : les schémas d'outils pèsent le double du prompt,\n"+
"et une consigne écrite dans un schéma n'a pas à être répétée dans le prompt.",
total, total/4, promptCharBudget, promptCharBudget/4)
}
}
// Le prompt ne doit pas redevenir un catalogue d'outils : leurs schémas partent
// dans la MÊME requête et les décrivent déjà un par un.
func TestSystemPromptDoesNotRelistTools(t *testing.T) {
sp := baseSystemPrompt(Caps{Agent: true, Internet: true, Mem: MemAlways})
for _, line := range strings.Split(sp, "\n") {
l := strings.TrimSpace(line)
if !strings.HasPrefix(l, "- ") {
continue
}
// Une puce qui commence par un nom d'outil = un catalogue qui revient.
for _, tool := range []string{"bash ", "write ", "edit ", "mem_", "web_"} {
if strings.HasPrefix(l[2:], tool) {
t.Fatalf("le prompt réénumère un outil : %q", l)
}
}
}
}
// Sans agent ni mémoire, aucun préambule : un modèle de chat simple à qui on
// ordonne d'appeler des outils invente des appels textuels qui fuient dans la
// réponse.
func TestSystemPromptEmptyWithoutTools(t *testing.T) {
if sp := baseSystemPrompt(Caps{Mem: MemOff}); sp != "" {
t.Fatalf("préambule non vide sans outils : %q", sp)
}
}