mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
feat(ai,coding-agent): add DeepInfra, Nebius, Ollama Cloud, Scaleway, SiliconFlow, and StepFun providers
Adds deepinfra, nebius, ollama-cloud, scaleway, siliconflow, siliconflow-cn, stepfun, and stepfun-cn from models.dev. Hosts without verified support for OpenAI-only request features leave out store, developer messages, long cache retention, and max_completion_tokens, and send reasoning_effort only where models.dev lists effort levels. SiliconFlow toggles thinking with enable_thinking; StepFun uses DeepSeek-style reasoning.
This commit is contained in:
parent
538f1e1f6c
commit
63dfe49bfa
47 changed files with 1664 additions and 10 deletions
|
|
@ -97,6 +97,12 @@ Unified LLM API with provider collections, automatic auth resolution, token and
|
||||||
- **Xiaomi MiMo** (defaults to API billing endpoint, with separate Token Plan providers for `cn`/`ams`/`sgp` regions)
|
- **Xiaomi MiMo** (defaults to API billing endpoint, with separate Token Plan providers for `cn`/`ams`/`sgp` regions)
|
||||||
- **Alibaba Cloud Model Studio** (DashScope pay-as-you-go, with a separate China provider)
|
- **Alibaba Cloud Model Studio** (DashScope pay-as-you-go, with a separate China provider)
|
||||||
- **Z.AI API** (pay-as-you-go, with a separate China provider)
|
- **Z.AI API** (pay-as-you-go, with a separate China provider)
|
||||||
|
- **DeepInfra**
|
||||||
|
- **Nebius Token Factory**
|
||||||
|
- **Ollama Cloud**
|
||||||
|
- **Scaleway Generative APIs**
|
||||||
|
- **SiliconFlow** (with a separate China provider)
|
||||||
|
- **StepFun** (with a separate China provider)
|
||||||
- **Any OpenAI-compatible API**: Ollama, vLLM, LM Studio, etc.
|
- **Any OpenAI-compatible API**: Ollama, vLLM, LM Studio, etc.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
@ -533,6 +539,14 @@ Built-in providers resolve these env vars (Node.js; in browsers pass `apiKey` ex
|
||||||
| Xiaomi MiMo Token Plan (China) | `XIAOMI_TOKEN_PLAN_CN_API_KEY` |
|
| Xiaomi MiMo Token Plan (China) | `XIAOMI_TOKEN_PLAN_CN_API_KEY` |
|
||||||
| Xiaomi MiMo Token Plan (Amsterdam) | `XIAOMI_TOKEN_PLAN_AMS_API_KEY` |
|
| Xiaomi MiMo Token Plan (Amsterdam) | `XIAOMI_TOKEN_PLAN_AMS_API_KEY` |
|
||||||
| Xiaomi MiMo Token Plan (Singapore) | `XIAOMI_TOKEN_PLAN_SGP_API_KEY` |
|
| Xiaomi MiMo Token Plan (Singapore) | `XIAOMI_TOKEN_PLAN_SGP_API_KEY` |
|
||||||
|
| DeepInfra | `DEEPINFRA_API_KEY` |
|
||||||
|
| Nebius Token Factory | `NEBIUS_API_KEY` |
|
||||||
|
| Ollama Cloud | `OLLAMA_API_KEY` |
|
||||||
|
| Scaleway Generative APIs | `SCALEWAY_API_KEY` |
|
||||||
|
| SiliconFlow | `SILICONFLOW_API_KEY` |
|
||||||
|
| SiliconFlow (China) | `SILICONFLOW_CN_API_KEY` |
|
||||||
|
| StepFun | `STEPFUN_API_KEY` |
|
||||||
|
| StepFun (China) | `STEPFUN_CN_API_KEY` |
|
||||||
| GitHub Copilot | `COPILOT_GITHUB_TOKEN` |
|
| GitHub Copilot | `COPILOT_GITHUB_TOKEN` |
|
||||||
|
|
||||||
The Z.AI pay-as-you-go APIs (`zai-api`, `zai-api-cn`) and Alibaba Cloud Model Studio (`alibaba`, `alibaba-cn`) bill usage to the account balance, while `zai`, `zai-coding-cn`, and the Qwen Token Plan providers draw on a plan. They read separate variables, so a key set for a plan never makes the pay-as-you-go models selectable.
|
The Z.AI pay-as-you-go APIs (`zai-api`, `zai-api-cn`) and Alibaba Cloud Model Studio (`alibaba`, `alibaba-cn`) bill usage to the account balance, while `zai`, `zai-coding-cn`, and the Qwen Token Plan providers draw on a plan. They read separate variables, so a key set for a plan never makes the pay-as-you-go models selectable.
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,16 @@ const AZURE_DEEPSEEK_V4_THINKING_LEVEL_MAP = {
|
||||||
max: null,
|
max: null,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// Alibaba Cloud Model Studio (Token Plan and pay-as-you-go) serves DeepSeek V4
|
// Alibaba Cloud Model Studio (Token Plan and pay-as-you-go) and SiliconFlow
|
||||||
// through Qwen's own thinking format.
|
// serve DeepSeek V4 through the `enable_thinking` toggle (Qwen's format).
|
||||||
const QWEN_FORMAT_PROVIDERS = new Set([
|
const QWEN_FORMAT_PROVIDERS = new Set([
|
||||||
"alibaba",
|
"alibaba",
|
||||||
"alibaba-cn",
|
"alibaba-cn",
|
||||||
"qwen-token-plan",
|
"qwen-token-plan",
|
||||||
"qwen-token-plan-cn",
|
"qwen-token-plan-cn",
|
||||||
"qwen-token-plan-individual",
|
"qwen-token-plan-individual",
|
||||||
|
"siliconflow",
|
||||||
|
"siliconflow-cn",
|
||||||
]);
|
]);
|
||||||
// These hosts accept native reasoning efforts instead of DeepSeek's thinking toggle.
|
// These hosts accept native reasoning efforts instead of DeepSeek's thinking toggle.
|
||||||
const NATIVE_EFFORT_PROVIDERS = new Set(["openrouter", "opencode"]);
|
const NATIVE_EFFORT_PROVIDERS = new Set(["openrouter", "opencode"]);
|
||||||
|
|
|
||||||
21
packages/ai/catalog/openai-compatible.ts
Normal file
21
packages/ai/catalog/openai-compatible.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Defaults for OpenAI-compatible hosts whose support for OpenAI-only request
|
||||||
|
// features has not been verified. Hosts that verify a feature override these.
|
||||||
|
|
||||||
|
import type { OpenAICompletionsCompat } from "../src/types.ts";
|
||||||
|
import type { ModelsDevModel } from "./sources/models-dev.ts";
|
||||||
|
|
||||||
|
/** Leave out `store`, developer messages, long cache retention, and `max_completion_tokens`. */
|
||||||
|
export const OPENAI_COMPATIBLE_HOST_COMPAT: OpenAICompletionsCompat = {
|
||||||
|
supportsStore: false,
|
||||||
|
supportsDeveloperRole: false,
|
||||||
|
maxTokensField: "max_tokens",
|
||||||
|
supportsLongCacheRetention: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send `reasoning_effort` only where models.dev lists effort levels; other
|
||||||
|
* reasoning models keep the host's default thinking behavior.
|
||||||
|
*/
|
||||||
|
export function catalogedEffortCompat(source: ModelsDevModel): OpenAICompletionsCompat {
|
||||||
|
return source.reasoningOptions?.some((option) => option.type === "effort") ? {} : { supportsReasoningEffort: false };
|
||||||
|
}
|
||||||
14
packages/ai/catalog/providers/deepinfra.ts
Normal file
14
packages/ai/catalog/providers/deepinfra.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { defineProvider, modelsDevModels } from "../define.ts";
|
||||||
|
import { catalogedEffortCompat, OPENAI_COMPATIBLE_HOST_COMPAT } from "../openai-compatible.ts";
|
||||||
|
|
||||||
|
// DeepInfra's OpenAI-compatible endpoint rejects developer messages with a 422.
|
||||||
|
export default defineProvider({
|
||||||
|
id: "deepinfra",
|
||||||
|
models: (ctx) =>
|
||||||
|
modelsDevModels(ctx, "deepinfra", {
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl: "https://api.deepinfra.com/v1/openai",
|
||||||
|
map: (model, source) => ({ ...model, compat: catalogedEffortCompat(source) }),
|
||||||
|
}),
|
||||||
|
compat: { "openai-completions": OPENAI_COMPATIBLE_HOST_COMPAT },
|
||||||
|
});
|
||||||
|
|
@ -11,6 +11,7 @@ import baseten from "./baseten.ts";
|
||||||
import cerebras from "./cerebras.ts";
|
import cerebras from "./cerebras.ts";
|
||||||
import cloudflareAiGateway from "./cloudflare-ai-gateway.ts";
|
import cloudflareAiGateway from "./cloudflare-ai-gateway.ts";
|
||||||
import cloudflareWorkersAi from "./cloudflare-workers-ai.ts";
|
import cloudflareWorkersAi from "./cloudflare-workers-ai.ts";
|
||||||
|
import deepinfra from "./deepinfra.ts";
|
||||||
import deepseek from "./deepseek.ts";
|
import deepseek from "./deepseek.ts";
|
||||||
import fireworks from "./fireworks.ts";
|
import fireworks from "./fireworks.ts";
|
||||||
import githubCopilot from "./github-copilot.ts";
|
import githubCopilot from "./github-copilot.ts";
|
||||||
|
|
@ -25,7 +26,9 @@ import minimaxCn from "./minimax-cn.ts";
|
||||||
import mistral from "./mistral.ts";
|
import mistral from "./mistral.ts";
|
||||||
import moonshotai from "./moonshotai.ts";
|
import moonshotai from "./moonshotai.ts";
|
||||||
import moonshotaiCn from "./moonshotai-cn.ts";
|
import moonshotaiCn from "./moonshotai-cn.ts";
|
||||||
|
import nebius from "./nebius.ts";
|
||||||
import nvidia from "./nvidia.ts";
|
import nvidia from "./nvidia.ts";
|
||||||
|
import ollamaCloud from "./ollama-cloud.ts";
|
||||||
import openai from "./openai.ts";
|
import openai from "./openai.ts";
|
||||||
import openaiCodex from "./openai-codex.ts";
|
import openaiCodex from "./openai-codex.ts";
|
||||||
import opencode from "./opencode.ts";
|
import opencode from "./opencode.ts";
|
||||||
|
|
@ -35,6 +38,11 @@ import qwenTokenPlan from "./qwen-token-plan.ts";
|
||||||
import qwenTokenPlanCn from "./qwen-token-plan-cn.ts";
|
import qwenTokenPlanCn from "./qwen-token-plan-cn.ts";
|
||||||
import qwenTokenPlanIndividual from "./qwen-token-plan-individual.ts";
|
import qwenTokenPlanIndividual from "./qwen-token-plan-individual.ts";
|
||||||
import radius from "./radius.ts";
|
import radius from "./radius.ts";
|
||||||
|
import scaleway from "./scaleway.ts";
|
||||||
|
import siliconflow from "./siliconflow.ts";
|
||||||
|
import siliconflowCn from "./siliconflow-cn.ts";
|
||||||
|
import stepfun from "./stepfun.ts";
|
||||||
|
import stepfunCn from "./stepfun-cn.ts";
|
||||||
import together from "./together.ts";
|
import together from "./together.ts";
|
||||||
import typesafe from "./typesafe.ts";
|
import typesafe from "./typesafe.ts";
|
||||||
import vercelAiGateway from "./vercel-ai-gateway.ts";
|
import vercelAiGateway from "./vercel-ai-gateway.ts";
|
||||||
|
|
@ -59,6 +67,7 @@ export const PROVIDERS: readonly ProviderDefinition[] = [
|
||||||
cerebras,
|
cerebras,
|
||||||
cloudflareAiGateway,
|
cloudflareAiGateway,
|
||||||
cloudflareWorkersAi,
|
cloudflareWorkersAi,
|
||||||
|
deepinfra,
|
||||||
deepseek,
|
deepseek,
|
||||||
fireworks,
|
fireworks,
|
||||||
githubCopilot,
|
githubCopilot,
|
||||||
|
|
@ -73,7 +82,9 @@ export const PROVIDERS: readonly ProviderDefinition[] = [
|
||||||
mistral,
|
mistral,
|
||||||
moonshotaiCn,
|
moonshotaiCn,
|
||||||
moonshotai,
|
moonshotai,
|
||||||
|
nebius,
|
||||||
nvidia,
|
nvidia,
|
||||||
|
ollamaCloud,
|
||||||
openaiCodex,
|
openaiCodex,
|
||||||
openai,
|
openai,
|
||||||
opencodeGo,
|
opencodeGo,
|
||||||
|
|
@ -83,6 +94,11 @@ export const PROVIDERS: readonly ProviderDefinition[] = [
|
||||||
qwenTokenPlanIndividual,
|
qwenTokenPlanIndividual,
|
||||||
qwenTokenPlan,
|
qwenTokenPlan,
|
||||||
radius,
|
radius,
|
||||||
|
scaleway,
|
||||||
|
siliconflowCn,
|
||||||
|
siliconflow,
|
||||||
|
stepfunCn,
|
||||||
|
stepfun,
|
||||||
together,
|
together,
|
||||||
typesafe,
|
typesafe,
|
||||||
vercelAiGateway,
|
vercelAiGateway,
|
||||||
|
|
|
||||||
14
packages/ai/catalog/providers/nebius.ts
Normal file
14
packages/ai/catalog/providers/nebius.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { defineProvider, modelsDevModels } from "../define.ts";
|
||||||
|
import { catalogedEffortCompat, OPENAI_COMPATIBLE_HOST_COMPAT } from "../openai-compatible.ts";
|
||||||
|
|
||||||
|
// Nebius Token Factory.
|
||||||
|
export default defineProvider({
|
||||||
|
id: "nebius",
|
||||||
|
models: (ctx) =>
|
||||||
|
modelsDevModels(ctx, "nebius", {
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl: "https://api.tokenfactory.nebius.com/v1",
|
||||||
|
map: (model, source) => ({ ...model, compat: catalogedEffortCompat(source) }),
|
||||||
|
}),
|
||||||
|
compat: { "openai-completions": OPENAI_COMPATIBLE_HOST_COMPAT },
|
||||||
|
});
|
||||||
14
packages/ai/catalog/providers/ollama-cloud.ts
Normal file
14
packages/ai/catalog/providers/ollama-cloud.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { defineProvider, modelsDevModels } from "../define.ts";
|
||||||
|
import { catalogedEffortCompat, OPENAI_COMPATIBLE_HOST_COMPAT } from "../openai-compatible.ts";
|
||||||
|
|
||||||
|
// Ollama Cloud's OpenAI-compatible endpoint does not report usage while streaming.
|
||||||
|
export default defineProvider({
|
||||||
|
id: "ollama-cloud",
|
||||||
|
models: (ctx) =>
|
||||||
|
modelsDevModels(ctx, "ollama-cloud", {
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl: "https://ollama.com/v1",
|
||||||
|
map: (model, source) => ({ ...model, compat: catalogedEffortCompat(source) }),
|
||||||
|
}),
|
||||||
|
compat: { "openai-completions": { ...OPENAI_COMPATIBLE_HOST_COMPAT, supportsUsageInStreaming: false } },
|
||||||
|
});
|
||||||
16
packages/ai/catalog/providers/scaleway.ts
Normal file
16
packages/ai/catalog/providers/scaleway.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { defineProvider, modelsDevModels } from "../define.ts";
|
||||||
|
import { catalogedEffortCompat, OPENAI_COMPATIBLE_HOST_COMPAT } from "../openai-compatible.ts";
|
||||||
|
|
||||||
|
// Scaleway Generative APIs take `max_completion_tokens` and native `reasoning_effort`.
|
||||||
|
export default defineProvider({
|
||||||
|
id: "scaleway",
|
||||||
|
models: (ctx) =>
|
||||||
|
modelsDevModels(ctx, "scaleway", {
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl: "https://api.scaleway.ai/v1",
|
||||||
|
map: (model, source) => ({ ...model, compat: catalogedEffortCompat(source) }),
|
||||||
|
}),
|
||||||
|
compat: {
|
||||||
|
"openai-completions": { ...OPENAI_COMPATIBLE_HOST_COMPAT, maxTokensField: "max_completion_tokens" },
|
||||||
|
},
|
||||||
|
});
|
||||||
9
packages/ai/catalog/providers/siliconflow-cn.ts
Normal file
9
packages/ai/catalog/providers/siliconflow-cn.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { defineProvider } from "../define.ts";
|
||||||
|
import { OPENAI_COMPATIBLE_HOST_COMPAT } from "../openai-compatible.ts";
|
||||||
|
import { siliconflowModels } from "./siliconflow.ts";
|
||||||
|
|
||||||
|
export default defineProvider({
|
||||||
|
id: "siliconflow-cn",
|
||||||
|
models: (ctx) => siliconflowModels(ctx, "siliconflow-cn", "https://api.siliconflow.cn/v1"),
|
||||||
|
compat: { "openai-completions": OPENAI_COMPATIBLE_HOST_COMPAT },
|
||||||
|
});
|
||||||
28
packages/ai/catalog/providers/siliconflow.ts
Normal file
28
packages/ai/catalog/providers/siliconflow.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import type { Model } from "../../src/types.ts";
|
||||||
|
import { defineProvider, modelsDevModels, type ProviderContext } from "../define.ts";
|
||||||
|
import { catalogedEffortCompat, OPENAI_COMPATIBLE_HOST_COMPAT } from "../openai-compatible.ts";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SiliconFlow. Reasoning models with a thinking toggle take a top-level
|
||||||
|
* `enable_thinking` flag (Qwen's thinking format); other reasoning models keep
|
||||||
|
* the server default unless models.dev lists effort levels.
|
||||||
|
*/
|
||||||
|
export function siliconflowModels(ctx: ProviderContext, source: string, baseUrl: string) {
|
||||||
|
return modelsDevModels(ctx, source, {
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl,
|
||||||
|
map: (model, source): Model<"openai-completions"> => ({
|
||||||
|
...model,
|
||||||
|
compat: {
|
||||||
|
...catalogedEffortCompat(source),
|
||||||
|
...(source.reasoningOptions?.some((option) => option.type === "toggle") ? { thinkingFormat: "qwen" } : {}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineProvider({
|
||||||
|
id: "siliconflow",
|
||||||
|
models: (ctx) => siliconflowModels(ctx, "siliconflow", "https://api.siliconflow.com/v1"),
|
||||||
|
compat: { "openai-completions": OPENAI_COMPATIBLE_HOST_COMPAT },
|
||||||
|
});
|
||||||
8
packages/ai/catalog/providers/stepfun-cn.ts
Normal file
8
packages/ai/catalog/providers/stepfun-cn.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { defineProvider } from "../define.ts";
|
||||||
|
import { STEPFUN_COMPLETIONS_COMPAT, stepfunModels } from "./stepfun.ts";
|
||||||
|
|
||||||
|
export default defineProvider({
|
||||||
|
id: "stepfun-cn",
|
||||||
|
models: (ctx) => stepfunModels(ctx, "stepfun", "https://api.stepfun.com/v1"),
|
||||||
|
compat: { "openai-completions": STEPFUN_COMPLETIONS_COMPAT },
|
||||||
|
});
|
||||||
41
packages/ai/catalog/providers/stepfun.ts
Normal file
41
packages/ai/catalog/providers/stepfun.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import type { Model } from "../../src/types.ts";
|
||||||
|
import { defineProvider, modelsDevModels, type ProviderContext } from "../define.ts";
|
||||||
|
import { OPENAI_COMPATIBLE_HOST_COMPAT } from "../openai-compatible.ts";
|
||||||
|
import { getEffortThinkingLevelMap } from "../reasoning.ts";
|
||||||
|
|
||||||
|
// Models StepFun has taken offline. Skip them even if models.dev still lists them.
|
||||||
|
const OFFLINE_MODEL_IDS = new Set(["step-1-32k", "step-2-16k"]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StepFun's Global (stepfun.ai) and China (stepfun.com) platforms. Reasoning
|
||||||
|
* uses DeepSeek's shape: a `thinking` toggle, top-level `reasoning_effort` with
|
||||||
|
* per-model values, and `reasoning_content` that must be sent back.
|
||||||
|
*/
|
||||||
|
export function stepfunModels(ctx: ProviderContext, source: string, baseUrl: string) {
|
||||||
|
return modelsDevModels(ctx, source, {
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl,
|
||||||
|
recordReasoning: false,
|
||||||
|
include: (model) => !OFFLINE_MODEL_IDS.has(model.id),
|
||||||
|
map: (model, source): Model<"openai-completions"> => {
|
||||||
|
const thinkingLevelMap = getEffortThinkingLevelMap(source.reasoningOptions ?? []);
|
||||||
|
return {
|
||||||
|
...model,
|
||||||
|
...(thinkingLevelMap ? { thinkingLevelMap } : {}),
|
||||||
|
compat: { supportsReasoningEffort: thinkingLevelMap !== undefined },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const STEPFUN_COMPLETIONS_COMPAT = {
|
||||||
|
...OPENAI_COMPATIBLE_HOST_COMPAT,
|
||||||
|
thinkingFormat: "deepseek",
|
||||||
|
requiresReasoningContentOnAssistantMessages: true,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export default defineProvider({
|
||||||
|
id: "stepfun",
|
||||||
|
models: (ctx) => stepfunModels(ctx, "stepfun-ai", "https://api.stepfun.ai/v1"),
|
||||||
|
compat: { "openai-completions": STEPFUN_COMPLETIONS_COMPAT },
|
||||||
|
});
|
||||||
|
|
@ -120,6 +120,14 @@ function getApiKeyEnvVars(provider: string): readonly string[] | undefined {
|
||||||
"xiaomi-token-plan-cn": "XIAOMI_TOKEN_PLAN_CN_API_KEY",
|
"xiaomi-token-plan-cn": "XIAOMI_TOKEN_PLAN_CN_API_KEY",
|
||||||
"xiaomi-token-plan-ams": "XIAOMI_TOKEN_PLAN_AMS_API_KEY",
|
"xiaomi-token-plan-ams": "XIAOMI_TOKEN_PLAN_AMS_API_KEY",
|
||||||
"xiaomi-token-plan-sgp": "XIAOMI_TOKEN_PLAN_SGP_API_KEY",
|
"xiaomi-token-plan-sgp": "XIAOMI_TOKEN_PLAN_SGP_API_KEY",
|
||||||
|
deepinfra: "DEEPINFRA_API_KEY",
|
||||||
|
nebius: "NEBIUS_API_KEY",
|
||||||
|
"ollama-cloud": "OLLAMA_API_KEY",
|
||||||
|
scaleway: "SCALEWAY_API_KEY",
|
||||||
|
siliconflow: "SILICONFLOW_API_KEY",
|
||||||
|
"siliconflow-cn": "SILICONFLOW_CN_API_KEY",
|
||||||
|
stepfun: "STEPFUN_API_KEY",
|
||||||
|
"stepfun-cn": "STEPFUN_CN_API_KEY",
|
||||||
alibaba: "DASHSCOPE_API_KEY",
|
alibaba: "DASHSCOPE_API_KEY",
|
||||||
"alibaba-cn": "DASHSCOPE_CN_API_KEY",
|
"alibaba-cn": "DASHSCOPE_CN_API_KEY",
|
||||||
"zai-api": "ZAI_PAYG_API_KEY",
|
"zai-api": "ZAI_PAYG_API_KEY",
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import { BASETEN_CLASSIFIER_MODELS, BASETEN_IMAGE_MODELS, BASETEN_MODELS } from
|
||||||
import { CEREBRAS_CLASSIFIER_MODELS, CEREBRAS_IMAGE_MODELS, CEREBRAS_MODELS } from "./providers/cerebras.models.ts";
|
import { CEREBRAS_CLASSIFIER_MODELS, CEREBRAS_IMAGE_MODELS, CEREBRAS_MODELS } from "./providers/cerebras.models.ts";
|
||||||
import { CLOUDFLARE_AI_GATEWAY_CLASSIFIER_MODELS, CLOUDFLARE_AI_GATEWAY_IMAGE_MODELS, CLOUDFLARE_AI_GATEWAY_MODELS } from "./providers/cloudflare-ai-gateway.models.ts";
|
import { CLOUDFLARE_AI_GATEWAY_CLASSIFIER_MODELS, CLOUDFLARE_AI_GATEWAY_IMAGE_MODELS, CLOUDFLARE_AI_GATEWAY_MODELS } from "./providers/cloudflare-ai-gateway.models.ts";
|
||||||
import { CLOUDFLARE_WORKERS_AI_CLASSIFIER_MODELS, CLOUDFLARE_WORKERS_AI_IMAGE_MODELS, CLOUDFLARE_WORKERS_AI_MODELS } from "./providers/cloudflare-workers-ai.models.ts";
|
import { CLOUDFLARE_WORKERS_AI_CLASSIFIER_MODELS, CLOUDFLARE_WORKERS_AI_IMAGE_MODELS, CLOUDFLARE_WORKERS_AI_MODELS } from "./providers/cloudflare-workers-ai.models.ts";
|
||||||
|
import { DEEPINFRA_CLASSIFIER_MODELS, DEEPINFRA_IMAGE_MODELS, DEEPINFRA_MODELS } from "./providers/deepinfra.models.ts";
|
||||||
import { DEEPSEEK_CLASSIFIER_MODELS, DEEPSEEK_IMAGE_MODELS, DEEPSEEK_MODELS } from "./providers/deepseek.models.ts";
|
import { DEEPSEEK_CLASSIFIER_MODELS, DEEPSEEK_IMAGE_MODELS, DEEPSEEK_MODELS } from "./providers/deepseek.models.ts";
|
||||||
import { FIREWORKS_CLASSIFIER_MODELS, FIREWORKS_IMAGE_MODELS, FIREWORKS_MODELS } from "./providers/fireworks.models.ts";
|
import { FIREWORKS_CLASSIFIER_MODELS, FIREWORKS_IMAGE_MODELS, FIREWORKS_MODELS } from "./providers/fireworks.models.ts";
|
||||||
import { GITHUB_COPILOT_CLASSIFIER_MODELS, GITHUB_COPILOT_IMAGE_MODELS, GITHUB_COPILOT_MODELS } from "./providers/github-copilot.models.ts";
|
import { GITHUB_COPILOT_CLASSIFIER_MODELS, GITHUB_COPILOT_IMAGE_MODELS, GITHUB_COPILOT_MODELS } from "./providers/github-copilot.models.ts";
|
||||||
|
|
@ -25,7 +26,9 @@ import { MINIMAX_CN_CLASSIFIER_MODELS, MINIMAX_CN_IMAGE_MODELS, MINIMAX_CN_MODEL
|
||||||
import { MISTRAL_CLASSIFIER_MODELS, MISTRAL_IMAGE_MODELS, MISTRAL_MODELS } from "./providers/mistral.models.ts";
|
import { MISTRAL_CLASSIFIER_MODELS, MISTRAL_IMAGE_MODELS, MISTRAL_MODELS } from "./providers/mistral.models.ts";
|
||||||
import { MOONSHOTAI_CLASSIFIER_MODELS, MOONSHOTAI_IMAGE_MODELS, MOONSHOTAI_MODELS } from "./providers/moonshotai.models.ts";
|
import { MOONSHOTAI_CLASSIFIER_MODELS, MOONSHOTAI_IMAGE_MODELS, MOONSHOTAI_MODELS } from "./providers/moonshotai.models.ts";
|
||||||
import { MOONSHOTAI_CN_CLASSIFIER_MODELS, MOONSHOTAI_CN_IMAGE_MODELS, MOONSHOTAI_CN_MODELS } from "./providers/moonshotai-cn.models.ts";
|
import { MOONSHOTAI_CN_CLASSIFIER_MODELS, MOONSHOTAI_CN_IMAGE_MODELS, MOONSHOTAI_CN_MODELS } from "./providers/moonshotai-cn.models.ts";
|
||||||
|
import { NEBIUS_CLASSIFIER_MODELS, NEBIUS_IMAGE_MODELS, NEBIUS_MODELS } from "./providers/nebius.models.ts";
|
||||||
import { NVIDIA_CLASSIFIER_MODELS, NVIDIA_IMAGE_MODELS, NVIDIA_MODELS } from "./providers/nvidia.models.ts";
|
import { NVIDIA_CLASSIFIER_MODELS, NVIDIA_IMAGE_MODELS, NVIDIA_MODELS } from "./providers/nvidia.models.ts";
|
||||||
|
import { OLLAMA_CLOUD_CLASSIFIER_MODELS, OLLAMA_CLOUD_IMAGE_MODELS, OLLAMA_CLOUD_MODELS } from "./providers/ollama-cloud.models.ts";
|
||||||
import { OPENAI_CLASSIFIER_MODELS, OPENAI_IMAGE_MODELS, OPENAI_MODELS } from "./providers/openai.models.ts";
|
import { OPENAI_CLASSIFIER_MODELS, OPENAI_IMAGE_MODELS, OPENAI_MODELS } from "./providers/openai.models.ts";
|
||||||
import { OPENAI_CODEX_CLASSIFIER_MODELS, OPENAI_CODEX_IMAGE_MODELS, OPENAI_CODEX_MODELS } from "./providers/openai-codex.models.ts";
|
import { OPENAI_CODEX_CLASSIFIER_MODELS, OPENAI_CODEX_IMAGE_MODELS, OPENAI_CODEX_MODELS } from "./providers/openai-codex.models.ts";
|
||||||
import { OPENCODE_CLASSIFIER_MODELS, OPENCODE_IMAGE_MODELS, OPENCODE_MODELS } from "./providers/opencode.models.ts";
|
import { OPENCODE_CLASSIFIER_MODELS, OPENCODE_IMAGE_MODELS, OPENCODE_MODELS } from "./providers/opencode.models.ts";
|
||||||
|
|
@ -35,6 +38,11 @@ import { QWEN_TOKEN_PLAN_CLASSIFIER_MODELS, QWEN_TOKEN_PLAN_IMAGE_MODELS, QWEN_T
|
||||||
import { QWEN_TOKEN_PLAN_CN_CLASSIFIER_MODELS, QWEN_TOKEN_PLAN_CN_IMAGE_MODELS, QWEN_TOKEN_PLAN_CN_MODELS } from "./providers/qwen-token-plan-cn.models.ts";
|
import { QWEN_TOKEN_PLAN_CN_CLASSIFIER_MODELS, QWEN_TOKEN_PLAN_CN_IMAGE_MODELS, QWEN_TOKEN_PLAN_CN_MODELS } from "./providers/qwen-token-plan-cn.models.ts";
|
||||||
import { QWEN_TOKEN_PLAN_INDIVIDUAL_CLASSIFIER_MODELS, QWEN_TOKEN_PLAN_INDIVIDUAL_IMAGE_MODELS, QWEN_TOKEN_PLAN_INDIVIDUAL_MODELS } from "./providers/qwen-token-plan-individual.models.ts";
|
import { QWEN_TOKEN_PLAN_INDIVIDUAL_CLASSIFIER_MODELS, QWEN_TOKEN_PLAN_INDIVIDUAL_IMAGE_MODELS, QWEN_TOKEN_PLAN_INDIVIDUAL_MODELS } from "./providers/qwen-token-plan-individual.models.ts";
|
||||||
import { RADIUS_CLASSIFIER_MODELS, RADIUS_IMAGE_MODELS, RADIUS_MODELS } from "./providers/radius.models.ts";
|
import { RADIUS_CLASSIFIER_MODELS, RADIUS_IMAGE_MODELS, RADIUS_MODELS } from "./providers/radius.models.ts";
|
||||||
|
import { SCALEWAY_CLASSIFIER_MODELS, SCALEWAY_IMAGE_MODELS, SCALEWAY_MODELS } from "./providers/scaleway.models.ts";
|
||||||
|
import { SILICONFLOW_CLASSIFIER_MODELS, SILICONFLOW_IMAGE_MODELS, SILICONFLOW_MODELS } from "./providers/siliconflow.models.ts";
|
||||||
|
import { SILICONFLOW_CN_CLASSIFIER_MODELS, SILICONFLOW_CN_IMAGE_MODELS, SILICONFLOW_CN_MODELS } from "./providers/siliconflow-cn.models.ts";
|
||||||
|
import { STEPFUN_CLASSIFIER_MODELS, STEPFUN_IMAGE_MODELS, STEPFUN_MODELS } from "./providers/stepfun.models.ts";
|
||||||
|
import { STEPFUN_CN_CLASSIFIER_MODELS, STEPFUN_CN_IMAGE_MODELS, STEPFUN_CN_MODELS } from "./providers/stepfun-cn.models.ts";
|
||||||
import { TOGETHER_CLASSIFIER_MODELS, TOGETHER_IMAGE_MODELS, TOGETHER_MODELS } from "./providers/together.models.ts";
|
import { TOGETHER_CLASSIFIER_MODELS, TOGETHER_IMAGE_MODELS, TOGETHER_MODELS } from "./providers/together.models.ts";
|
||||||
import { TYPESAFE_CLASSIFIER_MODELS, TYPESAFE_IMAGE_MODELS, TYPESAFE_MODELS } from "./providers/typesafe.models.ts";
|
import { TYPESAFE_CLASSIFIER_MODELS, TYPESAFE_IMAGE_MODELS, TYPESAFE_MODELS } from "./providers/typesafe.models.ts";
|
||||||
import { VERCEL_AI_GATEWAY_CLASSIFIER_MODELS, VERCEL_AI_GATEWAY_IMAGE_MODELS, VERCEL_AI_GATEWAY_MODELS } from "./providers/vercel-ai-gateway.models.ts";
|
import { VERCEL_AI_GATEWAY_CLASSIFIER_MODELS, VERCEL_AI_GATEWAY_IMAGE_MODELS, VERCEL_AI_GATEWAY_MODELS } from "./providers/vercel-ai-gateway.models.ts";
|
||||||
|
|
@ -59,6 +67,7 @@ export const MODELS: {
|
||||||
readonly "cerebras": typeof CEREBRAS_MODELS;
|
readonly "cerebras": typeof CEREBRAS_MODELS;
|
||||||
readonly "cloudflare-ai-gateway": typeof CLOUDFLARE_AI_GATEWAY_MODELS;
|
readonly "cloudflare-ai-gateway": typeof CLOUDFLARE_AI_GATEWAY_MODELS;
|
||||||
readonly "cloudflare-workers-ai": typeof CLOUDFLARE_WORKERS_AI_MODELS;
|
readonly "cloudflare-workers-ai": typeof CLOUDFLARE_WORKERS_AI_MODELS;
|
||||||
|
readonly "deepinfra": typeof DEEPINFRA_MODELS;
|
||||||
readonly "deepseek": typeof DEEPSEEK_MODELS;
|
readonly "deepseek": typeof DEEPSEEK_MODELS;
|
||||||
readonly "fireworks": typeof FIREWORKS_MODELS;
|
readonly "fireworks": typeof FIREWORKS_MODELS;
|
||||||
readonly "github-copilot": typeof GITHUB_COPILOT_MODELS;
|
readonly "github-copilot": typeof GITHUB_COPILOT_MODELS;
|
||||||
|
|
@ -73,7 +82,9 @@ export const MODELS: {
|
||||||
readonly "mistral": typeof MISTRAL_MODELS;
|
readonly "mistral": typeof MISTRAL_MODELS;
|
||||||
readonly "moonshotai": typeof MOONSHOTAI_MODELS;
|
readonly "moonshotai": typeof MOONSHOTAI_MODELS;
|
||||||
readonly "moonshotai-cn": typeof MOONSHOTAI_CN_MODELS;
|
readonly "moonshotai-cn": typeof MOONSHOTAI_CN_MODELS;
|
||||||
|
readonly "nebius": typeof NEBIUS_MODELS;
|
||||||
readonly "nvidia": typeof NVIDIA_MODELS;
|
readonly "nvidia": typeof NVIDIA_MODELS;
|
||||||
|
readonly "ollama-cloud": typeof OLLAMA_CLOUD_MODELS;
|
||||||
readonly "openai": typeof OPENAI_MODELS;
|
readonly "openai": typeof OPENAI_MODELS;
|
||||||
readonly "openai-codex": typeof OPENAI_CODEX_MODELS;
|
readonly "openai-codex": typeof OPENAI_CODEX_MODELS;
|
||||||
readonly "opencode": typeof OPENCODE_MODELS;
|
readonly "opencode": typeof OPENCODE_MODELS;
|
||||||
|
|
@ -83,6 +94,11 @@ export const MODELS: {
|
||||||
readonly "qwen-token-plan-cn": typeof QWEN_TOKEN_PLAN_CN_MODELS;
|
readonly "qwen-token-plan-cn": typeof QWEN_TOKEN_PLAN_CN_MODELS;
|
||||||
readonly "qwen-token-plan-individual": typeof QWEN_TOKEN_PLAN_INDIVIDUAL_MODELS;
|
readonly "qwen-token-plan-individual": typeof QWEN_TOKEN_PLAN_INDIVIDUAL_MODELS;
|
||||||
readonly "radius": typeof RADIUS_MODELS;
|
readonly "radius": typeof RADIUS_MODELS;
|
||||||
|
readonly "scaleway": typeof SCALEWAY_MODELS;
|
||||||
|
readonly "siliconflow": typeof SILICONFLOW_MODELS;
|
||||||
|
readonly "siliconflow-cn": typeof SILICONFLOW_CN_MODELS;
|
||||||
|
readonly "stepfun": typeof STEPFUN_MODELS;
|
||||||
|
readonly "stepfun-cn": typeof STEPFUN_CN_MODELS;
|
||||||
readonly "together": typeof TOGETHER_MODELS;
|
readonly "together": typeof TOGETHER_MODELS;
|
||||||
readonly "typesafe": typeof TYPESAFE_MODELS;
|
readonly "typesafe": typeof TYPESAFE_MODELS;
|
||||||
readonly "vercel-ai-gateway": typeof VERCEL_AI_GATEWAY_MODELS;
|
readonly "vercel-ai-gateway": typeof VERCEL_AI_GATEWAY_MODELS;
|
||||||
|
|
@ -106,6 +122,7 @@ export const MODELS: {
|
||||||
"cerebras": CEREBRAS_MODELS,
|
"cerebras": CEREBRAS_MODELS,
|
||||||
"cloudflare-ai-gateway": CLOUDFLARE_AI_GATEWAY_MODELS,
|
"cloudflare-ai-gateway": CLOUDFLARE_AI_GATEWAY_MODELS,
|
||||||
"cloudflare-workers-ai": CLOUDFLARE_WORKERS_AI_MODELS,
|
"cloudflare-workers-ai": CLOUDFLARE_WORKERS_AI_MODELS,
|
||||||
|
"deepinfra": DEEPINFRA_MODELS,
|
||||||
"deepseek": DEEPSEEK_MODELS,
|
"deepseek": DEEPSEEK_MODELS,
|
||||||
"fireworks": FIREWORKS_MODELS,
|
"fireworks": FIREWORKS_MODELS,
|
||||||
"github-copilot": GITHUB_COPILOT_MODELS,
|
"github-copilot": GITHUB_COPILOT_MODELS,
|
||||||
|
|
@ -120,7 +137,9 @@ export const MODELS: {
|
||||||
"mistral": MISTRAL_MODELS,
|
"mistral": MISTRAL_MODELS,
|
||||||
"moonshotai": MOONSHOTAI_MODELS,
|
"moonshotai": MOONSHOTAI_MODELS,
|
||||||
"moonshotai-cn": MOONSHOTAI_CN_MODELS,
|
"moonshotai-cn": MOONSHOTAI_CN_MODELS,
|
||||||
|
"nebius": NEBIUS_MODELS,
|
||||||
"nvidia": NVIDIA_MODELS,
|
"nvidia": NVIDIA_MODELS,
|
||||||
|
"ollama-cloud": OLLAMA_CLOUD_MODELS,
|
||||||
"openai": OPENAI_MODELS,
|
"openai": OPENAI_MODELS,
|
||||||
"openai-codex": OPENAI_CODEX_MODELS,
|
"openai-codex": OPENAI_CODEX_MODELS,
|
||||||
"opencode": OPENCODE_MODELS,
|
"opencode": OPENCODE_MODELS,
|
||||||
|
|
@ -130,6 +149,11 @@ export const MODELS: {
|
||||||
"qwen-token-plan-cn": QWEN_TOKEN_PLAN_CN_MODELS,
|
"qwen-token-plan-cn": QWEN_TOKEN_PLAN_CN_MODELS,
|
||||||
"qwen-token-plan-individual": QWEN_TOKEN_PLAN_INDIVIDUAL_MODELS,
|
"qwen-token-plan-individual": QWEN_TOKEN_PLAN_INDIVIDUAL_MODELS,
|
||||||
"radius": RADIUS_MODELS,
|
"radius": RADIUS_MODELS,
|
||||||
|
"scaleway": SCALEWAY_MODELS,
|
||||||
|
"siliconflow": SILICONFLOW_MODELS,
|
||||||
|
"siliconflow-cn": SILICONFLOW_CN_MODELS,
|
||||||
|
"stepfun": STEPFUN_MODELS,
|
||||||
|
"stepfun-cn": STEPFUN_CN_MODELS,
|
||||||
"together": TOGETHER_MODELS,
|
"together": TOGETHER_MODELS,
|
||||||
"typesafe": TYPESAFE_MODELS,
|
"typesafe": TYPESAFE_MODELS,
|
||||||
"vercel-ai-gateway": VERCEL_AI_GATEWAY_MODELS,
|
"vercel-ai-gateway": VERCEL_AI_GATEWAY_MODELS,
|
||||||
|
|
@ -155,6 +179,7 @@ export const IMAGE_MODELS: {
|
||||||
readonly "cerebras": typeof CEREBRAS_IMAGE_MODELS;
|
readonly "cerebras": typeof CEREBRAS_IMAGE_MODELS;
|
||||||
readonly "cloudflare-ai-gateway": typeof CLOUDFLARE_AI_GATEWAY_IMAGE_MODELS;
|
readonly "cloudflare-ai-gateway": typeof CLOUDFLARE_AI_GATEWAY_IMAGE_MODELS;
|
||||||
readonly "cloudflare-workers-ai": typeof CLOUDFLARE_WORKERS_AI_IMAGE_MODELS;
|
readonly "cloudflare-workers-ai": typeof CLOUDFLARE_WORKERS_AI_IMAGE_MODELS;
|
||||||
|
readonly "deepinfra": typeof DEEPINFRA_IMAGE_MODELS;
|
||||||
readonly "deepseek": typeof DEEPSEEK_IMAGE_MODELS;
|
readonly "deepseek": typeof DEEPSEEK_IMAGE_MODELS;
|
||||||
readonly "fireworks": typeof FIREWORKS_IMAGE_MODELS;
|
readonly "fireworks": typeof FIREWORKS_IMAGE_MODELS;
|
||||||
readonly "github-copilot": typeof GITHUB_COPILOT_IMAGE_MODELS;
|
readonly "github-copilot": typeof GITHUB_COPILOT_IMAGE_MODELS;
|
||||||
|
|
@ -169,7 +194,9 @@ export const IMAGE_MODELS: {
|
||||||
readonly "mistral": typeof MISTRAL_IMAGE_MODELS;
|
readonly "mistral": typeof MISTRAL_IMAGE_MODELS;
|
||||||
readonly "moonshotai": typeof MOONSHOTAI_IMAGE_MODELS;
|
readonly "moonshotai": typeof MOONSHOTAI_IMAGE_MODELS;
|
||||||
readonly "moonshotai-cn": typeof MOONSHOTAI_CN_IMAGE_MODELS;
|
readonly "moonshotai-cn": typeof MOONSHOTAI_CN_IMAGE_MODELS;
|
||||||
|
readonly "nebius": typeof NEBIUS_IMAGE_MODELS;
|
||||||
readonly "nvidia": typeof NVIDIA_IMAGE_MODELS;
|
readonly "nvidia": typeof NVIDIA_IMAGE_MODELS;
|
||||||
|
readonly "ollama-cloud": typeof OLLAMA_CLOUD_IMAGE_MODELS;
|
||||||
readonly "openai": typeof OPENAI_IMAGE_MODELS;
|
readonly "openai": typeof OPENAI_IMAGE_MODELS;
|
||||||
readonly "openai-codex": typeof OPENAI_CODEX_IMAGE_MODELS;
|
readonly "openai-codex": typeof OPENAI_CODEX_IMAGE_MODELS;
|
||||||
readonly "opencode": typeof OPENCODE_IMAGE_MODELS;
|
readonly "opencode": typeof OPENCODE_IMAGE_MODELS;
|
||||||
|
|
@ -179,6 +206,11 @@ export const IMAGE_MODELS: {
|
||||||
readonly "qwen-token-plan-cn": typeof QWEN_TOKEN_PLAN_CN_IMAGE_MODELS;
|
readonly "qwen-token-plan-cn": typeof QWEN_TOKEN_PLAN_CN_IMAGE_MODELS;
|
||||||
readonly "qwen-token-plan-individual": typeof QWEN_TOKEN_PLAN_INDIVIDUAL_IMAGE_MODELS;
|
readonly "qwen-token-plan-individual": typeof QWEN_TOKEN_PLAN_INDIVIDUAL_IMAGE_MODELS;
|
||||||
readonly "radius": typeof RADIUS_IMAGE_MODELS;
|
readonly "radius": typeof RADIUS_IMAGE_MODELS;
|
||||||
|
readonly "scaleway": typeof SCALEWAY_IMAGE_MODELS;
|
||||||
|
readonly "siliconflow": typeof SILICONFLOW_IMAGE_MODELS;
|
||||||
|
readonly "siliconflow-cn": typeof SILICONFLOW_CN_IMAGE_MODELS;
|
||||||
|
readonly "stepfun": typeof STEPFUN_IMAGE_MODELS;
|
||||||
|
readonly "stepfun-cn": typeof STEPFUN_CN_IMAGE_MODELS;
|
||||||
readonly "together": typeof TOGETHER_IMAGE_MODELS;
|
readonly "together": typeof TOGETHER_IMAGE_MODELS;
|
||||||
readonly "typesafe": typeof TYPESAFE_IMAGE_MODELS;
|
readonly "typesafe": typeof TYPESAFE_IMAGE_MODELS;
|
||||||
readonly "vercel-ai-gateway": typeof VERCEL_AI_GATEWAY_IMAGE_MODELS;
|
readonly "vercel-ai-gateway": typeof VERCEL_AI_GATEWAY_IMAGE_MODELS;
|
||||||
|
|
@ -202,6 +234,7 @@ export const IMAGE_MODELS: {
|
||||||
"cerebras": CEREBRAS_IMAGE_MODELS,
|
"cerebras": CEREBRAS_IMAGE_MODELS,
|
||||||
"cloudflare-ai-gateway": CLOUDFLARE_AI_GATEWAY_IMAGE_MODELS,
|
"cloudflare-ai-gateway": CLOUDFLARE_AI_GATEWAY_IMAGE_MODELS,
|
||||||
"cloudflare-workers-ai": CLOUDFLARE_WORKERS_AI_IMAGE_MODELS,
|
"cloudflare-workers-ai": CLOUDFLARE_WORKERS_AI_IMAGE_MODELS,
|
||||||
|
"deepinfra": DEEPINFRA_IMAGE_MODELS,
|
||||||
"deepseek": DEEPSEEK_IMAGE_MODELS,
|
"deepseek": DEEPSEEK_IMAGE_MODELS,
|
||||||
"fireworks": FIREWORKS_IMAGE_MODELS,
|
"fireworks": FIREWORKS_IMAGE_MODELS,
|
||||||
"github-copilot": GITHUB_COPILOT_IMAGE_MODELS,
|
"github-copilot": GITHUB_COPILOT_IMAGE_MODELS,
|
||||||
|
|
@ -216,7 +249,9 @@ export const IMAGE_MODELS: {
|
||||||
"mistral": MISTRAL_IMAGE_MODELS,
|
"mistral": MISTRAL_IMAGE_MODELS,
|
||||||
"moonshotai": MOONSHOTAI_IMAGE_MODELS,
|
"moonshotai": MOONSHOTAI_IMAGE_MODELS,
|
||||||
"moonshotai-cn": MOONSHOTAI_CN_IMAGE_MODELS,
|
"moonshotai-cn": MOONSHOTAI_CN_IMAGE_MODELS,
|
||||||
|
"nebius": NEBIUS_IMAGE_MODELS,
|
||||||
"nvidia": NVIDIA_IMAGE_MODELS,
|
"nvidia": NVIDIA_IMAGE_MODELS,
|
||||||
|
"ollama-cloud": OLLAMA_CLOUD_IMAGE_MODELS,
|
||||||
"openai": OPENAI_IMAGE_MODELS,
|
"openai": OPENAI_IMAGE_MODELS,
|
||||||
"openai-codex": OPENAI_CODEX_IMAGE_MODELS,
|
"openai-codex": OPENAI_CODEX_IMAGE_MODELS,
|
||||||
"opencode": OPENCODE_IMAGE_MODELS,
|
"opencode": OPENCODE_IMAGE_MODELS,
|
||||||
|
|
@ -226,6 +261,11 @@ export const IMAGE_MODELS: {
|
||||||
"qwen-token-plan-cn": QWEN_TOKEN_PLAN_CN_IMAGE_MODELS,
|
"qwen-token-plan-cn": QWEN_TOKEN_PLAN_CN_IMAGE_MODELS,
|
||||||
"qwen-token-plan-individual": QWEN_TOKEN_PLAN_INDIVIDUAL_IMAGE_MODELS,
|
"qwen-token-plan-individual": QWEN_TOKEN_PLAN_INDIVIDUAL_IMAGE_MODELS,
|
||||||
"radius": RADIUS_IMAGE_MODELS,
|
"radius": RADIUS_IMAGE_MODELS,
|
||||||
|
"scaleway": SCALEWAY_IMAGE_MODELS,
|
||||||
|
"siliconflow": SILICONFLOW_IMAGE_MODELS,
|
||||||
|
"siliconflow-cn": SILICONFLOW_CN_IMAGE_MODELS,
|
||||||
|
"stepfun": STEPFUN_IMAGE_MODELS,
|
||||||
|
"stepfun-cn": STEPFUN_CN_IMAGE_MODELS,
|
||||||
"together": TOGETHER_IMAGE_MODELS,
|
"together": TOGETHER_IMAGE_MODELS,
|
||||||
"typesafe": TYPESAFE_IMAGE_MODELS,
|
"typesafe": TYPESAFE_IMAGE_MODELS,
|
||||||
"vercel-ai-gateway": VERCEL_AI_GATEWAY_IMAGE_MODELS,
|
"vercel-ai-gateway": VERCEL_AI_GATEWAY_IMAGE_MODELS,
|
||||||
|
|
@ -251,6 +291,7 @@ export const CLASSIFIER_MODELS: {
|
||||||
readonly "cerebras": typeof CEREBRAS_CLASSIFIER_MODELS;
|
readonly "cerebras": typeof CEREBRAS_CLASSIFIER_MODELS;
|
||||||
readonly "cloudflare-ai-gateway": typeof CLOUDFLARE_AI_GATEWAY_CLASSIFIER_MODELS;
|
readonly "cloudflare-ai-gateway": typeof CLOUDFLARE_AI_GATEWAY_CLASSIFIER_MODELS;
|
||||||
readonly "cloudflare-workers-ai": typeof CLOUDFLARE_WORKERS_AI_CLASSIFIER_MODELS;
|
readonly "cloudflare-workers-ai": typeof CLOUDFLARE_WORKERS_AI_CLASSIFIER_MODELS;
|
||||||
|
readonly "deepinfra": typeof DEEPINFRA_CLASSIFIER_MODELS;
|
||||||
readonly "deepseek": typeof DEEPSEEK_CLASSIFIER_MODELS;
|
readonly "deepseek": typeof DEEPSEEK_CLASSIFIER_MODELS;
|
||||||
readonly "fireworks": typeof FIREWORKS_CLASSIFIER_MODELS;
|
readonly "fireworks": typeof FIREWORKS_CLASSIFIER_MODELS;
|
||||||
readonly "github-copilot": typeof GITHUB_COPILOT_CLASSIFIER_MODELS;
|
readonly "github-copilot": typeof GITHUB_COPILOT_CLASSIFIER_MODELS;
|
||||||
|
|
@ -265,7 +306,9 @@ export const CLASSIFIER_MODELS: {
|
||||||
readonly "mistral": typeof MISTRAL_CLASSIFIER_MODELS;
|
readonly "mistral": typeof MISTRAL_CLASSIFIER_MODELS;
|
||||||
readonly "moonshotai": typeof MOONSHOTAI_CLASSIFIER_MODELS;
|
readonly "moonshotai": typeof MOONSHOTAI_CLASSIFIER_MODELS;
|
||||||
readonly "moonshotai-cn": typeof MOONSHOTAI_CN_CLASSIFIER_MODELS;
|
readonly "moonshotai-cn": typeof MOONSHOTAI_CN_CLASSIFIER_MODELS;
|
||||||
|
readonly "nebius": typeof NEBIUS_CLASSIFIER_MODELS;
|
||||||
readonly "nvidia": typeof NVIDIA_CLASSIFIER_MODELS;
|
readonly "nvidia": typeof NVIDIA_CLASSIFIER_MODELS;
|
||||||
|
readonly "ollama-cloud": typeof OLLAMA_CLOUD_CLASSIFIER_MODELS;
|
||||||
readonly "openai": typeof OPENAI_CLASSIFIER_MODELS;
|
readonly "openai": typeof OPENAI_CLASSIFIER_MODELS;
|
||||||
readonly "openai-codex": typeof OPENAI_CODEX_CLASSIFIER_MODELS;
|
readonly "openai-codex": typeof OPENAI_CODEX_CLASSIFIER_MODELS;
|
||||||
readonly "opencode": typeof OPENCODE_CLASSIFIER_MODELS;
|
readonly "opencode": typeof OPENCODE_CLASSIFIER_MODELS;
|
||||||
|
|
@ -275,6 +318,11 @@ export const CLASSIFIER_MODELS: {
|
||||||
readonly "qwen-token-plan-cn": typeof QWEN_TOKEN_PLAN_CN_CLASSIFIER_MODELS;
|
readonly "qwen-token-plan-cn": typeof QWEN_TOKEN_PLAN_CN_CLASSIFIER_MODELS;
|
||||||
readonly "qwen-token-plan-individual": typeof QWEN_TOKEN_PLAN_INDIVIDUAL_CLASSIFIER_MODELS;
|
readonly "qwen-token-plan-individual": typeof QWEN_TOKEN_PLAN_INDIVIDUAL_CLASSIFIER_MODELS;
|
||||||
readonly "radius": typeof RADIUS_CLASSIFIER_MODELS;
|
readonly "radius": typeof RADIUS_CLASSIFIER_MODELS;
|
||||||
|
readonly "scaleway": typeof SCALEWAY_CLASSIFIER_MODELS;
|
||||||
|
readonly "siliconflow": typeof SILICONFLOW_CLASSIFIER_MODELS;
|
||||||
|
readonly "siliconflow-cn": typeof SILICONFLOW_CN_CLASSIFIER_MODELS;
|
||||||
|
readonly "stepfun": typeof STEPFUN_CLASSIFIER_MODELS;
|
||||||
|
readonly "stepfun-cn": typeof STEPFUN_CN_CLASSIFIER_MODELS;
|
||||||
readonly "together": typeof TOGETHER_CLASSIFIER_MODELS;
|
readonly "together": typeof TOGETHER_CLASSIFIER_MODELS;
|
||||||
readonly "typesafe": typeof TYPESAFE_CLASSIFIER_MODELS;
|
readonly "typesafe": typeof TYPESAFE_CLASSIFIER_MODELS;
|
||||||
readonly "vercel-ai-gateway": typeof VERCEL_AI_GATEWAY_CLASSIFIER_MODELS;
|
readonly "vercel-ai-gateway": typeof VERCEL_AI_GATEWAY_CLASSIFIER_MODELS;
|
||||||
|
|
@ -298,6 +346,7 @@ export const CLASSIFIER_MODELS: {
|
||||||
"cerebras": CEREBRAS_CLASSIFIER_MODELS,
|
"cerebras": CEREBRAS_CLASSIFIER_MODELS,
|
||||||
"cloudflare-ai-gateway": CLOUDFLARE_AI_GATEWAY_CLASSIFIER_MODELS,
|
"cloudflare-ai-gateway": CLOUDFLARE_AI_GATEWAY_CLASSIFIER_MODELS,
|
||||||
"cloudflare-workers-ai": CLOUDFLARE_WORKERS_AI_CLASSIFIER_MODELS,
|
"cloudflare-workers-ai": CLOUDFLARE_WORKERS_AI_CLASSIFIER_MODELS,
|
||||||
|
"deepinfra": DEEPINFRA_CLASSIFIER_MODELS,
|
||||||
"deepseek": DEEPSEEK_CLASSIFIER_MODELS,
|
"deepseek": DEEPSEEK_CLASSIFIER_MODELS,
|
||||||
"fireworks": FIREWORKS_CLASSIFIER_MODELS,
|
"fireworks": FIREWORKS_CLASSIFIER_MODELS,
|
||||||
"github-copilot": GITHUB_COPILOT_CLASSIFIER_MODELS,
|
"github-copilot": GITHUB_COPILOT_CLASSIFIER_MODELS,
|
||||||
|
|
@ -312,7 +361,9 @@ export const CLASSIFIER_MODELS: {
|
||||||
"mistral": MISTRAL_CLASSIFIER_MODELS,
|
"mistral": MISTRAL_CLASSIFIER_MODELS,
|
||||||
"moonshotai": MOONSHOTAI_CLASSIFIER_MODELS,
|
"moonshotai": MOONSHOTAI_CLASSIFIER_MODELS,
|
||||||
"moonshotai-cn": MOONSHOTAI_CN_CLASSIFIER_MODELS,
|
"moonshotai-cn": MOONSHOTAI_CN_CLASSIFIER_MODELS,
|
||||||
|
"nebius": NEBIUS_CLASSIFIER_MODELS,
|
||||||
"nvidia": NVIDIA_CLASSIFIER_MODELS,
|
"nvidia": NVIDIA_CLASSIFIER_MODELS,
|
||||||
|
"ollama-cloud": OLLAMA_CLOUD_CLASSIFIER_MODELS,
|
||||||
"openai": OPENAI_CLASSIFIER_MODELS,
|
"openai": OPENAI_CLASSIFIER_MODELS,
|
||||||
"openai-codex": OPENAI_CODEX_CLASSIFIER_MODELS,
|
"openai-codex": OPENAI_CODEX_CLASSIFIER_MODELS,
|
||||||
"opencode": OPENCODE_CLASSIFIER_MODELS,
|
"opencode": OPENCODE_CLASSIFIER_MODELS,
|
||||||
|
|
@ -322,6 +373,11 @@ export const CLASSIFIER_MODELS: {
|
||||||
"qwen-token-plan-cn": QWEN_TOKEN_PLAN_CN_CLASSIFIER_MODELS,
|
"qwen-token-plan-cn": QWEN_TOKEN_PLAN_CN_CLASSIFIER_MODELS,
|
||||||
"qwen-token-plan-individual": QWEN_TOKEN_PLAN_INDIVIDUAL_CLASSIFIER_MODELS,
|
"qwen-token-plan-individual": QWEN_TOKEN_PLAN_INDIVIDUAL_CLASSIFIER_MODELS,
|
||||||
"radius": RADIUS_CLASSIFIER_MODELS,
|
"radius": RADIUS_CLASSIFIER_MODELS,
|
||||||
|
"scaleway": SCALEWAY_CLASSIFIER_MODELS,
|
||||||
|
"siliconflow": SILICONFLOW_CLASSIFIER_MODELS,
|
||||||
|
"siliconflow-cn": SILICONFLOW_CN_CLASSIFIER_MODELS,
|
||||||
|
"stepfun": STEPFUN_CLASSIFIER_MODELS,
|
||||||
|
"stepfun-cn": STEPFUN_CN_CLASSIFIER_MODELS,
|
||||||
"together": TOGETHER_CLASSIFIER_MODELS,
|
"together": TOGETHER_CLASSIFIER_MODELS,
|
||||||
"typesafe": TYPESAFE_CLASSIFIER_MODELS,
|
"typesafe": TYPESAFE_CLASSIFIER_MODELS,
|
||||||
"vercel-ai-gateway": VERCEL_AI_GATEWAY_CLASSIFIER_MODELS,
|
"vercel-ai-gateway": VERCEL_AI_GATEWAY_CLASSIFIER_MODELS,
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import { cerebrasProvider } from "./cerebras.ts";
|
||||||
import { cloudflareAIGatewayProvider } from "./cloudflare-ai-gateway.ts";
|
import { cloudflareAIGatewayProvider } from "./cloudflare-ai-gateway.ts";
|
||||||
import { cloudflareWorkersAIProvider } from "./cloudflare-workers-ai.ts";
|
import { cloudflareWorkersAIProvider } from "./cloudflare-workers-ai.ts";
|
||||||
import modelDataManifest from "./data/.manifest.json" with { type: "json" };
|
import modelDataManifest from "./data/.manifest.json" with { type: "json" };
|
||||||
|
import { deepinfraProvider } from "./deepinfra.ts";
|
||||||
import { deepseekProvider } from "./deepseek.ts";
|
import { deepseekProvider } from "./deepseek.ts";
|
||||||
import { fireworksProvider } from "./fireworks.ts";
|
import { fireworksProvider } from "./fireworks.ts";
|
||||||
import { githubCopilotProvider } from "./github-copilot.ts";
|
import { githubCopilotProvider } from "./github-copilot.ts";
|
||||||
|
|
@ -26,7 +27,9 @@ import { minimaxCnProvider } from "./minimax-cn.ts";
|
||||||
import { mistralProvider } from "./mistral.ts";
|
import { mistralProvider } from "./mistral.ts";
|
||||||
import { moonshotaiProvider } from "./moonshotai.ts";
|
import { moonshotaiProvider } from "./moonshotai.ts";
|
||||||
import { moonshotaiCnProvider } from "./moonshotai-cn.ts";
|
import { moonshotaiCnProvider } from "./moonshotai-cn.ts";
|
||||||
|
import { nebiusProvider } from "./nebius.ts";
|
||||||
import { nvidiaProvider } from "./nvidia.ts";
|
import { nvidiaProvider } from "./nvidia.ts";
|
||||||
|
import { ollamaCloudProvider } from "./ollama-cloud.ts";
|
||||||
import { openaiProvider } from "./openai.ts";
|
import { openaiProvider } from "./openai.ts";
|
||||||
import { openaiCodexProvider } from "./openai-codex.ts";
|
import { openaiCodexProvider } from "./openai-codex.ts";
|
||||||
import { opencodeProvider } from "./opencode.ts";
|
import { opencodeProvider } from "./opencode.ts";
|
||||||
|
|
@ -36,6 +39,11 @@ import { qwenTokenPlanProvider } from "./qwen-token-plan.ts";
|
||||||
import { qwenTokenPlanCnProvider } from "./qwen-token-plan-cn.ts";
|
import { qwenTokenPlanCnProvider } from "./qwen-token-plan-cn.ts";
|
||||||
import { qwenTokenPlanIndividualProvider } from "./qwen-token-plan-individual.ts";
|
import { qwenTokenPlanIndividualProvider } from "./qwen-token-plan-individual.ts";
|
||||||
import { radiusProvider } from "./radius.ts";
|
import { radiusProvider } from "./radius.ts";
|
||||||
|
import { scalewayProvider } from "./scaleway.ts";
|
||||||
|
import { siliconflowProvider } from "./siliconflow.ts";
|
||||||
|
import { siliconflowCnProvider } from "./siliconflow-cn.ts";
|
||||||
|
import { stepfunProvider } from "./stepfun.ts";
|
||||||
|
import { stepfunCnProvider } from "./stepfun-cn.ts";
|
||||||
import { togetherProvider } from "./together.ts";
|
import { togetherProvider } from "./together.ts";
|
||||||
import { typesafeProvider } from "./typesafe.ts";
|
import { typesafeProvider } from "./typesafe.ts";
|
||||||
import { vercelAIGatewayProvider } from "./vercel-ai-gateway.ts";
|
import { vercelAIGatewayProvider } from "./vercel-ai-gateway.ts";
|
||||||
|
|
@ -149,6 +157,7 @@ export function builtinProviders(): Provider[] {
|
||||||
cerebrasProvider(),
|
cerebrasProvider(),
|
||||||
cloudflareAIGatewayProvider(),
|
cloudflareAIGatewayProvider(),
|
||||||
cloudflareWorkersAIProvider(),
|
cloudflareWorkersAIProvider(),
|
||||||
|
deepinfraProvider(),
|
||||||
deepseekProvider(),
|
deepseekProvider(),
|
||||||
fireworksProvider(),
|
fireworksProvider(),
|
||||||
githubCopilotProvider(),
|
githubCopilotProvider(),
|
||||||
|
|
@ -163,7 +172,9 @@ export function builtinProviders(): Provider[] {
|
||||||
mistralProvider(),
|
mistralProvider(),
|
||||||
moonshotaiProvider(),
|
moonshotaiProvider(),
|
||||||
moonshotaiCnProvider(),
|
moonshotaiCnProvider(),
|
||||||
|
nebiusProvider(),
|
||||||
nvidiaProvider(),
|
nvidiaProvider(),
|
||||||
|
ollamaCloudProvider(),
|
||||||
openaiProvider(),
|
openaiProvider(),
|
||||||
openaiCodexProvider(),
|
openaiCodexProvider(),
|
||||||
opencodeProvider(),
|
opencodeProvider(),
|
||||||
|
|
@ -173,6 +184,11 @@ export function builtinProviders(): Provider[] {
|
||||||
qwenTokenPlanCnProvider(),
|
qwenTokenPlanCnProvider(),
|
||||||
qwenTokenPlanIndividualProvider(),
|
qwenTokenPlanIndividualProvider(),
|
||||||
radiusProvider(),
|
radiusProvider(),
|
||||||
|
scalewayProvider(),
|
||||||
|
siliconflowProvider(),
|
||||||
|
siliconflowCnProvider(),
|
||||||
|
stepfunProvider(),
|
||||||
|
stepfunCnProvider(),
|
||||||
togetherProvider(),
|
togetherProvider(),
|
||||||
typesafeProvider(),
|
typesafeProvider(),
|
||||||
vercelAIGatewayProvider(),
|
vercelAIGatewayProvider(),
|
||||||
|
|
|
||||||
14
packages/ai/src/providers/deepinfra.models.ts
Normal file
14
packages/ai/src/providers/deepinfra.models.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// This file is auto-generated by catalog/generate.ts
|
||||||
|
// Do not edit manually - run 'npm run generate-models' to update
|
||||||
|
|
||||||
|
import values from "./data/deepinfra.json" with { type: "json" };
|
||||||
|
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||||
|
|
||||||
|
export const DEEPINFRA_MODELS: ChatModelCatalog<typeof values, "deepinfra"> =
|
||||||
|
flattenChatModelCatalog("deepinfra", values);
|
||||||
|
|
||||||
|
export const DEEPINFRA_IMAGE_MODELS: ImageModelCatalog<typeof values, "deepinfra"> =
|
||||||
|
flattenImageModelCatalog("deepinfra", values);
|
||||||
|
|
||||||
|
export const DEEPINFRA_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "deepinfra"> =
|
||||||
|
flattenClassifierModelCatalog("deepinfra", values);
|
||||||
15
packages/ai/src/providers/deepinfra.ts
Normal file
15
packages/ai/src/providers/deepinfra.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||||
|
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||||
|
import { createProvider, type Provider } from "../models.ts";
|
||||||
|
import { DEEPINFRA_MODELS } from "./deepinfra.models.ts";
|
||||||
|
|
||||||
|
export function deepinfraProvider(): Provider<"openai-completions"> {
|
||||||
|
return createProvider({
|
||||||
|
id: "deepinfra",
|
||||||
|
name: "DeepInfra",
|
||||||
|
baseUrl: "https://api.deepinfra.com/v1/openai",
|
||||||
|
auth: { apiKey: envApiKeyAuth("DeepInfra API key", ["DEEPINFRA_API_KEY"]) },
|
||||||
|
models: Object.values(DEEPINFRA_MODELS),
|
||||||
|
api: openAICompletionsApi(),
|
||||||
|
});
|
||||||
|
}
|
||||||
14
packages/ai/src/providers/nebius.models.ts
Normal file
14
packages/ai/src/providers/nebius.models.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// This file is auto-generated by catalog/generate.ts
|
||||||
|
// Do not edit manually - run 'npm run generate-models' to update
|
||||||
|
|
||||||
|
import values from "./data/nebius.json" with { type: "json" };
|
||||||
|
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||||
|
|
||||||
|
export const NEBIUS_MODELS: ChatModelCatalog<typeof values, "nebius"> =
|
||||||
|
flattenChatModelCatalog("nebius", values);
|
||||||
|
|
||||||
|
export const NEBIUS_IMAGE_MODELS: ImageModelCatalog<typeof values, "nebius"> =
|
||||||
|
flattenImageModelCatalog("nebius", values);
|
||||||
|
|
||||||
|
export const NEBIUS_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "nebius"> =
|
||||||
|
flattenClassifierModelCatalog("nebius", values);
|
||||||
15
packages/ai/src/providers/nebius.ts
Normal file
15
packages/ai/src/providers/nebius.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||||
|
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||||
|
import { createProvider, type Provider } from "../models.ts";
|
||||||
|
import { NEBIUS_MODELS } from "./nebius.models.ts";
|
||||||
|
|
||||||
|
export function nebiusProvider(): Provider<"openai-completions"> {
|
||||||
|
return createProvider({
|
||||||
|
id: "nebius",
|
||||||
|
name: "Nebius Token Factory",
|
||||||
|
baseUrl: "https://api.tokenfactory.nebius.com/v1",
|
||||||
|
auth: { apiKey: envApiKeyAuth("Nebius Token Factory API key", ["NEBIUS_API_KEY"]) },
|
||||||
|
models: Object.values(NEBIUS_MODELS),
|
||||||
|
api: openAICompletionsApi(),
|
||||||
|
});
|
||||||
|
}
|
||||||
14
packages/ai/src/providers/ollama-cloud.models.ts
Normal file
14
packages/ai/src/providers/ollama-cloud.models.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// This file is auto-generated by catalog/generate.ts
|
||||||
|
// Do not edit manually - run 'npm run generate-models' to update
|
||||||
|
|
||||||
|
import values from "./data/ollama-cloud.json" with { type: "json" };
|
||||||
|
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||||
|
|
||||||
|
export const OLLAMA_CLOUD_MODELS: ChatModelCatalog<typeof values, "ollama-cloud"> =
|
||||||
|
flattenChatModelCatalog("ollama-cloud", values);
|
||||||
|
|
||||||
|
export const OLLAMA_CLOUD_IMAGE_MODELS: ImageModelCatalog<typeof values, "ollama-cloud"> =
|
||||||
|
flattenImageModelCatalog("ollama-cloud", values);
|
||||||
|
|
||||||
|
export const OLLAMA_CLOUD_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "ollama-cloud"> =
|
||||||
|
flattenClassifierModelCatalog("ollama-cloud", values);
|
||||||
15
packages/ai/src/providers/ollama-cloud.ts
Normal file
15
packages/ai/src/providers/ollama-cloud.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||||
|
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||||
|
import { createProvider, type Provider } from "../models.ts";
|
||||||
|
import { OLLAMA_CLOUD_MODELS } from "./ollama-cloud.models.ts";
|
||||||
|
|
||||||
|
export function ollamaCloudProvider(): Provider<"openai-completions"> {
|
||||||
|
return createProvider({
|
||||||
|
id: "ollama-cloud",
|
||||||
|
name: "Ollama Cloud",
|
||||||
|
baseUrl: "https://ollama.com/v1",
|
||||||
|
auth: { apiKey: envApiKeyAuth("Ollama Cloud API key", ["OLLAMA_API_KEY"]) },
|
||||||
|
models: Object.values(OLLAMA_CLOUD_MODELS),
|
||||||
|
api: openAICompletionsApi(),
|
||||||
|
});
|
||||||
|
}
|
||||||
14
packages/ai/src/providers/scaleway.models.ts
Normal file
14
packages/ai/src/providers/scaleway.models.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// This file is auto-generated by catalog/generate.ts
|
||||||
|
// Do not edit manually - run 'npm run generate-models' to update
|
||||||
|
|
||||||
|
import values from "./data/scaleway.json" with { type: "json" };
|
||||||
|
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||||
|
|
||||||
|
export const SCALEWAY_MODELS: ChatModelCatalog<typeof values, "scaleway"> =
|
||||||
|
flattenChatModelCatalog("scaleway", values);
|
||||||
|
|
||||||
|
export const SCALEWAY_IMAGE_MODELS: ImageModelCatalog<typeof values, "scaleway"> =
|
||||||
|
flattenImageModelCatalog("scaleway", values);
|
||||||
|
|
||||||
|
export const SCALEWAY_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "scaleway"> =
|
||||||
|
flattenClassifierModelCatalog("scaleway", values);
|
||||||
15
packages/ai/src/providers/scaleway.ts
Normal file
15
packages/ai/src/providers/scaleway.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||||
|
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||||
|
import { createProvider, type Provider } from "../models.ts";
|
||||||
|
import { SCALEWAY_MODELS } from "./scaleway.models.ts";
|
||||||
|
|
||||||
|
export function scalewayProvider(): Provider<"openai-completions"> {
|
||||||
|
return createProvider({
|
||||||
|
id: "scaleway",
|
||||||
|
name: "Scaleway",
|
||||||
|
baseUrl: "https://api.scaleway.ai/v1",
|
||||||
|
auth: { apiKey: envApiKeyAuth("Scaleway API key", ["SCALEWAY_API_KEY"]) },
|
||||||
|
models: Object.values(SCALEWAY_MODELS),
|
||||||
|
api: openAICompletionsApi(),
|
||||||
|
});
|
||||||
|
}
|
||||||
14
packages/ai/src/providers/siliconflow-cn.models.ts
Normal file
14
packages/ai/src/providers/siliconflow-cn.models.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// This file is auto-generated by catalog/generate.ts
|
||||||
|
// Do not edit manually - run 'npm run generate-models' to update
|
||||||
|
|
||||||
|
import values from "./data/siliconflow-cn.json" with { type: "json" };
|
||||||
|
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||||
|
|
||||||
|
export const SILICONFLOW_CN_MODELS: ChatModelCatalog<typeof values, "siliconflow-cn"> =
|
||||||
|
flattenChatModelCatalog("siliconflow-cn", values);
|
||||||
|
|
||||||
|
export const SILICONFLOW_CN_IMAGE_MODELS: ImageModelCatalog<typeof values, "siliconflow-cn"> =
|
||||||
|
flattenImageModelCatalog("siliconflow-cn", values);
|
||||||
|
|
||||||
|
export const SILICONFLOW_CN_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "siliconflow-cn"> =
|
||||||
|
flattenClassifierModelCatalog("siliconflow-cn", values);
|
||||||
15
packages/ai/src/providers/siliconflow-cn.ts
Normal file
15
packages/ai/src/providers/siliconflow-cn.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||||
|
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||||
|
import { createProvider, type Provider } from "../models.ts";
|
||||||
|
import { SILICONFLOW_CN_MODELS } from "./siliconflow-cn.models.ts";
|
||||||
|
|
||||||
|
export function siliconflowCnProvider(): Provider<"openai-completions"> {
|
||||||
|
return createProvider({
|
||||||
|
id: "siliconflow-cn",
|
||||||
|
name: "SiliconFlow CN",
|
||||||
|
baseUrl: "https://api.siliconflow.cn/v1",
|
||||||
|
auth: { apiKey: envApiKeyAuth("SiliconFlow CN API key", ["SILICONFLOW_CN_API_KEY"]) },
|
||||||
|
models: Object.values(SILICONFLOW_CN_MODELS),
|
||||||
|
api: openAICompletionsApi(),
|
||||||
|
});
|
||||||
|
}
|
||||||
14
packages/ai/src/providers/siliconflow.models.ts
Normal file
14
packages/ai/src/providers/siliconflow.models.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// This file is auto-generated by catalog/generate.ts
|
||||||
|
// Do not edit manually - run 'npm run generate-models' to update
|
||||||
|
|
||||||
|
import values from "./data/siliconflow.json" with { type: "json" };
|
||||||
|
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||||
|
|
||||||
|
export const SILICONFLOW_MODELS: ChatModelCatalog<typeof values, "siliconflow"> =
|
||||||
|
flattenChatModelCatalog("siliconflow", values);
|
||||||
|
|
||||||
|
export const SILICONFLOW_IMAGE_MODELS: ImageModelCatalog<typeof values, "siliconflow"> =
|
||||||
|
flattenImageModelCatalog("siliconflow", values);
|
||||||
|
|
||||||
|
export const SILICONFLOW_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "siliconflow"> =
|
||||||
|
flattenClassifierModelCatalog("siliconflow", values);
|
||||||
15
packages/ai/src/providers/siliconflow.ts
Normal file
15
packages/ai/src/providers/siliconflow.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||||
|
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||||
|
import { createProvider, type Provider } from "../models.ts";
|
||||||
|
import { SILICONFLOW_MODELS } from "./siliconflow.models.ts";
|
||||||
|
|
||||||
|
export function siliconflowProvider(): Provider<"openai-completions"> {
|
||||||
|
return createProvider({
|
||||||
|
id: "siliconflow",
|
||||||
|
name: "SiliconFlow",
|
||||||
|
baseUrl: "https://api.siliconflow.com/v1",
|
||||||
|
auth: { apiKey: envApiKeyAuth("SiliconFlow API key", ["SILICONFLOW_API_KEY"]) },
|
||||||
|
models: Object.values(SILICONFLOW_MODELS),
|
||||||
|
api: openAICompletionsApi(),
|
||||||
|
});
|
||||||
|
}
|
||||||
14
packages/ai/src/providers/stepfun-cn.models.ts
Normal file
14
packages/ai/src/providers/stepfun-cn.models.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// This file is auto-generated by catalog/generate.ts
|
||||||
|
// Do not edit manually - run 'npm run generate-models' to update
|
||||||
|
|
||||||
|
import values from "./data/stepfun-cn.json" with { type: "json" };
|
||||||
|
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||||
|
|
||||||
|
export const STEPFUN_CN_MODELS: ChatModelCatalog<typeof values, "stepfun-cn"> =
|
||||||
|
flattenChatModelCatalog("stepfun-cn", values);
|
||||||
|
|
||||||
|
export const STEPFUN_CN_IMAGE_MODELS: ImageModelCatalog<typeof values, "stepfun-cn"> =
|
||||||
|
flattenImageModelCatalog("stepfun-cn", values);
|
||||||
|
|
||||||
|
export const STEPFUN_CN_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "stepfun-cn"> =
|
||||||
|
flattenClassifierModelCatalog("stepfun-cn", values);
|
||||||
15
packages/ai/src/providers/stepfun-cn.ts
Normal file
15
packages/ai/src/providers/stepfun-cn.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||||
|
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||||
|
import { createProvider, type Provider } from "../models.ts";
|
||||||
|
import { STEPFUN_CN_MODELS } from "./stepfun-cn.models.ts";
|
||||||
|
|
||||||
|
export function stepfunCnProvider(): Provider<"openai-completions"> {
|
||||||
|
return createProvider({
|
||||||
|
id: "stepfun-cn",
|
||||||
|
name: "StepFun CN",
|
||||||
|
baseUrl: "https://api.stepfun.com/v1",
|
||||||
|
auth: { apiKey: envApiKeyAuth("StepFun CN API key", ["STEPFUN_CN_API_KEY"]) },
|
||||||
|
models: Object.values(STEPFUN_CN_MODELS),
|
||||||
|
api: openAICompletionsApi(),
|
||||||
|
});
|
||||||
|
}
|
||||||
14
packages/ai/src/providers/stepfun.models.ts
Normal file
14
packages/ai/src/providers/stepfun.models.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// This file is auto-generated by catalog/generate.ts
|
||||||
|
// Do not edit manually - run 'npm run generate-models' to update
|
||||||
|
|
||||||
|
import values from "./data/stepfun.json" with { type: "json" };
|
||||||
|
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||||
|
|
||||||
|
export const STEPFUN_MODELS: ChatModelCatalog<typeof values, "stepfun"> =
|
||||||
|
flattenChatModelCatalog("stepfun", values);
|
||||||
|
|
||||||
|
export const STEPFUN_IMAGE_MODELS: ImageModelCatalog<typeof values, "stepfun"> =
|
||||||
|
flattenImageModelCatalog("stepfun", values);
|
||||||
|
|
||||||
|
export const STEPFUN_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "stepfun"> =
|
||||||
|
flattenClassifierModelCatalog("stepfun", values);
|
||||||
15
packages/ai/src/providers/stepfun.ts
Normal file
15
packages/ai/src/providers/stepfun.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||||
|
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||||
|
import { createProvider, type Provider } from "../models.ts";
|
||||||
|
import { STEPFUN_MODELS } from "./stepfun.models.ts";
|
||||||
|
|
||||||
|
export function stepfunProvider(): Provider<"openai-completions"> {
|
||||||
|
return createProvider({
|
||||||
|
id: "stepfun",
|
||||||
|
name: "StepFun",
|
||||||
|
baseUrl: "https://api.stepfun.ai/v1",
|
||||||
|
auth: { apiKey: envApiKeyAuth("StepFun API key", ["STEPFUN_API_KEY"]) },
|
||||||
|
models: Object.values(STEPFUN_MODELS),
|
||||||
|
api: openAICompletionsApi(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -133,7 +133,15 @@ export type KnownProvider =
|
||||||
| "alibaba"
|
| "alibaba"
|
||||||
| "alibaba-cn"
|
| "alibaba-cn"
|
||||||
| "zai-api"
|
| "zai-api"
|
||||||
| "zai-api-cn";
|
| "zai-api-cn"
|
||||||
|
| "deepinfra"
|
||||||
|
| "nebius"
|
||||||
|
| "ollama-cloud"
|
||||||
|
| "scaleway"
|
||||||
|
| "siliconflow"
|
||||||
|
| "siliconflow-cn"
|
||||||
|
| "stepfun"
|
||||||
|
| "stepfun-cn";
|
||||||
export type ProviderId = KnownProvider | string;
|
export type ProviderId = KnownProvider | string;
|
||||||
|
|
||||||
export type ToolChoice = "auto" | "none";
|
export type ToolChoice = "auto" | "none";
|
||||||
|
|
|
||||||
|
|
@ -345,6 +345,102 @@ describe("AI Providers Abort Tests", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.DEEPINFRA_API_KEY)("DeepInfra Provider Abort", () => {
|
||||||
|
const llm = getModel("deepinfra", "openai/gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should abort mid-stream", { retry: 3 }, async () => {
|
||||||
|
await testAbortSignal(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle immediate abort", { retry: 3 }, async () => {
|
||||||
|
await testImmediateAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.NEBIUS_API_KEY)("Nebius Token Factory Provider Abort", () => {
|
||||||
|
const llm = getModel("nebius", "openai/gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should abort mid-stream", { retry: 3 }, async () => {
|
||||||
|
await testAbortSignal(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle immediate abort", { retry: 3 }, async () => {
|
||||||
|
await testImmediateAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.OLLAMA_API_KEY)("Ollama Cloud Provider Abort", () => {
|
||||||
|
const llm = getModel("ollama-cloud", "gpt-oss:120b");
|
||||||
|
|
||||||
|
it("should abort mid-stream", { retry: 3 }, async () => {
|
||||||
|
await testAbortSignal(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle immediate abort", { retry: 3 }, async () => {
|
||||||
|
await testImmediateAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SCALEWAY_API_KEY)("Scaleway Generative APIs Provider Abort", () => {
|
||||||
|
const llm = getModel("scaleway", "gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should abort mid-stream", { retry: 3 }, async () => {
|
||||||
|
await testAbortSignal(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle immediate abort", { retry: 3 }, async () => {
|
||||||
|
await testImmediateAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_API_KEY)("SiliconFlow Provider Abort", () => {
|
||||||
|
const llm = getModel("siliconflow", "zai-org/GLM-5.2");
|
||||||
|
|
||||||
|
it("should abort mid-stream", { retry: 3 }, async () => {
|
||||||
|
await testAbortSignal(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle immediate abort", { retry: 3 }, async () => {
|
||||||
|
await testImmediateAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_CN_API_KEY)("SiliconFlow (China) Provider Abort", () => {
|
||||||
|
const llm = getModel("siliconflow-cn", "zai-org/GLM-5.2");
|
||||||
|
|
||||||
|
it("should abort mid-stream", { retry: 3 }, async () => {
|
||||||
|
await testAbortSignal(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle immediate abort", { retry: 3 }, async () => {
|
||||||
|
await testImmediateAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_API_KEY)("StepFun Provider Abort", () => {
|
||||||
|
const llm = getModel("stepfun", "step-3.7-flash");
|
||||||
|
|
||||||
|
it("should abort mid-stream", { retry: 3 }, async () => {
|
||||||
|
await testAbortSignal(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle immediate abort", { retry: 3 }, async () => {
|
||||||
|
await testImmediateAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_CN_API_KEY)("StepFun (China) Provider Abort", () => {
|
||||||
|
const llm = getModel("stepfun-cn", "step-3.7-flash");
|
||||||
|
|
||||||
|
it("should abort mid-stream", { retry: 3 }, async () => {
|
||||||
|
await testAbortSignal(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle immediate abort", { retry: 3 }, async () => {
|
||||||
|
await testImmediateAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe.skipIf(!process.env.KIMI_API_KEY)("Kimi For Coding Provider Abort", () => {
|
describe.skipIf(!process.env.KIMI_API_KEY)("Kimi For Coding Provider Abort", () => {
|
||||||
const llm = getModel("kimi-coding", "kimi-for-coding");
|
const llm = getModel("kimi-coding", "kimi-for-coding");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -551,6 +551,102 @@ describe("Context overflow error handling", () => {
|
||||||
}, 120000);
|
}, 120000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.DEEPINFRA_API_KEY)("DeepInfra", () => {
|
||||||
|
it("openai/gpt-oss-120b - should detect overflow via isContextOverflow", async () => {
|
||||||
|
const model = getModel("deepinfra", "openai/gpt-oss-120b");
|
||||||
|
const result = await testContextOverflow(model, process.env.DEEPINFRA_API_KEY!);
|
||||||
|
logResult(result);
|
||||||
|
|
||||||
|
expect(result.stopReason).toBe("error");
|
||||||
|
expect(result.errorMessage).toMatch(/input length/i);
|
||||||
|
expect(isContextOverflow(result.response, model.contextWindow)).toBe(true);
|
||||||
|
}, 120000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.NEBIUS_API_KEY)("Nebius Token Factory", () => {
|
||||||
|
it("openai/gpt-oss-120b - should detect overflow via isContextOverflow", async () => {
|
||||||
|
const model = getModel("nebius", "openai/gpt-oss-120b");
|
||||||
|
const result = await testContextOverflow(model, process.env.NEBIUS_API_KEY!);
|
||||||
|
logResult(result);
|
||||||
|
|
||||||
|
expect(result.stopReason).toBe("error");
|
||||||
|
expect(result.errorMessage).toMatch(/input length/i);
|
||||||
|
expect(isContextOverflow(result.response, model.contextWindow)).toBe(true);
|
||||||
|
}, 120000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.OLLAMA_API_KEY)("Ollama Cloud", () => {
|
||||||
|
it("gpt-oss:120b - should detect overflow via isContextOverflow", async () => {
|
||||||
|
const model = getModel("ollama-cloud", "gpt-oss:120b");
|
||||||
|
const result = await testContextOverflow(model, process.env.OLLAMA_API_KEY!);
|
||||||
|
logResult(result);
|
||||||
|
|
||||||
|
expect(result.stopReason).toBe("error");
|
||||||
|
expect(result.errorMessage).toMatch(/input length/i);
|
||||||
|
expect(isContextOverflow(result.response, model.contextWindow)).toBe(true);
|
||||||
|
}, 120000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SCALEWAY_API_KEY)("Scaleway Generative APIs", () => {
|
||||||
|
it("gpt-oss-120b - should detect overflow via isContextOverflow", async () => {
|
||||||
|
const model = getModel("scaleway", "gpt-oss-120b");
|
||||||
|
const result = await testContextOverflow(model, process.env.SCALEWAY_API_KEY!);
|
||||||
|
logResult(result);
|
||||||
|
|
||||||
|
expect(result.stopReason).toBe("error");
|
||||||
|
expect(result.errorMessage).toMatch(/input length/i);
|
||||||
|
expect(isContextOverflow(result.response, model.contextWindow)).toBe(true);
|
||||||
|
}, 120000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_API_KEY)("SiliconFlow", () => {
|
||||||
|
it("zai-org/GLM-5.2 - should detect overflow via isContextOverflow", async () => {
|
||||||
|
const model = getModel("siliconflow", "zai-org/GLM-5.2");
|
||||||
|
const result = await testContextOverflow(model, process.env.SILICONFLOW_API_KEY!);
|
||||||
|
logResult(result);
|
||||||
|
|
||||||
|
expect(result.stopReason).toBe("error");
|
||||||
|
expect(result.errorMessage).toMatch(/input length/i);
|
||||||
|
expect(isContextOverflow(result.response, model.contextWindow)).toBe(true);
|
||||||
|
}, 120000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_CN_API_KEY)("SiliconFlow (China)", () => {
|
||||||
|
it("zai-org/GLM-5.2 - should detect overflow via isContextOverflow", async () => {
|
||||||
|
const model = getModel("siliconflow-cn", "zai-org/GLM-5.2");
|
||||||
|
const result = await testContextOverflow(model, process.env.SILICONFLOW_CN_API_KEY!);
|
||||||
|
logResult(result);
|
||||||
|
|
||||||
|
expect(result.stopReason).toBe("error");
|
||||||
|
expect(result.errorMessage).toMatch(/input length/i);
|
||||||
|
expect(isContextOverflow(result.response, model.contextWindow)).toBe(true);
|
||||||
|
}, 120000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_API_KEY)("StepFun", () => {
|
||||||
|
it("step-3.7-flash - should detect overflow via isContextOverflow", async () => {
|
||||||
|
const model = getModel("stepfun", "step-3.7-flash");
|
||||||
|
const result = await testContextOverflow(model, process.env.STEPFUN_API_KEY!);
|
||||||
|
logResult(result);
|
||||||
|
|
||||||
|
expect(result.stopReason).toBe("error");
|
||||||
|
expect(result.errorMessage).toMatch(/input length/i);
|
||||||
|
expect(isContextOverflow(result.response, model.contextWindow)).toBe(true);
|
||||||
|
}, 120000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_CN_API_KEY)("StepFun (China)", () => {
|
||||||
|
it("step-3.7-flash - should detect overflow via isContextOverflow", async () => {
|
||||||
|
const model = getModel("stepfun-cn", "step-3.7-flash");
|
||||||
|
const result = await testContextOverflow(model, process.env.STEPFUN_CN_API_KEY!);
|
||||||
|
logResult(result);
|
||||||
|
|
||||||
|
expect(result.stopReason).toBe("error");
|
||||||
|
expect(result.errorMessage).toMatch(/input length/i);
|
||||||
|
expect(isContextOverflow(result.response, model.contextWindow)).toBe(true);
|
||||||
|
}, 120000);
|
||||||
|
});
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Kimi For Coding
|
// Kimi For Coding
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,14 @@ const PROVIDER_MODEL_PAIRS: ProviderModelPair[] = [
|
||||||
{ provider: "alibaba-cn", model: "qwen3.7-max", label: "alibaba-cn-qwen3.7-max" },
|
{ provider: "alibaba-cn", model: "qwen3.7-max", label: "alibaba-cn-qwen3.7-max" },
|
||||||
{ provider: "zai-api", model: "glm-5.3", label: "zai-api-glm-5.3" },
|
{ provider: "zai-api", model: "glm-5.3", label: "zai-api-glm-5.3" },
|
||||||
{ provider: "zai-api-cn", model: "glm-5.3", label: "zai-api-cn-glm-5.3" },
|
{ provider: "zai-api-cn", model: "glm-5.3", label: "zai-api-cn-glm-5.3" },
|
||||||
|
{ provider: "deepinfra", model: "openai/gpt-oss-120b", label: "deepinfra-openai-gpt-oss-120b" },
|
||||||
|
{ provider: "nebius", model: "openai/gpt-oss-120b", label: "nebius-openai-gpt-oss-120b" },
|
||||||
|
{ provider: "ollama-cloud", model: "gpt-oss:120b", label: "ollama-cloud-gpt-oss:120b" },
|
||||||
|
{ provider: "scaleway", model: "gpt-oss-120b", label: "scaleway-gpt-oss-120b" },
|
||||||
|
{ provider: "siliconflow", model: "zai-org/GLM-5.2", label: "siliconflow-zai-org-GLM-5.2" },
|
||||||
|
{ provider: "siliconflow-cn", model: "zai-org/GLM-5.2", label: "siliconflow-cn-zai-org-GLM-5.2" },
|
||||||
|
{ provider: "stepfun", model: "step-3.7-flash", label: "stepfun-step-3.7-flash" },
|
||||||
|
{ provider: "stepfun-cn", model: "step-3.7-flash", label: "stepfun-cn-step-3.7-flash" },
|
||||||
{
|
{
|
||||||
provider: "qwen-token-plan-individual",
|
provider: "qwen-token-plan-individual",
|
||||||
model: "qwen3.8-max",
|
model: "qwen3.8-max",
|
||||||
|
|
|
||||||
|
|
@ -699,6 +699,166 @@ describe("AI Providers Empty Message Tests", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.DEEPINFRA_API_KEY)("DeepInfra Provider Empty Messages", () => {
|
||||||
|
const llm = getModel("deepinfra", "openai/gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should handle empty content array", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty string content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyStringMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle whitespace-only content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testWhitespaceOnlyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty assistant message in conversation", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyAssistantMessage(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.NEBIUS_API_KEY)("Nebius Token Factory Provider Empty Messages", () => {
|
||||||
|
const llm = getModel("nebius", "openai/gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should handle empty content array", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty string content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyStringMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle whitespace-only content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testWhitespaceOnlyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty assistant message in conversation", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyAssistantMessage(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.OLLAMA_API_KEY)("Ollama Cloud Provider Empty Messages", () => {
|
||||||
|
const llm = getModel("ollama-cloud", "gpt-oss:120b");
|
||||||
|
|
||||||
|
it("should handle empty content array", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty string content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyStringMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle whitespace-only content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testWhitespaceOnlyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty assistant message in conversation", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyAssistantMessage(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SCALEWAY_API_KEY)("Scaleway Generative APIs Provider Empty Messages", () => {
|
||||||
|
const llm = getModel("scaleway", "gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should handle empty content array", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty string content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyStringMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle whitespace-only content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testWhitespaceOnlyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty assistant message in conversation", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyAssistantMessage(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_API_KEY)("SiliconFlow Provider Empty Messages", () => {
|
||||||
|
const llm = getModel("siliconflow", "zai-org/GLM-5.2");
|
||||||
|
|
||||||
|
it("should handle empty content array", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty string content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyStringMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle whitespace-only content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testWhitespaceOnlyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty assistant message in conversation", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyAssistantMessage(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_CN_API_KEY)("SiliconFlow (China) Provider Empty Messages", () => {
|
||||||
|
const llm = getModel("siliconflow-cn", "zai-org/GLM-5.2");
|
||||||
|
|
||||||
|
it("should handle empty content array", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty string content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyStringMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle whitespace-only content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testWhitespaceOnlyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty assistant message in conversation", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyAssistantMessage(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_API_KEY)("StepFun Provider Empty Messages", () => {
|
||||||
|
const llm = getModel("stepfun", "step-3.7-flash");
|
||||||
|
|
||||||
|
it("should handle empty content array", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty string content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyStringMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle whitespace-only content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testWhitespaceOnlyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty assistant message in conversation", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyAssistantMessage(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_CN_API_KEY)("StepFun (China) Provider Empty Messages", () => {
|
||||||
|
const llm = getModel("stepfun-cn", "step-3.7-flash");
|
||||||
|
|
||||||
|
it("should handle empty content array", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty string content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyStringMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle whitespace-only content", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testWhitespaceOnlyMessage(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty assistant message in conversation", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmptyAssistantMessage(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe.skipIf(!process.env.KIMI_API_KEY)("Kimi For Coding Provider Empty Messages", () => {
|
describe.skipIf(!process.env.KIMI_API_KEY)("Kimi For Coding Provider Empty Messages", () => {
|
||||||
const llm = getModel("kimi-coding", "kimi-for-coding");
|
const llm = getModel("kimi-coding", "kimi-for-coding");
|
||||||
|
|
||||||
|
|
|
||||||
69
packages/ai/test/hosted-provider-models.test.ts
Normal file
69
packages/ai/test/hosted-provider-models.test.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { hasApi } from "../src/models.ts";
|
||||||
|
import { getBuiltinModel, getBuiltinModels } from "../src/providers/all.ts";
|
||||||
|
import type { Model } from "../src/types.ts";
|
||||||
|
|
||||||
|
const HOSTS = [
|
||||||
|
["deepinfra", "https://api.deepinfra.com/v1/openai"],
|
||||||
|
["nebius", "https://api.tokenfactory.nebius.com/v1"],
|
||||||
|
["ollama-cloud", "https://ollama.com/v1"],
|
||||||
|
["scaleway", "https://api.scaleway.ai/v1"],
|
||||||
|
["siliconflow", "https://api.siliconflow.com/v1"],
|
||||||
|
["siliconflow-cn", "https://api.siliconflow.cn/v1"],
|
||||||
|
["stepfun", "https://api.stepfun.ai/v1"],
|
||||||
|
["stepfun-cn", "https://api.stepfun.com/v1"],
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
function completionsModels(provider: (typeof HOSTS)[number][0]): Model<"openai-completions">[] {
|
||||||
|
return getBuiltinModels(provider).filter((model) => hasApi(model, "openai-completions"));
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("hosted OpenAI-compatible providers", () => {
|
||||||
|
it.each(HOSTS)("serves %s through Chat Completions without OpenAI-only request features", (provider, baseUrl) => {
|
||||||
|
const models = getBuiltinModels(provider);
|
||||||
|
expect(models.length).toBeGreaterThan(0);
|
||||||
|
for (const model of models) {
|
||||||
|
expect(model).toMatchObject({ provider, api: "openai-completions", baseUrl });
|
||||||
|
expect(model.compat).toMatchObject({
|
||||||
|
supportsStore: false,
|
||||||
|
supportsDeveloperRole: false,
|
||||||
|
supportsLongCacheRetention: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each(HOSTS)("sends reasoning_effort on %s only for models with cataloged effort levels", (provider) => {
|
||||||
|
for (const model of completionsModels(provider)) {
|
||||||
|
if (!model.reasoning) continue;
|
||||||
|
if (model.compat?.supportsReasoningEffort === false) {
|
||||||
|
expect(model.thinkingLevelMap).toBeUndefined();
|
||||||
|
} else {
|
||||||
|
expect(model.thinkingLevelMap).toBeDefined();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("toggles SiliconFlow thinking with enable_thinking, including for DeepSeek V4", () => {
|
||||||
|
const models = completionsModels("siliconflow");
|
||||||
|
expect(models.filter((model) => model.compat?.thinkingFormat === "qwen").length).toBeGreaterThan(0);
|
||||||
|
for (const model of models) {
|
||||||
|
expect(model.compat?.thinkingFormat).not.toBe("deepseek");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses DeepSeek-style reasoning on StepFun", () => {
|
||||||
|
for (const provider of ["stepfun", "stepfun-cn"] as const) {
|
||||||
|
expect(getBuiltinModel(provider, "step-3.7-flash").compat).toMatchObject({
|
||||||
|
thinkingFormat: "deepseek",
|
||||||
|
requiresReasoningContentOnAssistantMessages: true,
|
||||||
|
supportsReasoningEffort: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("caps Scaleway output with max_completion_tokens", () => {
|
||||||
|
for (const model of completionsModels("scaleway")) {
|
||||||
|
expect(model.compat?.maxTokensField).toBe("max_completion_tokens");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -417,6 +417,30 @@ describe("Tool Results with Images", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_API_KEY)("StepFun Provider (step-3.7-flash)", () => {
|
||||||
|
const llm = getModel("stepfun", "step-3.7-flash");
|
||||||
|
|
||||||
|
it("should handle tool result with only image", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await handleToolWithImageResult(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle tool result with text and image", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await handleToolWithTextAndImageResult(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_CN_API_KEY)("StepFun (China) Provider (step-3.7-flash)", () => {
|
||||||
|
const llm = getModel("stepfun-cn", "step-3.7-flash");
|
||||||
|
|
||||||
|
it("should handle tool result with only image", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await handleToolWithImageResult(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle tool result with text and image", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await handleToolWithTextAndImageResult(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe.skipIf(!process.env.KIMI_API_KEY)("Kimi For Coding Provider (kimi-for-coding)", () => {
|
describe.skipIf(!process.env.KIMI_API_KEY)("Kimi For Coding Provider (kimi-for-coding)", () => {
|
||||||
const llm = getModel("kimi-coding", "kimi-for-coding");
|
const llm = getModel("kimi-coding", "kimi-for-coding");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1420,6 +1420,230 @@ describe("Generate E2E Tests", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.DEEPINFRA_API_KEY)("DeepInfra Provider (openai/gpt-oss-120b)", () => {
|
||||||
|
const llm = getModel("deepinfra", "openai/gpt-oss-120b");
|
||||||
|
const thinkingOptions = {
|
||||||
|
thinkingEnabled: true,
|
||||||
|
reasoningEffort: "high",
|
||||||
|
} satisfies StreamOptionsWithExtras;
|
||||||
|
|
||||||
|
it("should complete basic text generation", { retry: 3 }, async () => {
|
||||||
|
await basicTextGeneration(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle tool calling", { retry: 3 }, async () => {
|
||||||
|
await handleToolCall(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle streaming", { retry: 3 }, async () => {
|
||||||
|
await handleStreaming(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle thinking mode", { retry: 3 }, async () => {
|
||||||
|
await handleThinking(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle multi-turn with thinking and tools", { retry: 3 }, async () => {
|
||||||
|
await multiTurn(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.NEBIUS_API_KEY)("Nebius Token Factory Provider (openai/gpt-oss-120b)", () => {
|
||||||
|
const llm = getModel("nebius", "openai/gpt-oss-120b");
|
||||||
|
const thinkingOptions = {
|
||||||
|
thinkingEnabled: true,
|
||||||
|
reasoningEffort: "high",
|
||||||
|
} satisfies StreamOptionsWithExtras;
|
||||||
|
|
||||||
|
it("should complete basic text generation", { retry: 3 }, async () => {
|
||||||
|
await basicTextGeneration(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle tool calling", { retry: 3 }, async () => {
|
||||||
|
await handleToolCall(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle streaming", { retry: 3 }, async () => {
|
||||||
|
await handleStreaming(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle thinking mode", { retry: 3 }, async () => {
|
||||||
|
await handleThinking(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle multi-turn with thinking and tools", { retry: 3 }, async () => {
|
||||||
|
await multiTurn(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.OLLAMA_API_KEY)("Ollama Cloud Provider (gpt-oss:120b)", () => {
|
||||||
|
const llm = getModel("ollama-cloud", "gpt-oss:120b");
|
||||||
|
const thinkingOptions = {
|
||||||
|
thinkingEnabled: true,
|
||||||
|
reasoningEffort: "high",
|
||||||
|
} satisfies StreamOptionsWithExtras;
|
||||||
|
|
||||||
|
it("should complete basic text generation", { retry: 3 }, async () => {
|
||||||
|
await basicTextGeneration(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle tool calling", { retry: 3 }, async () => {
|
||||||
|
await handleToolCall(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle streaming", { retry: 3 }, async () => {
|
||||||
|
await handleStreaming(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle thinking mode", { retry: 3 }, async () => {
|
||||||
|
await handleThinking(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle multi-turn with thinking and tools", { retry: 3 }, async () => {
|
||||||
|
await multiTurn(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SCALEWAY_API_KEY)("Scaleway Generative APIs Provider (gpt-oss-120b)", () => {
|
||||||
|
const llm = getModel("scaleway", "gpt-oss-120b");
|
||||||
|
const thinkingOptions = {
|
||||||
|
thinkingEnabled: true,
|
||||||
|
reasoningEffort: "high",
|
||||||
|
} satisfies StreamOptionsWithExtras;
|
||||||
|
|
||||||
|
it("should complete basic text generation", { retry: 3 }, async () => {
|
||||||
|
await basicTextGeneration(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle tool calling", { retry: 3 }, async () => {
|
||||||
|
await handleToolCall(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle streaming", { retry: 3 }, async () => {
|
||||||
|
await handleStreaming(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle thinking mode", { retry: 3 }, async () => {
|
||||||
|
await handleThinking(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle multi-turn with thinking and tools", { retry: 3 }, async () => {
|
||||||
|
await multiTurn(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_API_KEY)("SiliconFlow Provider (zai-org/GLM-5.2)", () => {
|
||||||
|
const llm = getModel("siliconflow", "zai-org/GLM-5.2");
|
||||||
|
const thinkingOptions = {
|
||||||
|
thinkingEnabled: true,
|
||||||
|
reasoningEffort: "high",
|
||||||
|
} satisfies StreamOptionsWithExtras;
|
||||||
|
|
||||||
|
it("should complete basic text generation", { retry: 3 }, async () => {
|
||||||
|
await basicTextGeneration(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle tool calling", { retry: 3 }, async () => {
|
||||||
|
await handleToolCall(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle streaming", { retry: 3 }, async () => {
|
||||||
|
await handleStreaming(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle thinking mode", { retry: 3 }, async () => {
|
||||||
|
await handleThinking(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle multi-turn with thinking and tools", { retry: 3 }, async () => {
|
||||||
|
await multiTurn(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_CN_API_KEY)("SiliconFlow (China) Provider (zai-org/GLM-5.2)", () => {
|
||||||
|
const llm = getModel("siliconflow-cn", "zai-org/GLM-5.2");
|
||||||
|
const thinkingOptions = {
|
||||||
|
thinkingEnabled: true,
|
||||||
|
reasoningEffort: "high",
|
||||||
|
} satisfies StreamOptionsWithExtras;
|
||||||
|
|
||||||
|
it("should complete basic text generation", { retry: 3 }, async () => {
|
||||||
|
await basicTextGeneration(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle tool calling", { retry: 3 }, async () => {
|
||||||
|
await handleToolCall(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle streaming", { retry: 3 }, async () => {
|
||||||
|
await handleStreaming(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle thinking mode", { retry: 3 }, async () => {
|
||||||
|
await handleThinking(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle multi-turn with thinking and tools", { retry: 3 }, async () => {
|
||||||
|
await multiTurn(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_API_KEY)("StepFun Provider (step-3.7-flash)", () => {
|
||||||
|
const llm = getModel("stepfun", "step-3.7-flash");
|
||||||
|
const thinkingOptions = {
|
||||||
|
thinkingEnabled: true,
|
||||||
|
reasoningEffort: "high",
|
||||||
|
} satisfies StreamOptionsWithExtras;
|
||||||
|
|
||||||
|
it("should complete basic text generation", { retry: 3 }, async () => {
|
||||||
|
await basicTextGeneration(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle tool calling", { retry: 3 }, async () => {
|
||||||
|
await handleToolCall(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle streaming", { retry: 3 }, async () => {
|
||||||
|
await handleStreaming(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle thinking mode", { retry: 3 }, async () => {
|
||||||
|
await handleThinking(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle multi-turn with thinking and tools", { retry: 3 }, async () => {
|
||||||
|
await multiTurn(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_CN_API_KEY)("StepFun (China) Provider (step-3.7-flash)", () => {
|
||||||
|
const llm = getModel("stepfun-cn", "step-3.7-flash");
|
||||||
|
const thinkingOptions = {
|
||||||
|
thinkingEnabled: true,
|
||||||
|
reasoningEffort: "high",
|
||||||
|
} satisfies StreamOptionsWithExtras;
|
||||||
|
|
||||||
|
it("should complete basic text generation", { retry: 3 }, async () => {
|
||||||
|
await basicTextGeneration(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle tool calling", { retry: 3 }, async () => {
|
||||||
|
await handleToolCall(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle streaming", { retry: 3 }, async () => {
|
||||||
|
await handleStreaming(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle thinking mode", { retry: 3 }, async () => {
|
||||||
|
await handleThinking(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle multi-turn with thinking and tools", { retry: 3 }, async () => {
|
||||||
|
await multiTurn(llm, thinkingOptions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe.skipIf(!process.env.ANT_LING_API_KEY)("Ant Ling Provider (Ling 2.6 Flash via OpenAI Completions)", () => {
|
describe.skipIf(!process.env.ANT_LING_API_KEY)("Ant Ling Provider (Ling 2.6 Flash via OpenAI Completions)", () => {
|
||||||
const llm = getModel("ant-ling", "Ling-2.6-flash");
|
const llm = getModel("ant-ling", "Ling-2.6-flash");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -348,6 +348,70 @@ describe("Token Statistics on Abort", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.DEEPINFRA_API_KEY)("DeepInfra Provider", () => {
|
||||||
|
const llm = getModel("deepinfra", "openai/gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should include token stats when aborted mid-stream", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testTokensOnAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.NEBIUS_API_KEY)("Nebius Token Factory Provider", () => {
|
||||||
|
const llm = getModel("nebius", "openai/gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should include token stats when aborted mid-stream", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testTokensOnAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.OLLAMA_API_KEY)("Ollama Cloud Provider", () => {
|
||||||
|
const llm = getModel("ollama-cloud", "gpt-oss:120b");
|
||||||
|
|
||||||
|
it("should include token stats when aborted mid-stream", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testTokensOnAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SCALEWAY_API_KEY)("Scaleway Generative APIs Provider", () => {
|
||||||
|
const llm = getModel("scaleway", "gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should include token stats when aborted mid-stream", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testTokensOnAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_API_KEY)("SiliconFlow Provider", () => {
|
||||||
|
const llm = getModel("siliconflow", "zai-org/GLM-5.2");
|
||||||
|
|
||||||
|
it("should include token stats when aborted mid-stream", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testTokensOnAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_CN_API_KEY)("SiliconFlow (China) Provider", () => {
|
||||||
|
const llm = getModel("siliconflow-cn", "zai-org/GLM-5.2");
|
||||||
|
|
||||||
|
it("should include token stats when aborted mid-stream", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testTokensOnAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_API_KEY)("StepFun Provider", () => {
|
||||||
|
const llm = getModel("stepfun", "step-3.7-flash");
|
||||||
|
|
||||||
|
it("should include token stats when aborted mid-stream", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testTokensOnAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_CN_API_KEY)("StepFun (China) Provider", () => {
|
||||||
|
const llm = getModel("stepfun-cn", "step-3.7-flash");
|
||||||
|
|
||||||
|
it("should include token stats when aborted mid-stream", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testTokensOnAbort(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// OAuth-based providers (credentials from ~/.pi/agent/oauth.json)
|
// OAuth-based providers (credentials from ~/.pi/agent/oauth.json)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
|
||||||
|
|
@ -318,6 +318,70 @@ describe("Tool Call Without Result Tests", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.DEEPINFRA_API_KEY)("DeepInfra Provider", () => {
|
||||||
|
const model = getModel("deepinfra", "openai/gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should filter out tool calls without corresponding tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testToolCallWithoutResult(model);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.NEBIUS_API_KEY)("Nebius Token Factory Provider", () => {
|
||||||
|
const model = getModel("nebius", "openai/gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should filter out tool calls without corresponding tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testToolCallWithoutResult(model);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.OLLAMA_API_KEY)("Ollama Cloud Provider", () => {
|
||||||
|
const model = getModel("ollama-cloud", "gpt-oss:120b");
|
||||||
|
|
||||||
|
it("should filter out tool calls without corresponding tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testToolCallWithoutResult(model);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SCALEWAY_API_KEY)("Scaleway Generative APIs Provider", () => {
|
||||||
|
const model = getModel("scaleway", "gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should filter out tool calls without corresponding tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testToolCallWithoutResult(model);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_API_KEY)("SiliconFlow Provider", () => {
|
||||||
|
const model = getModel("siliconflow", "zai-org/GLM-5.2");
|
||||||
|
|
||||||
|
it("should filter out tool calls without corresponding tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testToolCallWithoutResult(model);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_CN_API_KEY)("SiliconFlow (China) Provider", () => {
|
||||||
|
const model = getModel("siliconflow-cn", "zai-org/GLM-5.2");
|
||||||
|
|
||||||
|
it("should filter out tool calls without corresponding tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testToolCallWithoutResult(model);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_API_KEY)("StepFun Provider", () => {
|
||||||
|
const model = getModel("stepfun", "step-3.7-flash");
|
||||||
|
|
||||||
|
it("should filter out tool calls without corresponding tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testToolCallWithoutResult(model);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_CN_API_KEY)("StepFun (China) Provider", () => {
|
||||||
|
const model = getModel("stepfun-cn", "step-3.7-flash");
|
||||||
|
|
||||||
|
it("should filter out tool calls without corresponding tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testToolCallWithoutResult(model);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe.skipIf(!process.env.KIMI_API_KEY)("Kimi For Coding Provider", () => {
|
describe.skipIf(!process.env.KIMI_API_KEY)("Kimi For Coding Provider", () => {
|
||||||
const model = getModel("kimi-coding", "kimi-for-coding");
|
const model = getModel("kimi-coding", "kimi-for-coding");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -731,6 +731,174 @@ describe("totalTokens field", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.DEEPINFRA_API_KEY)("DeepInfra", () => {
|
||||||
|
it(
|
||||||
|
"openai/gpt-oss-120b - should return totalTokens equal to sum of components",
|
||||||
|
{ retry: 3, timeout: 60000 },
|
||||||
|
async () => {
|
||||||
|
const llm = getModel("deepinfra", "openai/gpt-oss-120b");
|
||||||
|
|
||||||
|
console.log(`\nDeepInfra / ${llm.id}:`);
|
||||||
|
const { first, second } = await testTotalTokensWithCache(llm, {
|
||||||
|
apiKey: process.env.DEEPINFRA_API_KEY,
|
||||||
|
});
|
||||||
|
|
||||||
|
logUsage("First request", first);
|
||||||
|
logUsage("Second request", second);
|
||||||
|
|
||||||
|
assertTotalTokensEqualsComponents(first);
|
||||||
|
assertTotalTokensEqualsComponents(second);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.NEBIUS_API_KEY)("Nebius Token Factory", () => {
|
||||||
|
it(
|
||||||
|
"openai/gpt-oss-120b - should return totalTokens equal to sum of components",
|
||||||
|
{ retry: 3, timeout: 60000 },
|
||||||
|
async () => {
|
||||||
|
const llm = getModel("nebius", "openai/gpt-oss-120b");
|
||||||
|
|
||||||
|
console.log(`\nNebius Token Factory / ${llm.id}:`);
|
||||||
|
const { first, second } = await testTotalTokensWithCache(llm, {
|
||||||
|
apiKey: process.env.NEBIUS_API_KEY,
|
||||||
|
});
|
||||||
|
|
||||||
|
logUsage("First request", first);
|
||||||
|
logUsage("Second request", second);
|
||||||
|
|
||||||
|
assertTotalTokensEqualsComponents(first);
|
||||||
|
assertTotalTokensEqualsComponents(second);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.OLLAMA_API_KEY)("Ollama Cloud", () => {
|
||||||
|
it(
|
||||||
|
"gpt-oss:120b - should return totalTokens equal to sum of components",
|
||||||
|
{ retry: 3, timeout: 60000 },
|
||||||
|
async () => {
|
||||||
|
const llm = getModel("ollama-cloud", "gpt-oss:120b");
|
||||||
|
|
||||||
|
console.log(`\nOllama Cloud / ${llm.id}:`);
|
||||||
|
const { first, second } = await testTotalTokensWithCache(llm, {
|
||||||
|
apiKey: process.env.OLLAMA_API_KEY,
|
||||||
|
});
|
||||||
|
|
||||||
|
logUsage("First request", first);
|
||||||
|
logUsage("Second request", second);
|
||||||
|
|
||||||
|
assertTotalTokensEqualsComponents(first);
|
||||||
|
assertTotalTokensEqualsComponents(second);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SCALEWAY_API_KEY)("Scaleway Generative APIs", () => {
|
||||||
|
it(
|
||||||
|
"gpt-oss-120b - should return totalTokens equal to sum of components",
|
||||||
|
{ retry: 3, timeout: 60000 },
|
||||||
|
async () => {
|
||||||
|
const llm = getModel("scaleway", "gpt-oss-120b");
|
||||||
|
|
||||||
|
console.log(`\nScaleway Generative APIs / ${llm.id}:`);
|
||||||
|
const { first, second } = await testTotalTokensWithCache(llm, {
|
||||||
|
apiKey: process.env.SCALEWAY_API_KEY,
|
||||||
|
});
|
||||||
|
|
||||||
|
logUsage("First request", first);
|
||||||
|
logUsage("Second request", second);
|
||||||
|
|
||||||
|
assertTotalTokensEqualsComponents(first);
|
||||||
|
assertTotalTokensEqualsComponents(second);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_API_KEY)("SiliconFlow", () => {
|
||||||
|
it(
|
||||||
|
"zai-org/GLM-5.2 - should return totalTokens equal to sum of components",
|
||||||
|
{ retry: 3, timeout: 60000 },
|
||||||
|
async () => {
|
||||||
|
const llm = getModel("siliconflow", "zai-org/GLM-5.2");
|
||||||
|
|
||||||
|
console.log(`\nSiliconFlow / ${llm.id}:`);
|
||||||
|
const { first, second } = await testTotalTokensWithCache(llm, {
|
||||||
|
apiKey: process.env.SILICONFLOW_API_KEY,
|
||||||
|
});
|
||||||
|
|
||||||
|
logUsage("First request", first);
|
||||||
|
logUsage("Second request", second);
|
||||||
|
|
||||||
|
assertTotalTokensEqualsComponents(first);
|
||||||
|
assertTotalTokensEqualsComponents(second);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_CN_API_KEY)("SiliconFlow (China)", () => {
|
||||||
|
it(
|
||||||
|
"zai-org/GLM-5.2 - should return totalTokens equal to sum of components",
|
||||||
|
{ retry: 3, timeout: 60000 },
|
||||||
|
async () => {
|
||||||
|
const llm = getModel("siliconflow-cn", "zai-org/GLM-5.2");
|
||||||
|
|
||||||
|
console.log(`\nSiliconFlow (China) / ${llm.id}:`);
|
||||||
|
const { first, second } = await testTotalTokensWithCache(llm, {
|
||||||
|
apiKey: process.env.SILICONFLOW_CN_API_KEY,
|
||||||
|
});
|
||||||
|
|
||||||
|
logUsage("First request", first);
|
||||||
|
logUsage("Second request", second);
|
||||||
|
|
||||||
|
assertTotalTokensEqualsComponents(first);
|
||||||
|
assertTotalTokensEqualsComponents(second);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_API_KEY)("StepFun", () => {
|
||||||
|
it(
|
||||||
|
"step-3.7-flash - should return totalTokens equal to sum of components",
|
||||||
|
{ retry: 3, timeout: 60000 },
|
||||||
|
async () => {
|
||||||
|
const llm = getModel("stepfun", "step-3.7-flash");
|
||||||
|
|
||||||
|
console.log(`\nStepFun / ${llm.id}:`);
|
||||||
|
const { first, second } = await testTotalTokensWithCache(llm, {
|
||||||
|
apiKey: process.env.STEPFUN_API_KEY,
|
||||||
|
});
|
||||||
|
|
||||||
|
logUsage("First request", first);
|
||||||
|
logUsage("Second request", second);
|
||||||
|
|
||||||
|
assertTotalTokensEqualsComponents(first);
|
||||||
|
assertTotalTokensEqualsComponents(second);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_CN_API_KEY)("StepFun (China)", () => {
|
||||||
|
it(
|
||||||
|
"step-3.7-flash - should return totalTokens equal to sum of components",
|
||||||
|
{ retry: 3, timeout: 60000 },
|
||||||
|
async () => {
|
||||||
|
const llm = getModel("stepfun-cn", "step-3.7-flash");
|
||||||
|
|
||||||
|
console.log(`\nStepFun (China) / ${llm.id}:`);
|
||||||
|
const { first, second } = await testTotalTokensWithCache(llm, {
|
||||||
|
apiKey: process.env.STEPFUN_CN_API_KEY,
|
||||||
|
});
|
||||||
|
|
||||||
|
logUsage("First request", first);
|
||||||
|
logUsage("Second request", second);
|
||||||
|
|
||||||
|
assertTotalTokensEqualsComponents(first);
|
||||||
|
assertTotalTokensEqualsComponents(second);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Kimi For Coding
|
// Kimi For Coding
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
|
||||||
|
|
@ -838,6 +838,134 @@ describe("AI Providers Unicode Surrogate Pair Tests", () => {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.DEEPINFRA_API_KEY)("DeepInfra Provider Unicode Handling", () => {
|
||||||
|
const llm = getModel("deepinfra", "openai/gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should handle emoji in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmojiInToolResults(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle real-world LinkedIn comment data with emoji", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testRealWorldLinkedInData(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle unpaired high surrogate (0xD83D) in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testUnpairedHighSurrogate(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.NEBIUS_API_KEY)("Nebius Token Factory Provider Unicode Handling", () => {
|
||||||
|
const llm = getModel("nebius", "openai/gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should handle emoji in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmojiInToolResults(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle real-world LinkedIn comment data with emoji", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testRealWorldLinkedInData(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle unpaired high surrogate (0xD83D) in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testUnpairedHighSurrogate(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.OLLAMA_API_KEY)("Ollama Cloud Provider Unicode Handling", () => {
|
||||||
|
const llm = getModel("ollama-cloud", "gpt-oss:120b");
|
||||||
|
|
||||||
|
it("should handle emoji in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmojiInToolResults(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle real-world LinkedIn comment data with emoji", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testRealWorldLinkedInData(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle unpaired high surrogate (0xD83D) in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testUnpairedHighSurrogate(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SCALEWAY_API_KEY)("Scaleway Generative APIs Provider Unicode Handling", () => {
|
||||||
|
const llm = getModel("scaleway", "gpt-oss-120b");
|
||||||
|
|
||||||
|
it("should handle emoji in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmojiInToolResults(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle real-world LinkedIn comment data with emoji", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testRealWorldLinkedInData(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle unpaired high surrogate (0xD83D) in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testUnpairedHighSurrogate(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_API_KEY)("SiliconFlow Provider Unicode Handling", () => {
|
||||||
|
const llm = getModel("siliconflow", "zai-org/GLM-5.2");
|
||||||
|
|
||||||
|
it("should handle emoji in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmojiInToolResults(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle real-world LinkedIn comment data with emoji", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testRealWorldLinkedInData(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle unpaired high surrogate (0xD83D) in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testUnpairedHighSurrogate(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.SILICONFLOW_CN_API_KEY)("SiliconFlow (China) Provider Unicode Handling", () => {
|
||||||
|
const llm = getModel("siliconflow-cn", "zai-org/GLM-5.2");
|
||||||
|
|
||||||
|
it("should handle emoji in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmojiInToolResults(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle real-world LinkedIn comment data with emoji", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testRealWorldLinkedInData(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle unpaired high surrogate (0xD83D) in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testUnpairedHighSurrogate(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_API_KEY)("StepFun Provider Unicode Handling", () => {
|
||||||
|
const llm = getModel("stepfun", "step-3.7-flash");
|
||||||
|
|
||||||
|
it("should handle emoji in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmojiInToolResults(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle real-world LinkedIn comment data with emoji", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testRealWorldLinkedInData(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle unpaired high surrogate (0xD83D) in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testUnpairedHighSurrogate(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.skipIf(!process.env.STEPFUN_CN_API_KEY)("StepFun (China) Provider Unicode Handling", () => {
|
||||||
|
const llm = getModel("stepfun-cn", "step-3.7-flash");
|
||||||
|
|
||||||
|
it("should handle emoji in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testEmojiInToolResults(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle real-world LinkedIn comment data with emoji", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testRealWorldLinkedInData(llm);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle unpaired high surrogate (0xD83D) in tool results", { retry: 3, timeout: 30000 }, async () => {
|
||||||
|
await testUnpairedHighSurrogate(llm);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe.skipIf(!process.env.KIMI_API_KEY)("Kimi For Coding Provider Unicode Handling", () => {
|
describe.skipIf(!process.env.KIMI_API_KEY)("Kimi For Coding Provider Unicode Handling", () => {
|
||||||
const llm = getModel("kimi-coding", "kimi-for-coding");
|
const llm = getModel("kimi-coding", "kimi-for-coding");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,9 +67,19 @@ This table covers providers with a single primary API-key variable. Providers th
|
||||||
| Xiaomi MiMo Token Plan (China) | `XIAOMI_TOKEN_PLAN_CN_API_KEY` |
|
| Xiaomi MiMo Token Plan (China) | `XIAOMI_TOKEN_PLAN_CN_API_KEY` |
|
||||||
| Xiaomi MiMo Token Plan (Amsterdam) | `XIAOMI_TOKEN_PLAN_AMS_API_KEY` |
|
| Xiaomi MiMo Token Plan (Amsterdam) | `XIAOMI_TOKEN_PLAN_AMS_API_KEY` |
|
||||||
| Xiaomi MiMo Token Plan (Singapore) | `XIAOMI_TOKEN_PLAN_SGP_API_KEY` |
|
| Xiaomi MiMo Token Plan (Singapore) | `XIAOMI_TOKEN_PLAN_SGP_API_KEY` |
|
||||||
|
| DeepInfra | `DEEPINFRA_API_KEY` |
|
||||||
|
| Nebius Token Factory | `NEBIUS_API_KEY` |
|
||||||
|
| Ollama Cloud | `OLLAMA_API_KEY` |
|
||||||
|
| Scaleway Generative APIs | `SCALEWAY_API_KEY` |
|
||||||
|
| SiliconFlow | `SILICONFLOW_API_KEY` |
|
||||||
|
| SiliconFlow (China) | `SILICONFLOW_CN_API_KEY` |
|
||||||
|
| StepFun | `STEPFUN_API_KEY` |
|
||||||
|
| StepFun (China) | `STEPFUN_CN_API_KEY` |
|
||||||
|
|
||||||
The Z.AI pay-as-you-go APIs (`zai-api`, `zai-api-cn`) and Alibaba Cloud Model Studio (`alibaba`, `alibaba-cn`) bill usage to the account balance, while `zai`, `zai-coding-cn`, and the Qwen Token Plan providers draw on a plan. They read separate variables, so a key set for a plan never makes the pay-as-you-go models selectable.
|
The Z.AI pay-as-you-go APIs (`zai-api`, `zai-api-cn`) and Alibaba Cloud Model Studio (`alibaba`, `alibaba-cn`) bill usage to the account balance, while `zai`, `zai-coding-cn`, and the Qwen Token Plan providers draw on a plan. They read separate variables, so a key set for a plan never makes the pay-as-you-go models selectable.
|
||||||
|
|
||||||
|
`ollama-cloud` is Ollama's hosted API at `ollama.com`. For a local Ollama server, add it as a [compatible endpoint](models.md#configure-a-compatible-endpoint).
|
||||||
|
|
||||||
Anthropic also recognizes `ANTHROPIC_OAUTH_TOKEN` as an API credential and `ANTHROPIC_AUTH_TOKEN` as bearer authentication.
|
Anthropic also recognizes `ANTHROPIC_OAUTH_TOKEN` as an API credential and `ANTHROPIC_AUTH_TOKEN` as bearer authentication.
|
||||||
|
|
||||||
With no key or token set, Anthropic uses workload identity federation when `ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID` and `ANTHROPIC_IDENTITY_TOKEN_FILE` are set: the Anthropic SDK exchanges the identity token for a short-lived access token and refreshes it itself (re-reading the identity token file, so keep that file fresh for long sessions). `ANTHROPIC_SERVICE_ACCOUNT_ID` and `ANTHROPIC_WORKSPACE_ID` are passed through when set.
|
With no key or token set, Anthropic uses workload identity federation when `ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID` and `ANTHROPIC_IDENTITY_TOKEN_FILE` are set: the Anthropic SDK exchanges the identity token for a short-lived access token and refreshes it itself (re-reading the identity token file, so keep that file fresh for long sessions). `ANTHROPIC_SERVICE_ACCOUNT_ID` and `ANTHROPIC_WORKSPACE_ID` are passed through when set.
|
||||||
|
|
|
||||||
|
|
@ -458,6 +458,14 @@ ${chalk.bold("Environment Variables:")}
|
||||||
DASHSCOPE_CN_API_KEY - Alibaba Cloud Model Studio (DashScope) API key (China region)
|
DASHSCOPE_CN_API_KEY - Alibaba Cloud Model Studio (DashScope) API key (China region)
|
||||||
ZAI_PAYG_API_KEY - Z.AI pay-as-you-go API key (Global)
|
ZAI_PAYG_API_KEY - Z.AI pay-as-you-go API key (Global)
|
||||||
ZAI_PAYG_CN_API_KEY - Z.AI pay-as-you-go API key (China, bigmodel.cn)
|
ZAI_PAYG_CN_API_KEY - Z.AI pay-as-you-go API key (China, bigmodel.cn)
|
||||||
|
DEEPINFRA_API_KEY - DeepInfra API key
|
||||||
|
NEBIUS_API_KEY - Nebius Token Factory API key
|
||||||
|
OLLAMA_API_KEY - Ollama Cloud API key
|
||||||
|
SCALEWAY_API_KEY - Scaleway Generative APIs secret key
|
||||||
|
SILICONFLOW_API_KEY - SiliconFlow API key (Global)
|
||||||
|
SILICONFLOW_CN_API_KEY - SiliconFlow API key (China)
|
||||||
|
STEPFUN_API_KEY - StepFun API key (Global, stepfun.ai)
|
||||||
|
STEPFUN_CN_API_KEY - StepFun API key (China, stepfun.com)
|
||||||
AWS_PROFILE - AWS profile for Amazon Bedrock
|
AWS_PROFILE - AWS profile for Amazon Bedrock
|
||||||
AWS_ACCESS_KEY_ID - AWS access key for Amazon Bedrock
|
AWS_ACCESS_KEY_ID - AWS access key for Amazon Bedrock
|
||||||
AWS_SECRET_ACCESS_KEY - AWS secret key for Amazon Bedrock
|
AWS_SECRET_ACCESS_KEY - AWS secret key for Amazon Bedrock
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,14 @@ export const defaultModelPerProvider: Partial<Record<KnownProvider, string>> = {
|
||||||
"xiaomi-token-plan-cn": "mimo-v2.6-pro",
|
"xiaomi-token-plan-cn": "mimo-v2.6-pro",
|
||||||
"xiaomi-token-plan-ams": "mimo-v2.6-pro",
|
"xiaomi-token-plan-ams": "mimo-v2.6-pro",
|
||||||
"xiaomi-token-plan-sgp": "mimo-v2.6-pro",
|
"xiaomi-token-plan-sgp": "mimo-v2.6-pro",
|
||||||
|
deepinfra: "moonshotai/Kimi-K3",
|
||||||
|
nebius: "moonshotai/Kimi-K3",
|
||||||
|
"ollama-cloud": "kimi-k3",
|
||||||
|
scaleway: "glm-5.3",
|
||||||
|
siliconflow: "moonshotai/Kimi-K3",
|
||||||
|
"siliconflow-cn": "zai-org/GLM-5.2",
|
||||||
|
stepfun: "step-3.7-flash",
|
||||||
|
"stepfun-cn": "step-3.7-flash",
|
||||||
alibaba: "qwen3.8-max",
|
alibaba: "qwen3.8-max",
|
||||||
"alibaba-cn": "qwen3.8-max",
|
"alibaba-cn": "qwen3.8-max",
|
||||||
"zai-api": "glm-5.3",
|
"zai-api": "glm-5.3",
|
||||||
|
|
|
||||||
|
|
@ -702,13 +702,23 @@ describe("default model selection", () => {
|
||||||
expect(defaultModelPerProvider["openai-codex"]).toBe("gpt-6.1-sol");
|
expect(defaultModelPerProvider["openai-codex"]).toBe("gpt-6.1-sol");
|
||||||
});
|
});
|
||||||
|
|
||||||
test.each(["alibaba", "alibaba-cn", "zai-api", "zai-api-cn"] as const)(
|
test.each([
|
||||||
"%s default is in its built-in catalog",
|
"alibaba",
|
||||||
(provider) => {
|
"alibaba-cn",
|
||||||
const modelId = defaultModelPerProvider[provider];
|
"zai-api",
|
||||||
expect(getBuiltinModels(provider).some((model) => model.id === modelId)).toBe(true);
|
"zai-api-cn",
|
||||||
},
|
"deepinfra",
|
||||||
);
|
"nebius",
|
||||||
|
"ollama-cloud",
|
||||||
|
"scaleway",
|
||||||
|
"siliconflow",
|
||||||
|
"siliconflow-cn",
|
||||||
|
"stepfun",
|
||||||
|
"stepfun-cn",
|
||||||
|
] as const)("%s default is in its built-in catalog", (provider) => {
|
||||||
|
const modelId = defaultModelPerProvider[provider];
|
||||||
|
expect(getBuiltinModels(provider).some((model) => model.id === modelId)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
test("zai, minimax, cerebras, and ant-ling defaults track current models", () => {
|
test("zai, minimax, cerebras, and ant-ling defaults track current models", () => {
|
||||||
expect(defaultModelPerProvider.zai).toBe("glm-5.3");
|
expect(defaultModelPerProvider.zai).toBe("glm-5.3");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue