feat: add alibaba-coding-plan provider support (#295)
This commit is contained in:
parent
6a39f7226b
commit
c3ceb077d9
5 changed files with 155 additions and 6 deletions
|
|
@ -122,6 +122,7 @@ export function getEnvApiKey(provider: any): string | undefined {
|
||||||
opencode: "OPENCODE_API_KEY",
|
opencode: "OPENCODE_API_KEY",
|
||||||
"opencode-go": "OPENCODE_API_KEY",
|
"opencode-go": "OPENCODE_API_KEY",
|
||||||
"kimi-coding": "KIMI_API_KEY",
|
"kimi-coding": "KIMI_API_KEY",
|
||||||
|
"alibaba-coding-plan": "ALIBABA_API_KEY",
|
||||||
};
|
};
|
||||||
|
|
||||||
const envVar = envMap[provider];
|
const envVar = envMap[provider];
|
||||||
|
|
|
||||||
|
|
@ -13384,4 +13384,142 @@ export const MODELS = {
|
||||||
maxTokens: 131072,
|
maxTokens: 131072,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
},
|
},
|
||||||
|
"alibaba-coding-plan": {
|
||||||
|
"qwen3.5-plus": {
|
||||||
|
id: "qwen3.5-plus",
|
||||||
|
name: "Qwen3.5 Plus",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
provider: "alibaba-coding-plan",
|
||||||
|
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic",
|
||||||
|
reasoning: true,
|
||||||
|
input: ["text", "image"],
|
||||||
|
cost: {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
},
|
||||||
|
contextWindow: 1000000,
|
||||||
|
maxTokens: 65536,
|
||||||
|
} satisfies Model<"anthropic-messages">,
|
||||||
|
"qwen3-max-2026-01-23": {
|
||||||
|
id: "qwen3-max-2026-01-23",
|
||||||
|
name: "Qwen3 Max 2026-01-23",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
provider: "alibaba-coding-plan",
|
||||||
|
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
cost: {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
},
|
||||||
|
contextWindow: 262144,
|
||||||
|
maxTokens: 32768,
|
||||||
|
} satisfies Model<"anthropic-messages">,
|
||||||
|
"qwen3-coder-next": {
|
||||||
|
id: "qwen3-coder-next",
|
||||||
|
name: "Qwen3 Coder Next",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
provider: "alibaba-coding-plan",
|
||||||
|
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
cost: {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
},
|
||||||
|
contextWindow: 262144,
|
||||||
|
maxTokens: 65536,
|
||||||
|
} satisfies Model<"anthropic-messages">,
|
||||||
|
"qwen3-coder-plus": {
|
||||||
|
id: "qwen3-coder-plus",
|
||||||
|
name: "Qwen3 Coder Plus",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
provider: "alibaba-coding-plan",
|
||||||
|
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
cost: {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
},
|
||||||
|
contextWindow: 1000000,
|
||||||
|
maxTokens: 65536,
|
||||||
|
} satisfies Model<"anthropic-messages">,
|
||||||
|
"MiniMax-M2.5": {
|
||||||
|
id: "MiniMax-M2.5",
|
||||||
|
name: "MiniMax M2.5",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
provider: "alibaba-coding-plan",
|
||||||
|
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic",
|
||||||
|
reasoning: true,
|
||||||
|
input: ["text"],
|
||||||
|
cost: {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
},
|
||||||
|
contextWindow: 196608,
|
||||||
|
maxTokens: 24576,
|
||||||
|
} satisfies Model<"anthropic-messages">,
|
||||||
|
"glm-5": {
|
||||||
|
id: "glm-5",
|
||||||
|
name: "GLM-5",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
provider: "alibaba-coding-plan",
|
||||||
|
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic",
|
||||||
|
reasoning: true,
|
||||||
|
input: ["text"],
|
||||||
|
cost: {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
},
|
||||||
|
contextWindow: 202752,
|
||||||
|
maxTokens: 16384,
|
||||||
|
} satisfies Model<"anthropic-messages">,
|
||||||
|
"glm-4.7": {
|
||||||
|
id: "glm-4.7",
|
||||||
|
name: "GLM-4.7",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
provider: "alibaba-coding-plan",
|
||||||
|
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic",
|
||||||
|
reasoning: true,
|
||||||
|
input: ["text"],
|
||||||
|
cost: {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
},
|
||||||
|
contextWindow: 202752,
|
||||||
|
maxTokens: 16384,
|
||||||
|
} satisfies Model<"anthropic-messages">,
|
||||||
|
"kimi-k2.5": {
|
||||||
|
id: "kimi-k2.5",
|
||||||
|
name: "Kimi K2.5",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
provider: "alibaba-coding-plan",
|
||||||
|
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic",
|
||||||
|
reasoning: true,
|
||||||
|
input: ["text", "image"],
|
||||||
|
cost: {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
},
|
||||||
|
contextWindow: 262144,
|
||||||
|
maxTokens: 32768,
|
||||||
|
} satisfies Model<"anthropic-messages">,
|
||||||
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
||||||
|
|
@ -452,6 +452,9 @@ export const streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOpti
|
||||||
for (const block of output.content) delete (block as any).index;
|
for (const block of output.content) delete (block as any).index;
|
||||||
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
||||||
output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
||||||
|
if (model.provider === "alibaba-coding-plan") {
|
||||||
|
output.errorMessage = `[alibaba-coding-plan] ${output.errorMessage}`;
|
||||||
|
}
|
||||||
if (error instanceof Anthropic.APIError && error.headers) {
|
if (error instanceof Anthropic.APIError && error.headers) {
|
||||||
const retryAfterMs = extractRetryAfterMs(error.headers, error.message);
|
const retryAfterMs = extractRetryAfterMs(error.headers, error.message);
|
||||||
if (retryAfterMs !== undefined) {
|
if (retryAfterMs !== undefined) {
|
||||||
|
|
@ -583,8 +586,10 @@ function createClient(
|
||||||
return { client, isOAuthToken: false };
|
return { client, isOAuthToken: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
const betaFeatures = ["fine-grained-tool-streaming-2025-05-14"];
|
// Skip beta headers for providers that don't support them (e.g., Alibaba Coding Plan)
|
||||||
if (needsInterleavedBeta) {
|
const skipBetaHeaders = model.provider === "alibaba-coding-plan";
|
||||||
|
const betaFeatures = skipBetaHeaders ? [] : ["fine-grained-tool-streaming-2025-05-14"];
|
||||||
|
if (needsInterleavedBeta && !skipBetaHeaders) {
|
||||||
betaFeatures.push("interleaved-thinking-2025-05-14");
|
betaFeatures.push("interleaved-thinking-2025-05-14");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -599,7 +604,7 @@ function createClient(
|
||||||
{
|
{
|
||||||
accept: "application/json",
|
accept: "application/json",
|
||||||
"anthropic-dangerous-direct-browser-access": "true",
|
"anthropic-dangerous-direct-browser-access": "true",
|
||||||
"anthropic-beta": `claude-code-20250219,oauth-2025-04-20,${betaFeatures.join(",")}`,
|
...(betaFeatures.length > 0 ? { "anthropic-beta": `claude-code-20250219,oauth-2025-04-20,${betaFeatures.join(",")}` } : {}),
|
||||||
"user-agent": `claude-cli/${claudeCodeVersion}`,
|
"user-agent": `claude-cli/${claudeCodeVersion}`,
|
||||||
"x-app": "cli",
|
"x-app": "cli",
|
||||||
},
|
},
|
||||||
|
|
@ -612,15 +617,18 @@ function createClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
// API key auth
|
// API key auth
|
||||||
|
// Alibaba Coding Plan uses Bearer token auth instead of x-api-key
|
||||||
|
const isAlibabaProvider = model.provider === "alibaba-coding-plan";
|
||||||
const client = new Anthropic({
|
const client = new Anthropic({
|
||||||
apiKey,
|
apiKey: isAlibabaProvider ? null : apiKey,
|
||||||
|
authToken: isAlibabaProvider ? apiKey : undefined,
|
||||||
baseURL: model.baseUrl,
|
baseURL: model.baseUrl,
|
||||||
dangerouslyAllowBrowser: true,
|
dangerouslyAllowBrowser: true,
|
||||||
defaultHeaders: mergeHeaders(
|
defaultHeaders: mergeHeaders(
|
||||||
{
|
{
|
||||||
accept: "application/json",
|
accept: "application/json",
|
||||||
"anthropic-dangerous-direct-browser-access": "true",
|
"anthropic-dangerous-direct-browser-access": "true",
|
||||||
"anthropic-beta": betaFeatures.join(","),
|
...(betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}),
|
||||||
},
|
},
|
||||||
model.headers,
|
model.headers,
|
||||||
optionsHeaders,
|
optionsHeaders,
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ export type KnownProvider =
|
||||||
| "huggingface"
|
| "huggingface"
|
||||||
| "opencode"
|
| "opencode"
|
||||||
| "opencode-go"
|
| "opencode-go"
|
||||||
| "kimi-coding";
|
| "kimi-coding"
|
||||||
|
| "alibaba-coding-plan";
|
||||||
export type Provider = KnownProvider | string;
|
export type Provider = KnownProvider | string;
|
||||||
|
|
||||||
export type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh";
|
export type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh";
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ export const defaultModelPerProvider: Record<KnownProvider, string> = {
|
||||||
opencode: "claude-opus-4-6",
|
opencode: "claude-opus-4-6",
|
||||||
"opencode-go": "kimi-k2.5",
|
"opencode-go": "kimi-k2.5",
|
||||||
"kimi-coding": "kimi-k2-thinking",
|
"kimi-coding": "kimi-k2-thinking",
|
||||||
|
"alibaba-coding-plan": "qwen3.5-plus",
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ScopedModel {
|
export interface ScopedModel {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue