diff --git a/package.json b/package.json index cd5b272..8ba7e1a 100644 --- a/package.json +++ b/package.json @@ -24,5 +24,10 @@ "scripts": { "postinstall": "patch-package", "start": "node main.js" + }, + "devDependencies": { + "@eslint/js": "^9.13.0", + "eslint": "^9.13.0", + "globals": "^15.11.0" } } diff --git a/settings.js b/settings.js index 1de12c0..1b33d94 100644 --- a/settings.js +++ b/settings.js @@ -21,7 +21,7 @@ export default "show_bot_views": false, // show bot's view in browser at localhost:3000, 3001... "allow_insecure_coding": false, // allows newAction command and model can write/run code on your computer. enable at own risk - "code_timeout_mins": 10, // minutes code is allowed to run. -1 for no timeout + "code_timeout_mins": 1, // minutes code is allowed to run. -1 for no timeout,set 1.Set 1 min to timely code adjustments "max_messages": 15, // max number of messages to keep in context "max_commands": -1, // max number of commands to use in a response. -1 for no limit diff --git a/src/agent/coder.js b/src/agent/coder.js index d312387..fad23ea 100644 --- a/src/agent/coder.js +++ b/src/agent/coder.js @@ -1,6 +1,7 @@ import { writeFile, readFile, mkdirSync } from 'fs'; import { checkSafe } from '../utils/safety.js'; import settings from '../../settings.js'; +import {ESLint} from "eslint"; export class Coder { constructor(agent) { @@ -20,7 +21,31 @@ export class Coder { mkdirSync('.' + this.fp, { recursive: true }); } + + async checkCode(code) { + const eslint = new ESLint(); + const results = await eslint.lintText(code); + const codeLines = code.split('\n'); + let result = '#### CODE ERROR INFO ###\n'; + const exceptions = results.map(r => r.messages).flat(); + if (exceptions.length > 0) { + exceptions.forEach((exc, index) => { + if (exc.line && exc.column ) { + const errorLine = codeLines[exc.line - 1]?.trim() || 'Unable to retrieve error line content'; + result += `#ERROR ${index + 1}\n`; + result += `Message: ${exc.message}\n`; + result += `Location: Line ${exc.line}, Column ${exc.column}\n`; + result += `Related Code Line: ${errorLine}\n\n`; + } + }); + result += 'The code contains exceptions and cannot continue execution.\n'; + } else { + return null;//no error + } + + return result ; + } // write custom code to file and import it async stageCode(code) { code = this.sanitizeCode(code); @@ -48,12 +73,11 @@ export class Coder { this.file_counter++; let write_result = await this.writeFilePromise('.' + this.fp + filename, src) - if (write_result) { console.error('Error writing code execution file: ' + result); return null; } - return await import('../..' + this.fp + filename); + return {filename,src}; } sanitizeCode(code) { @@ -137,7 +161,14 @@ export class Coder { continue; } - const execution_file = await this.stageCode(code); + let {filename,src} = await this.stageCode(code); + const analysisResult = await this.checkCode(src); + if (analysisResult) { + const message = 'Error: Code syntax error. Please try again:'+'\n'+analysisResult+'\n'+await this.agent.prompter.getRelevantSkillDocs(analysisResult,3); + messages.push({ role: 'system', content: message }); + continue; + } + const execution_file = await import('../..' +this.fp+filename); if (!execution_file) { agent_history.add('system', 'Failed to stage code, something is wrong.'); return {success: false, message: null, interrupted: false, timedout: false}; @@ -219,10 +250,11 @@ export class Coder { this.executing = false; clearTimeout(TIMEOUT); this.cancelResume(); - console.error("Code execution triggered catch: " + err); await this.stop(); - let message = this.formatOutput(this.agent.bot) + '!!Code threw exception!! Error: ' + err; + err = err.toString(); + let relevant_skill_docs = await this.agent.prompter.getRelevantSkillDocs(err,5); + let message = this.formatOutput(this.agent.bot) + '!!Code threw exception!! Error: ' + err+'\n'+relevant_skill_docs; let interrupted = this.agent.bot.interrupt_code; this.clear(); if (!interrupted && !this.generating) this.agent.bot.emit('idle'); diff --git a/src/agent/prompter.js b/src/agent/prompter.js index 530de3d..317f4b6 100644 --- a/src/agent/prompter.js +++ b/src/agent/prompter.js @@ -125,9 +125,8 @@ export class Prompter { ]); } - async getRelevantSkillDocs(messages, select_num) { - let latest_message_content = messages.slice().reverse().find(msg => msg.role !== 'system')?.content || ''; - let latest_message_embedding = await this.embedding_model.embed([latest_message_content]); + async getRelevantSkillDocs(message, select_num) { + let latest_message_embedding = await this.embedding_model.embed(message); let skill_doc_similarities = Object.keys(this.skill_docs_embeddings) .map(doc_key => ({ @@ -143,9 +142,9 @@ export class Prompter { select_num = Math.min(Math.floor(select_num), length); } let selected_docs = skill_doc_similarities.slice(0, select_num); - let message = '\nThe following recommended functions are listed in descending order of task relevance.\nSkillDocs:\n'; - message += selected_docs.map(doc => `${doc.doc_key}`).join('\n'); - return message; + let relevant_skill_docs = '####RELEVENT DOCS INFO###\nThe following functions are listed in descending order of relevance.\nSkillDocs:\n'; + relevant_skill_docs += selected_docs.map(doc => `${doc.doc_key}`).join('\n'); + return relevant_skill_docs; } async replaceStrings(prompt, messages, examples=null, to_summarize=[], last_goals=null) { @@ -161,8 +160,10 @@ export class Prompter { } if (prompt.includes('$COMMAND_DOCS')) prompt = prompt.replaceAll('$COMMAND_DOCS', getCommandDocs()); - if (prompt.includes('$CODE_DOCS')) - prompt = prompt.replaceAll('$CODE_DOCS', this.getRelevantSkillDocs(messages, 0)); + if (prompt.includes('$CODE_DOCS')){ + let latest_message_content = messages.slice().reverse().find(msg => msg.role !== 'system')?.content || ''; + prompt = prompt.replaceAll('$CODE_DOCS', await this.getRelevantSkillDocs(latest_message_content, 5)); + } if (prompt.includes('$EXAMPLES') && examples !== null) prompt = prompt.replaceAll('$EXAMPLES', await examples.createExampleMessage(messages)); if (prompt.includes('$MEMORY'))