const inferenceClient = require('./inferenceClient'); const toolManager = require('./toolManager'); function stripCodeFences(text) { return text .trim() .replace(/^```[a-zA-Z]*\n?/, '') .replace(/```$/, '') .trim(); } // Given a broken tool and the error it threw, ask the model for a corrected // version and file it as a pending fix. Returns the new pending entry, or // null if the model failed to produce a usable patch. async function attemptFix(tool, error) { const prompt = [ `The tool "${tool.name}" threw an error when it ran.`, '', `Description: ${tool.description}`, '', 'Current code:', '---', tool.code, '---', '', `Error message: ${error.message}`, error.stack ? `Stack: ${error.stack}` : '', error.logs && error.logs.length ? `Console output before the error: ${error.logs.join(' | ')}` : '', '', 'Write a corrected full replacement for the tool code, using the exact same convention:', 'an async function named run(args) that returns a JSON-serializable result.', 'Reply with ONLY the corrected JavaScript code. No explanation, no markdown fences.', ] .filter(Boolean) .join('\n'); let message; try { message = await inferenceClient.chat([ { role: 'system', content: 'You are a careful senior JavaScript engineer patching a broken tool for a self-improving assistant. ' + 'You fix root causes, keep the same run(args) function signature, and never add explanations outside the code.', }, { role: 'user', content: prompt }, ]); } catch (e) { console.error('[errorHealer] fix request failed:', e.message); return null; } const code = stripCodeFences(message.content || ''); if (!code || !/async\s+function\s+run\s*\(/.test(code)) { console.error('[errorHealer] model did not return a usable run(args) function'); return null; } return toolManager.proposeFix(tool.id, code, `Auto-fix attempt for error: ${error.message}`); } module.exports = { attemptFix };