feat: add GitHub Copilot provider support with Claude/Copilot toggle#108
feat: add GitHub Copilot provider support with Claude/Copilot toggle#108JaxsonYorke wants to merge 1 commit intopablodelucca:mainfrom
Conversation
## Summary Adds GitHub Copilot CLI as a first-class agent provider alongside the existing Claude Code support. Users can switch providers in the Settings modal; the choice persists across VS Code sessions. ## What changed ### New provider abstraction - src/constants.ts: Added AGENT_PROVIDERS, AgentProvider type, GLOBAL_KEY_AGENT_PROVIDER, COPILOT_TERMINAL_NAME_PREFIX, CLAUDE_TERMINAL_NAME_PREFIX, and COPILOT_TURN_END_DELAY_MS. - src/types.ts: Added provider field to both AgentState and PersistedAgent so agents remember which CLI they belong to across extension reloads. ### Agent lifecycle (agentManager.ts) - getProjectDirPath(provider): Copilot uses ~/.copilot/session-state; Claude uses ~/.claude/projects/<workspace-hash>. - launchNewTerminal(provider): Selects the correct terminal name prefix and launch command (copilot --resume vs claude --resume), builds the expected JSONL path for each provider's on-disk layout. - restoreAgents: Reads provider from persisted data; defaults to 'copilot' for any pre-existing entries that predate this change. ### Session scanning (fileWatcher.ts) - ensureProjectScan(provider): Dispatches to the correct scanner. - scanForNewSessionFiles: Copilot-specific — walks nested UUID subdirectories looking for events.jsonl. Skips adoption when an active task tool is running (sub-agent spawned by parent, not a new top-level session). - scanForNewJsonlFiles: Claude-specific — scans flat project directory for new .jsonl files; reassigns active agent on /clear. ### Transcript parsing — split into three files The original monolithic transcriptParser.ts (~640 lines, ~85% provider-specific) was split for human readability: - src/copilotTranscriptParser.ts: Handles the Copilot event-stream format (tool.execution_start, tool.execution_complete, assistant.turn_start, assistant.turn_end, abort, etc.). Tool names are lowercase. Includes logic to synthesize a virtual explore_synth tool start/complete when Copilot reports explore mode without emitting discrete tool events — keeps the character animated rather than going idle. - src/claudeTranscriptParser.ts: Handles the Claude JSONL format (assistant/user/system records, progress for sub-agents). Tool names are PascalCase. Uses turn_duration as the reliable turn-end signal; falls back to a 5s text-idle timer for text-only turns. - src/transcriptParser.ts: Now a 28-line dispatcher that imports from the two provider files and re-exports the permission-exempt tool sets. All existing import paths remain unchanged. Design choice: fileWatcher.ts and agentManager.ts were NOT split — their provider-specific code is ~5% of each file and splitting would produce near-empty provider files with no meaningful gain. ### Settings UI - SettingsModal.tsx: Added an Agent Provider toggle (Claude | Copilot). Claude is listed first. Selection sends setAgentProvider to the extension, which persists it in globalState and restarts the project scanner for the new provider. - Removed duplicate provider menu items that were sending an unhandled setProvider message type (dead code). - useExtensionMessages.ts / App.tsx: Thread agentProvider state from settingsLoaded message down to SettingsModal. ### Bug fixes - Removed unreachable explore guard in the default branch of formatCopilotToolStatus (the case 'explore' above already handles it). - Fixed missing space in fileWatcher.ts import statement. ## Testing - Full build passes: tsc --noEmit, ESLint, esbuild, Vite. - Copilot agents created, restored on reload, tools animated, explore mode no longer shows as idle, sub-agent tool names displayed. - Claude agents unaffected — provider defaults to 'copilot' for backward compat, Claude path exercised by switching the toggle. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a provider abstraction so the extension can run either GitHub Copilot CLI or Claude Code, with a persisted UI toggle and provider-specific session/transcript handling.
Changes:
- Introduces
AgentProviderand persists provider selection in extensionglobalState, threading it into agent lifecycle and restoration. - Splits transcript parsing into provider-specific parsers and adds a dispatcher.
- Updates the webview UI to support an Agent Provider toggle and switches “open Claude” actions to a provider-agnostic
openAgentmessage.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| webview-ui/src/hooks/useExtensionMessages.ts | Adds provider state plumbing from settingsLoaded into the webview hook. |
| webview-ui/src/hooks/useEditorActions.ts | Switches command message from openClaude to openAgent. |
| webview-ui/src/components/SettingsModal.tsx | Adds Claude/Copilot provider toggle and posts setAgentProvider to extension. |
| webview-ui/src/components/BottomToolbar.tsx | Routes session launch via openAgent and passes provider props to Settings modal. |
| webview-ui/src/App.tsx | Threads provider state into the toolbar/settings UI. |
| src/types.ts | Persists provider on agents so restored agents keep their CLI association. |
| src/transcriptParser.ts | Replaces monolithic parser with provider-based dispatcher + re-exports exempt tool sets. |
| src/fileWatcher.ts | Makes project scanning provider-aware; adds Copilot session-state scanning behavior. |
| src/copilotTranscriptParser.ts | New Copilot events.jsonl transcript parser and tool activity mapping. |
| src/constants.ts | Adds provider constants/keys and provider-specific terminal name prefixes. |
| src/claudeTranscriptParser.ts | New Claude JSONL transcript parser extracted from prior monolith. |
| src/agentManager.ts | Provider-aware terminal launch, project dir resolution, persistence, and restoration. |
| src/PixelAgentsViewProvider.ts | Handles openAgent and setAgentProvider, persists provider selection, restarts scanning. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } else if (msg.type === 'settingsLoaded') { | ||
| const soundOn = msg.soundEnabled as boolean; | ||
| setSoundEnabled(soundOn); | ||
| const p = (msg.provider ?? msg.agentProvider) as string | undefined; | ||
| if (p === 'copilot' || p === 'claude') { | ||
| setAgentProvider(p as 'copilot' | 'claude'); | ||
| } |
There was a problem hiding this comment.
settingsLoaded from the extension sends soundEnabled, but this handler reads msg.soundEnabled. As a result soundOn will be undefined and the UI will likely disable sound unexpectedly on load. Read from msg.soundEnabled (or support both keys for backward-compat).
| @@ -103,7 +103,7 @@ export function useEditorActions( | |||
| ); | |||
|
|
|||
| const handleOpenClaude = useCallback(() => { | |||
There was a problem hiding this comment.
handleOpenClaude now posts an openAgent message. Renaming this callback (and any references) to reflect the new provider-agnostic behavior will avoid confusion and make future maintenance easier.
| const handleOpenClaude = useCallback(() => { | |
| const handleOpenAgent = useCallback(() => { |
| export const WORKSPACE_KEY_AGENT_SEATS = 'pixel-agents.agentSeats'; | ||
| export const WORKSPACE_KEY_LAYOUT = 'pixel-agents.layout'; | ||
| export const TERMINAL_NAME_PREFIX = 'Claude Code'; | ||
| export const TERMINAL_NAME_PREFIX = 'GitHub Copilot'; // kept for backward-compat restoration matching |
There was a problem hiding this comment.
TERMINAL_NAME_PREFIX is now set to 'GitHub Copilot' and appears unused (terminal naming now uses COPILOT_TERMINAL_NAME_PREFIX/CLAUDE_TERMINAL_NAME_PREFIX). Keeping an unused exported constant with a backward-compat comment is misleading; either remove it or update it to the actual legacy value and ensure it’s still referenced where needed.
| export const TERMINAL_NAME_PREFIX = 'GitHub Copilot'; // kept for backward-compat restoration matching |
Opening
I have GitHub education benefits due to being a student and that includes the AI Agents from copilot, I've always seen this extension and thought it was so cool, but it didint have support for the Copilot CLI. So I decided I would for fun see if I could prompt Copilot (Mostly claude model's) to add its own functionality to the project, Which I believe it succeeded in.
Though this is definitely not my first time coding, it is my first time every using agents to edit larger projects like this, and I have absolutely no experience with VS code extensions, so im sorry if these changes aren't great.
I hope this could get the ball rolling on copilot cli support and if you have any sugestions, things i could help with, or change, let me know!
Summary
Adds GitHub Copilot CLI as a first-class agent provider alongside the existing Claude Code support. Users can switch providers in the Settings modal; the choice persists across VS Code sessions.
What changed
New provider abstraction
Agent lifecycle (agentManager.ts)
Session scanning (fileWatcher.ts)
Transcript parsing — split into three files
The original monolithic transcriptParser.ts (~640 lines, ~85% provider-specific) was split for human readability:
src/copilotTranscriptParser.ts: Handles the Copilot event-stream format (tool.execution_start, tool.execution_complete, assistant.turn_start, assistant.turn_end, abort, etc.). Tool names are lowercase. Includes logic to synthesize a virtual explore_synth tool start/complete when Copilot reports explore mode without emitting discrete tool events — keeps the character animated rather than going idle.
src/claudeTranscriptParser.ts: Handles the Claude JSONL format (assistant/user/system records, progress for sub-agents). Tool names are PascalCase. Uses turn_duration as the reliable turn-end signal; falls back to a 5s text-idle timer for text-only turns.
src/transcriptParser.ts: Now a 28-line dispatcher that imports from the two provider files and re-exports the permission-exempt tool sets. All existing import paths remain unchanged.
Design choice: fileWatcher.ts and agentManager.ts were NOT split — their provider-specific code is ~5% of each file and splitting would produce near-empty provider files with no meaningful gain.
Settings UI
Testing
Copilot Limitations
It seems that some parts of the edits look like mising functionality, but it is because for some tasks the copilot CLI runs, it does not emit an event, which means we cannot track it. Therefore some things like exploring, or sending message to the user cannot be tracked.