v0.2.1 : anti-boucle + system prompt facon pi

- Nouveau system prompt structure facon pi (identite -> methode/guidelines
  -> date -> outils + conseils -> contexte machine/skills), injecte via
  InjectSkills. Corrige les boucles de raisonnement infinies.
- Plafond de reflexion par defaut (REASONING_BUDGET=2048 au lieu de -1) :
  coupe une reflexion qui derape au lieu de tourner a l'infini.
- Garde-fou anti-boucle dans runChat : stop si le modele relance
  exactement le meme appel d'outil plusieurs tours de suite.
- Descriptions d'outils enrichies (run_shell, skill).
- Bump version 0.2.0 -> 0.2.1.
This commit is contained in:
nathaninline committed 2026-06-21 09:14:08 +02:00
1 parent e606206d90
commit ca5d3f9197
6 files changed
+78 -10

No files matched your search

+25
View File
@@ -86,6 +86,8 @@ func runShellTool() Tool {
// skills are enabled). Merges with an existing system message if present.
func InjectSkills(msgs []Message) []Message {
var parts []string
// Always-on decisive-agent preamble (anti-loop). See baseSystemPrompt.
parts = append(parts, baseSystemPrompt())
if mp := machineSystemPrompt(); mp != "" {
parts = append(parts, mp)
}
@@ -234,6 +236,10 @@ func runChat(messages []Message, temperature float64, cb ChatCallback) error {
// retry the same turn once with tools removed so the model answers in plain
// text from the tool results already gathered, instead of dying mid-chat.
disableTools := false
// Anti-loop net: if the model re-emits the exact same tool call (name+args)
// several times, it's stuck — break instead of spinning to the iteration cap.
lastSig := ""
repeatSig := 0
for iter := 0; iter < 8; iter++ {
payload := map[string]any{
"model": "jean",
@@ -447,6 +453,25 @@ func runChat(messages []Message, temperature float64, cb ChatCallback) error {
assistant.Content = s
}
messages = append(messages, assistant)
// Loop guard: same exact call(s) as last turn? Count it; on the 3rd
// identical turn, stop so we don't churn the same command forever.
sig := strings.Builder{}
for _, tc := range tcs {
sig.WriteString(tc.Function.Name)
sig.WriteByte('\x00')
sig.WriteString(tc.Function.Arguments)
sig.WriteByte('\n')
}
if s := sig.String(); s == lastSig {
repeatSig++
if repeatSig >= 2 {
cb(StreamEvent{Content: "\n\n[stop: appel d'outil répété en boucle — " + tcs[0].Function.Name + "]"})
return nil
}
} else {
lastSig = s
repeatSig = 0
}
// 2. Execute each tool locally and append a "tool" reply.
for _, tc := range tcs {
var args map[string]any