copilot-custom-endpoint 1.3.10 → 1.3.12
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 +15 -0
- package/docs/example-config.md +9 -9
- package/docs/models/qwen.md +9 -5
- package/package.json +2 -2
- package/proxy/kimi-proxy.mjs +14 -2
- package/proxy/qwen-proxy.mjs +12 -2
package/README.md
CHANGED
|
@@ -107,6 +107,8 @@ For the full pricing comparison (cached rates, full Copilot roster, footnotes, s
|
|
|
107
107
|
|
|
108
108
|
## Companion tools
|
|
109
109
|
|
|
110
|
+
> **ℹ️ These are third-party tools — not built into the custom endpoints or proxies in this repo.** Each one must be installed, configured, and (where applicable) billed for **separately**, directly with its own provider. Nothing here is bundled, proxied, or auto-configured by `copilot-custom-endpoint` or the per-model setups above. The entries below are just pointers to tools the author has found useful alongside the model configs.
|
|
111
|
+
|
|
110
112
|
These work alongside the providers above and fill gaps that VS Code's built-in tool surface doesn't cover natively.
|
|
111
113
|
|
|
112
114
|
### 🎬 [Video Context MCP](https://www.videocontextmcp.com/) — _video understanding for AI coding assistants_
|
|
@@ -120,6 +122,19 @@ VS Code's built-in `view_image` tool only accepts **static images** (PNG, JPG, G
|
|
|
120
122
|
- **Answers natural-language questions** about the video grounded in actual frames: "what does the speaker click in the last 30 seconds?", "summarize the demo", "find the frame where the error appears".
|
|
121
123
|
- **Extras:** timestamp search, audio transcription with speaker diarization, and video metadata (resolution, duration, codec).
|
|
122
124
|
|
|
125
|
+
### 🪣 [Bitbucket MCP](https://bitbucketmcp.tugudush.com/) — _secure, read-only Bitbucket access for VS Code Copilot, Cursor, and Claude Code_
|
|
126
|
+
|
|
127
|
+
GitHub ships a first-party MCP server (and it's even bundled into Copilot), so asking "what's open in my org's repos / show me PR #123" works seamlessly on github.com. **Bitbucket has no equivalent** — Atlassian hasn't shipped one — which leaves Bitbucket Cloud users copy-pasting PR URLs, diffs, and file contents into chat by hand.
|
|
128
|
+
|
|
129
|
+
**Bitbucket MCP** is a small MCP server that closes that gap. It works with **VS Code GitHub Copilot, Cursor, and Claude Code** out of the box, and:
|
|
130
|
+
|
|
131
|
+
- **38 tools across 8 categories** — repositories, pull requests, branches & commits, diffs & comparisons, CI/CD pipelines, issues, code search, and users.
|
|
132
|
+
- **Read-only by design** — `makeRequest()` blocks all non-GET requests at runtime, so no write, delete, or modify operation is possible.
|
|
133
|
+
- **Token-friendly output** — every tool supports `text`, `json`, and `toon` (Token-Oriented Object Notation) formats; `toon` cuts LLM token consumption by 30–60% on large PR/commit lists.
|
|
134
|
+
- **JMESPath filtering** on all 38 tools, so you can trim responses (e.g. only open PRs, or just title + author) before they hit the model.
|
|
135
|
+
- **One-call PR context** — `bb_get_context` bundles PR metadata, diffstat, CI statuses, and comments in a single request.
|
|
136
|
+
- **Drop-in install** — `npm install -g @tugudush/bitbucket-mcp` plus a short `.vscode/mcp.json` entry, authenticated with a Bitbucket API token + your Atlassian email.
|
|
137
|
+
|
|
123
138
|
## Need help?
|
|
124
139
|
|
|
125
140
|
- **Per-model issues:** check the troubleshooting section at the bottom of each model's doc.
|
package/docs/example-config.md
CHANGED
|
@@ -14,7 +14,7 @@ Here's a complete, real-world `chatLanguageModels.json` that combines **all the
|
|
|
14
14
|
"models": [
|
|
15
15
|
{
|
|
16
16
|
"id": "qwen3.7-max",
|
|
17
|
-
"name": "Qwen 3.7 Max",
|
|
17
|
+
"name": "Qwen 3.7 Max (text)",
|
|
18
18
|
"url": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions",
|
|
19
19
|
"toolCalling": true,
|
|
20
20
|
"vision": false,
|
|
@@ -25,7 +25,7 @@ Here's a complete, real-world `chatLanguageModels.json` that combines **all the
|
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"id": "qwen3.7-plus",
|
|
28
|
-
"name": "Qwen 3.7 Plus",
|
|
28
|
+
"name": "Qwen 3.7 Plus (vision)",
|
|
29
29
|
"url": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions",
|
|
30
30
|
"toolCalling": true,
|
|
31
31
|
"vision": true,
|
|
@@ -44,7 +44,7 @@ Here's a complete, real-world `chatLanguageModels.json` that combines **all the
|
|
|
44
44
|
"models": [
|
|
45
45
|
{
|
|
46
46
|
"id": "kimi-k2.6",
|
|
47
|
-
"name": "Kimi K2.6",
|
|
47
|
+
"name": "Kimi K2.6 (vision)",
|
|
48
48
|
"url": "http://127.0.0.1:3457/v1/chat/completions",
|
|
49
49
|
"requestBody": {
|
|
50
50
|
"temperature": 1
|
|
@@ -65,7 +65,7 @@ Here's a complete, real-world `chatLanguageModels.json` that combines **all the
|
|
|
65
65
|
"models": [
|
|
66
66
|
{
|
|
67
67
|
"id": "mimo-v2.5-pro",
|
|
68
|
-
"name": "MiMo V2.5 Pro",
|
|
68
|
+
"name": "MiMo V2.5 Pro (text)",
|
|
69
69
|
"url": "https://api.xiaomimimo.com/v1/chat/completions",
|
|
70
70
|
"toolCalling": true,
|
|
71
71
|
"vision": false,
|
|
@@ -80,7 +80,7 @@ Here's a complete, real-world `chatLanguageModels.json` that combines **all the
|
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
82
|
"id": "mimo-v2.5",
|
|
83
|
-
"name": "MiMo V2.5",
|
|
83
|
+
"name": "MiMo V2.5 (vision)",
|
|
84
84
|
"url": "https://api.xiaomimimo.com/v1/chat/completions",
|
|
85
85
|
"toolCalling": true,
|
|
86
86
|
"vision": true,
|
|
@@ -95,7 +95,7 @@ Here's a complete, real-world `chatLanguageModels.json` that combines **all the
|
|
|
95
95
|
},
|
|
96
96
|
{
|
|
97
97
|
"id": "mimo-v2-flash",
|
|
98
|
-
"name": "MiMo V2 Flash",
|
|
98
|
+
"name": "MiMo V2 Flash (text)",
|
|
99
99
|
"url": "https://api.xiaomimimo.com/v1/chat/completions",
|
|
100
100
|
"toolCalling": true,
|
|
101
101
|
"vision": false,
|
|
@@ -118,7 +118,7 @@ Here's a complete, real-world `chatLanguageModels.json` that combines **all the
|
|
|
118
118
|
"models": [
|
|
119
119
|
{
|
|
120
120
|
"id": "MiniMax-M3",
|
|
121
|
-
"name": "MiniMax M3",
|
|
121
|
+
"name": "MiniMax M3 (vision)",
|
|
122
122
|
"url": "https://api.minimax.io/v1/chat/completions",
|
|
123
123
|
"toolCalling": true,
|
|
124
124
|
"vision": true,
|
|
@@ -142,7 +142,7 @@ Here's a complete, real-world `chatLanguageModels.json` that combines **all the
|
|
|
142
142
|
"models": [
|
|
143
143
|
{
|
|
144
144
|
"id": "glm-5.1",
|
|
145
|
-
"name": "GLM 5.1 (
|
|
145
|
+
"name": "GLM 5.1 (text)",
|
|
146
146
|
"url": "https://api.z.ai/api/paas/v4/chat/completions",
|
|
147
147
|
"toolCalling": true,
|
|
148
148
|
"vision": false,
|
|
@@ -158,7 +158,7 @@ Here's a complete, real-world `chatLanguageModels.json` that combines **all the
|
|
|
158
158
|
|
|
159
159
|
{
|
|
160
160
|
"id": "glm-5v-turbo",
|
|
161
|
-
"name": "GLM 5V Turbo (vision
|
|
161
|
+
"name": "GLM 5V Turbo (vision)",
|
|
162
162
|
"url": "https://api.z.ai/api/paas/v4/chat/completions",
|
|
163
163
|
"toolCalling": true,
|
|
164
164
|
"vision": true,
|
package/docs/models/qwen.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
| Tool calling | ✅ Yes |
|
|
12
12
|
| Context | 1M |
|
|
13
13
|
| Required `requestBody` (direct) | `enable_thinking: false` |
|
|
14
|
-
| Required `requestBody` (proxy) | none — proxy injects based on
|
|
14
|
+
| Required `requestBody` (proxy) | none — proxy injects based on tool activity in the conversation |
|
|
15
15
|
| Endpoint | `https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions` |
|
|
16
16
|
| Proxy endpoint | `http://127.0.0.1:3458/v1/chat/completions` |
|
|
17
17
|
|
|
@@ -165,12 +165,16 @@ All can be set in a `.env` file at the repo root (both proxies `import 'dotenv/c
|
|
|
165
165
|
|
|
166
166
|
#### Proxy request rewriting rules
|
|
167
167
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
|
171
|
-
|
|
|
168
|
+
The proxy detects active tool use by examining the conversation state, not just the `tools` array:
|
|
169
|
+
|
|
170
|
+
| Condition | Action |
|
|
171
|
+
| ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
|
|
172
|
+
| A `"tool"`-role message exists in the conversation **or** `tool_choice` is set to a non-default value | Set `body.enable_thinking = false` |
|
|
173
|
+
| No tool-role messages and no non-default `tool_choice` (plain chat) | Delete `body.enable_thinking` (let model default to `true`) |
|
|
172
174
|
|
|
173
175
|
> **Why delete rather than set `true`?** Omitting the key lets Qwen use its built-in default (`true`). Deletion is closer to "don't interfere."
|
|
176
|
+
>
|
|
177
|
+
> **Why not check `body.tools`?** The proxy checks for tool _activity_ — tool results in the message history or an explicit `tool_choice` directive — rather than the mere presence of a tools array. This correctly handles tool-enabled conversations even when the client sends `tools` in an earlier request but omits it from subsequent turns.
|
|
174
178
|
|
|
175
179
|
### API key
|
|
176
180
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "copilot-custom-endpoint",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.12",
|
|
4
4
|
"description": "Local proxies for VS Code Copilot custom endpoints — Kimi K2 & Qwen 3.x",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -55,4 +55,4 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"dotenv": "^17.4.2"
|
|
57
57
|
}
|
|
58
|
-
}
|
|
58
|
+
}
|
package/proxy/kimi-proxy.mjs
CHANGED
|
@@ -104,7 +104,18 @@ function rewriteKimi(payload) {
|
|
|
104
104
|
const incomingTemperature = payload.temperature
|
|
105
105
|
const incomingTopP = payload.top_p
|
|
106
106
|
const incomingThinkingType = payload?.thinking?.type
|
|
107
|
-
|
|
107
|
+
|
|
108
|
+
// Determine if a tool is actually being invoked:
|
|
109
|
+
// - tool_choice is set and not "none"
|
|
110
|
+
// - OR there is a "tool" role message in the conversation
|
|
111
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : []
|
|
112
|
+
const hasToolRole = messages.some((message) => message?.role === 'tool')
|
|
113
|
+
const toolChoice = payload.tool_choice
|
|
114
|
+
const hasActiveToolCall =
|
|
115
|
+
hasToolRole ||
|
|
116
|
+
(toolChoice !== undefined && toolChoice !== 'none' && toolChoice !== null)
|
|
117
|
+
const hasTools = hasActiveToolCall
|
|
118
|
+
|
|
108
119
|
const useNonThinkingMode = disableThinkingWithTools && hasTools
|
|
109
120
|
const rewrittenTemperature = useNonThinkingMode
|
|
110
121
|
? forcedNonThinkingTemperature
|
|
@@ -133,7 +144,8 @@ function rewriteKimi(payload) {
|
|
|
133
144
|
|
|
134
145
|
const summary = summarizePayload(payload, hasTools, rewriteInfo)
|
|
135
146
|
|
|
136
|
-
const
|
|
147
|
+
const modeTag = hasTools ? '[tools]' : '[chat]'
|
|
148
|
+
const consoleMsg = `${modeTag} temperature ${String(incomingTemperature)} -> ${String(rewrittenTemperature)}, top_p ${String(incomingTopP)} -> ${String(forcedTopP)}, thinking ${String(incomingThinkingType)} -> ${String(rewrittenThinkingType)}`
|
|
137
149
|
|
|
138
150
|
// Clean up internal key before forwarding
|
|
139
151
|
delete payload.__incomingThinkingType
|
package/proxy/qwen-proxy.mjs
CHANGED
|
@@ -72,7 +72,16 @@ function summarizePayload(payload, hasTools, rewriteInfo) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
function rewriteQwen(payload) {
|
|
75
|
-
|
|
75
|
+
// Determine if a tool is actually being invoked:
|
|
76
|
+
// - tool_choice is set and not "none"
|
|
77
|
+
// - OR there is a "tool" role message in the conversation
|
|
78
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : []
|
|
79
|
+
const hasToolRole = messages.some((message) => message?.role === 'tool')
|
|
80
|
+
const toolChoice = payload.tool_choice
|
|
81
|
+
const hasActiveToolCall =
|
|
82
|
+
hasToolRole ||
|
|
83
|
+
(toolChoice !== undefined && toolChoice !== 'none' && toolChoice !== null)
|
|
84
|
+
const hasTools = hasActiveToolCall
|
|
76
85
|
const incomingEnableThinking = payload.enable_thinking
|
|
77
86
|
|
|
78
87
|
if (disableThinkingWithTools && hasTools) {
|
|
@@ -91,7 +100,8 @@ function rewriteQwen(payload) {
|
|
|
91
100
|
rewrittenEnableThinking
|
|
92
101
|
})
|
|
93
102
|
|
|
94
|
-
const
|
|
103
|
+
const modeTag = hasTools ? '[tools]' : '[chat]'
|
|
104
|
+
const consoleMsg = `${modeTag} enable_thinking=${String(incomingEnableThinking)} -> ${
|
|
95
105
|
hasTools && disableThinkingWithTools ? 'false' : '<deleted>'
|
|
96
106
|
}, model=${payload.model ?? '?'}`
|
|
97
107
|
|