mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-20 21:48:47 +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
@@ -15,6 +15,9 @@ export function ChatPanel() {
|
||||
sendMessage,
|
||||
currentSessionId,
|
||||
config,
|
||||
pendingShell,
|
||||
approveShell,
|
||||
rejectShell,
|
||||
} = useStore();
|
||||
|
||||
const activeTools = config
|
||||
@@ -100,6 +103,13 @@ export function ChatPanel() {
|
||||
pending
|
||||
/>
|
||||
)}
|
||||
{pendingShell && (
|
||||
<ShellConfirm
|
||||
command={pendingShell}
|
||||
onApprove={approveShell}
|
||||
onReject={rejectShell}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -201,6 +211,46 @@ function Bubble({ msg, pending }: { msg: Message; pending?: boolean }) {
|
||||
);
|
||||
}
|
||||
|
||||
function ShellConfirm({
|
||||
command,
|
||||
onApprove,
|
||||
onReject,
|
||||
}: {
|
||||
command: string;
|
||||
onApprove: () => void;
|
||||
onReject: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="ml-[43px] overflow-hidden rounded-[11px] border border-[#4a3a2a] bg-card-deep">
|
||||
<div className="flex items-center gap-2 border-b border-line-soft px-[13px] py-2.5">
|
||||
<span className="font-mono text-[12.5px] font-semibold text-warn">
|
||||
run_shell
|
||||
</span>
|
||||
<span className="text-xs text-muted-2">· commande sensible à valider</span>
|
||||
</div>
|
||||
<div className="px-[13px] py-3">
|
||||
<pre className="m-0 mb-3 overflow-auto whitespace-pre-wrap rounded-lg bg-sunken px-3 py-2.5 font-mono text-[12px] text-ink-2">
|
||||
$ {command}
|
||||
</pre>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={onApprove}
|
||||
className="flex h-[30px] items-center gap-1.5 rounded-lg bg-accent px-3.5 text-[12.5px] font-bold text-[#1f1b16]"
|
||||
>
|
||||
Approuver & exécuter
|
||||
</button>
|
||||
<button
|
||||
onClick={onReject}
|
||||
className="flex h-[30px] items-center rounded-lg border border-line-strong px-3.5 text-[12.5px] font-semibold text-ink-3"
|
||||
>
|
||||
Refuser
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Chip({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="flex h-[25px] items-center gap-1.5 rounded-[7px] border border-line-strong bg-card-soft px-[9px] text-[11.5px] text-ink-3">
|
||||
|
||||
Reference in new issue
Block a user