Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | /**
* Outils IA — Exécution des outils disponibles pour les agents IA.
*
* Commun à tous les providers (Claude, OpenAI, Mistral).
* Gère : bash_exec, read_file, write_file.
*
* @module services/tools
*/
const { exec } = require('./ssh');
const { analyzeCommand } = require('./commandAnalyzer');
const { shellEscape } = require('../utils/shell');
const { validatePath } = require('../utils/pathValidator');
const SYSTEM_PROMPT = `Tu es IliaCloud Assistant, un agent IA expert en administration système Linux et Docker.
Tu as accès à un serveur distant via SSH.
Tu peux exécuter des commandes bash pour diagnostiquer des problèmes, lire des fichiers et aider l'utilisateur.
Règles impératives :
- Avant d'exécuter une commande destructive (rm -rf, docker stop, etc.), annonce-la et attends la confirmation.
- Ne jamais exécuter plus d'une commande destructive à la fois.
- Explique ce que tu fais avant de le faire.
- En cas d'erreur, analyse le message et propose une solution.
- Réponds en français sauf si l'utilisateur écrit dans une autre langue.`;
// Définition des outils au format Anthropic (Claude)
const ANTHROPIC_TOOLS = [
{
name: 'bash_exec',
description: 'Exécute une commande bash sur le serveur distant via SSH. Retourne stdout, stderr et le code de sortie.',
input_schema: {
type: 'object',
properties: { command: { type: 'string', description: 'La commande bash à exécuter sur le serveur.' } },
required: ['command'],
},
},
{
name: 'read_file',
description: 'Lit le contenu d\'un fichier sur le serveur distant.',
input_schema: {
type: 'object',
properties: { path: { type: 'string', description: 'Chemin absolu du fichier à lire.' } },
required: ['path'],
},
},
{
name: 'write_file',
description: 'Écrit ou modifie un fichier sur le serveur distant. ATTENTION : nécessite confirmation utilisateur.',
input_schema: {
type: 'object',
properties: {
path: { type: 'string', description: 'Chemin absolu du fichier à écrire.' },
content: { type: 'string', description: 'Contenu à écrire dans le fichier.' },
},
required: ['path', 'content'],
},
},
];
// Définition des outils au format OpenAI (compatible Mistral)
const OPENAI_TOOLS = ANTHROPIC_TOOLS.map((t) => ({
type: 'function',
function: {
name: t.name,
description: t.description,
parameters: t.input_schema,
},
}));
async function executeBashExec({ userId, serverId, input, onPendingAction }) {
const analysis = analyzeCommand(input.command);
if (analysis.level === 'dangerous' && onPendingAction) {
const confirmed = await onPendingAction({ tool: 'bash_exec', input, analysis });
if (!confirmed) return 'Action refusée par l\'utilisateur.';
}
const { stdout, stderr, code } = await exec(userId, serverId, input.command, 60000);
return JSON.stringify({ stdout, stderr, exit_code: code });
}
async function executeReadFile({ userId, serverId, input }) {
const pathCheck = validatePath(input.path);
if (!pathCheck.valid) throw new Error(`Chemin invalide : ${pathCheck.reason}`);
const safePath = shellEscape(input.path);
const { stdout, stderr, code } = await exec(userId, serverId, `cat ${safePath}`, 15000);
if (code !== 0) return `Erreur (code ${code}): ${stderr}`;
return stdout;
}
async function executeWriteFile({ userId, serverId, input, onPendingAction }) {
if (onPendingAction) {
const confirmed = await onPendingAction({ tool: 'write_file', input, analysis: { level: 'write' } });
if (!confirmed) return 'Écriture annulée par l\'utilisateur.';
}
const pathCheck = validatePath(input.path);
if (!pathCheck.valid) throw new Error(`Chemin invalide : ${pathCheck.reason}`);
const base64Content = Buffer.from(input.content, 'utf8').toString('base64');
const safePath = shellEscape(input.path);
const cmd = `echo ${shellEscape(base64Content)} | base64 -d > ${safePath}`;
const { stderr, code } = await exec(userId, serverId, cmd, 15000);
if (code !== 0) return `Erreur : ${stderr}`;
return `Fichier ${input.path} écrit avec succès.`;
}
/**
* Exécute un outil par son nom.
* @returns {Promise<string>}
*/
async function executeTool(name, params) {
if (name === 'bash_exec') return executeBashExec(params);
if (name === 'read_file') return executeReadFile(params);
if (name === 'write_file') return executeWriteFile(params);
return 'Outil inconnu.';
}
module.exports = { SYSTEM_PROMPT, ANTHROPIC_TOOLS, OPENAI_TOOLS, executeTool };
|