feat: add language-specific code execution commands
- Add /js, /python, /py, /ts, /bash, /sh commands for quick code execution - Add /run <lang> <code> for any supported language - Update /status to show sandbox backend (docker/piston/none) - Update /start and /help with new command documentation - Update AI system prompts to know about available commands - Bot now guides users to use /js, /python etc. when they ask to run code - Fixes issue where AI was hallucinating non-existent commands Supported languages via Piston API fallback: python, javascript, typescript, bash, rust, go, c, cpp, java, ruby, php https://claude.ai/code/session_015VqJ7gN4vaxtYfYc92UjLs
This commit is contained in:
parent
095d476acc
commit
64e840849f
@ -46,7 +46,7 @@ const DEFAULT_ANTHROPIC_MODEL = "claude-sonnet-4-20250514";
|
||||
const DEFAULT_OPENAI_MODEL = "gpt-4o";
|
||||
const DEFAULT_OPENROUTER_MODEL = "anthropic/claude-3.5-sonnet";
|
||||
|
||||
const DEFAULT_SYSTEM_PROMPT = `You are a helpful AI assistant running as a secure, self-hosted bot.
|
||||
const DEFAULT_SYSTEM_PROMPT = `You are AssureBot, a helpful AI assistant running as a secure Telegram bot.
|
||||
|
||||
You are direct, concise, and helpful. You can:
|
||||
- Answer questions and have conversations
|
||||
@ -54,7 +54,17 @@ You are direct, concise, and helpful. You can:
|
||||
- Help with coding and technical tasks
|
||||
- Summarize content and extract information
|
||||
|
||||
When you receive webhook notifications, summarize them helpfully for the user.
|
||||
## Available Commands (tell users about these when relevant)
|
||||
- /js <code> - Run JavaScript
|
||||
- /python <code> - Run Python
|
||||
- /ts <code> - Run TypeScript
|
||||
- /bash <code> - Run shell commands
|
||||
- /run <lang> <code> - Run code in any language (python, js, ts, bash, rust, go, c, cpp, java, ruby, php)
|
||||
- /status - Check bot status
|
||||
- /clear - Clear conversation history
|
||||
|
||||
When users ask to run or test code, guide them to use the appropriate command.
|
||||
Example: "Use /js console.log('hello')" or "Try /python print('hello')"
|
||||
|
||||
Be security-conscious:
|
||||
- Never reveal API keys, tokens, or secrets
|
||||
|
||||
@ -96,7 +96,7 @@ export async function createPersonality(storage: Storage): Promise<Personality>
|
||||
async getSystemPrompt(userId: number): Promise<string> {
|
||||
const profile = await loadUserProfile(userId);
|
||||
|
||||
let prompt = `You are ${traits.name}, a helpful AI assistant.
|
||||
let prompt = `You are ${traits.name}, a helpful AI assistant running as a Telegram bot.
|
||||
|
||||
## Personality
|
||||
- Tone: ${profile.preferredTone}
|
||||
@ -112,11 +112,28 @@ ${traits.expertiseAreas.map(e => `- ${e}`).join("\n")}
|
||||
- Recent topics: ${profile.recentTopics.length > 0 ? profile.recentTopics.slice(-3).join(", ") : "None yet"}
|
||||
${profile.notes.length > 0 ? `- Notes: ${profile.notes.slice(-3).join("; ")}` : ""}
|
||||
|
||||
## Available Commands (you can tell users about these)
|
||||
- /js <code> - Run JavaScript code
|
||||
- /python <code> or /py <code> - Run Python code
|
||||
- /ts <code> - Run TypeScript code
|
||||
- /bash <code> or /sh <code> - Run shell commands
|
||||
- /run <language> <code> - Run code in any supported language (python, javascript, typescript, bash, rust, go, c, cpp, java, ruby, php)
|
||||
- /status - Check bot and sandbox status
|
||||
- /clear - Clear conversation history
|
||||
- /schedule "<cron>" "<name>" <prompt> - Schedule recurring AI tasks
|
||||
- /tasks - List scheduled tasks
|
||||
- /deltask <id> - Delete a task
|
||||
|
||||
When a user asks to run code, you can either:
|
||||
1. Tell them to use the appropriate command (e.g., "Use /js console.log('hello')")
|
||||
2. Just answer their question directly if they don't need to execute code
|
||||
|
||||
## Guidelines
|
||||
- Be helpful, accurate, and security-conscious
|
||||
- Never reveal API keys, tokens, or secrets
|
||||
- Adapt to the user's communication style
|
||||
- Remember context from this conversation
|
||||
- When users want to run code, guide them to use the right command
|
||||
${traits.commonPhrases.length > 0 ? `- Phrases you like: ${traits.commonPhrases.join(", ")}` : ""}
|
||||
${traits.avoidPhrases.length > 0 ? `- Avoid saying: ${traits.avoidPhrases.join(", ")}` : ""}`;
|
||||
|
||||
|
||||
@ -73,19 +73,25 @@ export function createTelegramBot(deps: TelegramDeps): TelegramBot {
|
||||
|
||||
You are authorized to use this bot.
|
||||
|
||||
Commands:
|
||||
/start - Show this message
|
||||
/clear - Clear conversation history
|
||||
Code Execution:
|
||||
/js <code> - Run JavaScript
|
||||
/python <code> - Run Python
|
||||
/ts <code> - Run TypeScript
|
||||
/bash <code> - Run shell commands
|
||||
/run <lang> <code> - Run any language
|
||||
|
||||
Other Commands:
|
||||
/status - Check bot status
|
||||
/sandbox <code> - Run code in sandbox
|
||||
/schedule <cron> <task> - Schedule a task
|
||||
/clear - Clear conversation history
|
||||
/schedule - Schedule AI tasks
|
||||
/tasks - List scheduled tasks
|
||||
/help - Show help
|
||||
/help - Show full help
|
||||
|
||||
Features:
|
||||
- Send text messages to chat
|
||||
- Send images for analysis
|
||||
- Forward content for analysis`
|
||||
- Chat with AI
|
||||
- Image analysis (send photos)
|
||||
- Document analysis (send PDFs)
|
||||
- Code execution (15+ languages)`
|
||||
);
|
||||
});
|
||||
|
||||
@ -108,11 +114,15 @@ Features:
|
||||
}
|
||||
|
||||
const history = conversations.get(userId);
|
||||
const sandboxStatus = sandbox
|
||||
? `${sandbox.backend} (${await sandbox.isAvailable() ? "ready" : "unavailable"})`
|
||||
: "not configured";
|
||||
|
||||
await ctx.reply(
|
||||
`Status:
|
||||
- AI Provider: ${agent.provider}
|
||||
- Conversation: ${history.length} messages
|
||||
- Sandbox: ${config.sandbox.enabled ? "enabled" : "disabled"}
|
||||
- Sandbox: ${sandboxStatus}
|
||||
- Webhooks: ${config.webhooks.enabled ? "enabled" : "disabled"}
|
||||
- Scheduler: ${config.scheduler.enabled ? "enabled" : "disabled"}`
|
||||
);
|
||||
@ -130,27 +140,32 @@ Features:
|
||||
|
||||
A secure, self-hosted AI assistant.
|
||||
|
||||
Features:
|
||||
- Chat with AI (text messages)
|
||||
- Image analysis (send photos)
|
||||
- Forward content for analysis
|
||||
- Run code in isolated sandbox
|
||||
- Schedule recurring AI tasks
|
||||
CODE EXECUTION:
|
||||
/js <code> - Run JavaScript
|
||||
/python <code> or /py <code> - Run Python
|
||||
/ts <code> - Run TypeScript
|
||||
/bash <code> or /sh <code> - Run shell
|
||||
/run <lang> <code> - Run any language
|
||||
|
||||
Commands:
|
||||
/start - Welcome message
|
||||
/clear - Clear conversation history
|
||||
/status - Bot status
|
||||
/sandbox <code> - Run code in sandbox
|
||||
/schedule "<cron>" "<name>" <prompt> - Schedule task
|
||||
/tasks - List scheduled tasks
|
||||
/deltask <id> - Delete a task
|
||||
Supported: python, javascript, typescript, bash, rust, go, c, cpp, java, ruby, php
|
||||
|
||||
SCHEDULING:
|
||||
/schedule "<cron>" "<name>" <prompt>
|
||||
/tasks - List tasks
|
||||
/deltask <id> - Delete task
|
||||
|
||||
Example: /schedule "0 9 * * *" "Morning" Good morning!
|
||||
|
||||
OTHER:
|
||||
/status - Bot & sandbox status
|
||||
/clear - Clear conversation
|
||||
/help - This message
|
||||
|
||||
Security:
|
||||
- Only authorized users can interact
|
||||
- All interactions are logged
|
||||
- Sandbox runs in isolated Docker (no network)`
|
||||
FEATURES:
|
||||
- Chat naturally with AI
|
||||
- Send images for analysis
|
||||
- Send PDFs/docs for analysis
|
||||
- Code runs in isolated sandbox`
|
||||
);
|
||||
});
|
||||
|
||||
@ -206,6 +221,141 @@ Security:
|
||||
}
|
||||
});
|
||||
|
||||
// Helper for language-specific code execution
|
||||
async function runCodeCommand(
|
||||
ctx: Context,
|
||||
language: string,
|
||||
commandName: string
|
||||
): Promise<void> {
|
||||
const userId = ctx.from?.id;
|
||||
if (!userId || !isUserAllowed(userId, config.telegram.allowedUsers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sandbox) {
|
||||
await ctx.reply("Sandbox is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
const isAvailable = await sandbox.isAvailable();
|
||||
if (!isAvailable) {
|
||||
await ctx.reply(`Sandbox unavailable. Backend: ${sandbox.backend}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const code = ctx.message?.text?.replace(new RegExp(`^/${commandName}\\s*`), "").trim() ?? "";
|
||||
if (!code) {
|
||||
await ctx.reply(`Usage: /${commandName} <code>\n\nExample: /${commandName} console.log("Hello!")`);
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.replyWithChatAction("typing");
|
||||
|
||||
try {
|
||||
const result = await sandbox.runCode(language, code);
|
||||
const output = result.stdout || result.stderr || "(no output)";
|
||||
const status = result.exitCode === 0 ? "✓" : `✗ (exit ${result.exitCode})`;
|
||||
const timeout = result.timedOut ? " [TIMED OUT]" : "";
|
||||
const backend = sandbox.backend === "piston" ? " [Piston]" : "";
|
||||
|
||||
await ctx.reply(
|
||||
`**${language}** ${status}${timeout}${backend}\n\`\`\`\n${output.slice(0, 3000)}\n\`\`\`\nDuration: ${result.durationMs}ms`,
|
||||
{ parse_mode: "Markdown" }
|
||||
).catch(async () => {
|
||||
await ctx.reply(`${language} ${status}${timeout}${backend}\n\n${output.slice(0, 3500)}\n\nDuration: ${result.durationMs}ms`);
|
||||
});
|
||||
|
||||
audit.sandbox({
|
||||
command: `[${language}] ${code.slice(0, 100)}`,
|
||||
exitCode: result.exitCode,
|
||||
durationMs: result.durationMs,
|
||||
});
|
||||
} catch (err) {
|
||||
const errorMsg = err instanceof Error ? err.message : String(err);
|
||||
audit.error({ error: `Code execution error: ${errorMsg}`, metadata: { userId, language, code } });
|
||||
await ctx.reply(`Error: ${errorMsg}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Command: /js <code> - Run JavaScript
|
||||
bot.command("js", (ctx) => runCodeCommand(ctx, "javascript", "js"));
|
||||
|
||||
// Command: /python <code> - Run Python
|
||||
bot.command("python", (ctx) => runCodeCommand(ctx, "python", "python"));
|
||||
bot.command("py", (ctx) => runCodeCommand(ctx, "python", "py"));
|
||||
|
||||
// Command: /ts <code> - Run TypeScript
|
||||
bot.command("ts", (ctx) => runCodeCommand(ctx, "typescript", "ts"));
|
||||
|
||||
// Command: /bash <code> - Run Bash
|
||||
bot.command("bash", (ctx) => runCodeCommand(ctx, "bash", "bash"));
|
||||
bot.command("sh", (ctx) => runCodeCommand(ctx, "bash", "sh"));
|
||||
|
||||
// Command: /run <language> <code> - Run code in any supported language
|
||||
bot.command("run", async (ctx) => {
|
||||
const userId = ctx.from?.id;
|
||||
if (!userId || !isUserAllowed(userId, config.telegram.allowedUsers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sandbox) {
|
||||
await ctx.reply("Sandbox is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
const isAvailable = await sandbox.isAvailable();
|
||||
if (!isAvailable) {
|
||||
await ctx.reply(`Sandbox unavailable. Backend: ${sandbox.backend}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const text = ctx.message?.text?.replace(/^\/run\s*/, "").trim() ?? "";
|
||||
const match = text.match(/^(\w+)\s+([\s\S]+)$/);
|
||||
if (!match) {
|
||||
await ctx.reply(
|
||||
`Usage: /run <language> <code>
|
||||
|
||||
Supported languages:
|
||||
- javascript, js
|
||||
- typescript, ts
|
||||
- python, py
|
||||
- bash, sh
|
||||
- rust, go, c, cpp, java, ruby, php
|
||||
|
||||
Example: /run python print("Hello!")`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const [, language, code] = match;
|
||||
await ctx.replyWithChatAction("typing");
|
||||
|
||||
try {
|
||||
const result = await sandbox.runCode(language, code);
|
||||
const output = result.stdout || result.stderr || "(no output)";
|
||||
const status = result.exitCode === 0 ? "✓" : `✗ (exit ${result.exitCode})`;
|
||||
const timeout = result.timedOut ? " [TIMED OUT]" : "";
|
||||
const backend = sandbox.backend === "piston" ? " [Piston]" : "";
|
||||
|
||||
await ctx.reply(
|
||||
`**${language}** ${status}${timeout}${backend}\n\`\`\`\n${output.slice(0, 3000)}\n\`\`\`\nDuration: ${result.durationMs}ms`,
|
||||
{ parse_mode: "Markdown" }
|
||||
).catch(async () => {
|
||||
await ctx.reply(`${language} ${status}${timeout}${backend}\n\n${output.slice(0, 3500)}\n\nDuration: ${result.durationMs}ms`);
|
||||
});
|
||||
|
||||
audit.sandbox({
|
||||
command: `[${language}] ${code.slice(0, 100)}`,
|
||||
exitCode: result.exitCode,
|
||||
durationMs: result.durationMs,
|
||||
});
|
||||
} catch (err) {
|
||||
const errorMsg = err instanceof Error ? err.message : String(err);
|
||||
audit.error({ error: `Code execution error: ${errorMsg}`, metadata: { userId, language, code } });
|
||||
await ctx.reply(`Error: ${errorMsg}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Command: /schedule <cron> <name> <prompt>
|
||||
bot.command("schedule", async (ctx) => {
|
||||
const userId = ctx.from?.id;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user