Skip to content

feat: add GitHub Copilot provider support with Claude/Copilot toggle#108

Open
JaxsonYorke wants to merge 1 commit intopablodelucca:mainfrom
JaxsonYorke:main
Open

feat: add GitHub Copilot provider support with Claude/Copilot toggle#108
JaxsonYorke wants to merge 1 commit intopablodelucca:mainfrom
JaxsonYorke:main

Conversation

@JaxsonYorke
Copy link

@JaxsonYorke JaxsonYorke commented Mar 11, 2026

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

  • 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/.
  • 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.

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.

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.

## 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>
Copilot AI review requested due to automatic review settings March 11, 2026 04:25
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 AgentProvider and persists provider selection in extension globalState, 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 openAgent message.

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.

Comment on lines 378 to +384
} 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');
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
@@ -103,7 +103,7 @@ export function useEditorActions(
);

const handleOpenClaude = useCallback(() => {
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
const handleOpenClaude = useCallback(() => {
const handleOpenAgent = useCallback(() => {

Copilot uses AI. Check for mistakes.
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
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
export const TERMINAL_NAME_PREFIX = 'GitHub Copilot'; // kept for backward-compat restoration matching

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants