Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cascade coder agent calls #161

Open
hatkyinc2 opened this issue Apr 30, 2023 · 1 comment
Open

Cascade coder agent calls #161

hatkyinc2 opened this issue Apr 30, 2023 · 1 comment
Labels
enhancement New feature or request

Comments

@hatkyinc2
Copy link
Collaborator

Background story explaining the current situation:
Due to token limits, we can't contain all the project context at once.
That's why a code gets to see one or a few files at a time.
After updating code in one file it is likely that other files counting on it would need to be updated.

Desired new situation:
After a code is done, pull the list of files that have 'dependenciesList' in the DB including this file.
For each of these files call a new coding agent with the task, diff produced so far and the new file context and ask it to update accordingly.
A test case we want to see passing is a testing file updated after a code file update, for example
asking the name of autopilot dir updated in autopilotConfig.js would update it's test file autopilotConfig.test.js to pass

Implementation details:
Make up a new coder agent or adjust the current one to accept the possible diff input as well.
Pull the dependent files after a file update.
Call the agent with the details mentioned so far above.

re: https://github.com/fjrdomingues/autopilot/pull/158/files #157

@hatkyinc2 hatkyinc2 added the enhancement New feature or request label Apr 30, 2023
@codeautopilot
Copy link

codeautopilot bot commented Apr 30, 2023

🤖 This is my suggestion:

File: modules/db.js
To implement the desired new situation, we need to add a function in modules/db.js that queries the database to get the list of dependent files. We can do this by adding a new function called getDependentFiles that takes the codeBaseDirectory and the filePath as input parameters and returns a list of dependent files.

Here's the plan for this file:

  1. Add a new function getDependentFiles that takes codeBaseDirectory and filePath as input parameters.
  2. Inside the function, get the database instance using the getDB function.
  3. Write a SQL query to fetch the list of dependent files that have the given filePath in their dependenciesLibs column.
  4. Execute the SQL query and return the list of dependent files.

Here's the updated code for modules/db.js:

// ... (existing code)

/**
 * @description Gets the list of dependent files that have the given filePath in their dependenciesLibs column
 * @param {string} codeBaseDirectory - The path to the codebase
 * @param {string} filePath - The file path to search for in the dependenciesLibs column
 * @returns {Array<string>} - An array of dependent file paths
 * @throws {Error} If an error occurs during the database query.
 */
async function getDependentFiles(codeBaseDirectory, filePath) {
  const db = getDB(codeBaseDirectory);
  const sql = `
SELECT path
FROM files
WHERE dependenciesLibs LIKE ?
`;
  const wildcardFilePath = `%${filePath}%`;
  const dependentFiles = await new Promise((resolve, reject) => {
    db.all(sql, [wildcardFilePath], (err, rows) => {
      if (err) {
        reject(err);
      } else {
        resolve(rows.map(row => row.path));
      }
    });
  });
  return dependentFiles;
}

// ... (existing code)

module.exports = {
  createDB,
  createFilesTable,
  insertOrUpdateFile,
  getDB,
  getDBFiles,
  deleteFile,
  getDBFilePath,
  getDependentFiles, // Export the new function
};

Now, you can use the getDependentFiles function in the agents/coder.js file to get the list of dependent files and call the coder agent with the necessary details.

File: agents/coder.js
To implement the desired new situation, we need to modify the suggestChanges function in the agents/coder.js file to accept a diff input and call the coder agent for each dependent file after a file update. Here's the plan for this file:

  1. Update the suggestChanges function signature to accept an additional parameter diff which will be the diff input.

  2. After receiving the parsedResponse, check if the updateDependentFiles flag is set to true in the response. If it is, call a function (e.g., updateDependentFiles) that will handle updating the dependent files.

  3. Implement the updateDependentFiles function that will:

    • Call a function from modules/db.js to get the list of dependent files (we will implement this function in the modules/db.js file later).
    • For each dependent file, call the suggestChanges function with the task, diff, and the new file context.

Here's the updated agents/coder.js file with the changes:

const { z } = require('zod');
const { PromptTemplate } = require('langchain/prompts');
const { StructuredOutputParser, OutputFixingParser } = require('langchain/output_parsers');
const { getModel } = require('../modules/model');
const { saveLog } = require('../modules/fsOutput');
const { getDependentFiles } = require('../modules/db'); // Import the function to get dependent files

const promptTemplate = 
` 
# USER INPUT
{task}

# YOUR TASK
As a senior software developer, make the requested changes from the USER INPUT.
Write out new code before deleting old code.

{format_instructions}

# SOURCE CODE
{code}
` 

const parser = StructuredOutputParser.fromZodSchema(
  z.object({
    thoughts: z.object({
      text: z.string().describe('your thoughts'),
      reasoning: z.string().describe('your reasoning'),
      criticism: z.string().describe('constructive self-criticism'),
    }),
    output: z.array(
      z.object({
        fileToUpdate: z.string().describe('File to write. (can be the current file or a new file)'),
        content: z.string().describe('Full content for that file'),
      }),
    ),
  })
);

const formatInstructions = parser.getFormatInstructions();

const prompt = new PromptTemplate({
  template: promptTemplate,
  inputVariables: ['task', 'code'],
  partialVariables: { format_instructions: formatInstructions },
});

async function suggestChanges(task, file, diff) {
  const code = formatCode(file)

  const model = getModel(process.env.INDEXER_MODEL);

  const input = await prompt.format({ task, code });
  const response = await model.call(input);

  let parsedResponse
  try {
    parsedResponse = await parser.parse(response);
  } catch (e){
    const fixParser = OutputFixingParser.fromLLM(
      model,
      parser
    );
    parsedResponse = await fixParser.parse(response);
  }

  saveLog(`coder agent INPUT:\n${input}`)
  saveLog(`coder agent OUTPUT:\n${response}`)
  
  if (parsedResponse.updateDependentFiles) {
    await updateDependentFiles(task, diff);
  }

  return parsedResponse.output;
}

async function updateDependentFiles(task, diff) {
  const dependentFiles = await getDependentFiles();

  for (const file of dependentFiles) {
    await suggestChanges(task, file, diff);
  }
}

function formatCode(file) {
  // format code for prompt
  let code = '';
  code += `### ${file.path}`;
  code += `\n`;
  code += '```';
  code += `\n`;
  code += `${file.code}`;
  code += `\n`;
  code += '```';
  code += `\n`;
  return code
}

module.exports = { suggestChanges }

Now, you can implement the getDependentFiles function in the modules/db.js file to get the list of dependent files from the database.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant