mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
- 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.
66 lines
2.4 KiB
Go
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)
|
|
}
|
|
}
|