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:
Janu Yoga
2026-06-19 15:33:26 +07:00
committed by decolua
co-authored by Cursor
parent db4499d6df
commit efd20be8d8
18 changed files with 234 additions and 59 deletions
+2 -2
View File
@@ -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",
};
+10 -7
View File
@@ -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: {},
}),
},