Skip to content

Commit 34535b5

Browse files
authored
Merge branch 'main' into feat/provider-improvements
2 parents 83e55a5 + 396aefb commit 34535b5

8 files changed

Lines changed: 748 additions & 87 deletions

File tree

README.md

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,50 +7,62 @@ GitHub Copilot SDK integration for Amplifier via Copilot CLI.
77
## Prerequisites
88

99
- **Python 3.11+**
10-
- **Node.js 18+** — Required to install the Copilot CLI
1110
- **GitHub Copilot subscription** — Active Business or Enterprise subscription
1211
- **[UV](https://github.com/astral-sh/uv)** (optional) — Fast Python package manager (pip works too)
1312

14-
### Installing Copilot CLI
13+
> **No Node.js required.** The Copilot SDK binary is bundled with the Python package
14+
> and discovered automatically.
1515
16-
The Copilot CLI is a Node.js binary that the Python SDK controls via JSON-RPC.
17-
Both the CLI and the SDK are required.
16+
## Authentication
1817

19-
```bash
20-
# Install Copilot CLI (requires Node.js/npm)
21-
npm install -g @github/copilot
18+
Set a GitHub token as an environment variable. The provider checks these in order:
19+
`COPILOT_GITHUB_TOKEN`, `GH_TOKEN`, `GITHUB_TOKEN`.
20+
21+
### Option 1: Environment variable (recommended)
2222

23-
# Verify installation
24-
copilot --version
23+
```bash
24+
export GITHUB_TOKEN="ghp_your_token_here"
2525
```
2626

27-
### Authentication
27+
> **Tip:** Many developers already have `GITHUB_TOKEN` set from `gh` CLI usage —
28+
> if so, you're already authenticated. No extra setup needed.
29+
30+
### Option 2: `amplifier init` setup wizard
31+
32+
```bash
33+
amplifier init
34+
# Select "GitHub Copilot" from the provider list
35+
# Launches browser OAuth flow if no token is set
36+
```
2837

29-
You must be authenticated to GitHub Copilot:
38+
### Option 3: `gh` CLI bridge
3039

3140
```bash
32-
copilot auth login
41+
export GITHUB_TOKEN=$(gh auth token)
3342
```
3443

44+
One command to bridge your existing `gh` CLI authentication into Amplifier.
45+
3546
## Installation
3647

37-
Register the module, install its dependencies, and set it as your active provider:
48+
GitHub Copilot is a well-known provider — `amplifier init` handles everything:
3849

3950
```bash
40-
amplifier module add provider-github-copilot \
41-
--source git+https://github.com/microsoft/amplifier-module-provider-github-copilot@main
51+
# Interactive setup — select Copilot from the provider list
52+
amplifier init
4253

43-
amplifier provider install github-copilot
54+
# Non-interactive — auto-detects GITHUB_TOKEN
55+
amplifier init --yes
56+
```
57+
58+
Or install manually:
4459

60+
```bash
61+
amplifier provider install github-copilot
4562
amplifier provider use github-copilot
4663
```
4764

48-
> **Note:** The `provider install` step is required to install the module's Python
49-
> dependencies (including the GitHub Copilot SDK) into the Amplifier environment.
50-
> The built-in providers skip this step because they are pre-installed during
51-
> `amplifier init`.
52-
53-
Or reference it directly in a bundle (no separate install needed):
65+
Or reference it directly in a bundle:
5466

5567
```yaml
5668
providers:

amplifier_module_provider_github_copilot/__init__.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -322,9 +322,12 @@ def _find_copilot_cli(config: dict[str, Any]) -> str | None:
322322
"""
323323
Find the Copilot CLI executable path.
324324
325-
Uses the SDK's bundled CLI binary by default. Falls back to system PATH
326-
if the bundled binary is not found. The SDK bundles its own CLI binary
327-
which is version-matched, avoiding potential version mismatches.
325+
Resolution order:
326+
1. SDK bundled binary (import copilot -> copilot/bin/copilot)
327+
2. System PATH fallback (shutil.which)
328+
329+
The SDK bundles its own CLI binary which is version-matched,
330+
avoiding potential version mismatches with separately installed CLIs.
328331
329332
Args:
330333
config: Provider configuration (unused, kept for API compatibility)
@@ -333,14 +336,32 @@ def _find_copilot_cli(config: dict[str, Any]) -> str | None:
333336
Resolved CLI path, or None if not found
334337
"""
335338
try:
336-
# Let SDK use its bundled CLI - only fall back to system PATH
339+
try:
340+
from pathlib import Path
341+
342+
import copilot as _copilot_mod # type: ignore[import-untyped]
343+
344+
_mod_file = _copilot_mod.__file__
345+
if _mod_file is None:
346+
raise ImportError("copilot module has no __file__")
347+
_cli_bin = Path(_mod_file).parent / "bin" / "copilot"
348+
if _cli_bin.exists():
349+
cli_path = str(_cli_bin)
350+
_ensure_executable(cli_path)
351+
logger.debug(f"[MOUNT] Found SDK bundled CLI at: {cli_path}")
352+
return cli_path
353+
else:
354+
logger.debug("[MOUNT] SDK bundled CLI binary not found on disk")
355+
except ImportError:
356+
logger.debug("[MOUNT] copilot SDK not installed, trying PATH")
357+
337358
found = shutil.which("copilot") or shutil.which("copilot.exe")
338359
if found:
339360
_ensure_executable(found)
340-
logger.debug(f"[MOUNT] Found Copilot CLI at: {found}")
361+
logger.debug(f"[MOUNT] Found Copilot CLI in PATH at: {found}")
341362
return found
342363

343-
logger.debug("[MOUNT] Copilot CLI not found in PATH")
364+
logger.debug("[MOUNT] Copilot CLI not found via SDK or PATH")
344365
return None
345366

346367
except Exception as e:

amplifier_module_provider_github_copilot/client.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,13 @@ def _build_client_options(self) -> dict[str, Any]:
315315
316316
The SDK bundles its own CLI binary which is version-matched to the SDK.
317317
We always use the bundled CLI to avoid version mismatches and auth issues.
318+
319+
Token precedence (highest to lowest):
320+
1. config["github_token"] (explicit config)
321+
2. COPILOT_GITHUB_TOKEN env var (SDK-preferred)
322+
3. GH_TOKEN env var (gh CLI compat)
323+
4. GITHUB_TOKEN env var (most common)
324+
5. No token — SDK uses stored OAuth creds (use_logged_in_user=True)
318325
"""
319326
options: dict[str, Any] = {}
320327

@@ -327,6 +334,18 @@ def _build_client_options(self) -> dict[str, Any]:
327334
if self._config.get("cwd"):
328335
options["cwd"] = self._config["cwd"]
329336

337+
# Token resolution: config > COPILOT_GITHUB_TOKEN > GH_TOKEN > GITHUB_TOKEN
338+
token = self._config.get("github_token") or None
339+
if not token:
340+
for env_var in ("COPILOT_GITHUB_TOKEN", "GH_TOKEN", "GITHUB_TOKEN"):
341+
token = os.environ.get(env_var)
342+
if token:
343+
logger.debug(f"[CLIENT] Using token from {env_var}")
344+
break
345+
346+
if token:
347+
options["github_token"] = token
348+
330349
return options
331350

332351
async def _verify_authentication(self) -> None:
@@ -343,7 +362,9 @@ async def _verify_authentication(self) -> None:
343362
auth_status = await self._client.get_auth_status()
344363
if not auth_status.isAuthenticated:
345364
raise CopilotAuthenticationError(
346-
"Not authenticated to GitHub Copilot. Run 'copilot auth login' to authenticate."
365+
"Not authenticated to GitHub Copilot. "
366+
"Set GITHUB_TOKEN, run 'gh auth login', "
367+
"or run 'amplifier init' to authenticate."
347368
)
348369
logger.debug(f"[CLIENT] Authenticated as: {auth_status.login}")
349370
except CopilotAuthenticationError:

0 commit comments

Comments
 (0)