Add Ant Ling provider

This commit is contained in:
Mario Zechner
2026-06-02 16:37:44 +02:00
parent 6cb23f9b5d
commit 25a4a8ed1e
16 changed files with 275 additions and 12 deletions

View File

@@ -99,6 +99,7 @@ function getApiKeyEnvVars(provider: string): readonly string[] | undefined {
}
const envMap: Record<string, string> = {
"ant-ling": "ANT_LING_API_KEY",
openai: "OPENAI_API_KEY",
"azure-openai-responses": "AZURE_OPENAI_API_KEY",
nvidia: "NVIDIA_API_KEY",

View File

@@ -1552,6 +1552,63 @@ export const MODELS = {
maxTokens: 101376,
} satisfies Model<"bedrock-converse-stream">,
},
"ant-ling": {
"Ling-2.6-1T": {
id: "Ling-2.6-1T",
name: "Ling 2.6 1T",
api: "openai-completions",
provider: "ant-ling",
baseUrl: "https://api.ant-ling.com/v1",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},
reasoning: false,
input: ["text"],
cost: {
input: 0.06,
output: 0.25,
cacheRead: 0,
cacheWrite: 0,
},
contextWindow: 262144,
maxTokens: 65536,
} satisfies Model<"openai-completions">,
"Ling-2.6-flash": {
id: "Ling-2.6-flash",
name: "Ling 2.6 Flash",
api: "openai-completions",
provider: "ant-ling",
baseUrl: "https://api.ant-ling.com/v1",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},
reasoning: false,
input: ["text"],
cost: {
input: 0.01,
output: 0.02,
cacheRead: 0,
cacheWrite: 0,
},
contextWindow: 262144,
maxTokens: 65536,
} satisfies Model<"openai-completions">,
"Ring-2.6-1T": {
id: "Ring-2.6-1T",
name: "Ring 2.6 1T",
api: "openai-completions",
provider: "ant-ling",
baseUrl: "https://api.ant-ling.com/v1",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false,"thinkingFormat":"ant-ling"},
reasoning: true,
thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh"},
input: ["text"],
cost: {
input: 0.06,
output: 0.25,
cacheRead: 0,
cacheWrite: 0,
},
contextWindow: 262144,
maxTokens: 65536,
} satisfies Model<"openai-completions">,
},
"anthropic": {
"claude-3-5-haiku-20241022": {
id: "claude-3-5-haiku-20241022",

View File

@@ -578,6 +578,11 @@ function buildParams(
} else if (model.thinkingLevelMap?.off !== null) {
openRouterParams.reasoning = { effort: model.thinkingLevelMap?.off ?? "none" };
}
} else if (compat.thinkingFormat === "ant-ling" && model.reasoning && options?.reasoningEffort) {
const effort = model.thinkingLevelMap?.[options.reasoningEffort];
if (typeof effort === "string") {
(params as typeof params & { reasoning?: { effort: string } }).reasoning = { effort };
}
} else if (compat.thinkingFormat === "together" && model.reasoning) {
const togetherParams = params as Omit<typeof params, "reasoning_effort"> & {
reasoning?: { enabled: boolean };
@@ -1079,6 +1084,7 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet
const isCloudflareWorkersAI = provider === "cloudflare-workers-ai" || baseUrl.includes("api.cloudflare.com");
const isCloudflareAiGateway = provider === "cloudflare-ai-gateway" || baseUrl.includes("gateway.ai.cloudflare.com");
const isNvidia = provider === "nvidia" || baseUrl.includes("integrate.api.nvidia.com");
const isAntLing = provider === "ant-ling" || baseUrl.includes("api.ant-ling.com");
const isNonStandard =
isNvidia ||
@@ -1094,9 +1100,11 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet
provider === "opencode" ||
baseUrl.includes("opencode.ai") ||
isCloudflareWorkersAI ||
isCloudflareAiGateway;
isCloudflareAiGateway ||
isAntLing;
const useMaxTokens = baseUrl.includes("chutes.ai") || isMoonshot || isCloudflareAiGateway || isTogether || isNvidia;
const useMaxTokens =
baseUrl.includes("chutes.ai") || isMoonshot || isCloudflareAiGateway || isTogether || isNvidia || isAntLing;
const isGrok = provider === "xai" || baseUrl.includes("api.x.ai");
const isDeepSeek = provider === "deepseek" || baseUrl.includes("deepseek.com");
@@ -1107,7 +1115,8 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet
return {
supportsStore: !isNonStandard,
supportsDeveloperRole: isOpenRouterDeveloperRoleModel || (!isNonStandard && !isOpenRouter),
supportsReasoningEffort: !isGrok && !isZai && !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia,
supportsReasoningEffort:
!isGrok && !isZai && !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia && !isAntLing,
supportsUsageInStreaming: true,
maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens",
requiresToolResultName: false,
@@ -1120,16 +1129,24 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet
? "zai"
: isTogether
? "together"
: isOpenRouter
? "openrouter"
: "openai",
: isAntLing
? "ant-ling"
: isOpenRouter
? "openrouter"
: "openai",
openRouterRouting: {},
vercelGatewayRouting: {},
zaiToolStream: false,
supportsStrictMode: !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia,
cacheControlFormat,
sendSessionAffinityHeaders: false,
supportsLongCacheRetention: !(isTogether || isCloudflareWorkersAI || isCloudflareAiGateway || isNvidia),
supportsLongCacheRetention: !(
isTogether ||
isCloudflareWorkersAI ||
isCloudflareAiGateway ||
isNvidia ||
isAntLing
),
};
}

View File

@@ -22,6 +22,7 @@ export type ImagesApi = KnownImagesApi | (string & {});
export type KnownProvider =
| "amazon-bedrock"
| "ant-ling"
| "anthropic"
| "google"
| "google-vertex"
@@ -390,7 +391,7 @@ export interface OpenAICompletionsCompat {
requiresThinkingAsText?: boolean;
/** Whether all replayed assistant messages must include an empty reasoning_content field when reasoning is enabled. Default: auto-detected from URL. */
requiresReasoningContentOnAssistantMessages?: boolean;
/** Format for reasoning/thinking parameter. "openai" uses reasoning_effort, "openrouter" uses reasoning: { effort }, "deepseek" uses thinking: { type } plus reasoning_effort when supported, "together" uses reasoning: { enabled } plus reasoning_effort when supported, "zai" uses top-level enable_thinking: boolean, "qwen" uses top-level enable_thinking: boolean, "qwen-chat-template" uses chat_template_kwargs.enable_thinking, and "string-thinking" uses top-level thinking: string. Default: "openai". */
/** Format for reasoning/thinking parameter. "openai" uses reasoning_effort, "openrouter" uses reasoning: { effort }, "deepseek" uses thinking: { type } plus reasoning_effort when supported, "together" uses reasoning: { enabled } plus reasoning_effort when supported, "zai" uses top-level enable_thinking: boolean, "qwen" uses top-level enable_thinking: boolean, "qwen-chat-template" uses chat_template_kwargs.enable_thinking, "string-thinking" uses top-level thinking: string, and "ant-ling" uses reasoning: { effort } only when the mapped effort is non-null. Default: "openai". */
thinkingFormat?:
| "openai"
| "openrouter"
@@ -399,7 +400,8 @@ export interface OpenAICompletionsCompat {
| "zai"
| "qwen"
| "qwen-chat-template"
| "string-thinking";
| "string-thinking"
| "ant-ling";
/** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */
openRouterRouting?: OpenRouterRouting;
/** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */