discord-linux-groq-agent/agent.mjs
2024-12-10 04:10:46 -05:00

166 lines
5.3 KiB
JavaScript

import 'dotenv/config';
import Groq from 'groq-sdk';
import unirest from 'unirest';
const DISCORD_LINUX_API_URL = 'https://api.ssh.surf';
const DISCORD_LINUX_API_KEY = process.env['DISCORD_LINUX_API_KEY'];
const GROQ_API_KEY = process.env['GROQ_API_KEY'];
const MAX_ITERATIONS = 5;
// Initialize the Groq client
const groqClient = new Groq({
apiKey: GROQ_API_KEY,
});
// A small helper for nice verbose logging:
function logHeader(message) {
console.log('\n' + '═'.repeat(80));
console.log('═ ' + message);
console.log('═'.repeat(80) + '\n');
}
function logSubHeader(message) {
console.log('\n' + '-'.repeat(60));
console.log('> ' + message);
console.log('-'.repeat(60) + '\n');
}
function logInfo(message) {
console.log(`INFO: ${message}`);
}
function logCommandStart(cmd) {
console.log(`\n[EXECUTING COMMAND]\n$ ${cmd}\n`);
}
function logCommandResult(stdout, stderr) {
if (stdout && stdout.trim().length > 0) {
console.log("[STDOUT]:\n" + indentMultiline(stdout));
} else {
console.log("[STDOUT]: (empty)\n");
}
if (stderr && stderr.trim().length > 0) {
console.log("[STDERR]:\n" + indentMultiline(stderr));
} else {
console.log("[STDERR]: (empty)\n");
}
}
function indentMultiline(text) {
return text.split('\n').map(line => ' ' + line).join('\n');
}
// Helper to execute a command in the container:
async function execCommandInContainer(cmd, pwd = '/home') {
const response = await unirest
.post(`${DISCORD_LINUX_API_URL}/exec`)
.headers({
'Accept': 'application/json',
'Content-Type': 'application/json',
'x-ssh-auth': DISCORD_LINUX_API_KEY
})
.send({ cmd, pwd });
return response.body;
}
// This function queries the AI for instructions. It returns a series of commands to try.
async function askAIForInstructions(context, goal) {
const systemPrompt = `You are a world-class Linux system administration assistant, given the ability to access and run commands on a remote Debian/Ubuntu-based Linux container. Your mission is to help achieve the following goal: ${goal}.
Rules:
1. Return only shell commands needed, line-by-line, no explanation.
2. If previous attempts failed, refine your approach and fix the issues based on the provided errors and output.
3. If you need to run multiple commands, separate them by new lines.
4. Consider common steps: updating package lists, installing packages, verifying installation.
5. The container might be minimal, so consider installing or fixing repositories if needed.
6. Always ensure commands are non-interactive.
7. Do not use markdown formatting at all ever.
8. All commands are non-interactive
9. If installing packages, always use -y to allow for non-interactive commands
`;
const userPrompt = `CONTEXT:\n${context}\n\nPlease provide the exact shell commands to achieve the goal above.`;
const params = {
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
],
model: 'llama3-8b-8192',
};
const chatCompletion = await groqClient.chat.completions.create(params);
const aiResponse = chatCompletion.choices[0].message.content.trim();
return aiResponse;
}
function parseCommandsFromAIResponse(aiResponse) {
const lines = aiResponse.split('\n').map(l => l.trim()).filter(l => l.length > 0);
return lines;
}
async function main() {
const goal = 'install apache2 (apache2) on the container and run it with service';
let context = "Initial attempt. No commands have been run yet.\n" +
"We are working with a Debian/Ubuntu container.\n" +
"Goal: " + goal;
logHeader(`STARTING PROCESS TO ACHIEVE GOAL: ${goal}`);
let iteration = 0;
let success = false;
while (iteration < MAX_ITERATIONS && !success) {
iteration++;
logHeader(`ITERATION ${iteration} OF ${MAX_ITERATIONS}`);
logSubHeader('Asking AI for instructions');
const instructions = await askAIForInstructions(context, goal);
console.log("AI PROVIDED COMMANDS:\n" + indentMultiline(instructions));
const commands = parseCommandsFromAIResponse(instructions);
let allCommandsSucceeded = true;
let attemptLog = `Attempt #${iteration}:\nAI instructions:\n${instructions}\n\nCommand results:\n`;
for (const cmd of commands) {
logCommandStart(cmd);
const result = await execCommandInContainer(cmd);
const stdout = result.stdout || '';
const stderr = result.stderr || '';
logCommandResult(stdout, stderr);
attemptLog += `\n> ${cmd}\nstdout:\n${stdout}\nstderr:\n${stderr}\n`;
if (stderr && stderr.trim().length > 0) {
logInfo(`Command failed with error detected in STDERR. Will request refined instructions next iteration.`);
allCommandsSucceeded = false;
break;
} else {
logInfo(`Command executed successfully.`);
}
}
context += `\n\n${attemptLog}`;
if (allCommandsSucceeded) {
logInfo("All commands executed successfully.");
success = true;
} else {
logInfo("At least one command failed. The AI will refine approach in next iteration.");
}
}
if (success) {
logHeader("SUCCESS! The goal appears to have been achieved.");
} else {
logHeader("FAILURE TO ACHIEVE GOAL WITHIN MAX ITERATIONS");
logInfo("Below is the final accumulated context/logs:\n" + context);
}
}
main().catch(err => {
console.error("An error occurred:", err);
});