v0.2.8 : l'IA garde la trace de ses appels d'outils entre les tours

Les tours d'outils (lecture de skill, commandes shell) ne survivaient
qu'a l'interieur de la boucle agentique d'un seul tour : seul le texte
final etait persiste. Resultat : a chaque nouveau message le modele
n'avait aucune trace d'avoir deja lu un skill, donc il le re-appelait
en boucle et confabulait des chemins/resultats disparus du contexte.

runChat retourne desormais les messages intermediaires (assistant
tool_calls + resultats tool). Le CLI les insere dans l'historique avant
la reponse finale ; le serveur web les emet en fin de flux SSE pour que
le client (stateless) les stocke. Couvre aussi ajean.link via E2E
(handleE2EChat -> runChatStream).
This commit is contained in:
nathaninline committed 2026-06-25 21:26:20 +02:00
1 parent a453229642
commit f632b7b42c
7 files changed
+54 -19

No files matched your search

+8 -1
View File
@@ -630,7 +630,7 @@ func runChatStream(ctx context.Context, body chatReq, emit func(map[string]any)
caps.Skills = *body.Skills
}
msgs := InjectSkills(body.Messages, caps)
_ = runChat(ctx, msgs, body.Temperature, caps, func(ev StreamEvent) bool {
extra, _ := runChat(ctx, msgs, body.Temperature, caps, func(ev StreamEvent) bool {
if ev.Err != nil {
return emit(map[string]any{"error": ev.Err.Error()})
}
@@ -648,6 +648,13 @@ func runChatStream(ctx context.Context, body chatReq, emit func(map[string]any)
}
return true
})
// Surface the tool-turn messages (assistant tool_calls + tool results) as a
// final event so the stateless web client can store them in its history,
// BEFORE the final assistant text. Without this the browser only keeps the
// final answer and the model re-invokes the same skill/command every turn.
if len(extra) > 0 {
emit(map[string]any{"tool_messages": extra})
}
}
func handleChat(w http.ResponseWriter, r *http.Request) {