-
Notifications
You must be signed in to change notification settings - Fork 15
feat: add GitHub Copilot agent support to Rover CLI #233
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
base: main
Are you sure you want to change the base?
Conversation
- Introduced CopilotAgent class for GitHub Copilot integration - Enhanced CLI commands to check for Copilot installation - Updated agent creation logic to include Copilot - Added necessary environment variable checks and configurations for Copilot
- Revised description to mention Copilot alongside existing agents - Updated features list to reflect the inclusion of Copilot - Added installation link for GitHub Copilot CLI
- Introduced a new COPILOT.md file providing comprehensive guidance for using the GitHub Copilot agent within the Rover workspace. - Included installation instructions, authentication methods, environment variables, usage examples, best practices, troubleshooting tips, and security considerations. - Enhanced documentation to support developers in effectively utilizing the Copilot agent for AI-powered code assistance.
ereslibre
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is amazing, thank you @fran!
Added some comments, this one seems to be the trickiest one in terms of authentication compared to the other agents.
| try { | ||
| // Clean the response to extract JSON from various formats | ||
| let cleanedResult = result; | ||
|
|
||
| // Remove bullet points and other formatting characters from the start | ||
| cleanedResult = cleanedResult.replace(/^[●•*\-+]\s*/, ''); | ||
|
|
||
| // Remove common conversational prefixes | ||
| cleanedResult = cleanedResult.replace(/^(I understand|Here's|Here is|The JSON|Response:|Answer:)\s*/i, ''); | ||
|
|
||
| // Find JSON object in markdown code blocks (```json ... ```) | ||
| const jsonCodeBlockMatch = cleanedResult.match(/```json\s*([\s\S]*?)\s*```/); | ||
| if (jsonCodeBlockMatch) { | ||
| cleanedResult = jsonCodeBlockMatch[1].trim(); | ||
| } else { | ||
| // Look for JSON object directly - find the first { and last } | ||
| const firstBrace = cleanedResult.indexOf('{'); | ||
| const lastBrace = cleanedResult.lastIndexOf('}'); | ||
| if (firstBrace !== -1 && lastBrace !== -1 && lastBrace > firstBrace) { | ||
| cleanedResult = cleanedResult.substring(firstBrace, lastBrace + 1); | ||
| } | ||
| } | ||
|
|
||
| // Clean up whitespace and fix JSON formatting issues | ||
| cleanedResult = cleanedResult.trim(); | ||
|
|
||
| // Fix common JSON formatting issues from Copilot's multiline responses | ||
| // First, handle newlines within JSON strings properly | ||
| // We need to be careful to only escape newlines that are inside string values | ||
| cleanedResult = cleanedResult.replace(/\n\s*/g, '\\n'); | ||
|
|
||
| // Remove any remaining control characters that could break JSON parsing | ||
| // Keep only printable ASCII characters and essential JSON characters | ||
| cleanedResult = cleanedResult.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, ''); | ||
|
|
||
| // Additional cleanup for common formatting issues | ||
| cleanedResult = cleanedResult.replace(/\s+/g, ' '); // Normalize whitespace | ||
|
|
||
| const parsed = JSON.parse(cleanedResult); | ||
| return JSON.stringify(parsed); | ||
| } catch (jsonErr) { | ||
| // If JSON parsing fails, log the issue and return the raw result for parseJsonResponse to handle | ||
| console.error('Copilot JSON parsing failed:', jsonErr.message); | ||
| console.error('Cleaned result that failed to parse:', JSON.stringify(cleanedResult)); | ||
| return result; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this despite being explicit in the prompt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main reason I added was I was getting a lot of errors due to copilot was returning formatted code and I don't see any flat to allow copilot to force to be a valid json output. Anyhow, with the change in the prompt where it was added "Nothing else" we may avoid the problem.
I'm playing a bit with it, I will get something tomorrow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for the effort @fran!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I have tried
- Find a flag for copilot to avoid some symbols, bullets points and formatting characters
I didn't find anything in Copilot cli doc. - Improve the prompt
I changed the current prompt specifying the symbols , bullets and characters to avoid but we have the same output. - add a parser to remove symbols, bullets and special characters.
I moved the code to json-parser.ts and keep it simple.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @fran! I think this will do for now. Just for reference, it seems they have an issue open regarding the JSON output: github/copilot-cli#52.
| // GitHub Copilot CLI config directory | ||
| const copilotConfigDir = join(process.env.HOME || '~', '.copilot'); | ||
| if (existsSync(copilotConfigDir)) { | ||
| credentials.push({ | ||
| path: copilotConfigDir, | ||
| description: 'GitHub Copilot CLI configuration directory', | ||
| required: true, | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one seems that will be closer to Claude's implementation since it also uses the Keychain in Mac OS X.
- Mac OS X:
security find-generic-password -s copilot-cli -w(orsecurity find-generic-password -s gh:github.com -wif you logged in withgh auth): in this case we need to implement a similar logic to the one implemented with Claude, so that we read the token from the Mac OS X Keychain to a temporary file. What differs here from the Claude implementation is that on the container guest, it will expect/.copilot/config.jsonwith.copilot_tokens."https://github.com:<username>", so there needs to be a bit of massaging of the mounted configuration. - Linux:
/.copilot/config.json
|
thanks for review @ereslibre!. I will take care of all your comments. |
Co-authored-by: Rafael Fernández López <ereslibre@gmail.com>
Co-authored-by: Rafael Fernández López <ereslibre@gmail.com>
Co-authored-by: Rafael Fernández López <ereslibre@gmail.com>
- Removed extensive JSON parsing logic from the Copilot agent, streamlining the response handling process. - Added bullet point and formatting character cleanup to the json-parser utility for improved consistency in JSON responses.
- Removed unnecessary bullet point and formatting character cleanup from the json-parser utility.
|
|
||
| getInstallCommand(): string { | ||
| // Install GitHub Copilot CLI standalone | ||
| return 'npm install -g @github/copilot'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on github/copilot-cli#287 (comment), we need to use a prerelease version to fix an error related to missing modules (sharp).
| return 'npm install -g @github/copilot'; | |
| // @see https://github.com/github/copilot-cli/issues/287#issuecomment-3434844899 | |
| return 'npm install -g @github/copilot@0.0.354-29'; |
Changes
Notes
I haven't integrated with
gh copilotas copilot extension for gh does not allow -p argument aka no user prompt so , makes impossible integrate it with rover as it stop when detect a wait.what can be integrated is copilot directly.
It is not clear to me what should have COPILOT.md file, the reason all other agents files are a copy of AGENTS.md file.
Closes #223