converse-mcp-server 2.27.2 → 2.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/docs/API.md +21 -19
- package/docs/ARCHITECTURE.md +0 -1
- package/docs/PROVIDERS.md +33 -32
- package/package.json +16 -18
- package/src/config.js +23 -4
- package/src/prompts/helpPrompt.js +2 -2
- package/src/providers/copilot.js +92 -8
- package/src/providers/gemini-cli.js +665 -438
- package/src/tools/chat.js +26 -7
- package/src/tools/consensus.js +31 -3
- package/src/tools/conversation.js +20 -4
- package/src/utils/modelRouting.js +50 -0
package/README.md
CHANGED
|
@@ -424,7 +424,7 @@ Use `"auto"` for automatic model selection, or specify exact models:
|
|
|
424
424
|
Provider priority order (subscription-based SDK providers first, then API-key providers):
|
|
425
425
|
|
|
426
426
|
1. Codex (`codex`)
|
|
427
|
-
2. Gemini CLI (`gemini`)
|
|
427
|
+
2. Gemini via Antigravity CLI (`gemini`, `gemini:flash`)
|
|
428
428
|
3. Claude Agent SDK (`claude` → Claude Fable 5)
|
|
429
429
|
4. Copilot (`copilot`)
|
|
430
430
|
5. OpenAI (`gpt-5`)
|
|
@@ -601,7 +601,7 @@ npm run test:watch # Run tests in watch mode
|
|
|
601
601
|
# Code quality
|
|
602
602
|
npm run lint # Check code style
|
|
603
603
|
npm run lint:fix # Fix code style issues
|
|
604
|
-
npm run format # Format code with
|
|
604
|
+
npm run format # Format code with ESLint (alias for lint:fix)
|
|
605
605
|
npm run validate # Full validation (lint + test)
|
|
606
606
|
|
|
607
607
|
# Utilities
|
package/docs/API.md
CHANGED
|
@@ -534,7 +534,7 @@ When complete, `check_status` for the continuation_id renders the full lap trans
|
|
|
534
534
|
| `gemini-2.5-pro` | `pro 2.5` | 1M | 65K | Thinking mode | Deep reasoning, architecture |
|
|
535
535
|
| `gemini-2.5-flash` | `flash` | 1M | 65K | Ultra-fast | Quick analysis, simple queries |
|
|
536
536
|
|
|
537
|
-
**Note:** The short model name `gemini`
|
|
537
|
+
**Note:** The short model name `gemini` (and `gemini:flash` / `gemini:pro`) routes to the **Antigravity CLI** (`agy`, OAuth-based). For Google API access, use specific model names like `gemini-2.5-pro` or `gemini-2.5-flash` (bare `gemini-pro`/`gemini-flash` also route to the Google API).
|
|
538
538
|
|
|
539
539
|
### X.AI/Grok Models
|
|
540
540
|
|
|
@@ -608,29 +608,31 @@ When complete, `check_status` for the continuation_id renders the full lap trans
|
|
|
608
608
|
- **Direct file access**: Reads files from working directory
|
|
609
609
|
- **Note**: `temperature`, `use_websearch`, and `reasoning_effort` are managed by the SDK (ignored if specified)
|
|
610
610
|
|
|
611
|
-
### Gemini CLI
|
|
611
|
+
### Gemini Models via Antigravity CLI (OAuth-based)
|
|
612
612
|
|
|
613
|
-
**
|
|
613
|
+
The **Antigravity CLI** (`agy`) provides subscription-based access to Gemini models through Google OAuth:
|
|
614
614
|
|
|
615
|
-
- **
|
|
616
|
-
- **Authentication**: OAuth via
|
|
617
|
-
- **Setup**: Install
|
|
618
|
-
- **Billing**: Uses
|
|
619
|
-
- **
|
|
620
|
-
- **
|
|
621
|
-
- **Context**: 1M tokens
|
|
622
|
-
- **
|
|
615
|
+
- **Models** (text-only): `gemini` (= `gemini:pro`, Gemini 3.1 Pro), `gemini:flash` (Gemini 3.5 Flash)
|
|
616
|
+
- **Authentication**: Google OAuth via `agy` (requires one-time interactive login)
|
|
617
|
+
- **Setup**: Install the Antigravity CLI and run `agy` once to log in
|
|
618
|
+
- **Billing**: Uses your Antigravity subscription/compute allowance instead of API credits
|
|
619
|
+
- **Detection**: The provider locates the `agy` binary on PATH or at the platform install location (no credentials file)
|
|
620
|
+
- **Reasoning effort**: `low`/`medium`/`high`/`max` select the model variant (e.g. Flash Low/Medium/High; Pro Low/High)
|
|
621
|
+
- **Context**: 1M tokens
|
|
622
|
+
- **Note**: One-shot responses (no token-level streaming); ~7s minimum per call
|
|
623
|
+
|
|
624
|
+
> Replaces the previous `@google/gemini-cli` integration, whose OAuth access Google sunsets on 2026-06-18.
|
|
623
625
|
|
|
624
626
|
**Authentication Setup:**
|
|
625
627
|
```bash
|
|
626
|
-
# Install
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
#
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
#
|
|
633
|
-
|
|
628
|
+
# Install the Antigravity CLI (agy)
|
|
629
|
+
# Windows (PowerShell):
|
|
630
|
+
irm https://antigravity.google/cli/install.ps1 | iex
|
|
631
|
+
# macOS/Linux:
|
|
632
|
+
curl -fsSL https://antigravity.google/cli/install.sh | bash
|
|
633
|
+
|
|
634
|
+
# Run interactive login (one-time) — also establishes workspace trust
|
|
635
|
+
agy
|
|
634
636
|
```
|
|
635
637
|
|
|
636
638
|
**Usage Example:**
|
package/docs/ARCHITECTURE.md
CHANGED
package/docs/PROVIDERS.md
CHANGED
|
@@ -22,7 +22,7 @@ This guide documents all supported AI providers in the Converse MCP Server and t
|
|
|
22
22
|
- `gemini-3-pro-preview` (alias: `pro`) - Enhanced reasoning with thinking levels (1M context, 64K output)
|
|
23
23
|
- `gemini-2.5-pro` (alias: `pro 2.5`) - Deep reasoning with thinking budget (1M context, 65K output)
|
|
24
24
|
- `gemini-2.5-flash` (alias: `flash`) - Ultra-fast model with thinking budget (1M context, 65K output)
|
|
25
|
-
- **Note**: The short model name `gemini`
|
|
25
|
+
- **Note**: The short model name `gemini` (and `gemini:flash` / `gemini:pro`) routes to the **Antigravity CLI** (`agy`, OAuth-based access). For Google API access, use specific model names like `gemini-2.5-pro` or `gemini-2.5-flash` (bare `gemini-pro`/`gemini-flash` also route to the Google API).
|
|
26
26
|
|
|
27
27
|
### X.AI (Grok)
|
|
28
28
|
- **API Key Format**: `xai-...` (starts with `xai-`)
|
|
@@ -111,35 +111,36 @@ This guide documents all supported AI providers in the Converse MCP Server and t
|
|
|
111
111
|
- Use `CODEX_APPROVAL_POLICY=never` for headless server deployments
|
|
112
112
|
- Always use `continuation_id` for thread continuation
|
|
113
113
|
|
|
114
|
-
### Gemini CLI
|
|
115
|
-
- **Authentication**: OAuth via
|
|
114
|
+
### Gemini (Antigravity CLI)
|
|
115
|
+
- **Authentication**: Google OAuth via the Antigravity CLI (`agy`) — no API key needed
|
|
116
116
|
- **Setup Required**:
|
|
117
|
-
1. Install
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
- **
|
|
122
|
-
|
|
123
|
-
-
|
|
117
|
+
1. Install the Antigravity CLI (`agy`):
|
|
118
|
+
- Windows (PowerShell): `irm https://antigravity.google/cli/install.ps1 | iex`
|
|
119
|
+
- macOS/Linux: `curl -fsSL https://antigravity.google/cli/install.sh | bash`
|
|
120
|
+
2. Authenticate: run `agy` once interactively and complete the Google OAuth login. This also establishes workspace trust for your home directory (the provider spawns each call in a per-call subdirectory under `~/.converse/agy-runs`).
|
|
121
|
+
- **Environment Variables**: None (the provider detects the `agy` binary on PATH or at the platform install location)
|
|
122
|
+
- **Supported Models** (text-only — print mode has no image input channel):
|
|
123
|
+
- `gemini` (= `gemini:pro`) - Gemini 3.1 Pro
|
|
124
|
+
- `gemini:flash` - Gemini 3.5 Flash
|
|
125
|
+
- `reasoning_effort` selects the variant: `low` → (Low), `medium` → (Medium) for Flash / (High) for Pro, `high`/`max` → (High); unset defaults to (High)
|
|
124
126
|
|
|
125
127
|
**Key Features:**
|
|
126
|
-
- **OAuth Authentication**: Uses Google
|
|
127
|
-
- **Subscription Access**:
|
|
128
|
-
- **
|
|
129
|
-
|
|
128
|
+
- **OAuth Authentication**: Uses your Antigravity Google login instead of API keys
|
|
129
|
+
- **Subscription Access**: Leverages the Antigravity weekly compute allowance instead of pay-per-API-call
|
|
130
|
+
- **One-shot responses**: The provider shells out to `agy -p` under a pseudo-terminal and returns the full response in a single chunk (no token-level streaming; ~7s minimum per call, ~30-60s for very large prompts)
|
|
131
|
+
|
|
132
|
+
> Note: This replaces the previous `@google/gemini-cli` (`ai-sdk-provider-gemini-cli`) integration, whose OAuth access Google sunsets on 2026-06-18.
|
|
130
133
|
|
|
131
134
|
**Authentication Setup:**
|
|
132
135
|
```bash
|
|
133
|
-
# Install
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
#
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
#
|
|
140
|
-
|
|
141
|
-
# 2. Authorize via browser
|
|
142
|
-
# 3. Credentials are saved to ~/.gemini/oauth_creds.json
|
|
136
|
+
# Install the Antigravity CLI (agy)
|
|
137
|
+
# Windows (PowerShell):
|
|
138
|
+
irm https://antigravity.google/cli/install.ps1 | iex
|
|
139
|
+
# macOS/Linux:
|
|
140
|
+
curl -fsSL https://antigravity.google/cli/install.sh | bash
|
|
141
|
+
|
|
142
|
+
# Run interactive login (one-time setup) — also establishes workspace trust
|
|
143
|
+
agy
|
|
143
144
|
```
|
|
144
145
|
|
|
145
146
|
**Usage Examples:**
|
|
@@ -167,16 +168,16 @@ gemini
|
|
|
167
168
|
```
|
|
168
169
|
|
|
169
170
|
**Best Practices:**
|
|
170
|
-
- Authenticate before first use (run `
|
|
171
|
+
- Authenticate before first use (run `agy` once interactively to log in)
|
|
171
172
|
- Use specific model names for Google API access (e.g., `gemini-2.5-pro`)
|
|
172
|
-
- Model
|
|
173
|
-
-
|
|
173
|
+
- Model names `gemini`, `gemini:pro`, and `gemini:flash` are reserved for Antigravity CLI access
|
|
174
|
+
- If a call returns an empty response, the CLI is likely not authenticated — run `agy` interactively once
|
|
174
175
|
|
|
175
176
|
**Differences from Google API Provider:**
|
|
176
|
-
- **Authentication**: OAuth
|
|
177
|
-
- **Billing**:
|
|
178
|
-
- **Model Routing**: `gemini` → CLI provider, specific names (e.g., `gemini-2.5-pro`) → API provider
|
|
179
|
-
- **
|
|
177
|
+
- **Authentication**: Google OAuth via `agy` vs API Key (Google API)
|
|
178
|
+
- **Billing**: Antigravity subscription/compute allowance vs pay-per-use API
|
|
179
|
+
- **Model Routing**: `gemini` / `gemini:flash` / `gemini:pro` → Antigravity CLI provider, specific names (e.g., `gemini-2.5-pro`, bare `gemini-pro`) → Google API provider
|
|
180
|
+
- **Images**: Not supported (text-only) vs full multimodal on the Google API provider
|
|
180
181
|
|
|
181
182
|
### Claude Agent SDK
|
|
182
183
|
- **Authentication**: Claude Code CLI login (no API key needed)
|
|
@@ -281,7 +282,7 @@ When using the chat or consensus tools, specify models using their identifiers:
|
|
|
281
282
|
|
|
282
283
|
1. **SDK Providers** (exact matches and prefixes, checked first):
|
|
283
284
|
- `codex` → Codex
|
|
284
|
-
- `gemini`, `gemini-cli` → Gemini CLI
|
|
285
|
+
- `gemini`, `gemini-cli`, and any `gemini:`-prefixed name (e.g., `gemini:flash`, `gemini:pro`) → Gemini via Antigravity CLI
|
|
285
286
|
- `claude`, `claude-sdk`, `claude-code` and any `claude:`-prefixed name (e.g., `claude:fable`, `claude:opus`) → Claude Agent SDK
|
|
286
287
|
- `copilot`, `copilot-sdk`, `github-copilot` and any `copilot:`-prefixed name (e.g., `copilot:codex`) → Copilot SDK
|
|
287
288
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "converse-mcp-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.28.1",
|
|
4
4
|
"description": "Converse MCP Server - Converse with other LLMs with chat and consensus tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -49,10 +49,9 @@
|
|
|
49
49
|
"lint": "eslint src/ tests/",
|
|
50
50
|
"lint:fix": "eslint src/ tests/ --fix",
|
|
51
51
|
"lint:watch": "nodemon --exec \"npm run lint\" --watch src --watch tests",
|
|
52
|
-
"format": "
|
|
53
|
-
"format:check": "prettier --check src/ tests/ *.md *.json",
|
|
52
|
+
"format": "eslint src/ tests/ --fix",
|
|
54
53
|
"typecheck": "node scripts/typecheck.js",
|
|
55
|
-
"validate:simple": "npm run typecheck && npm run lint && npm run
|
|
54
|
+
"validate:simple": "npm run typecheck && npm run lint && npm run test",
|
|
56
55
|
"clean": "rimraf node_modules package-lock.json && npm install",
|
|
57
56
|
"debug": "cross-env NODE_ENV=development LOG_LEVEL=trace node --inspect src/index.js",
|
|
58
57
|
"debug:break": "cross-env NODE_ENV=development LOG_LEVEL=trace node --inspect-brk src/index.js",
|
|
@@ -94,30 +93,29 @@
|
|
|
94
93
|
".env.example"
|
|
95
94
|
],
|
|
96
95
|
"dependencies": {
|
|
97
|
-
"@anthropic-ai/claude-agent-sdk": "^0.3.
|
|
98
|
-
"@anthropic-ai/sdk": "^0.
|
|
99
|
-
"@github/copilot-sdk": "^1.0.
|
|
100
|
-
"@google/genai": "^2.
|
|
101
|
-
"@
|
|
96
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.185",
|
|
97
|
+
"@anthropic-ai/sdk": "^0.105.0",
|
|
98
|
+
"@github/copilot-sdk": "^1.0.3",
|
|
99
|
+
"@google/genai": "^2.9.0",
|
|
100
|
+
"@lydell/node-pty": "1.2.0-beta.12",
|
|
101
|
+
"@mistralai/mistralai": "^2.2.6",
|
|
102
102
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
103
|
-
"@openai/codex-sdk": "^0.
|
|
104
|
-
"ai": "^6.0.
|
|
105
|
-
"ai-sdk-provider-gemini-cli": "^2.0.1",
|
|
103
|
+
"@openai/codex-sdk": "^0.141.0",
|
|
104
|
+
"ai": "^6.0.208",
|
|
106
105
|
"cors": "^2.8.6",
|
|
107
106
|
"dotenv": "^17.4.2",
|
|
108
107
|
"express": "^5.2.1",
|
|
109
108
|
"lru-cache": "^11.5.1",
|
|
110
|
-
"nanoid": "^5.1.
|
|
111
|
-
"openai": "^6.
|
|
109
|
+
"nanoid": "^5.1.15",
|
|
110
|
+
"openai": "^6.44.0",
|
|
112
111
|
"p-limit": "^7.3.0",
|
|
113
112
|
"vite": "^8.0.16"
|
|
114
113
|
},
|
|
115
114
|
"devDependencies": {
|
|
116
|
-
"@vitest/coverage-v8": "^4.1.
|
|
115
|
+
"@vitest/coverage-v8": "^4.1.9",
|
|
117
116
|
"cross-env": "^10.1.0",
|
|
118
|
-
"eslint": "^10.
|
|
119
|
-
"prettier": "^3.8.3",
|
|
117
|
+
"eslint": "^10.5.0",
|
|
120
118
|
"rimraf": "^6.1.3",
|
|
121
|
-
"vitest": "^4.1.
|
|
119
|
+
"vitest": "^4.1.9"
|
|
122
120
|
}
|
|
123
121
|
}
|
package/src/config.js
CHANGED
|
@@ -12,6 +12,7 @@ import { ConfigurationError } from './utils/errorHandler.js';
|
|
|
12
12
|
import { fileURLToPath } from 'url';
|
|
13
13
|
import { dirname, join, resolve } from 'path';
|
|
14
14
|
import { readFileSync } from 'fs';
|
|
15
|
+
import { findAgyBinary } from './providers/gemini-cli.js';
|
|
15
16
|
|
|
16
17
|
// Load environment variables from appropriate .env file
|
|
17
18
|
// Priority: .env.test (for test env) > .env (default)
|
|
@@ -295,6 +296,12 @@ const CONFIG_SCHEMA = {
|
|
|
295
296
|
description:
|
|
296
297
|
'Default model for Copilot SDK sessions (e.g., gpt-5, claude-sonnet-4.5)',
|
|
297
298
|
},
|
|
299
|
+
COPILOT_CLI_PATH: {
|
|
300
|
+
type: 'string',
|
|
301
|
+
required: false,
|
|
302
|
+
description:
|
|
303
|
+
'Explicit path to the Copilot CLI runtime (index.js or copilot binary). Overrides automatic resolution.',
|
|
304
|
+
},
|
|
298
305
|
},
|
|
299
306
|
|
|
300
307
|
// MCP configuration
|
|
@@ -655,12 +662,11 @@ export async function loadConfig() {
|
|
|
655
662
|
config.providers.googlecloudproject &&
|
|
656
663
|
config.providers.googlecloudlocation;
|
|
657
664
|
const sdkPackages = {
|
|
658
|
-
codex: '@
|
|
665
|
+
codex: '@openai/codex-sdk',
|
|
659
666
|
claude: '@anthropic-ai/claude-agent-sdk',
|
|
660
|
-
'gemini-cli': '@anthropic-ai/claude-code', // shares codex check
|
|
661
667
|
copilot: '@github/copilot-sdk',
|
|
662
668
|
};
|
|
663
|
-
|
|
669
|
+
let hasSdkProvider = Object.values(sdkPackages).some((pkg) => {
|
|
664
670
|
try {
|
|
665
671
|
import.meta.resolve(pkg);
|
|
666
672
|
return true;
|
|
@@ -669,9 +675,22 @@ export async function loadConfig() {
|
|
|
669
675
|
}
|
|
670
676
|
});
|
|
671
677
|
|
|
678
|
+
// gemini-cli availability comes from the Antigravity CLI binary, not an
|
|
679
|
+
// npm package — reuse the provider's probe (safe to import: node-pty is
|
|
680
|
+
// lazy-loaded at invoke time). Only probed when validation would otherwise
|
|
681
|
+
// fail, since hasSdkProvider is only read by the check below.
|
|
682
|
+
if (
|
|
683
|
+
availableKeys.length === 0 &&
|
|
684
|
+
!hasVertexAI &&
|
|
685
|
+
!hasSdkProvider &&
|
|
686
|
+
findAgyBinary() !== null
|
|
687
|
+
) {
|
|
688
|
+
hasSdkProvider = true;
|
|
689
|
+
}
|
|
690
|
+
|
|
672
691
|
if (availableKeys.length === 0 && !hasVertexAI && !hasSdkProvider) {
|
|
673
692
|
errors.push(
|
|
674
|
-
'At least one API key must be configured: OPENAI_API_KEY, XAI_API_KEY, GOOGLE_API_KEY, GEMINI_API_KEY, ANTHROPIC_API_KEY, MISTRAL_API_KEY, DEEPSEEK_API_KEY, or OPENROUTER_API_KEY. Alternatively, configure Google Vertex AI or use an SDK-based provider (codex, claude, gemini-cli
|
|
693
|
+
'At least one API key must be configured: OPENAI_API_KEY, XAI_API_KEY, GOOGLE_API_KEY, GEMINI_API_KEY, ANTHROPIC_API_KEY, MISTRAL_API_KEY, DEEPSEEK_API_KEY, or OPENROUTER_API_KEY. Alternatively, configure Google Vertex AI or use an SDK-based provider (codex, claude, copilot) or the Antigravity CLI (gemini-cli).',
|
|
675
694
|
);
|
|
676
695
|
}
|
|
677
696
|
|
|
@@ -462,7 +462,7 @@ ${formatProviderModels('DeepSeek', allModels.deepseek)}
|
|
|
462
462
|
${formatProviderModels('OpenRouter', allModels.openrouter)}
|
|
463
463
|
${formatProviderModels('Codex', allModels.codex)}
|
|
464
464
|
${formatProviderModels('Claude CLI', allModels.claude)}
|
|
465
|
-
${formatProviderModels('Gemini CLI', allModels['gemini-cli'])}
|
|
465
|
+
${formatProviderModels('Gemini (Antigravity CLI)', allModels['gemini-cli'])}
|
|
466
466
|
|
|
467
467
|
${generateModelCategories(allModels)}
|
|
468
468
|
|
|
@@ -500,7 +500,7 @@ These providers use local CLI tools and don't require API keys:
|
|
|
500
500
|
|
|
501
501
|
- **codex**: Requires ChatGPT login or CODEX_API_KEY environment variable
|
|
502
502
|
- **claude**: Requires \`claude login\` command (Claude Code CLI authentication)
|
|
503
|
-
- **gemini-cli**: Requires
|
|
503
|
+
- **gemini-cli**: Requires the Antigravity CLI (\`agy\`) installed and authenticated via Google OAuth (run \`agy\` once interactively to log in)
|
|
504
504
|
|
|
505
505
|
## Need More Help?
|
|
506
506
|
|
package/src/providers/copilot.js
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
* - Requires GitHub CLI authenticated (gh auth login) with active Copilot subscription
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
import { existsSync } from 'node:fs';
|
|
16
|
+
import { delimiter, dirname, join } from 'node:path';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
15
18
|
import { debugLog, debugError } from '../utils/console.js';
|
|
16
19
|
import { ProviderError, ErrorCodes, StopReasons } from './interface.js';
|
|
17
20
|
|
|
@@ -321,8 +324,10 @@ function isCopilotSDKAvailable() {
|
|
|
321
324
|
*/
|
|
322
325
|
async function getCopilotSDK() {
|
|
323
326
|
try {
|
|
324
|
-
const { CopilotClient } = await import(
|
|
325
|
-
|
|
327
|
+
const { CopilotClient, RuntimeConnection } = await import(
|
|
328
|
+
'@github/copilot-sdk'
|
|
329
|
+
);
|
|
330
|
+
return { CopilotClient, RuntimeConnection };
|
|
326
331
|
} catch (error) {
|
|
327
332
|
throw new CopilotProviderError(
|
|
328
333
|
`Copilot SDK import failed: ${error.message}`,
|
|
@@ -332,6 +337,78 @@ async function getCopilotSDK() {
|
|
|
332
337
|
}
|
|
333
338
|
}
|
|
334
339
|
|
|
340
|
+
/**
|
|
341
|
+
* Locate a runnable `copilot` executable on PATH (e.g. a winget or global
|
|
342
|
+
* install). On Windows only real executables (.exe/.com) qualify — .cmd/.bat
|
|
343
|
+
* shims can't be spawned without a shell, and the SDK spawns the CLI without
|
|
344
|
+
* one, so handing it a shim would fail.
|
|
345
|
+
*/
|
|
346
|
+
function findCopilotBinaryOnPath() {
|
|
347
|
+
const pathDirs = (process.env.PATH || process.env.Path || '')
|
|
348
|
+
.split(delimiter)
|
|
349
|
+
.filter(Boolean);
|
|
350
|
+
const exts = process.platform === 'win32' ? ['.exe', '.com'] : [''];
|
|
351
|
+
for (const dir of pathDirs) {
|
|
352
|
+
for (const ext of exts) {
|
|
353
|
+
const candidate = join(dir, `copilot${ext}`);
|
|
354
|
+
if (existsSync(candidate)) return candidate;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Resolve the Copilot CLI runtime path deterministically.
|
|
362
|
+
*
|
|
363
|
+
* The SDK's built-in resolver (getBundledCliPath) reconstructs
|
|
364
|
+
* `<@github/copilot root>/index.js` from the package's `./sdk` export. That
|
|
365
|
+
* assumption breaks across layouts — pnpm stores with multiple versions, global
|
|
366
|
+
* installs, and loader-style `@github/copilot` variants that ship no root
|
|
367
|
+
* `index.js` — and there is no escape hatch wired up, so a wrong/missing
|
|
368
|
+
* bundled copy takes down the whole provider (the "Copilot CLI not found at
|
|
369
|
+
* ...@github\index.js" failure). We own discovery here and hand the SDK an
|
|
370
|
+
* explicit, verified path so that entire class of resolution failures can't
|
|
371
|
+
* occur.
|
|
372
|
+
*
|
|
373
|
+
* Precedence: explicit override → bundled npm CLI (index.js, run via node) →
|
|
374
|
+
* `copilot` on PATH. Returns null to let the SDK fall back to its own
|
|
375
|
+
* resolution as a last resort (preserves behavior on flat installs).
|
|
376
|
+
*/
|
|
377
|
+
function resolveCopilotCliPath(config) {
|
|
378
|
+
// 1. Explicit override (COPILOT_CLI_PATH via config or env)
|
|
379
|
+
const override =
|
|
380
|
+
config?.providers?.copilotclipath || process.env.COPILOT_CLI_PATH;
|
|
381
|
+
if (override && existsSync(override)) {
|
|
382
|
+
debugLog('[Copilot SDK] Using configured CLI path: %s', override);
|
|
383
|
+
return override;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// 2. Bundled npm CLI: resolve the @github/copilot/sdk export, walk to the
|
|
387
|
+
// package root, and use its index.js. A .js path is spawned via `node`, which
|
|
388
|
+
// also sidesteps Windows .cmd/.bat shim issues.
|
|
389
|
+
try {
|
|
390
|
+
const sdkEntry = fileURLToPath(import.meta.resolve('@github/copilot/sdk'));
|
|
391
|
+
const candidate = join(dirname(dirname(sdkEntry)), 'index.js');
|
|
392
|
+
if (existsSync(candidate)) {
|
|
393
|
+
debugLog('[Copilot SDK] Using bundled CLI: %s', candidate);
|
|
394
|
+
return candidate;
|
|
395
|
+
}
|
|
396
|
+
} catch {
|
|
397
|
+
// @github/copilot not resolvable from here — fall through.
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// 3. Standalone `copilot` binary on PATH.
|
|
401
|
+
const binary = findCopilotBinaryOnPath();
|
|
402
|
+
if (binary) {
|
|
403
|
+
debugLog('[Copilot SDK] Using copilot binary from PATH: %s', binary);
|
|
404
|
+
return binary;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// 4. Nothing found — defer to the SDK's own resolution.
|
|
408
|
+
debugLog('[Copilot SDK] No CLI path resolved — deferring to SDK default');
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
|
|
335
412
|
// Module-level singleton client
|
|
336
413
|
let clientInstance = null;
|
|
337
414
|
let clientInitPromise = null;
|
|
@@ -340,7 +417,7 @@ let clientInitPromise = null;
|
|
|
340
417
|
* Get or create the singleton CopilotClient
|
|
341
418
|
* The client manages the CLI process lifecycle via JSON-RPC
|
|
342
419
|
*/
|
|
343
|
-
async function getCopilotClient(cwd) {
|
|
420
|
+
async function getCopilotClient(cwd, config) {
|
|
344
421
|
if (clientInstance) {
|
|
345
422
|
return clientInstance;
|
|
346
423
|
}
|
|
@@ -350,12 +427,19 @@ async function getCopilotClient(cwd) {
|
|
|
350
427
|
}
|
|
351
428
|
|
|
352
429
|
clientInitPromise = (async () => {
|
|
353
|
-
const CopilotClient = await getCopilotSDK();
|
|
430
|
+
const { CopilotClient, RuntimeConnection } = await getCopilotSDK();
|
|
354
431
|
const workingDirectory = cwd || process.cwd();
|
|
355
|
-
|
|
432
|
+
const clientOptions = {
|
|
356
433
|
useLoggedInUser: true,
|
|
357
434
|
workingDirectory,
|
|
358
|
-
}
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
const cliPath = resolveCopilotCliPath(config);
|
|
438
|
+
if (cliPath) {
|
|
439
|
+
clientOptions.connection = RuntimeConnection.forStdio({ path: cliPath });
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
clientInstance = new CopilotClient(clientOptions);
|
|
359
443
|
await clientInstance.start();
|
|
360
444
|
debugLog('[Copilot SDK] Client started (cwd: %s)', workingDirectory);
|
|
361
445
|
return clientInstance;
|
|
@@ -795,7 +879,7 @@ async function* createStreamingGenerator(client, prompt, options, signal, config
|
|
|
795
879
|
}
|
|
796
880
|
}
|
|
797
881
|
|
|
798
|
-
export { resolveModelAlias, resolveSessionModel };
|
|
882
|
+
export { resolveModelAlias, resolveSessionModel, resolveCopilotCliPath };
|
|
799
883
|
|
|
800
884
|
/**
|
|
801
885
|
* Copilot SDK Provider Implementation
|
|
@@ -831,7 +915,7 @@ export const copilotProvider = {
|
|
|
831
915
|
}
|
|
832
916
|
try {
|
|
833
917
|
const cwd = config.server?.client_cwd || process.cwd();
|
|
834
|
-
const client = await getCopilotClient(cwd);
|
|
918
|
+
const client = await getCopilotClient(cwd, config);
|
|
835
919
|
const prompt = convertMessagesToPrompt(messages);
|
|
836
920
|
|
|
837
921
|
const sessionModel = resolveSessionModel(model, config);
|