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:
29
open-sse/providers/registry/agnes.js
Normal file
29
open-sse/providers/registry/agnes.js
Normal 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,
|
||||
};
|
||||
32
open-sse/providers/registry/atria.js
Normal file
32
open-sse/providers/registry/atria.js
Normal 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,
|
||||
};
|
||||
30
open-sse/providers/registry/bai.js
Normal file
30
open-sse/providers/registry/bai.js
Normal 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,
|
||||
};
|
||||
@@ -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: [
|
||||
|
||||
@@ -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" },
|
||||
|
||||
35
open-sse/providers/registry/dahl.js
Normal file
35
open-sse/providers/registry/dahl.js
Normal 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,
|
||||
};
|
||||
@@ -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" },
|
||||
|
||||
@@ -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,
|
||||
];
|
||||
|
||||
@@ -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,
|
||||
|
||||
49
open-sse/providers/registry/tokenharbor.js
Normal file
49
open-sse/providers/registry/tokenharbor.js
Normal 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,
|
||||
};
|
||||
Reference in New Issue
Block a user