converse-mcp-server 2.29.2 → 3.0.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/.env.example +6 -3
- package/README.md +96 -94
- package/docs/API.md +703 -1562
- package/docs/ARCHITECTURE.md +13 -11
- package/docs/EXAMPLES.md +241 -667
- package/docs/PROVIDERS.md +104 -79
- package/package.json +1 -1
- package/src/async/asyncJobStore.js +2 -2
- package/src/async/jobRunner.js +6 -1
- package/src/async/providerStreamNormalizer.js +59 -1
- package/src/config.js +4 -3
- package/src/prompts/helpPrompt.js +43 -61
- package/src/providers/anthropic.js +0 -31
- package/src/providers/claude.js +0 -14
- package/src/providers/codex.js +15 -21
- package/src/providers/copilot.js +36 -202
- package/src/providers/deepseek.js +73 -53
- package/src/providers/gemini-cli.js +0 -3
- package/src/providers/google.js +10 -27
- package/src/providers/interface.js +0 -3
- package/src/providers/mistral.js +169 -63
- package/src/providers/openai-compatible.js +113 -28
- package/src/providers/openai.js +14 -66
- package/src/providers/openrouter-discovery.js +308 -0
- package/src/providers/openrouter.js +452 -282
- package/src/providers/xai.js +298 -280
- package/src/services/summarizationService.js +4 -14
- package/src/systemPrompts.js +19 -2
- package/src/tools/cancelJob.js +7 -1
- package/src/tools/chat.js +957 -995
- package/src/tools/checkStatus.js +1 -0
- package/src/tools/index.js +2 -6
- package/src/tools/modes/parallel.js +488 -0
- package/src/tools/modes/roundtable.js +495 -0
- package/src/tools/modes/streamShared.js +31 -0
- package/src/utils/contextProcessor.js +1 -38
- package/src/utils/conversationExporter.js +6 -26
- package/src/utils/formatStatus.js +46 -19
- package/src/utils/modelRouting.js +207 -4
- package/src/providers/openrouter-endpoints-client.js +0 -220
- package/src/tools/consensus.js +0 -1813
- package/src/tools/conversation.js +0 -1233
package/docs/PROVIDERS.md
CHANGED
|
@@ -22,18 +22,22 @@ This guide documents all supported AI providers in the Converse MCP Server and t
|
|
|
22
22
|
- **Get Key**: [makersuite.google.com/app/apikey](https://makersuite.google.com/app/apikey)
|
|
23
23
|
- **Environment Variable**: `GOOGLE_API_KEY`
|
|
24
24
|
- **Supported Models**:
|
|
25
|
-
- `gemini-3-pro-preview` (
|
|
25
|
+
- `gemini-3.1-pro-preview` (aliases: `pro`, `gemini-pro`) - Most advanced reasoning with expanded thinking levels (1M context, 64K output)
|
|
26
|
+
- `gemini-3.5-flash` (aliases: `gemini-3.5`, `flash-3.5`) - Frontier-level agentic and coding performance at Flash speed (1M context, 65K output)
|
|
26
27
|
- `gemini-2.5-pro` (alias: `pro 2.5`) - Deep reasoning with thinking budget (1M context, 65K output)
|
|
27
28
|
- `gemini-2.5-flash` (alias: `flash`) - Ultra-fast model with thinking budget (1M context, 65K output)
|
|
28
|
-
-
|
|
29
|
+
- `gemini-2.5-flash-lite` (alias: `flash-lite`) - Lightweight fast model (1M context, 65K output)
|
|
30
|
+
- **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-3.1-pro-preview` or `gemini-2.5-flash` (bare `gemini-pro`/`gemini-flash` also route to the Google API).
|
|
29
31
|
|
|
30
32
|
### X.AI (Grok)
|
|
31
33
|
- **API Key Format**: `xai-...` (starts with `xai-`)
|
|
32
34
|
- **Get Key**: [console.x.ai](https://console.x.ai/)
|
|
33
35
|
- **Environment Variable**: `XAI_API_KEY`
|
|
34
36
|
- **Supported Models**:
|
|
35
|
-
- `grok-4-
|
|
36
|
-
|
|
37
|
+
- `grok-4.5` (default; aliases: `grok`, `grok-4.5-latest`, `grok-build-latest`) - Flagship model with image input, reasoning content, and native web/X search (500K context)
|
|
38
|
+
- **Reasoning**: `reasoning_effort` maps to Grok's `low`/`medium`/`high`. Grok 4.5 always reasons and cannot be turned off, so `none`/`minimal`/`low` clamp to `low`, `medium` stays `medium`, and `high`/`max` clamp to `high`.
|
|
39
|
+
- **Web search**: Automatic — native web/X search (Agent Tools) is attached on every Grok 4.5 request; the model decides per-request whether to search, and any citations are returned in metadata.
|
|
40
|
+
- **Retired IDs**: Older Grok identifiers (e.g. `grok-4-0709`, `grok-code-fast-1`) still pass through as explicit model strings, but xAI does not surface a retirement error for them — it silently remaps them upstream to a current model (HTTP 200). Use `grok-4.5` for predictable results.
|
|
37
41
|
|
|
38
42
|
### Anthropic (Claude)
|
|
39
43
|
- **API Key Format**: `sk-ant-...` (starts with `sk-ant-`)
|
|
@@ -53,39 +57,40 @@ This guide documents all supported AI providers in the Converse MCP Server and t
|
|
|
53
57
|
- **Get Key**: [console.mistral.ai](https://console.mistral.ai/)
|
|
54
58
|
- **Environment Variable**: `MISTRAL_API_KEY`
|
|
55
59
|
- **Supported Models**:
|
|
56
|
-
- `mistral-
|
|
57
|
-
- `mistral-
|
|
58
|
-
- `mistral-
|
|
59
|
-
|
|
60
|
+
- `mistral-medium-3-5` (default; aliases: `mistral`, `mistral-medium`, `mistral-medium-latest`) - Frontier-class multimodal model with adjustable reasoning (256K context)
|
|
61
|
+
- `mistral-small-2603` (aliases: `mistral-small`, `mistral-small-latest`) - Hybrid multimodal model unifying instruct, reasoning, and coding (256K context)
|
|
62
|
+
- `mistral-large-2512` (aliases: `mistral-large`, `mistral-large-latest`) - Open-weight MoE flagship, image-capable (256K context)
|
|
63
|
+
- **Reasoning**: Mistral exposes only `high` and `none`. On the reasoning-capable models (`mistral-medium-3-5`, `mistral-small-2603`), every enabled `reasoning_effort` level maps to `high` and only `none` disables thinking. `mistral-large-2512` has no adjustable reasoning, so `reasoning_effort` is never sent for it.
|
|
64
|
+
- **Images**: `mistral-medium-3-5` and `mistral-small-2603` accept image input; `mistral-large-2512` is text-only.
|
|
60
65
|
|
|
61
66
|
### DeepSeek
|
|
62
67
|
- **API Key Format**: 32+ character string
|
|
63
68
|
- **Get Key**: [platform.deepseek.com](https://platform.deepseek.com/)
|
|
64
69
|
- **Environment Variable**: `DEEPSEEK_API_KEY`
|
|
65
70
|
- **Supported Models**:
|
|
66
|
-
- `deepseek-
|
|
67
|
-
- `deepseek-
|
|
71
|
+
- `deepseek-v4-pro` (default; aliases: `deepseek`, `deepseek-pro`) - Flagship MoE model with thinking mode (1M context, 384K max output, text-only)
|
|
72
|
+
- `deepseek-v4-flash` (alias: `deepseek-flash`) - Faster, lower-cost V4 tier with thinking mode (1M context, 384K max output, text-only)
|
|
73
|
+
- **Reasoning**: DeepSeek V4 exposes thinking mode via a `thinking` toggle plus a `reasoning_effort` of `high` or `max`. `none` disables thinking; `minimal`/`low`/`medium`/`high` enable thinking at `high`; `max` enables thinking at `max`.
|
|
68
74
|
|
|
69
75
|
### OpenRouter
|
|
70
76
|
- **API Key Format**: `sk-or-...` (starts with `sk-or-`)
|
|
71
77
|
- **Get Key**: [openrouter.ai/keys](https://openrouter.ai/keys)
|
|
72
|
-
- **Environment Variables**:
|
|
78
|
+
- **Environment Variables**:
|
|
73
79
|
- `OPENROUTER_API_KEY` - Your API key
|
|
74
|
-
- `OPENROUTER_REFERER` -
|
|
75
|
-
- `OPENROUTER_TITLE` - Optional title for
|
|
76
|
-
|
|
77
|
-
-
|
|
78
|
-
- `
|
|
79
|
-
- `
|
|
80
|
-
- `
|
|
81
|
-
- `
|
|
82
|
-
-
|
|
83
|
-
- `
|
|
84
|
-
- `
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
- And many more - see [openrouter.ai/models](https://openrouter.ai/models)
|
|
80
|
+
- `OPENROUTER_REFERER` - Optional referer URL (e.g., your GitHub repo) for OpenRouter ranking credit; omitting it is valid
|
|
81
|
+
- `OPENROUTER_TITLE` - Optional title for OpenRouter ranking credit
|
|
82
|
+
- **Curated Models** (default `z-ai/glm-5.2`):
|
|
83
|
+
- `z-ai/glm-5.2` (aliases: `glm`, `glm-5.2`) - Large-scale reasoning model, text-only (1M context)
|
|
84
|
+
- `deepseek/deepseek-v4-pro` - DeepSeek V4 Pro reasoning model, text-only (1M context, 384K output)
|
|
85
|
+
- `deepseek/deepseek-v4-flash` - Faster, lower-cost DeepSeek V4 tier, text-only (1M context, 384K output)
|
|
86
|
+
- `qwen/qwen3.7-max` (alias: `qwen3.7-max`) - Flagship Qwen, text-only (1M context)
|
|
87
|
+
- `qwen/qwen3.7-plus` (alias: `qwen3.7-plus`) - Image-capable Qwen (1M context)
|
|
88
|
+
- `moonshotai/kimi-k2.7-code` (alias: `kimi-k2.7-code`) - Coding model, image-capable, reasoning always on (256K context)
|
|
89
|
+
- `moonshotai/kimi-k2.6` (alias: `kimi-k2.6`) - Image-capable general model (256K context)
|
|
90
|
+
- `openrouter/auto` - Auto-selects the best model for your prompt
|
|
91
|
+
- **Any other model**: Use the full `provider/model` slug directly (e.g. `anthropic/claude-sonnet-5`, `meta-llama/llama-3.1-405b-instruct`) or the `openrouter:` namespace (e.g. `openrouter:z-ai/glm-5.2`). No extra configuration is needed — slugs route to OpenRouter as-is. A slug absent from OpenRouter's live catalog fails before inference with `MODEL_NOT_FOUND`. See [openrouter.ai/models](https://openrouter.ai/models) for the full catalog.
|
|
92
|
+
- **Reasoning**: Per-model. `z-ai/glm-5.2` and the `deepseek/deepseek-v4-*` slugs are effort-tiered (`max` → `xhigh`, other enabled levels → `high`, `none` disables); `qwen/qwen3.7-*` and `moonshotai/kimi-k2.6` are enable/disable only (`none` disables, any other level enables); `moonshotai/kimi-k2.7-code` always reasons and cannot be disabled; `openrouter/auto` lets the router choose.
|
|
93
|
+
- **Web search (opt-in, adds cost)**: OpenRouter web search is off by default because it incurs a real per-request charge. Enable it explicitly by appending `:online` to a slug (e.g. `z-ai/glm-5.2:online` or `openrouter:qwen/qwen3.7-max:online`). When enabled, `annotations[].url_citation` citations are captured into metadata. Ordinary requests never attach a web-search plugin.
|
|
89
94
|
|
|
90
95
|
### Codex
|
|
91
96
|
- **API Key Format**: Optional (uses ChatGPT login by default)
|
|
@@ -133,8 +138,6 @@ This guide documents all supported AI providers in the Converse MCP Server and t
|
|
|
133
138
|
- **Subscription Access**: Leverages the Antigravity weekly compute allowance instead of pay-per-API-call
|
|
134
139
|
- **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)
|
|
135
140
|
|
|
136
|
-
> Note: This replaces the previous `@google/gemini-cli` (`ai-sdk-provider-gemini-cli`) integration, whose OAuth access Google sunsets on 2026-06-18.
|
|
137
|
-
|
|
138
141
|
**Authentication Setup:**
|
|
139
142
|
```bash
|
|
140
143
|
# Install the Antigravity CLI (agy)
|
|
@@ -155,18 +158,19 @@ agy
|
|
|
155
158
|
"name": "chat",
|
|
156
159
|
"arguments": {
|
|
157
160
|
"prompt": "Explain async/await in JavaScript",
|
|
158
|
-
"
|
|
161
|
+
"models": ["gemini"]
|
|
159
162
|
}
|
|
160
163
|
}
|
|
161
164
|
```
|
|
162
165
|
|
|
163
|
-
*Consensus
|
|
166
|
+
*Consensus mode:*
|
|
164
167
|
```json
|
|
165
168
|
{
|
|
166
|
-
"name": "
|
|
169
|
+
"name": "chat",
|
|
167
170
|
"arguments": {
|
|
168
171
|
"prompt": "Should we use TypeScript for this component?",
|
|
169
|
-
"models": ["gemini", "gpt-5", "claude
|
|
172
|
+
"models": ["gemini", "gpt-5.6", "claude"],
|
|
173
|
+
"mode": "consensus"
|
|
170
174
|
}
|
|
171
175
|
}
|
|
172
176
|
```
|
|
@@ -197,13 +201,30 @@ agy
|
|
|
197
201
|
- **Subscription Access**: Uses your Claude subscription instead of API credits
|
|
198
202
|
- **Local File Access**: Reads files directly from the working directory
|
|
199
203
|
- **Image Support**: Via the SDK's streaming input mode
|
|
200
|
-
- **SDK-Managed Parameters**: `
|
|
204
|
+
- **SDK-Managed Parameters**: `reasoning_effort` and other sampling parameters are managed internally by the SDK
|
|
201
205
|
|
|
202
206
|
**Differences from Anthropic API Provider:**
|
|
203
207
|
- **Authentication**: Claude Code login vs `ANTHROPIC_API_KEY`
|
|
204
208
|
- **Billing**: Claude subscription vs pay-per-use API
|
|
205
209
|
- **Model Routing**: `claude` and `claude:*` → SDK provider; specific names (e.g., `claude-fable-5`, `opus`, `sonnet`) → API provider
|
|
206
210
|
|
|
211
|
+
### GitHub Copilot SDK
|
|
212
|
+
- **Authentication**: GitHub Copilot subscription via the Copilot CLI (`gh auth login` with an active Copilot subscription) — no API key needed
|
|
213
|
+
- **Setup Required**: Authenticate the GitHub CLI and ensure your account has an active Copilot subscription
|
|
214
|
+
- **Environment Variables**: None
|
|
215
|
+
- **Supported Models** (reach them with the `copilot:` namespace, e.g. `copilot:gpt-5.6-terra`):
|
|
216
|
+
- `copilot` - Uses Copilot's default or env-configured model
|
|
217
|
+
- OpenAI: `gpt-5.6-sol` (aliases: bare `gpt-5.6`, `gpt-5`), `gpt-5.6-terra` (recommended balanced tier), `gpt-5.6-luna`
|
|
218
|
+
- Anthropic: `claude-fable-5` (alias: `fable`), `claude-sonnet-5` (alias: `sonnet`), `claude-opus-4.8` (aliases: `opus`, `claude`)
|
|
219
|
+
- Google: `gemini-3.1-pro-preview` (aliases: `gemini`, `gemini-3.1-pro`), `gemini-3.5-flash` (alias: `gemini-flash`)
|
|
220
|
+
- **Reasoning**: The `gpt-5.6-sol`/`terra`/`luna` tiers accept `reasoning_effort`.
|
|
221
|
+
- **Explicit pass-through**: Any other `copilot:<id>` model string is forwarded to the Copilot backend verbatim, so IDs outside the curated list still work while the backend accepts them.
|
|
222
|
+
|
|
223
|
+
**Key Features:**
|
|
224
|
+
- **Subscription Access**: Uses your GitHub Copilot subscription instead of API credits
|
|
225
|
+
- **Multiple Backends**: OpenAI, Anthropic, and Google models through a single subscription
|
|
226
|
+
- **Model IDs**: Lowercase dot-versioned (e.g. `claude-opus-4.8`, `gemini-3.1-pro-preview`)
|
|
227
|
+
|
|
207
228
|
## Configuration Examples
|
|
208
229
|
|
|
209
230
|
### Basic Configuration (.env file)
|
|
@@ -214,12 +235,10 @@ ANTHROPIC_API_KEY=sk-ant-your_key_here
|
|
|
214
235
|
MISTRAL_API_KEY=your_mistral_key_here
|
|
215
236
|
DEEPSEEK_API_KEY=your_deepseek_key_here
|
|
216
237
|
|
|
217
|
-
# OpenRouter
|
|
238
|
+
# OpenRouter needs only an API key; any provider/model slug works directly
|
|
218
239
|
OPENROUTER_API_KEY=sk-or-your_key_here
|
|
240
|
+
# Optional: referer and title for OpenRouter ranking credit
|
|
219
241
|
OPENROUTER_REFERER=https://github.com/YourUsername/YourApp
|
|
220
|
-
# Optional: Enable dynamic model discovery to use any OpenRouter model
|
|
221
|
-
OPENROUTER_DYNAMIC_MODELS=true
|
|
222
|
-
# Optional: Add title for request tracking
|
|
223
242
|
OPENROUTER_TITLE=Converse
|
|
224
243
|
|
|
225
244
|
# Codex - Optional API key (uses ChatGPT login by default)
|
|
@@ -243,7 +262,6 @@ CODEX_APPROVAL_POLICY=never # never (default), untrusted, on-fa
|
|
|
243
262
|
"DEEPSEEK_API_KEY": "your_key_here",
|
|
244
263
|
"OPENROUTER_API_KEY": "your_key_here",
|
|
245
264
|
"OPENROUTER_REFERER": "https://github.com/YourUsername/YourApp",
|
|
246
|
-
"OPENROUTER_DYNAMIC_MODELS": "true",
|
|
247
265
|
"OPENROUTER_TITLE": "Converse"
|
|
248
266
|
}
|
|
249
267
|
}
|
|
@@ -257,20 +275,26 @@ CODEX_APPROVAL_POLICY=never # never (default), untrusted, on-fa
|
|
|
257
275
|
All providers support streaming responses for real-time output.
|
|
258
276
|
|
|
259
277
|
### Image Support
|
|
260
|
-
- **Full Support**: OpenAI, Google, X.AI (Grok
|
|
261
|
-
- **
|
|
262
|
-
- **
|
|
278
|
+
- **Full Support**: OpenAI, Google, X.AI (Grok 4.5), Anthropic (Claude-4 series, Claude-3-Opus)
|
|
279
|
+
- **Mistral**: `mistral-medium-3-5` and `mistral-small-2603` accept images; `mistral-large-2512` is text-only
|
|
280
|
+
- **Via OpenRouter**: Depends on the model — `qwen/qwen3.7-plus`, `moonshotai/kimi-k2.7-code`, and `moonshotai/kimi-k2.6` accept images; `z-ai/glm-5.2` and the `deepseek/deepseek-v4-*` slugs are text-only
|
|
281
|
+
- **No Support**: DeepSeek (native), Codex
|
|
263
282
|
|
|
264
283
|
### Web Search
|
|
265
|
-
- **
|
|
266
|
-
- **
|
|
284
|
+
- **Automatic where supported**: OpenAI, Google, and X.AI (Grok 4.5, via Agent Tools) attach web search on every request for capable models; the model decides whether to use it
|
|
285
|
+
- **OpenRouter (opt-in, adds cost)**: Off by default; append `:online` to a slug to enable it per request (real per-request charge), with citations captured into metadata
|
|
286
|
+
- **No Support**: Anthropic, Mistral, DeepSeek, Codex
|
|
267
287
|
|
|
268
288
|
### Thinking/Reasoning Modes
|
|
269
|
-
- **OpenAI**: O3 series models support `reasoning_effort` parameter
|
|
289
|
+
- **OpenAI**: GPT-5 family and O3 series models support the `reasoning_effort` parameter (GPT-5.6 accepts `none` through `max`, mapping `minimal` to `low`; GPT-5 Pro is fixed at `high`)
|
|
270
290
|
- **Google**:
|
|
271
291
|
- Gemini 3.0 Pro: Thinking levels (low/high) via `reasoning_effort` - always enabled
|
|
272
292
|
- Gemini 2.5 Pro/Flash: Thinking budget (token-based) via `reasoning_effort`
|
|
273
293
|
- **Anthropic**: Claude Fable 5, Opus 4.6+, and Sonnet 4.6 use adaptive thinking (depth controlled by `reasoning_effort` via Anthropic's `effort` parameter); older Claude 4 models use budget-based extended thinking
|
|
294
|
+
- **X.AI**: Grok 4.5 maps `reasoning_effort` to `low`/`medium`/`high` and always reasons (cannot be disabled)
|
|
295
|
+
- **Mistral**: `mistral-medium-3-5` and `mistral-small-2603` map `reasoning_effort` to `high` (enabled) or `none` (disabled); `mistral-large-2512` has no adjustable reasoning
|
|
296
|
+
- **DeepSeek**: V4 models use thinking mode via `reasoning_effort` (`none` disables; enabled levels use `high`, `max` uses `max`)
|
|
297
|
+
- **OpenRouter**: Reasoning is per-model (effort-tiered, enable/disable-only, mandatory, or router-chosen — see the OpenRouter section)
|
|
274
298
|
- **Codex**: Thread-based agentic reasoning with persistent context
|
|
275
299
|
- **Others**: Standard inference only
|
|
276
300
|
|
|
@@ -280,7 +304,7 @@ All providers support streaming responses for real-time output.
|
|
|
280
304
|
|
|
281
305
|
## Model Selection in Tools
|
|
282
306
|
|
|
283
|
-
When using the chat
|
|
307
|
+
When using the chat tool in any mode, specify models using their identifiers:
|
|
284
308
|
|
|
285
309
|
### Model Routing Logic
|
|
286
310
|
|
|
@@ -307,31 +331,34 @@ When using the chat or consensus tools, specify models using their identifiers:
|
|
|
307
331
|
4. **OpenRouter Auto**: Special aliases route to OpenRouter's auto-selection:
|
|
308
332
|
- "openrouter/auto", "openrouter auto", "auto router", "auto-router"
|
|
309
333
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
334
|
+
The `models` array always holds plain model-name strings. Each string routes as follows:
|
|
335
|
+
|
|
336
|
+
```text
|
|
337
|
+
"gpt-5.6" // OpenAI (keyword match)
|
|
338
|
+
"fable" // Anthropic (keyword match -> claude-fable-5)
|
|
339
|
+
"opus" // Anthropic (keyword match -> claude-opus-4-8)
|
|
340
|
+
"sonnet" // Anthropic (keyword match -> claude-sonnet-4-6)
|
|
341
|
+
"claude" // Claude Agent SDK (defaults to Claude Fable 5)
|
|
342
|
+
"claude:opus" // Claude Agent SDK (Claude Opus 4.8)
|
|
343
|
+
"gemini-2.5-pro" // Google (keyword match)
|
|
344
|
+
"grok-4.5" // X.AI (keyword match)
|
|
345
|
+
"mistral-large" // Mistral (alias -> mistral-large-2512)
|
|
346
|
+
"deepseek" // DeepSeek (alias -> deepseek-v4-pro)
|
|
347
|
+
"z-ai/glm-5.2" // OpenRouter (curated slug)
|
|
348
|
+
"z-ai/glm-5.2:online" // OpenRouter with web search opt-in
|
|
349
|
+
"anthropic/claude-sonnet-5" // OpenRouter (any full slug routes as-is)
|
|
350
|
+
"openrouter/auto" // OpenRouter auto-selection
|
|
351
|
+
```
|
|
327
352
|
|
|
328
|
-
|
|
353
|
+
```json
|
|
354
|
+
// Consensus mode with multiple providers
|
|
329
355
|
{
|
|
330
|
-
"
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
356
|
+
"name": "chat",
|
|
357
|
+
"arguments": {
|
|
358
|
+
"prompt": "Which database fits our workload?",
|
|
359
|
+
"models": ["gpt-5.6", "claude", "gemini-2.5-pro"],
|
|
360
|
+
"mode": "consensus"
|
|
361
|
+
}
|
|
335
362
|
}
|
|
336
363
|
```
|
|
337
364
|
|
|
@@ -353,14 +380,12 @@ When using the chat or consensus tools, specify models using their identifiers:
|
|
|
353
380
|
- OpenRouter provides unified rate limiting across providers
|
|
354
381
|
- Consider using multiple providers for better availability
|
|
355
382
|
|
|
356
|
-
### OpenRouter
|
|
357
|
-
-
|
|
358
|
-
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
-
|
|
363
|
-
-
|
|
364
|
-
-
|
|
365
|
-
- Use any model from [openrouter.ai/models](https://openrouter.ai/models)
|
|
366
|
-
- Models must use `provider/model` format (e.g., `meta-llama/llama-3.2-90b`)
|
|
383
|
+
### OpenRouter Attribution
|
|
384
|
+
- `OPENROUTER_REFERER` and `OPENROUTER_TITLE` are optional — set them to your application URL / name for OpenRouter ranking credit
|
|
385
|
+
- Omitting them is valid and never blocks a request
|
|
386
|
+
|
|
387
|
+
### OpenRouter Model Selection
|
|
388
|
+
- The 8 curated slugs work out of the box; the default is `z-ai/glm-5.2`
|
|
389
|
+
- Any other model works via its full `provider/model` slug or the `openrouter:` namespace — no extra configuration
|
|
390
|
+
- The first request to a non-curated slug fetches its capabilities from OpenRouter's live catalog; a slug absent from that catalog fails before inference with `MODEL_NOT_FOUND`
|
|
391
|
+
- Append `:online` to a slug to enable web search for that request (adds a real per-request cost)
|
package/package.json
CHANGED
|
@@ -167,9 +167,9 @@ class LRUAsyncJobStore extends AsyncJobStoreInterface {
|
|
|
167
167
|
async create(tool, options = {}) {
|
|
168
168
|
try {
|
|
169
169
|
// Validate parameters
|
|
170
|
-
if (!tool || !['chat'
|
|
170
|
+
if (!tool || !['chat'].includes(tool)) {
|
|
171
171
|
throw new AsyncJobStoreError(
|
|
172
|
-
'Invalid tool: must be "chat"
|
|
172
|
+
'Invalid tool: must be "chat"',
|
|
173
173
|
'INVALID_TOOL',
|
|
174
174
|
);
|
|
175
175
|
}
|
package/src/async/jobRunner.js
CHANGED
|
@@ -81,7 +81,8 @@ export class JobRunner extends EventEmitter {
|
|
|
81
81
|
* Submit a job for background execution
|
|
82
82
|
* @param {object} jobSpec - Job specification
|
|
83
83
|
* @param {string} jobSpec.sessionId - Session identifier
|
|
84
|
-
* @param {string} jobSpec.tool - Tool name ('chat'
|
|
84
|
+
* @param {string} jobSpec.tool - Tool name (always 'chat')
|
|
85
|
+
* @param {string} jobSpec.mode - Chat mode ('chat' | 'consensus' | 'roundtable')
|
|
85
86
|
* @param {Function} runFunction - Function to execute (async)
|
|
86
87
|
* @param {object} options - Execution options
|
|
87
88
|
* @param {number} options.timeout - Job timeout in ms
|
|
@@ -112,6 +113,7 @@ export class JobRunner extends EventEmitter {
|
|
|
112
113
|
// Create job in store
|
|
113
114
|
const jobId = await this.asyncJobStore.create(jobSpec.tool, {
|
|
114
115
|
sessionId: jobSpec.sessionId,
|
|
116
|
+
mode: jobSpec.mode,
|
|
115
117
|
timeout: options.timeout || this.defaultTimeout,
|
|
116
118
|
priority: options.priority || false,
|
|
117
119
|
...jobSpec.options,
|
|
@@ -336,6 +338,7 @@ export class JobRunner extends EventEmitter {
|
|
|
336
338
|
jobId,
|
|
337
339
|
status: JOB_STATUS.COMPLETED,
|
|
338
340
|
tool: finalJobState.tool,
|
|
341
|
+
mode: finalJobState.mode,
|
|
339
342
|
result,
|
|
340
343
|
completedAt: Date.now(),
|
|
341
344
|
createdAt: finalJobState.createdAt,
|
|
@@ -396,6 +399,7 @@ export class JobRunner extends EventEmitter {
|
|
|
396
399
|
jobId,
|
|
397
400
|
status: JOB_STATUS.CANCELLED,
|
|
398
401
|
tool: cancelledJobState.tool,
|
|
402
|
+
mode: cancelledJobState.mode,
|
|
399
403
|
result: partialResult,
|
|
400
404
|
cancelledAt: Date.now(),
|
|
401
405
|
createdAt: cancelledJobState.createdAt,
|
|
@@ -446,6 +450,7 @@ export class JobRunner extends EventEmitter {
|
|
|
446
450
|
jobId,
|
|
447
451
|
status: JOB_STATUS.FAILED,
|
|
448
452
|
tool: failedJobState.tool,
|
|
453
|
+
mode: failedJobState.mode,
|
|
449
454
|
error: executionError.message || executionError,
|
|
450
455
|
failedAt: Date.now(),
|
|
451
456
|
createdAt: failedJobState.createdAt,
|
|
@@ -24,6 +24,7 @@ const EVENT_TYPES = {
|
|
|
24
24
|
END: 'end',
|
|
25
25
|
ERROR: 'error',
|
|
26
26
|
REASONING_SUMMARY: 'reasoning_summary',
|
|
27
|
+
REASONING: 'reasoning',
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -174,6 +175,7 @@ class ProviderStreamNormalizer {
|
|
|
174
175
|
|
|
175
176
|
let hasStarted = false;
|
|
176
177
|
let accumulatedContent = '';
|
|
178
|
+
let accumulatedReasoning = '';
|
|
177
179
|
let accumulatedUsage = null;
|
|
178
180
|
let finishReason = null;
|
|
179
181
|
const searchMetadata = {};
|
|
@@ -194,6 +196,13 @@ class ProviderStreamNormalizer {
|
|
|
194
196
|
continue;
|
|
195
197
|
}
|
|
196
198
|
|
|
199
|
+
// Handle reasoning/thinking events (kept separate from answer text)
|
|
200
|
+
if (event.type === 'thinking') {
|
|
201
|
+
accumulatedReasoning += event.content || '';
|
|
202
|
+
yield this.createReasoningEvent(event.content || '', provider, model);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
|
|
197
206
|
// Handle usage events (with XAI-specific search metadata)
|
|
198
207
|
if (event.type === 'usage') {
|
|
199
208
|
accumulatedUsage = event.usage;
|
|
@@ -212,6 +221,7 @@ class ProviderStreamNormalizer {
|
|
|
212
221
|
const endMetadata = {
|
|
213
222
|
...event.metadata,
|
|
214
223
|
...searchMetadata,
|
|
224
|
+
...(accumulatedReasoning && { reasoning: accumulatedReasoning }),
|
|
215
225
|
};
|
|
216
226
|
|
|
217
227
|
yield this.createEndEvent(
|
|
@@ -424,6 +434,7 @@ class ProviderStreamNormalizer {
|
|
|
424
434
|
|
|
425
435
|
let hasStarted = false;
|
|
426
436
|
let accumulatedContent = '';
|
|
437
|
+
let accumulatedReasoning = '';
|
|
427
438
|
let accumulatedUsage = null;
|
|
428
439
|
let finishReason = null;
|
|
429
440
|
|
|
@@ -443,6 +454,13 @@ class ProviderStreamNormalizer {
|
|
|
443
454
|
continue;
|
|
444
455
|
}
|
|
445
456
|
|
|
457
|
+
// Handle reasoning/thinking events (kept separate from answer text)
|
|
458
|
+
if (event.type === 'thinking') {
|
|
459
|
+
accumulatedReasoning += event.content || '';
|
|
460
|
+
yield this.createReasoningEvent(event.content || '', provider, model);
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
|
|
446
464
|
// Handle usage events
|
|
447
465
|
if (event.type === 'usage') {
|
|
448
466
|
accumulatedUsage = event.usage;
|
|
@@ -453,13 +471,17 @@ class ProviderStreamNormalizer {
|
|
|
453
471
|
// Handle end event
|
|
454
472
|
if (event.type === 'end') {
|
|
455
473
|
finishReason = event.stop_reason || event.metadata?.finish_reason;
|
|
474
|
+
const endMetadata = {
|
|
475
|
+
...event.metadata,
|
|
476
|
+
...(accumulatedReasoning && { reasoning: accumulatedReasoning }),
|
|
477
|
+
};
|
|
456
478
|
yield this.createEndEvent(
|
|
457
479
|
{
|
|
458
480
|
content: event.content || accumulatedContent,
|
|
459
481
|
stopReason: finishReason,
|
|
460
482
|
usage: event.metadata?.usage || accumulatedUsage,
|
|
461
483
|
responseTime: Date.now() - startTime,
|
|
462
|
-
metadata:
|
|
484
|
+
metadata: endMetadata,
|
|
463
485
|
},
|
|
464
486
|
provider,
|
|
465
487
|
model,
|
|
@@ -494,6 +516,7 @@ class ProviderStreamNormalizer {
|
|
|
494
516
|
|
|
495
517
|
let hasStarted = false;
|
|
496
518
|
let accumulatedContent = '';
|
|
519
|
+
let accumulatedReasoning = '';
|
|
497
520
|
let accumulatedUsage = null;
|
|
498
521
|
let finishReason = null;
|
|
499
522
|
const reasoningMetadata = {};
|
|
@@ -516,6 +539,13 @@ class ProviderStreamNormalizer {
|
|
|
516
539
|
continue;
|
|
517
540
|
}
|
|
518
541
|
|
|
542
|
+
// Handle reasoning/thinking events (kept separate from answer text)
|
|
543
|
+
if (event.type === 'thinking') {
|
|
544
|
+
accumulatedReasoning += event.content || '';
|
|
545
|
+
yield this.createReasoningEvent(event.content || '', provider, model);
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
|
|
519
549
|
// Handle usage events (with DeepSeek-specific reasoning tokens)
|
|
520
550
|
if (event.type === 'usage') {
|
|
521
551
|
accumulatedUsage = event.usage;
|
|
@@ -532,6 +562,7 @@ class ProviderStreamNormalizer {
|
|
|
532
562
|
const endMetadata = {
|
|
533
563
|
...event.metadata,
|
|
534
564
|
...reasoningMetadata,
|
|
565
|
+
...(accumulatedReasoning && { reasoning: accumulatedReasoning }),
|
|
535
566
|
};
|
|
536
567
|
|
|
537
568
|
yield this.createEndEvent(
|
|
@@ -575,6 +606,7 @@ class ProviderStreamNormalizer {
|
|
|
575
606
|
|
|
576
607
|
let hasStarted = false;
|
|
577
608
|
let accumulatedContent = '';
|
|
609
|
+
let accumulatedReasoning = '';
|
|
578
610
|
let accumulatedUsage = null;
|
|
579
611
|
let finishReason = null;
|
|
580
612
|
let routingMetadata = {};
|
|
@@ -595,6 +627,13 @@ class ProviderStreamNormalizer {
|
|
|
595
627
|
continue;
|
|
596
628
|
}
|
|
597
629
|
|
|
630
|
+
// Handle reasoning/thinking events (kept separate from answer text)
|
|
631
|
+
if (event.type === 'thinking') {
|
|
632
|
+
accumulatedReasoning += event.content || '';
|
|
633
|
+
yield this.createReasoningEvent(event.content || '', provider, model);
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
|
|
598
637
|
// Handle usage events (with OpenRouter-specific routing metadata)
|
|
599
638
|
if (event.type === 'usage') {
|
|
600
639
|
accumulatedUsage = event.usage;
|
|
@@ -611,6 +650,7 @@ class ProviderStreamNormalizer {
|
|
|
611
650
|
const endMetadata = {
|
|
612
651
|
...event.metadata,
|
|
613
652
|
...routingMetadata,
|
|
653
|
+
...(accumulatedReasoning && { reasoning: accumulatedReasoning }),
|
|
614
654
|
};
|
|
615
655
|
|
|
616
656
|
yield this.createEndEvent(
|
|
@@ -771,6 +811,24 @@ class ProviderStreamNormalizer {
|
|
|
771
811
|
};
|
|
772
812
|
}
|
|
773
813
|
|
|
814
|
+
/**
|
|
815
|
+
* Create standardized streamed-reasoning event. Distinct from a delta so
|
|
816
|
+
* downstream consumers keep reasoning separate from the visible answer.
|
|
817
|
+
*/
|
|
818
|
+
createReasoningEvent(content, provider, model) {
|
|
819
|
+
return {
|
|
820
|
+
type: EVENT_TYPES.REASONING,
|
|
821
|
+
provider,
|
|
822
|
+
model,
|
|
823
|
+
timestamp: Date.now(),
|
|
824
|
+
data: {
|
|
825
|
+
content: content || '',
|
|
826
|
+
role: 'assistant',
|
|
827
|
+
isReasoning: true,
|
|
828
|
+
},
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
|
|
774
832
|
/**
|
|
775
833
|
* Create standardized reasoning summary event
|
|
776
834
|
*/
|
package/src/config.js
CHANGED
|
@@ -222,13 +222,14 @@ const CONFIG_SCHEMA = {
|
|
|
222
222
|
OPENROUTER_TITLE: {
|
|
223
223
|
type: 'string',
|
|
224
224
|
required: false,
|
|
225
|
-
description:
|
|
225
|
+
description:
|
|
226
|
+
'Optional OpenRouter attribution title, sent as the canonical X-OpenRouter-Title header',
|
|
226
227
|
},
|
|
227
228
|
OPENROUTER_DYNAMIC_MODELS: {
|
|
228
229
|
type: 'boolean',
|
|
229
230
|
default: false,
|
|
230
231
|
description:
|
|
231
|
-
'
|
|
232
|
+
'Accepted but unnecessary — full OpenRouter provider/model slugs always resolve without it',
|
|
232
233
|
},
|
|
233
234
|
|
|
234
235
|
// Google Vertex AI configuration
|
|
@@ -294,7 +295,7 @@ const CONFIG_SCHEMA = {
|
|
|
294
295
|
type: 'string',
|
|
295
296
|
required: false,
|
|
296
297
|
description:
|
|
297
|
-
'Default model for Copilot SDK sessions (e.g., gpt-5, claude-sonnet-
|
|
298
|
+
'Default model for Copilot SDK sessions (e.g., gpt-5.6-sol, claude-sonnet-5)',
|
|
298
299
|
},
|
|
299
300
|
COPILOT_CLI_PATH: {
|
|
300
301
|
type: 'string',
|