Created
September 11, 2025 22:28
-
-
Save mikegwhit/c88437782e82c2fd3cb196da37d65ce9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const { GoogleGenerativeAI } = require('@google/generative-ai'); | |
| const dotenv = require('dotenv'); | |
| const { execSync } = require('child_process'); | |
| const fs = require('fs'); | |
| dotenv.config(); | |
| // Initialize the API with your key | |
| const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY); | |
| // Define the function declarations for the API | |
| const tools = [ | |
| { | |
| functionDeclarations: [ | |
| { | |
| name: 'run_npm_test', | |
| description: 'Runs the \'npm test\' command and returns the test results, including success or failure status and the console output.', | |
| parameters: { | |
| type: 'object', | |
| properties: {}, | |
| }, | |
| }, | |
| { | |
| name: 'read_file', | |
| description: 'Reads the content of a file.', | |
| parameters: { | |
| type: 'object', | |
| properties: { | |
| filePath: { | |
| type: 'string', | |
| description: 'The path to the file to read.', | |
| }, | |
| }, | |
| required: ['filePath'], | |
| }, | |
| }, | |
| { | |
| name: 'apply_fix', | |
| description: 'Applies a fix to a file.', | |
| parameters: { | |
| type: 'object', | |
| properties: { | |
| filePath: { | |
| type: 'string', | |
| description: 'The path to the file to fix.', | |
| }, | |
| code: { | |
| type: 'string', | |
| description: 'The new code to write to the file.', | |
| }, | |
| }, | |
| required: ['filePath', 'code'], | |
| }, | |
| } | |
| ], | |
| }, | |
| ]; | |
| // The function to run npm test | |
| function runNpmTest() { | |
| try { | |
| console.log('Running npm test...'); | |
| const output = execSync('npm test', { encoding: 'utf-8' }); | |
| return { status: 'passed', output: output }; | |
| } catch (error) { | |
| // Return a detailed error object if tests fail | |
| return { status: 'failed', output: error.stdout, error: error.stderr }; | |
| } | |
| } | |
| function readFile({ filePath }) { | |
| console.log(`Reading file ${filePath}...`); | |
| try { | |
| const content = fs.readFileSync(filePath, 'utf-8'); | |
| return { status: 'success', content: content }; | |
| } catch (error) { | |
| return { status: 'failed', error: error.message }; | |
| } | |
| } | |
| function applyFix({ filePath, code }) { | |
| console.log(`Applying fix to ${filePath}...`); | |
| try { | |
| fs.writeFileSync(filePath, code); | |
| return { status: 'success' }; | |
| } catch (error) { | |
| return { status: 'failed', error: error.message }; | |
| } | |
| } | |
| async function orchestrateDebugging() { | |
| const model = genAI.getGenerativeModel({ model: 'gemini-1.5-flash', tools }); | |
| const chat = model.startChat({ | |
| history: [ | |
| { | |
| role: "user", | |
| parts: [{ text: "You are an expert at debugging node.js applications." }], | |
| }, | |
| { | |
| role: "model", | |
| parts: [{ text: "I am an expert at debugging node.js applications. I will help you fix the errors in your code." }], | |
| } | |
| ] | |
| }); | |
| let userPrompt = 'Please run `npm test`. If it fails, read the test.js file, suggest a fix, and apply it. Repeat the process until the test passes.'; | |
| let iteration = 0; | |
| let hasReachedGoal = false; | |
| while (!hasReachedGoal && iteration < 5) { // Add an iteration limit to prevent infinite loops | |
| console.log(`--- Iteration ${iteration + 1} ---`); | |
| const result = await chat.sendMessage(userPrompt); | |
| const response = result.response; | |
| if (response.functionCalls && response.functionCalls.length > 0) { | |
| const functionCalls = response.functionCalls; | |
| const functionResponses = []; | |
| for (const call of functionCalls) { | |
| console.log(`Model requested a function call: ${call.name}`); | |
| let functionOutput; | |
| // Handle the function call | |
| if (call.name === 'run_npm_test') { | |
| const testResults = runNpmTest(); | |
| functionOutput = testResults; | |
| } else if (call.name === 'read_file') { | |
| const fileContent = readFile(call.args); | |
| functionOutput = fileContent; | |
| } else if (call.name === 'apply_fix') { | |
| const fixResult = applyFix(call.args); | |
| functionOutput = fixResult; | |
| } | |
| console.log(`Function output:`, functionOutput); | |
| functionResponses.push({ | |
| functionResponse: { | |
| name: call.name, | |
| response: functionOutput | |
| } | |
| }); | |
| } | |
| const responseWithFunctionResult = await chat.sendMessage(functionResponses); | |
| const nextResponse = responseWithFunctionResult.response; | |
| if (nextResponse) { | |
| const textResponse = nextResponse.text(); | |
| if (textResponse) { | |
| console.log(`Model's response: ${textResponse}`); | |
| if (textResponse.includes("Test passed!")) { | |
| hasReachedGoal = true; | |
| } | |
| } | |
| } | |
| userPrompt = "The test failed again, please try again."; | |
| } else if (response.text()) { | |
| // If the model did not request a function call, it's a text response | |
| const textResponse = response.text(); | |
| console.log(`Model's response: ${textResponse}`); | |
| if (textResponse.includes("Test passed!")) { | |
| hasReachedGoal = true; | |
| } | |
| } else { | |
| hasReachedGoal = true; | |
| } | |
| iteration++; | |
| } | |
| } | |
| orchestrateDebugging().catch(console.error); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment