mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-19 21:18:20 +02:00
Phase 7 : outils web_search et run_shell avec validation
Backend : - tools.py : web_search (DuckDuckGo HTML sans clé, ou SearxNG via SEARX_URL) et run_shell (confiné au workspace, sortie bornée, timeout) - agent.py : run_shell sensible -> émet tool_confirm et ne s'exécute pas tant que l'utilisateur n'a pas validé (confirm_shell) - agent_config.py : web_search/run_shell désactivés par défaut, flag confirm_shell - routes/shell.py : POST /api/shell/run exécute une commande validée - routes/chat.py : relaie l'événement tool_confirm, passe confirm_shell Frontend : - streamChat : événement tool_confirm - store : pendingShell + approveShell/rejectShell (réinjecte le résultat à l'agent) - ChatPanel : carte de validation de commande (Approuver / Refuser) - SettingsView : toggles web_search/run_shell, marqueur sensible, switch confirm_shell - ToolCard : glyphes web_search/run_shell, statut 'à valider', aperçu d'argument Tests : run_shell confiné, gate de confirmation (commande dangereuse non exécutée), route shell, parser DuckDuckGo. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
This commit is contained in:
1 parent
2db6beea5c
commit
de2befe31e
12 files changed
+398
-26
No files matched your search
@@ -9,6 +9,7 @@ import {
|
||||
fileContent,
|
||||
listFiles,
|
||||
listSessions,
|
||||
runShell,
|
||||
saveConfig,
|
||||
streamChat,
|
||||
type AgentConfig,
|
||||
@@ -42,6 +43,10 @@ interface LokiState {
|
||||
refreshConfig: () => Promise<void>;
|
||||
updateConfig: (patch: Partial<AgentConfig>) => Promise<void>;
|
||||
|
||||
pendingShell: string | null; // commande shell en attente de validation
|
||||
approveShell: () => Promise<void>;
|
||||
rejectShell: () => Promise<void>;
|
||||
|
||||
openPreview: (path: string) => Promise<void>;
|
||||
setSelectedModel: (name: string) => void;
|
||||
refreshStatus: () => Promise<void>;
|
||||
@@ -72,6 +77,32 @@ export const useStore = create<LokiState>((set, get) => ({
|
||||
previewContent: "",
|
||||
config: null,
|
||||
availableTools: [],
|
||||
pendingShell: null,
|
||||
|
||||
approveShell: async () => {
|
||||
const cmd = get().pendingShell;
|
||||
if (!cmd) return;
|
||||
set({ pendingShell: null });
|
||||
let report: string;
|
||||
try {
|
||||
const r = await runShell(cmd);
|
||||
report =
|
||||
`J'ai validé la commande \`${cmd}\` (code ${r.exit_code}).\n` +
|
||||
`Sortie :\n\`\`\`\n${r.output || "(vide)"}\n\`\`\``;
|
||||
} catch {
|
||||
report = `Échec de l'exécution de \`${cmd}\`.`;
|
||||
}
|
||||
await get().refreshFiles();
|
||||
// On renvoie le résultat à l'agent pour qu'il poursuive.
|
||||
await get().sendMessage(report);
|
||||
},
|
||||
|
||||
rejectShell: async () => {
|
||||
const cmd = get().pendingShell;
|
||||
if (!cmd) return;
|
||||
set({ pendingShell: null });
|
||||
await get().sendMessage(`J'ai refusé la commande \`${cmd}\`. N'exécute pas cette commande.`);
|
||||
},
|
||||
|
||||
refreshConfig: async () => {
|
||||
const { config, available_tools } = await getConfig();
|
||||
@@ -171,6 +202,7 @@ export const useStore = create<LokiState>((set, get) => ({
|
||||
streaming: true,
|
||||
streamContent: "",
|
||||
streamTools: [],
|
||||
pendingShell: null,
|
||||
});
|
||||
|
||||
await streamChat(
|
||||
@@ -190,6 +222,7 @@ export const useStore = create<LokiState>((set, get) => ({
|
||||
}
|
||||
set({ streamTools: tools });
|
||||
},
|
||||
onToolConfirm: (command) => set({ pendingShell: command }),
|
||||
onDone: async () => {
|
||||
// Repère un fichier HTML écrit pour l'afficher automatiquement.
|
||||
const writtenHtml = [...get().streamTools]
|
||||
|
||||
Reference in new issue
Block a user