Merge origin/master (v0.5.91) into gitea/new_feature

Resolve conflicts:
- streamingHandler.js: adopt upstreamResponseHeaders while keeping 0-token detail row avoidance
- capabilities.js: preserve user-asserted caps and globalThis slots without local caching of catalogSource
- AddCustomModelModal.js & providers/[id]/page.js: wire STT transport marker with custom model edits/assertions
- models/custom/route.js & aliasRepo.js: persist custom model transport and invalidate user caps
- usageRepo.js: key byApiKey live stats by full API key and keep tail in maskApiKey
- UsageStats.js: lazy load charts dynamically
This commit is contained in:
2026-09-28 21:17:33 +07:00
123 changed files with 5882 additions and 411 deletions

View File

@@ -0,0 +1,29 @@
export default {
id: "agnes",
priority: 120,
alias: "agnes",
aliases: [
"agnes-ai",
],
uiAlias: "agnes",
display: {
name: "Agnes AI",
icon: "auto_awesome",
color: "#7C3AED",
textIcon: "AG",
website: "https://agnes-ai.com",
notice: {
text: "OpenAI-compatible gateway from Agnes AI, offering free API credits on sign-up. Accepts a bearer token or an x-api-key header.",
apiKeyUrl: "https://platform.agnes-ai.com",
},
},
category: "freeTier",
authType: "apikey",
transport: {
baseUrl: "https://apihub.agnes-ai.com/v1/chat/completions",
validateUrl: "https://apihub.agnes-ai.com/v1/models",
},
// No model ids could be verified without a key, so discovery is left to the
// live endpoint and any id is accepted through passthroughModels.
passthroughModels: true,
};

View File

@@ -0,0 +1,32 @@
export default {
id: "atria",
priority: 120,
alias: "atria",
aliases: [
"atria-asi",
],
uiAlias: "atria",
display: {
name: "Atria Dawn",
icon: "flare",
color: "#C2410C",
textIcon: "AD",
website: "https://atria-asi.ai",
notice: {
text: "OpenAI-compatible endpoint from Atria Dawn (AtomInnoLab). Currently a research preview offering a single text model, Atria-Dawn-Preview.",
apiKeyUrl: "https://api.atria-asi.ai/dashboard",
},
},
category: "apikey",
authType: "apikey",
transport: {
baseUrl: "https://api.atria-asi.ai/v1/chat/completions",
validateUrl: "https://api.atria-asi.ai/v1/models",
},
// Docs pin the model field to one case-sensitive id. Text-only for now: the
// service ships a hook that blocks image/PDF input, so no vision is claimed.
models: [
{ id: "Atria-Dawn-Preview", name: "Atria Dawn Preview" },
],
passthroughModels: true,
};

View File

@@ -0,0 +1,30 @@
export default {
id: "bai",
priority: 120,
alias: "bai",
aliases: [
"b-ai",
],
uiAlias: "bai",
display: {
name: "B.AI",
icon: "account_balance",
color: "#0369A1",
textIcon: "BA",
website: "https://b.ai",
notice: {
text: "OpenAI-compatible gateway with one of the larger catalogues here. Accepts a bearer token or an x-api-key header. Model ids are fetched live from the provider.",
apiKeyUrl: "https://b.ai",
},
},
category: "apikey",
authType: "apikey",
transport: {
baseUrl: "https://api.b.ai/v1/chat/completions",
validateUrl: "https://api.b.ai/v1/models",
},
// No ids hardcoded: the catalogue is large and rotates, so the live endpoint
// is the source of truth and any id is accepted via passthroughModels.
modelsFetcher: { url: "https://api.b.ai/v1/models", type: "openai" },
passthroughModels: true,
};

View File

@@ -54,6 +54,8 @@ export default {
oauthUrl: "https://api.anthropic.com/api/oauth/usage",
orgUrl: "https://api.anthropic.com/v1/organizations/{org_id}/usage",
settingsUrl: "https://api.anthropic.com/v1/settings",
profileUrl: "https://api.anthropic.com/api/oauth/profile",
resetUrl: "https://api.anthropic.com/api/organizations/{org_id}/reset_rate_limits",
},
},
models: [

View File

@@ -2,7 +2,8 @@ import { withCodexReviewModels } from "../models/helpers.js";
// Codex CLI version seen by OpenAI's backend — single source for the Version /
// User-Agent identity headers. Bump when the installed codex CLI is upgraded.
const CODEX_CLI_VERSION = "0.154.0";
const CODEX_CLI_VERSION = "0.155.0";
const GPT_6_LITE_THINKING_LEVELS = ["low", "medium", "high", "xhigh", "max"];
export default {
id: "codex",
@@ -42,6 +43,7 @@ export default {
headers: {
originator: "codex_cli_rs",
"User-Agent": `codex_cli_rs/${CODEX_CLI_VERSION}`,
version: CODEX_CLI_VERSION,
},
usage: {
url: "https://chatgpt.com/backend-api/wham/usage",
@@ -51,6 +53,8 @@ export default {
},
models: [
{ id: "gpt-6-astra", name: "GPT 6.0 Astra" },
{ id: "gpt-6-sol", name: "GPT 6.0 Sol", responsesLite: true, thinkingLevels: GPT_6_LITE_THINKING_LEVELS },
{ id: "gpt-6-luna", name: "GPT 6.0 Luna", responsesLite: true, thinkingLevels: GPT_6_LITE_THINKING_LEVELS },
{ id: "gpt-5.6-sol", name: "GPT 5.6 Sol" },
{ id: "gpt-5.6-sol-review", name: "GPT 5.6 Sol Review", upstreamModelId: "gpt-5.6-sol", quotaFamily: "review" },
{ id: "gpt-5.6-terra", name: "GPT 5.6 Terra" },

View File

@@ -0,0 +1,35 @@
export default {
id: "dahl",
priority: 120,
alias: "dahl",
aliases: [
"dahl-inference",
],
uiAlias: "dahl",
display: {
name: "Dahl Inference",
icon: "hub",
color: "#1E40AF",
textIcon: "DH",
website: "https://dahl.global",
notice: {
text: "OpenAI-compatible Gonka inference node. Small, fixed catalogue (GLM-5.3-Flash, DeepSeek-V4-Flash, MiniMax-M2.7) at a flat per-token rate.",
apiKeyUrl: "https://dahl.global/dashboard",
},
},
category: "apikey",
authType: "apikey",
transport: {
baseUrl: "https://inference.dahl.global/v1/chat/completions",
validateUrl: "https://inference.dahl.global/v1/models",
},
// The live catalogue is public (no auth), so modelsFetcher works without a key
// and the ids below are a convenience seed rather than an exhaustive list.
models: [
{ id: "zai-org/GLM-5.3-Flash", name: "GLM-5.3 Flash" },
{ id: "deepseek-ai/DeepSeek-V4-Flash-0731", name: "DeepSeek V4 Flash 0731" },
{ id: "MiniMaxAI/MiniMax-M2.7", name: "MiniMax M2.7" },
],
modelsFetcher: { url: "https://inference.dahl.global/v1/models", type: "openai" },
passthroughModels: true,
};

View File

@@ -58,6 +58,7 @@ export default {
{ id: "gemini-2.5-flash", name: "Gemini 2.5 Flash", params: ["language","prompt"], kind: "stt" },
{ id: "gemini-2.5-flash-lite", name: "Gemini 2.5 Flash Lite (Cheapest)", params: ["language","prompt"], kind: "stt" },
{ id: "gemini-2.0-flash", name: "Gemini 2.0 Flash", params: ["language","prompt"], kind: "stt" },
{ id: "gemini-2.5-flash-native-audio-preview-09-17", name: "Gemini Live Transcription (Realtime)", params: ["language","prompt","system_instruction","setup_timeout_ms","turn_timeout_ms"], kind: "stt", transport: "gemini-live" },
{ id: "gemini-3.1-flash-tts-preview", name: "Gemini 3.1 Flash TTS", kind: "tts" },
{ id: "gemini-2.5-flash-preview-tts", name: "Gemini 2.5 Flash TTS", kind: "tts" },
{ id: "gemini-2.5-pro-preview-tts", name: "Gemini 2.5 Pro TTS", kind: "tts" },

View File

@@ -125,6 +125,11 @@ import p119 from "./selfhosted-embedding.js";
import p120 from "./fish-audio.js";
import p121 from "./alitp-intl.js";
import p122 from "./xquik.js";
import p125 from "./tokenharbor.js";
import p126 from "./dahl.js";
import p127 from "./atria.js";
import p129 from "./agnes.js";
import p130 from "./bai.js";
export default [
p0,
p1,
@@ -250,4 +255,9 @@ export default [
p120,
p121,
p122,
p125,
p126,
p127,
p129,
p130,
];

View File

@@ -35,37 +35,56 @@ export default {
],
// supportedFormats follow the endpoint table in https://opencode.ai/docs/go/
models: [
{ id: "deepseek-flash", name: "DeepSeek V4.1 Flash", supportedFormats: ["openai"] },
{ id: "deepseek-flash", name: "DeepSeek Flash", supportedFormats: ["openai"] },
{ id: "glm-5.3-flash", name: "GLM 5.3 Flash (Vision)", supportedFormats: ["openai"] },
{ id: "glm-5.3", name: "GLM 5.3", supportedFormats: ["openai"] },
{ id: "glm-5.2", name: "GLM 5.2", supportedFormats: ["openai"] },
{ id: "glm-5.1", name: "GLM 5.1", supportedFormats: ["openai"] },
{ id: "glm-5", name: "GLM 5", supportedFormats: ["openai"] },
{ id: "kimi-k2.7-code", name: "Kimi K2.7 Code", supportedFormats: ["openai"] },
{ id: "kimi-k2.6", name: "Kimi K2.6", supportedFormats: ["openai"] },
{ id: "kimi-k2.5", name: "Kimi K2.5", supportedFormats: ["openai"] },
{ id: "kimi-k3", name: "Kimi K3", supportedFormats: ["openai"] },
{ id: "deepseek-v4-pro", name: "DeepSeek V4 Pro", supportedFormats: ["openai", "claude", "openai-responses"] },
{ id: "deepseek-v4-flash", name: "DeepSeek V4 Flash", supportedFormats: ["openai", "claude", "openai-responses"] },
{ id: "deepseek-v4-flash-vision-exp", name: "DeepSeek V4 Flash Vision (Exp)", supportedFormats: ["openai", "claude", "openai-responses"] },
{ id: "deepseek-v4.1-flash", name: "DeepSeek V4.1 Flash", supportedFormats: ["openai", "claude", "openai-responses"] },
{ id: "longcat-2.0", name: "LongCat 2.0", supportedFormats: ["openai"] },
{ id: "mimo-v2.6-flash", name: "MiMo V2.6 Flash", supportedFormats: ["openai"] },
{ id: "mimo-v2.6-pro", name: "MiMo V2.6 Pro", supportedFormats: ["openai"] },
{ id: "mimo-v2.5", name: "MiMo V2.5", supportedFormats: ["openai"] },
{ id: "mimo-v2.5-pro", name: "MiMo V2.5 Pro", supportedFormats: ["openai"] },
{ id: "mimo-v2-pro", name: "MiMo V2 Pro", supportedFormats: ["openai"] },
{ id: "mimo-v2-omni", name: "MiMo V2 Omni", supportedFormats: ["openai"] },
{ id: "minimax-m3", name: "MiniMax M3", supportedFormats: ["openai", "claude"] },
{ id: "minimax-m2.7", name: "MiniMax M2.7", supportedFormats: ["openai", "claude"] },
{ id: "minimax-m2.5", name: "MiniMax M2.5", supportedFormats: ["openai", "claude"] },
{ id: "space-bunny-free", name: "Space Bunny Free", supportedFormats: ["openai", "claude"] },
{ id: "qwen3.8-max", name: "Qwen 3.8 Max", supportedFormats: ["openai", "claude"] },
{ id: "qwen3.8-flash", name: "Qwen 3.8 Flash", supportedFormats: ["openai", "claude"] },
{ id: "qwen3.7-max", name: "Qwen 3.7 Max", supportedFormats: ["openai", "claude"] },
{ id: "qwen3.7-plus", name: "Qwen 3.7 Plus", supportedFormats: ["openai", "claude"] },
{ id: "qwen3.6-plus", name: "Qwen 3.6 Plus", supportedFormats: ["openai", "claude"] },
{ id: "qwen3.5-plus", name: "Qwen 3.5 Plus", supportedFormats: ["openai", "claude"] },
{ id: "hy4-preview", name: "Hy4 Preview", supportedFormats: ["openai"] },
{ id: "hy3", name: "Hy3", supportedFormats: ["openai"] },
{ id: "hy3-preview", name: "Hy3 Preview", supportedFormats: ["openai"] },
// In /zen/go/v1/models but absent from the docs endpoint table — chat lane is the fallback guess
{ id: "omen-alpha", name: "Omen Alpha", supportedFormats: ["openai"] },
// Served by /zen/go/v1/responses only — the responses-only entry forces chatCore
// past the sourceFormat-matched transports into translation (see chatCore guard).
{ id: "grok-4.7", name: "Grok 4.7", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
{ id: "grok-4.6", name: "Grok 4.6", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
{ id: "grok-4.5", name: "Grok 4.5", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
{ id: "gpt-5.6-luna", name: "GPT 5.6 Luna", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
{ id: "gpt-6-luna", name: "GPT 6 Luna", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
{ id: "muse-spark-1.2-contributor", name: "Muse Spark 1.2 Contributor", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
{ id: "muse-spark-1.3-contributor", name: "Muse Spark 1.3 Contributor", targetFormat: "openai-responses", supportedFormats: ["openai-responses"] },
],
// Live catalogue; ids outside this curated list get their endpoint lane from the
// family regex in providers/models/helpers.js (opencodeFamilyFormats).
modelsFetcher: { url: "https://opencode.ai/zen/go/v1/models", type: "opencode-go" },
passthroughModels: true,
features: {
usage: true,
usageApikey: true,

View File

@@ -0,0 +1,49 @@
export default {
id: "tokenharbor",
priority: 120,
alias: "tokenharbor",
aliases: [
"th",
"thh",
],
uiAlias: "tokenharbor",
display: {
name: "Token Harbor",
icon: "anchor",
color: "#0F766E",
textIcon: "TH",
website: "https://tokenharbor.ai",
notice: {
text: "OpenAI-compatible aggregator. One API key reaches every model, billed per-token from a prepaid wallet. Model ids are bare (e.g. claude-opus-5.5, gpt-6-astra, deepseek-v4.1-flash:free) and are fetched live from the provider.",
apiKeyUrl: "https://tokenharbor.ai/dashboard",
},
},
category: "apikey",
authType: "apikey",
transport: {
// OpenAI-compatible. `format` is left at the shared "openai" default and
// `thinkingFormat` is deliberately NOT declared: Token Harbor forwards
// requests verbatim, so each model must resolve its own thinking wire
// format through providers/capabilities.js. Setting a provider-wide value
// would force one format (e.g. claude-adaptive) onto every model.
baseUrl: "https://tokenharbor.ai/v1/chat/completions",
validateUrl: "https://tokenharbor.ai/v1/models",
retry: {
429: 2,
},
},
// Curated seed; the live catalogue is fetched via modelsFetcher and any other
// id is accepted via passthroughModels. Their catalogue rotates (the :free set
// in particular), so this stays deliberately small and is only the offline
// fallback. Ids are bare — Token Harbor does not prefix them by upstream vendor.
models: [
{ id: "claude-opus-5.5", name: "Claude Opus 5.5" },
{ id: "claude-sonnet-5", name: "Claude Sonnet 5" },
{ id: "gpt-6-astra", name: "GPT-6 Astra" },
{ id: "gpt-6-sol", name: "GPT-6 Sol" },
{ id: "deepseek-v4.1-flash:free", name: "DeepSeek V4.1 Flash (Free)" },
{ id: "grok-4.7", name: "Grok 4.7" },
],
modelsFetcher: { url: "https://tokenharbor.ai/v1/models", type: "openai" },
passthroughModels: true,
};