Code capability enhancement & bot crash fix

This commit is contained in:
Qu Yi 2024-11-02 20:26:56 +08:00
parent 17fa2b6083
commit ecaf5e87e1
4 changed files with 52 additions and 14 deletions

View file

@ -24,5 +24,10 @@
"scripts": { "scripts": {
"postinstall": "patch-package", "postinstall": "patch-package",
"start": "node main.js" "start": "node main.js"
},
"devDependencies": {
"@eslint/js": "^9.13.0",
"eslint": "^9.13.0",
"globals": "^15.11.0"
} }
} }

View file

@ -21,7 +21,7 @@ export default
"show_bot_views": false, // show bot's view in browser at localhost:3000, 3001... "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 "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_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 "max_commands": -1, // max number of commands to use in a response. -1 for no limit

View file

@ -1,6 +1,7 @@
import { writeFile, readFile, mkdirSync } from 'fs'; import { writeFile, readFile, mkdirSync } from 'fs';
import { checkSafe } from '../utils/safety.js'; import { checkSafe } from '../utils/safety.js';
import settings from '../../settings.js'; import settings from '../../settings.js';
import {ESLint} from "eslint";
export class Coder { export class Coder {
constructor(agent) { constructor(agent) {
@ -21,6 +22,30 @@ export class Coder {
mkdirSync('.' + this.fp, { recursive: true }); 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 // write custom code to file and import it
async stageCode(code) { async stageCode(code) {
code = this.sanitizeCode(code); code = this.sanitizeCode(code);
@ -48,12 +73,11 @@ export class Coder {
this.file_counter++; this.file_counter++;
let write_result = await this.writeFilePromise('.' + this.fp + filename, src) let write_result = await this.writeFilePromise('.' + this.fp + filename, src)
if (write_result) { if (write_result) {
console.error('Error writing code execution file: ' + result); console.error('Error writing code execution file: ' + result);
return null; return null;
} }
return await import('../..' + this.fp + filename); return {filename,src};
} }
sanitizeCode(code) { sanitizeCode(code) {
@ -137,7 +161,14 @@ export class Coder {
continue; 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) { if (!execution_file) {
agent_history.add('system', 'Failed to stage code, something is wrong.'); agent_history.add('system', 'Failed to stage code, something is wrong.');
return {success: false, message: null, interrupted: false, timedout: false}; return {success: false, message: null, interrupted: false, timedout: false};
@ -219,10 +250,11 @@ export class Coder {
this.executing = false; this.executing = false;
clearTimeout(TIMEOUT); clearTimeout(TIMEOUT);
this.cancelResume(); this.cancelResume();
console.error("Code execution triggered catch: " + err);
await this.stop(); 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; let interrupted = this.agent.bot.interrupt_code;
this.clear(); this.clear();
if (!interrupted && !this.generating) this.agent.bot.emit('idle'); if (!interrupted && !this.generating) this.agent.bot.emit('idle');

View file

@ -125,9 +125,8 @@ export class Prompter {
]); ]);
} }
async getRelevantSkillDocs(messages, select_num) { async getRelevantSkillDocs(message, select_num) {
let latest_message_content = messages.slice().reverse().find(msg => msg.role !== 'system')?.content || ''; let latest_message_embedding = await this.embedding_model.embed(message);
let latest_message_embedding = await this.embedding_model.embed([latest_message_content]);
let skill_doc_similarities = Object.keys(this.skill_docs_embeddings) let skill_doc_similarities = Object.keys(this.skill_docs_embeddings)
.map(doc_key => ({ .map(doc_key => ({
@ -143,9 +142,9 @@ export class Prompter {
select_num = Math.min(Math.floor(select_num), length); select_num = Math.min(Math.floor(select_num), length);
} }
let selected_docs = skill_doc_similarities.slice(0, select_num); 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'; let relevant_skill_docs = '####RELEVENT DOCS INFO###\nThe following functions are listed in descending order of relevance.\nSkillDocs:\n';
message += selected_docs.map(doc => `${doc.doc_key}`).join('\n'); relevant_skill_docs += selected_docs.map(doc => `${doc.doc_key}`).join('\n');
return message; return relevant_skill_docs;
} }
async replaceStrings(prompt, messages, examples=null, to_summarize=[], last_goals=null) { async replaceStrings(prompt, messages, examples=null, to_summarize=[], last_goals=null) {
@ -161,8 +160,10 @@ export class Prompter {
} }
if (prompt.includes('$COMMAND_DOCS')) if (prompt.includes('$COMMAND_DOCS'))
prompt = prompt.replaceAll('$COMMAND_DOCS', getCommandDocs()); prompt = prompt.replaceAll('$COMMAND_DOCS', getCommandDocs());
if (prompt.includes('$CODE_DOCS')) if (prompt.includes('$CODE_DOCS')){
prompt = prompt.replaceAll('$CODE_DOCS', this.getRelevantSkillDocs(messages, 0)); 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) if (prompt.includes('$EXAMPLES') && examples !== null)
prompt = prompt.replaceAll('$EXAMPLES', await examples.createExampleMessage(messages)); prompt = prompt.replaceAll('$EXAMPLES', await examples.createExampleMessage(messages));
if (prompt.includes('$MEMORY')) if (prompt.includes('$MEMORY'))