Files
Loki/internal/loki/normalize_project_test.go
T
MichaelandClaude Opus 5.5 7dd319a058 Cache : la ligne MCP du préambule ne manque plus au premier tour après un démarrage
Le préambule système était bâti (InjectSkills → baseSystemPrompt) AVANT que
runChat n'appelle EnabledTools, donc avant que mcpTools n'ouvre les connexions.
mcpPromptLine lisait le pool encore vide : le premier tour après un démarrage
partait sans la ligne MCP, le second avec — tout le prompt à recalculer pour
une ligne. Elle comptait en plus les outils masqués par l'utilisateur, et
s'affichait pour le planner, qui ne reçoit aucun outil MCP.

- prepareTurn calcule les outils UNE fois par tour, puis le préambule à partir
  d'eux ; runChatTools les reprend tels quels (pas de second passage par
  mcpEnsureAll, qui retentait deux fois un serveur en panne).
- mcpPromptLine se déduit de cette tranche : seuls les outils réellement
  envoyés sont comptés, et rien n'est annoncé sans outil MCP.
- trackerList départage les égalités d'horodatage par nom puis slug : la liste
  part dans le contexte, un ordre tiré au sort changeait le prompt.
- Le commentaire de tasks_run.go ne prétend plus que le préfixe d'une tâche
  égale celui du chat (dossier de travail et taskCaps diffèrent).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 01:31:00 +02:00

54 lines
2.1 KiB
Go

package loki
import (
"reflect"
"strings"
"testing"
)
// Le contexte PROJET quitte le bloc système pour la tête du 1er message user :
// le système commun reste identique d'un projet à l'autre (cache de prompt), et
// l'historique d'origine n'est pas muté.
func TestNormalizeMovesProjectContextToFirstUser(t *testing.T) {
in := []Message{
{Role: "system", Content: "Préambule commun"},
{Role: "system", Content: projectContextPrefix + " — projet A"},
{Role: "system", Content: memIndexPrefix + " for project A"},
{Role: "user", Content: "bonjour"},
{Role: "assistant", Content: "salut"},
{Role: "user", Content: "suite"},
}
ref := append([]Message(nil), in...)
out := normalizeSystemMessages(in)
if len(out) != 4 || out[0].Content != "Préambule commun" {
t.Fatalf("système commun attendu seul en tête : %#v", out)
}
first, _ := out[1].Content.(string)
if !strings.HasPrefix(first, "<project_context>\n"+projectContextPrefix) ||
!strings.Contains(first, memIndexPrefix) || !strings.HasSuffix(first, "bonjour") {
t.Fatalf("contexte projet absent du 1er message user : %q", first)
}
if out[3].Content != "suite" {
t.Fatal("seul le PREMIER message user reçoit le contexte")
}
if !reflect.DeepEqual(in, ref) {
t.Fatal("l'entrée a été mutée (interdit)")
}
}
// Sans prompt de preset, le premier système est un message projet : le préambule
// ne doit pas l'absorber (il perdrait son préfixe et resterait dans le système).
func TestInjectSkillsKeepsProjectMessageSeparate(t *testing.T) {
in := []Message{
{Role: "system", Content: projectContextPrefix + " — projet A"},
{Role: "user", Content: "bonjour"},
}
out := normalizeSystemMessages(InjectSkills(in, Caps{Agent: true}, nil))
if s, _ := out[0].Content.(string); out[0].Role != "system" || strings.Contains(s, projectContextPrefix) {
t.Fatalf("le contexte projet ne doit pas rester dans le système : %#v", out[0])
}
if u, _ := out[1].Content.(string); !strings.Contains(u, projectContextPrefix) {
t.Fatalf("contexte projet attendu dans le 1er message user : %#v", out[1])
}
}