feat(provider): add CodeBuddy CN provider (copilot.tencent.com)
Add Tencent CodeBuddy CN (codebuddy-cn) OAuth provider with full support: OAuth login (GET poll with state query param), token refresh, 15-model catalog, /v2 inference endpoint, forced streaming, OpenAI-style reasoning, and per-model capabilities. Renamed from codebuddy to codebuddy-cn to allow a future codebuddy-ai variant. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -10,10 +10,15 @@ http.createServer = (...args) => {
|
||||
const rest = args.filter((a) => typeof a !== "function");
|
||||
if (!handler) return origCreate(...args);
|
||||
const wrapped = (req, res) => {
|
||||
const ip = req.socket && req.socket.remoteAddress ? req.socket.remoteAddress : "";
|
||||
// Forwarding headers present = request arrived via a reverse proxy; loopback
|
||||
// socket is the proxy hop, not the end-user, so it must not be trusted as local.
|
||||
const viaProxy = !!(req.headers["x-forwarded-for"] || req.headers["x-real-ip"]);
|
||||
const socketIp = req.socket && req.socket.remoteAddress ? req.socket.remoteAddress : "";
|
||||
const xff = req.headers["x-forwarded-for"];
|
||||
const xRealIp = req.headers["x-real-ip"];
|
||||
const viaProxy = !!(xff || xRealIp);
|
||||
const isLoopbackProxy = socketIp === "127.0.0.1" || socketIp === "::1" || socketIp === "::ffff:127.0.0.1";
|
||||
// Trust forwarding headers only when the TCP peer is a local reverse proxy.
|
||||
// Direct/public sockets remain keyed by the unspoofable peer address.
|
||||
const proxyIp = xRealIp || (xff ? String(xff).split(",")[0].trim() : "");
|
||||
const ip = isLoopbackProxy && proxyIp ? proxyIp : socketIp;
|
||||
delete req.headers["x-9r-real-ip"];
|
||||
delete req.headers["x-forwarded-for"];
|
||||
delete req.headers["x-9r-via-proxy"];
|
||||
|
||||
36
open-sse/executors/codebuddy-cn.js
Normal file
36
open-sse/executors/codebuddy-cn.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { DefaultExecutor } from "./default.js";
|
||||
|
||||
/**
|
||||
* CodeBuddyExecutor — talks to https://copilot.tencent.com/v2/chat/completions
|
||||
*
|
||||
* CodeBuddy is OpenAI-compatible but rejects non-stream chat requests
|
||||
* (HTTP 400, code 11101 "Non-stream chat request is currently not supported").
|
||||
* The same-format (openai→openai) translator path leaves body.stream as the
|
||||
* client sent it, so we force it true here — 9router still re-aggregates the
|
||||
* SSE into a JSON response for non-streaming clients.
|
||||
*/
|
||||
export class CodeBuddyExecutor extends DefaultExecutor {
|
||||
constructor() {
|
||||
super("codebuddy-cn");
|
||||
}
|
||||
|
||||
transformRequest(model, body, stream, credentials) {
|
||||
const transformed = super.transformRequest(model, body, stream, credentials);
|
||||
transformed.stream = true;
|
||||
|
||||
// CodeBuddy only surfaces model reasoning when the request carries the CLI's
|
||||
// OpenAI-style params: reasoning_effort + reasoning_summary:"auto". 9router's
|
||||
// thinking pipeline sets reasoning_effort only when the client asks, and never
|
||||
// sets reasoning_summary — so reasoning never shows. Mirror the CLI here.
|
||||
const eff = transformed.reasoning_effort;
|
||||
if (eff === "none" || eff === "off") {
|
||||
delete transformed.reasoning_effort; // gateway has no "none" — just omit
|
||||
} else {
|
||||
if (!eff) transformed.reasoning_effort = "medium";
|
||||
transformed.reasoning_summary = "auto";
|
||||
}
|
||||
return transformed;
|
||||
}
|
||||
}
|
||||
|
||||
export default CodeBuddyExecutor;
|
||||
@@ -17,6 +17,7 @@ import { OllamaLocalExecutor } from "./ollama-local.js";
|
||||
import { CommandCodeExecutor } from "./commandcode.js";
|
||||
import { XiaomiTokenplanExecutor } from "./xiaomi-tokenplan.js";
|
||||
import { MimoFreeExecutor } from "./mimo-free.js";
|
||||
import { CodeBuddyExecutor } from "./codebuddy-cn.js";
|
||||
import { DefaultExecutor } from "./default.js";
|
||||
|
||||
const executors = {
|
||||
@@ -42,6 +43,7 @@ const executors = {
|
||||
"xiaomi-tokenplan": new XiaomiTokenplanExecutor(),
|
||||
"mimo-free": new MimoFreeExecutor(),
|
||||
mmf: new MimoFreeExecutor(), // Alias for mimo-free
|
||||
"codebuddy-cn": new CodeBuddyExecutor(),
|
||||
};
|
||||
|
||||
const defaultCache = new Map();
|
||||
@@ -77,3 +79,4 @@ export { OllamaLocalExecutor } from "./ollama-local.js";
|
||||
export { CommandCodeExecutor } from "./commandcode.js";
|
||||
export { XiaomiTokenplanExecutor } from "./xiaomi-tokenplan.js";
|
||||
export { MimoFreeExecutor } from "./mimo-free.js";
|
||||
export { CodeBuddyExecutor } from "./codebuddy-cn.js";
|
||||
|
||||
@@ -92,7 +92,30 @@ export const MODEL_CAPABILITIES = {
|
||||
/**
|
||||
* Provider-specific capability overrides. Keyed by provider alias/id.
|
||||
*/
|
||||
export const PROVIDER_CAPABILITIES = {};
|
||||
export const PROVIDER_CAPABILITIES = {
|
||||
// CodeBuddy.cn — authoritative per-model metadata from the gateway's model
|
||||
// config (contextWindow=maxInputTokens, maxOutput=maxOutputTokens, vision=
|
||||
// supportsImages). Every model reasons via OpenAI-style reasoning_effort
|
||||
// (see registry thinkingFormat). `onlyReasoning` models can't turn thinking
|
||||
// off → thinkingCanDisable:false (clamped to minimal instead of disabled).
|
||||
"codebuddy-cn": {
|
||||
"glm-5.2": { reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 48000 },
|
||||
"glm-5.1": { reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 200000, maxOutput: 48000 },
|
||||
"glm-5.0": { reasoning: true, thinkingFormat: "openai", contextWindow: 200000, maxOutput: 48000 },
|
||||
"glm-5.0-turbo": { reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 200000, maxOutput: 48000 },
|
||||
"glm-5v-turbo": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 200000, maxOutput: 38000 },
|
||||
"glm-4.7": { reasoning: true, thinkingFormat: "openai", contextWindow: 200000, maxOutput: 48000 },
|
||||
"minimax-m3": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 512000, maxOutput: 48000 },
|
||||
"minimax-m2.7": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 200000, maxOutput: 48000 },
|
||||
"kimi-k2.7": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 256000, maxOutput: 32000 },
|
||||
"kimi-k2.6": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 256000, maxOutput: 32000 },
|
||||
"kimi-k2.5": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 164000, maxOutput: 32000 },
|
||||
"hy3-preview": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 192000, maxOutput: 64000 },
|
||||
"deepseek-v4-pro": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 50000 },
|
||||
"deepseek-v4-flash": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 50000 },
|
||||
"deepseek-v3-2-volc": { reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 96000, maxOutput: 32000 },
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Pattern fallback — glob (* = wildcard), matched case-insensitively and
|
||||
|
||||
62
open-sse/providers/registry/codebuddy-cn.js
Normal file
62
open-sse/providers/registry/codebuddy-cn.js
Normal file
@@ -0,0 +1,62 @@
|
||||
export default {
|
||||
id: "codebuddy-cn",
|
||||
hidden: false,
|
||||
priority: 90,
|
||||
display: {
|
||||
name: "CodeBuddy CN",
|
||||
icon: "smart_toy",
|
||||
color: "#006EFF",
|
||||
website: "https://copilot.tencent.com",
|
||||
notice: {
|
||||
signupUrl: "https://copilot.tencent.com",
|
||||
},
|
||||
},
|
||||
category: "oauth",
|
||||
transport: {
|
||||
baseUrl: "https://copilot.tencent.com/v2/chat/completions",
|
||||
forceStream: true,
|
||||
// CodeBuddy is a unified OpenAI-compatible gateway: every model (GLM, Kimi,
|
||||
// MiniMax, DeepSeek, Hunyuan) takes reasoning via OpenAI-style reasoning_effort,
|
||||
// not its vendor-native thinking shape. Force the openai thinking format.
|
||||
thinkingFormat: "openai",
|
||||
headers: {
|
||||
"User-Agent": "CLI/2.108.1 CodeBuddy/2.108.1",
|
||||
"X-Product": "SaaS",
|
||||
"X-IDE-Type": "CLI",
|
||||
"X-IDE-Name": "CLI",
|
||||
"x-requested-with": "XMLHttpRequest",
|
||||
"x-codebuddy-request": "1",
|
||||
},
|
||||
auth: {
|
||||
combined: true,
|
||||
header: "Authorization",
|
||||
scheme: "bearer",
|
||||
},
|
||||
},
|
||||
models: [
|
||||
{ id: "glm-5.2", name: "GLM-5.2" },
|
||||
{ id: "glm-5.1", name: "GLM-5.1" },
|
||||
{ id: "glm-5.0", name: "GLM-5.0" },
|
||||
{ id: "glm-5.0-turbo", name: "GLM-5.0-Turbo" },
|
||||
{ id: "glm-5v-turbo", name: "GLM-5v-Turbo" },
|
||||
{ id: "glm-4.7", name: "GLM-4.7" },
|
||||
{ id: "minimax-m3", name: "MiniMax-M3" },
|
||||
{ id: "minimax-m2.7", name: "MiniMax-M2.7" },
|
||||
{ id: "kimi-k2.7", name: "Kimi-K2.7-Code" },
|
||||
{ id: "kimi-k2.6", name: "Kimi-K2.6" },
|
||||
{ id: "kimi-k2.5", name: "Kimi-K2.5" },
|
||||
{ id: "hy3-preview", name: "Hy3 Preview" },
|
||||
{ id: "deepseek-v4-pro", name: "DeepSeek-V4-Pro" },
|
||||
{ id: "deepseek-v4-flash", name: "DeepSeek-V4-Flash" },
|
||||
{ id: "deepseek-v3-2-volc", name: "DeepSeek-V3.2" },
|
||||
],
|
||||
oauth: {
|
||||
baseUrl: "https://copilot.tencent.com",
|
||||
stateUrl: "https://copilot.tencent.com/v2/plugin/auth/state",
|
||||
tokenUrl: "https://copilot.tencent.com/v2/plugin/auth/token",
|
||||
refreshUrl: "https://copilot.tencent.com/v2/plugin/auth/token/refresh",
|
||||
userAgent: "CLI/2.63.2 CodeBuddy/2.63.2",
|
||||
platform: "CLI",
|
||||
pollInterval: 5000,
|
||||
},
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
export default {
|
||||
id: "codebuddy",
|
||||
hidden: true,
|
||||
priority: 90,
|
||||
display: {
|
||||
name: "CodeBuddy",
|
||||
icon: "smart_toy",
|
||||
color: "#006EFF",
|
||||
website: "https://copilot.tencent.com",
|
||||
notice: {
|
||||
signupUrl: "https://copilot.tencent.com",
|
||||
},
|
||||
},
|
||||
category: "oauth",
|
||||
transport: {
|
||||
baseUrl: "https://copilot.tencent.com/v1/chat/completions",
|
||||
auth: {
|
||||
combined: true,
|
||||
header: "Authorization",
|
||||
scheme: "bearer",
|
||||
},
|
||||
},
|
||||
oauth: {
|
||||
baseUrl: "https://copilot.tencent.com",
|
||||
stateUrl: "https://copilot.tencent.com/v2/plugin/auth/state",
|
||||
tokenUrl: "https://copilot.tencent.com/v2/plugin/auth/token",
|
||||
refreshUrl: "https://copilot.tencent.com/v2/plugin/auth/token/refresh",
|
||||
userAgent: "CLI/2.63.2 CodeBuddy/2.63.2",
|
||||
platform: "CLI",
|
||||
pollInterval: 5000,
|
||||
},
|
||||
};
|
||||
@@ -16,7 +16,7 @@ import p13 from "./chutes.js";
|
||||
import p14 from "./claude.js";
|
||||
import p15 from "./cline.js";
|
||||
import p16 from "./cloudflare-ai.js";
|
||||
import p17 from "./codebuddy.js";
|
||||
import p17 from "./codebuddy-cn.js";
|
||||
import p18 from "./codex.js";
|
||||
import p19 from "./cohere.js";
|
||||
import p20 from "./comfyui.js";
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
refreshIflowToken,
|
||||
refreshGitHubToken,
|
||||
refreshCopilotToken,
|
||||
refreshCodebuddyToken,
|
||||
classifyOAuthRefreshError,
|
||||
} from "./tokenRefresh/providers.js";
|
||||
|
||||
@@ -25,6 +26,7 @@ export {
|
||||
refreshIflowToken,
|
||||
refreshGitHubToken,
|
||||
refreshCopilotToken,
|
||||
refreshCodebuddyToken,
|
||||
classifyOAuthRefreshError,
|
||||
};
|
||||
|
||||
@@ -127,6 +129,7 @@ const REFRESH_HANDLERS = {
|
||||
github: (c, log) => refreshGitHubToken(c.refreshToken, log),
|
||||
kiro: (c, log) => refreshKiroToken(c.refreshToken, c.providerSpecificData, log),
|
||||
xai: (c, log) => refreshXaiToken(c.refreshToken, log),
|
||||
"codebuddy-cn": (c, log) => refreshCodebuddyToken(c.refreshToken, log),
|
||||
vertex: vertexRefreshHandler,
|
||||
"vertex-partner": vertexRefreshHandler
|
||||
};
|
||||
|
||||
@@ -524,3 +524,57 @@ export async function refreshCopilotToken(githubAccessToken, log) {
|
||||
}
|
||||
}, log);
|
||||
}
|
||||
|
||||
// CodeBuddy (Tencent) refresh — POST /v2/plugin/auth/token/refresh with the
|
||||
// refresh token carried in the X-Refresh-Token header (not a form body),
|
||||
// matching the official CodeBuddy CLI. Response: { code: 0, data: <token> }.
|
||||
export async function refreshCodebuddyToken(refreshToken, log) {
|
||||
if (!refreshToken) return null;
|
||||
return dedupRefresh("codebuddy-cn", refreshToken, async () => {
|
||||
const oauth = PROVIDER_OAUTH["codebuddy-cn"] || {};
|
||||
const response = await fetch(oauth.refreshUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
"User-Agent": oauth.userAgent,
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"X-Domain": "copilot.tencent.com",
|
||||
"X-Refresh-Token": refreshToken,
|
||||
"X-Auth-Refresh-Source": "plugin",
|
||||
"X-Product": "SaaS",
|
||||
},
|
||||
body: "{}",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
log?.error?.("TOKEN_REFRESH", "Failed to refresh CodeBuddy token", {
|
||||
status: response.status,
|
||||
error: errorText,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (data.code !== 0 || !data.data?.accessToken) {
|
||||
log?.error?.("TOKEN_REFRESH", "CodeBuddy token refresh returned no token", {
|
||||
code: data.code,
|
||||
msg: data.msg,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
log?.info?.("TOKEN_REFRESH", "Successfully refreshed CodeBuddy token", {
|
||||
hasNewAccessToken: !!data.data.accessToken,
|
||||
hasNewRefreshToken: !!data.data.refreshToken,
|
||||
expiresIn: data.data.expiresIn,
|
||||
});
|
||||
|
||||
return {
|
||||
accessToken: data.data.accessToken,
|
||||
refreshToken: data.data.refreshToken || refreshToken,
|
||||
expiresIn: data.data.expiresIn,
|
||||
};
|
||||
}, log);
|
||||
}
|
||||
|
||||
BIN
public/providers/codebuddy-cn.png
Normal file
BIN
public/providers/codebuddy-cn.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -151,7 +151,7 @@ export async function GET(request, { params }) {
|
||||
: undefined;
|
||||
|
||||
// Providers that don't use PKCE for device code
|
||||
const noPkceDeviceProviders = ["github", "kiro", "kimi-coding", "kilocode", "codebuddy", "qoder"];
|
||||
const noPkceDeviceProviders = ["github", "kiro", "kimi-coding", "kilocode", "codebuddy-cn", "qoder"];
|
||||
let deviceData;
|
||||
if (noPkceDeviceProviders.includes(provider)) {
|
||||
deviceData = await requestDeviceCode(provider, undefined, deviceOptions);
|
||||
@@ -271,7 +271,7 @@ export async function POST(request, { params }) {
|
||||
}
|
||||
|
||||
// Providers that don't use PKCE for device code
|
||||
const noPkceProviders = ["github", "kimi-coding", "kilocode", "codebuddy"];
|
||||
const noPkceProviders = ["github", "kimi-coding", "kilocode", "codebuddy-cn"];
|
||||
let result;
|
||||
if (noPkceProviders.includes(provider)) {
|
||||
result = await pollForToken(provider, deviceCode);
|
||||
|
||||
@@ -90,7 +90,7 @@ const OAUTH_TEST_CONFIG = {
|
||||
authHeader: "Authorization",
|
||||
authPrefix: "Bearer ",
|
||||
},
|
||||
codebuddy: { tokenExists: true },
|
||||
"codebuddy-cn": { tokenExists: true },
|
||||
};
|
||||
|
||||
async function probeClineAccessToken(accessToken) {
|
||||
|
||||
@@ -106,7 +106,7 @@ export const CLINE_CONFIG = { ...PROVIDER_OAUTH["cline"] };
|
||||
export const GITLAB_CONFIG = { ...PROVIDER_OAUTH["gitlab"] };
|
||||
|
||||
// CodeBuddy (Tencent) OAuth Configuration (Browser OAuth Polling Flow)
|
||||
export const CODEBUDDY_CONFIG = { ...PROVIDER_OAUTH["codebuddy"] };
|
||||
export const CODEBUDDY_CONFIG = { ...PROVIDER_OAUTH["codebuddy-cn"] };
|
||||
|
||||
// OAuth timeout (5 minutes)
|
||||
export const OAUTH_TIMEOUT = 300000;
|
||||
@@ -128,5 +128,5 @@ export const PROVIDERS = {
|
||||
KILOCODE: "kilocode",
|
||||
CLINE: "cline",
|
||||
GITLAB: "gitlab",
|
||||
CODEBUDDY: "codebuddy",
|
||||
CODEBUDDY: "codebuddy-cn",
|
||||
};
|
||||
|
||||
@@ -1180,7 +1180,7 @@ const PROVIDERS = {
|
||||
// 1. POST stateUrl → get { state, authUrl }
|
||||
// 2. Open authUrl in browser
|
||||
// 3. Poll tokenUrl with state until success (code 0) or timeout
|
||||
codebuddy: {
|
||||
"codebuddy-cn": {
|
||||
config: CODEBUDDY_CONFIG,
|
||||
flowType: "device_code",
|
||||
requestDeviceCode: async (config) => {
|
||||
@@ -1212,23 +1212,25 @@ const PROVIDERS = {
|
||||
};
|
||||
},
|
||||
pollToken: async (config, deviceCode) => {
|
||||
const response = await fetch(config.tokenUrl, {
|
||||
method: "POST",
|
||||
// CodeBuddy polls the token endpoint via GET with the state as a query
|
||||
// param (not POST/body) — matches the official CLI's /v2/plugin/auth/token?state=...
|
||||
const response = await fetch(`${config.tokenUrl}?state=${encodeURIComponent(deviceCode)}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
"User-Agent": config.userAgent,
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"X-Domain": "copilot.tencent.com",
|
||||
"X-No-Authorization": "true",
|
||||
"X-No-User-Id": "true",
|
||||
"X-No-Enterprise-Id": "true",
|
||||
"X-No-Department-Info": "true",
|
||||
"X-Product": "SaaS",
|
||||
},
|
||||
body: JSON.stringify({ state: deviceCode }),
|
||||
});
|
||||
if (!response.ok) return { ok: false, data: { error: "request_failed" } };
|
||||
const data = await response.json();
|
||||
// code 11217 = pending, code 0 = success
|
||||
// code 11217 = pending (RetryFetchToken), code 0 = success
|
||||
if (data.code === 0 && data.data?.accessToken) {
|
||||
return {
|
||||
ok: true,
|
||||
@@ -1236,6 +1238,7 @@ const PROVIDERS = {
|
||||
access_token: data.data.accessToken,
|
||||
refresh_token: data.data.refreshToken || "",
|
||||
token_type: data.data.tokenType || "Bearer",
|
||||
expires_in: data.data.expiresIn,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1245,7 +1248,7 @@ const PROVIDERS = {
|
||||
mapTokens: (tokens) => ({
|
||||
accessToken: tokens.access_token,
|
||||
refreshToken: tokens.refresh_token,
|
||||
expiresIn: 86400,
|
||||
expiresIn: tokens.expires_in || 86400,
|
||||
providerSpecificData: {},
|
||||
}),
|
||||
},
|
||||
|
||||
@@ -157,7 +157,7 @@ export default function OAuthModal({ isOpen, provider, providerInfo, onSuccess,
|
||||
setError(null);
|
||||
|
||||
// Device code flow providers
|
||||
const deviceCodeProviders = ["github", "qwen", "kiro", "kimi-coding", "kilocode", "codebuddy", "qoder"];
|
||||
const deviceCodeProviders = ["github", "qwen", "kiro", "kimi-coding", "kilocode", "codebuddy-cn", "qoder"];
|
||||
if (deviceCodeProviders.includes(provider)) {
|
||||
setIsDeviceCode(true);
|
||||
setStep("waiting");
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
"claude": "cc",
|
||||
"cline": "cl",
|
||||
"cloudflare-ai": "cloudflare-ai",
|
||||
"codebuddy": "codebuddy",
|
||||
"codebuddy-cn": "codebuddy-cn",
|
||||
"codex": "cx",
|
||||
"cohere": "cohere",
|
||||
"commandcode": "commandcode",
|
||||
@@ -231,4 +231,4 @@
|
||||
"xiaomi-mimo",
|
||||
"xiaomi-tokenplan"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,8 +349,8 @@
|
||||
"baseUrl": "https://gitlab.com/api/v4/chat/completions",
|
||||
"format": "openai"
|
||||
},
|
||||
"codebuddy": {
|
||||
"baseUrl": "https://copilot.tencent.com/v1/chat/completions",
|
||||
"codebuddy-cn": {
|
||||
"baseUrl": "https://copilot.tencent.com/v2/chat/completions",
|
||||
"format": "openai"
|
||||
},
|
||||
"opencode-go": {
|
||||
|
||||
@@ -287,21 +287,39 @@ exports[`GOLDEN buildHeaders (default executor providers) > cloudflare-ai → he
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > codebuddy → headers (apiKey / oauth) 1`] = `
|
||||
exports[`GOLDEN buildHeaders (default executor providers) > codebuddy-cn → headers (apiKey / oauth) 1`] = `
|
||||
{
|
||||
"apiKey": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "CLI/2.108.1 CodeBuddy/2.108.1",
|
||||
"X-IDE-Name": "CLI",
|
||||
"X-IDE-Type": "CLI",
|
||||
"X-Product": "SaaS",
|
||||
"x-codebuddy-request": "1",
|
||||
"x-requested-with": "XMLHttpRequest",
|
||||
},
|
||||
"nonStream": {
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "CLI/2.108.1 CodeBuddy/2.108.1",
|
||||
"X-IDE-Name": "CLI",
|
||||
"X-IDE-Type": "CLI",
|
||||
"X-Product": "SaaS",
|
||||
"x-codebuddy-request": "1",
|
||||
"x-requested-with": "XMLHttpRequest",
|
||||
},
|
||||
"oauth": {
|
||||
"Accept": "text/event-stream",
|
||||
"Authorization": "Bearer <TOK>",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "CLI/2.108.1 CodeBuddy/2.108.1",
|
||||
"X-IDE-Name": "CLI",
|
||||
"X-IDE-Type": "CLI",
|
||||
"X-Product": "SaaS",
|
||||
"x-codebuddy-request": "1",
|
||||
"x-requested-with": "XMLHttpRequest",
|
||||
},
|
||||
}
|
||||
`;
|
||||
@@ -1001,10 +1019,10 @@ exports[`GOLDEN buildUrl (default executor providers) > cloudflare-ai → url (s
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GOLDEN buildUrl (default executor providers) > codebuddy → url (stream + non-stream) 1`] = `
|
||||
exports[`GOLDEN buildUrl (default executor providers) > codebuddy-cn → url (stream + non-stream) 1`] = `
|
||||
{
|
||||
"nonStream": "https://copilot.tencent.com/v1/chat/completions",
|
||||
"stream": "https://copilot.tencent.com/v1/chat/completions",
|
||||
"nonStream": "https://copilot.tencent.com/v2/chat/completions",
|
||||
"stream": "https://copilot.tencent.com/v2/chat/completions",
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user