mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-16 11:49:43 +02:00
v0.2.11 : mémoire (mem_search/read/add/edit) remplace les skills + outil edit (old/new) + run_shell renommé bash ; migration auto SKILLS->MEMORY
This commit is contained in:
1 parent
d3a2f1c428
commit
4c8aafa898
12 files changed
+660
-124
No files matched your search
@@ -30,20 +30,44 @@ func baseSystemPrompt(caps Caps) string {
|
||||
if !caps.Agent {
|
||||
return ""
|
||||
}
|
||||
cwd, _ := os.Getwd()
|
||||
|
||||
var b strings.Builder
|
||||
b.WriteString("Tu es un assistant expert opérant dans jean, un agent qui agit directement sur cette machine. Tu aides l'utilisateur en inspectant le système, en exécutant des commandes et en gérant des skills réutilisables.\n\n")
|
||||
b.WriteString("Méthode :\n")
|
||||
b.WriteString("You are an expert coding assistant operating inside jean, a coding agent harness. You help users by reading files, executing commands, editing code, writing new files, and leveraging persistent memory to remember things across sessions.\n\n")
|
||||
|
||||
b.WriteString("Available tools:\n")
|
||||
for _, l := range []string{
|
||||
"Raisonne brièvement (1 à 2 phrases) puis AGIS. Dès qu'une action est possible, appelle l'outil immédiatement — ne l'annonce pas, fais-le.",
|
||||
"Ne répète JAMAIS deux fois la même étape de réflexion ni le même appel d'outil. Si tu hésites (« je devrais peut-être vérifier… »), arrête de réfléchir et appelle l'outil maintenant.",
|
||||
"Pour toute question système (fichiers, process, réseau, OS), utilise tes outils au lieu de supposer — tu as un accès réel, ne demande pas la permission pour inspecter.",
|
||||
"Quand la tâche est faite, donne une réponse finale courte et arrête-toi. N'enchaîne pas d'outils inutiles.",
|
||||
"Sois concis dans tes réponses.",
|
||||
"Affiche clairement les chemins de fichiers quand tu travailles dessus.",
|
||||
"bash: Execute a shell command on this machine (ls, grep, find, cat, sed, read logs, run scripts…) and return stdout, stderr and the exit code. This is your real access to the system.",
|
||||
"edit: Modify a file on disk by exact replacement (old → new; old must match exactly once). Use this to patch a file instead of rewriting it whole.",
|
||||
"mem_search: Search your memory (Markdown pages under MEMORY/). Returns a ranked list of {file, title, snippet}.",
|
||||
"mem_read: Read a memory page (Markdown file), line-numbered, with optional offset/limit.",
|
||||
"mem_add: Create a new memory page (one topic per page, descriptive kebab-case name, first line is a short # title).",
|
||||
"mem_edit: Edit a memory page by exact replacement (old → new; old must match exactly once).",
|
||||
} {
|
||||
b.WriteString("- " + l + "\n")
|
||||
}
|
||||
b.WriteString("\nDate du jour : " + time.Now().Format("2006-01-02"))
|
||||
|
||||
b.WriteString("\nGuidelines:\n")
|
||||
for _, l := range []string{
|
||||
"Reason briefly (1-2 sentences) then ACT. As soon as an action is possible, call the tool immediately — don't announce it, do it.",
|
||||
"Never repeat the same reasoning step or the same tool call twice. If you hesitate (\"maybe I should check…\"), stop thinking and call the tool now.",
|
||||
"Use bash for any system question (files, processes, network, OS) instead of assuming — you have real access, don't ask permission to inspect.",
|
||||
"Use bash to read files (cat, sed -n); to change a file, use the edit tool (old → new) instead of rewriting it whole with bash.",
|
||||
"Use mem_search FIRST whenever the user asks about something you might already know (preferences, ongoing projects, past decisions). Open the most relevant page with mem_read; snippets are hints, not the answer.",
|
||||
"Save anything worth keeping across sessions with mem_add; update an existing page with mem_edit. Don't save ephemeral conversation state.",
|
||||
"Prefer targeted, non-interactive commands; chain them with && when they depend on each other.",
|
||||
"Avoid destructive commands (rm -rf, mkfs, dd…) unless the user explicitly asks.",
|
||||
"If a command fails, read stderr and the exit code, then fix it — don't re-run the same command unchanged.",
|
||||
"Never invent a tool: you only have bash, edit and the mem_* tools. Anything else (reading code, web access) goes through bash.",
|
||||
"When the task is done, give a short final answer and stop. Don't chain useless tool calls.",
|
||||
"Be concise in your responses.",
|
||||
"Show file paths clearly when working with files.",
|
||||
} {
|
||||
b.WriteString("- " + l + "\n")
|
||||
}
|
||||
|
||||
b.WriteString("\nCurrent date: " + time.Now().Format("2006-01-02"))
|
||||
b.WriteString("\nCurrent working directory: " + cwd)
|
||||
return b.String()
|
||||
}
|
||||
|
||||
@@ -57,7 +81,7 @@ func machineSystemPrompt(caps Caps) string {
|
||||
}
|
||||
host, _ := os.Hostname()
|
||||
if host == "" {
|
||||
host = "inconnu"
|
||||
host = "unknown"
|
||||
}
|
||||
who := ""
|
||||
if u, err := user.Current(); err == nil {
|
||||
@@ -66,17 +90,7 @@ func machineSystemPrompt(caps Caps) string {
|
||||
cwd, _ := os.Getwd()
|
||||
|
||||
var b strings.Builder
|
||||
b.WriteString("Outil disponible — run_shell(command, timeout) : exécute une commande shell sur CETTE machine et renvoie stdout, stderr et le code de sortie. C'est ton accès réel ; ne dis jamais que tu n'y as pas accès.\n")
|
||||
b.WriteString("Conseils run_shell :\n")
|
||||
for _, l := range []string{
|
||||
"Sers-t'en pour toute question système (OS, disque, process, fichiers, réseau, lire un script) plutôt que de supposer.",
|
||||
"Préfère des commandes ciblées et non-interactives ; chaîne-les avec && quand elles sont dépendantes.",
|
||||
"Évite les commandes destructrices (rm -rf, mkfs, dd…) sauf demande explicite de l'utilisateur.",
|
||||
"Si une commande échoue, lis stderr et le code de sortie, puis corrige — ne relance pas la même commande à l'identique.",
|
||||
} {
|
||||
b.WriteString("- " + l + "\n")
|
||||
}
|
||||
b.WriteString(fmt.Sprintf("Machine : hôte=%s, %s/%s", host, runtime.GOOS, runtime.GOARCH))
|
||||
b.WriteString(fmt.Sprintf("Machine: host=%s, %s/%s", host, runtime.GOOS, runtime.GOARCH))
|
||||
if who != "" {
|
||||
b.WriteString(", user=" + who)
|
||||
}
|
||||
@@ -128,6 +142,35 @@ func runShell(command string, timeoutSec int) string {
|
||||
return strings.Join(parts, "\n\n")
|
||||
}
|
||||
|
||||
// fileEdit applies a single exact-text replacement to a file on disk: oldText
|
||||
// must appear EXACTLY once (otherwise it errors), so the model can patch a file
|
||||
// without rewriting it whole. Returns a short status string for the tool result.
|
||||
func fileEdit(path, oldText, newText string) string {
|
||||
if strings.TrimSpace(path) == "" {
|
||||
return "[erreur] chemin vide"
|
||||
}
|
||||
if oldText == "" {
|
||||
return "[erreur] old vide"
|
||||
}
|
||||
b, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "[erreur] " + err.Error()
|
||||
}
|
||||
content := string(b)
|
||||
n := strings.Count(content, oldText)
|
||||
if n == 0 {
|
||||
return "[erreur] old introuvable dans le fichier"
|
||||
}
|
||||
if n > 1 {
|
||||
return fmt.Sprintf("[erreur] old apparaît %d fois — ajoute du contexte pour le rendre unique", n)
|
||||
}
|
||||
updated := strings.Replace(content, oldText, newText, 1)
|
||||
if err := os.WriteFile(path, []byte(updated), 0o644); err != nil {
|
||||
return "[erreur] " + err.Error()
|
||||
}
|
||||
return fmt.Sprintf("[ok] %s modifié (1 remplacement)", path)
|
||||
}
|
||||
|
||||
// tailRunes returns the last n runes of s (used to cap tool output).
|
||||
func tailRunes(s string, n int) string {
|
||||
r := []rune(s)
|
||||
|
||||
Reference in new issue
Block a user