Merge origin/master (v0.5.69) into gitea/new_feature
This commit is contained in:
@@ -6,6 +6,16 @@
|
||||
// 3. PATTERN_CAPABILITIES — glob match, ordered specific -> generic
|
||||
// 4. DEFAULT_CAPABILITIES — safe floor (always returned)
|
||||
//
|
||||
// Two extra layers then refine the result, and neither can override the hand
|
||||
// written tables above (steps 1-2 short-circuit before they are consulted):
|
||||
// • the synced catalog — modalities keyed by model, limits keyed by provider
|
||||
// + model, refreshed from models.dev in the background. It reads a file, so
|
||||
// the server installs it via setCatalogSource(); this module stays free of
|
||||
// node:fs because the dashboard bundles it into the browser too.
|
||||
// • visionPatterns.js — name-based vision detection, last resort so a model
|
||||
// nobody has catalogued yet still accepts images.
|
||||
// Both only ever turn a capability ON.
|
||||
//
|
||||
// ── HOW TO ADD / UPDATE A MODEL ──────────────────────────────────────
|
||||
// Authoritative data source: https://models.dev/api.json (145 providers, 4000+
|
||||
// models, MIT). Each model exposes the exact fields we map below:
|
||||
@@ -23,6 +33,7 @@
|
||||
// 2.0+, Grok, Perplexity). Verify with: curl -s https://models.dev/api.json
|
||||
|
||||
import { matchPattern } from "./pricing.js";
|
||||
import { looksLikeVisionModel } from "./visionPatterns.js";
|
||||
|
||||
/**
|
||||
* Safe floor — every resolved result is merged over this so consumers
|
||||
@@ -46,6 +57,7 @@ export const DEFAULT_CAPABILITIES = {
|
||||
thinkingFormat: null,
|
||||
thinkingCanDisable: true, // false → model cannot turn thinking off (clamp to min instead of disable)
|
||||
thinkingRange: null, // { min, max } for budget formats; null = no clamp
|
||||
thinkingEffortSupported: false, // zai format only: model accepts a reasoning_effort level (GLM-5.2+; older GLM ignores it)
|
||||
// limits (tokens)
|
||||
contextWindow: 200000,
|
||||
maxOutput: 64000,
|
||||
@@ -71,7 +83,8 @@ export function capabilitiesFromServiceKind(kind) {
|
||||
* otherwise mis-match. Only declare deltas vs DEFAULT.
|
||||
*/
|
||||
export const MODEL_CAPABILITIES = {
|
||||
// Claude Opus 5, 4.6/4.7/4.8, and Kiro Sonnet 5 have 1M context + adaptive thinking (override generic claude pattern)
|
||||
// Claude Fable 5.1, Opus 5, 4.6/4.7/4.8, and Kiro Sonnet 5 have 1M context + adaptive thinking (override generic claude pattern)
|
||||
"claude-fable-5-1": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 128000 },
|
||||
"claude-opus-5": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||
"claude-opus-5-thinking": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||
"claude-opus-5-agentic": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||
@@ -94,8 +107,14 @@ export const MODEL_CAPABILITIES = {
|
||||
// Gemini image-gen / OpenAI image / xai image variants
|
||||
"gpt-image-1": { imageOutput: true, tools: false },
|
||||
|
||||
// GLM vision variant (text GLM has no vision)
|
||||
"glm-4.6v": { vision: true, reasoning: true, thinkingFormat: "zai", contextWindow: 128000 },
|
||||
// GLM vision variants (text GLM has no vision) — 5.3-Flash and 5V-Turbo are
|
||||
// natively multimodal per z.ai, and 5.3-Flash carries the full 1M window.
|
||||
"glm-5.3-flash": { vision: true, videoInput: true, pdf: true, reasoning: true, thinkingFormat: "zai", contextWindow: 1000000, maxOutput: 131072 },
|
||||
"glm-4.6v": { vision: true, videoInput: true, reasoning: true, thinkingFormat: "zai", contextWindow: 128000, maxOutput: 32768 },
|
||||
"glm-4.5v": { vision: true, videoInput: true, reasoning: true, thinkingFormat: "zai", contextWindow: 64000, maxOutput: 16384 },
|
||||
|
||||
// DeepSeek's first V4 model with image input; text limits match V4-Flash.
|
||||
"deepseek-v4-flash-vision-exp": { vision: true, reasoning: true, thinkingFormat: "deepseek", contextWindow: 1000000, maxOutput: 384000 },
|
||||
|
||||
// Qwen plain coder/text (no vision) — registry "vision-model" / "coder-model" aliases
|
||||
"vision-model": { vision: true, reasoning: true, thinkingFormat: "qwen", contextWindow: 1000000 },
|
||||
@@ -108,6 +127,10 @@ export const MODEL_CAPABILITIES = {
|
||||
"kimi-for-coding-highspeed": { vision: true, videoInput: true, reasoning: true, thinkingFormat: "kimi", thinkingCanDisable: false, contextWindow: 262144, maxOutput: 65536 },
|
||||
"kimi-k2.7-code": { vision: true, videoInput: true, reasoning: true, thinkingFormat: "kimi", thinkingCanDisable: false, contextWindow: 262144, maxOutput: 65536 },
|
||||
"kimi-k2.7-code-highspeed": { vision: true, videoInput: true, reasoning: true, thinkingFormat: "kimi", thinkingCanDisable: false, contextWindow: 262144, maxOutput: 65536 },
|
||||
// OpenCode Free Muse Spark — multimodal (text+image per models.dev meta/muse-spark)
|
||||
// via OpenAI Responses input_image; reasoning supports up to xhigh.
|
||||
"muse-spark-1.2-contributor-free": { vision: true, reasoning: true, thinkingFormat: "openai", contextWindow: 1048576, maxOutput: 131072 },
|
||||
"muse-spark-1.3-contributor-free": { vision: true, reasoning: true, thinkingFormat: "openai", contextWindow: 1048576, maxOutput: 131072 },
|
||||
};
|
||||
|
||||
const KIRO_GPT_5_6_CAPABILITIES = { vision: true, reasoning: true, search: true, thinkingFormat: "openai", contextWindow: 272000, maxOutput: 128000 };
|
||||
@@ -131,6 +154,7 @@ export const PROVIDER_CAPABILITIES = {
|
||||
"deepseek-ai/deepseek-v4-flash": { reasoning: true, thinkingFormat: "openai", contextWindow: 1000000, maxOutput: 65536 },
|
||||
},
|
||||
"codex": {
|
||||
"gpt-6-astra": { vision: true, reasoning: true, search: true, thinkingFormat: "openai", contextWindow: 272000, maxOutput: 128000 },
|
||||
"gpt-5.6-sol": CODEX_GPT_56_SOL_CAPS,
|
||||
"gpt-5.6-sol-review": CODEX_GPT_56_SOL_CAPS,
|
||||
"gpt-5.6-terra": CODEX_GPT_56_DEFAULT_CAPS,
|
||||
@@ -155,24 +179,69 @@ export const PROVIDER_CAPABILITIES = {
|
||||
// CodeBuddy.cn — authoritative per-model metadata from the gateway's model
|
||||
// config (contextWindow=maxInputTokens, maxOutput=maxOutputTokens, vision=
|
||||
// supportsImages). Every model reasons via OpenAI-style reasoning_effort
|
||||
// (see registry thinkingFormat). `onlyReasoning` models can't turn thinking
|
||||
// off → thinkingCanDisable:false (clamped to minimal instead of disabled).
|
||||
// (see registry thinkingFormat). For thinkingCanDisable use the server's
|
||||
// reasoning.canDisableThinking flag — see the note in the codebuddy-cn block
|
||||
// below; it is NOT the inverse of onlyReasoning.
|
||||
"codebuddy-cn": {
|
||||
"glm-5.2": { reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 48000 },
|
||||
"glm-5.1": { reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 200000, maxOutput: 48000 },
|
||||
"glm-5.2": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: true, contextWindow: 1000000, maxOutput: 48000 },
|
||||
"glm-5.1": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 200000, maxOutput: 48000 },
|
||||
"glm-5.0": { reasoning: true, thinkingFormat: "openai", contextWindow: 200000, maxOutput: 48000 },
|
||||
"glm-5.0-turbo": { reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 200000, maxOutput: 48000 },
|
||||
"glm-5v-turbo": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 200000, maxOutput: 38000 },
|
||||
// maxOutput 64000 per both the plugin-baked fallback and the live server
|
||||
// table (the old 38000 had no source and truncated output).
|
||||
"glm-5v-turbo": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 200000, maxOutput: 64000 },
|
||||
"glm-4.7": { reasoning: true, thinkingFormat: "openai", contextWindow: 200000, maxOutput: 48000 },
|
||||
"minimax-m3": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 512000, maxOutput: 48000 },
|
||||
"minimax-m2.7": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 200000, maxOutput: 48000 },
|
||||
"minimax-m3": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 512000, maxOutput: 128000 },
|
||||
"kimi-k2.7": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 256000, maxOutput: 32000 },
|
||||
"kimi-k2.6": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 256000, maxOutput: 32000 },
|
||||
"kimi-k2.5": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 164000, maxOutput: 32000 },
|
||||
"hy3-preview": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 192000, maxOutput: 64000 },
|
||||
"deepseek-v4-pro": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 50000 },
|
||||
"deepseek-v4-flash": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 50000 },
|
||||
"deepseek-v3-2-volc": { reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 96000, maxOutput: 32000 },
|
||||
// Per-model values mirror the server's product-config payload (the plugin
|
||||
// fetches it from copilot.tencent.com; the `models[]` entries carry
|
||||
// maxInputTokens/maxOutputTokens/supportsImages). contextWindow =
|
||||
// maxInputTokens, maxOutput = maxOutputTokens. Where the server and the
|
||||
// plugin-baked fallback disagree, the server table wins.
|
||||
// ⚠️ thinkingCanDisable maps to the server's reasoning.canDisableThinking —
|
||||
// it is NOT the inverse of onlyReasoning. onlyReasoning means "thinking is
|
||||
// on by default"; canDisableThinking means "it CAN be turned off". glm-5.3
|
||||
// and glm-5.3-flash are onlyReasoning:true BUT canDisableThinking:true, so
|
||||
// their thinking is switchable; the hy* models are forced always-on.
|
||||
"hy3": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 192000, maxOutput: 64000 },
|
||||
"hy4-preview": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 64000 },
|
||||
"glm-5.3": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: true, contextWindow: 1000000, maxOutput: 48000 },
|
||||
"glm-5.3-flash": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: true, contextWindow: 1000000, maxOutput: 32000 },
|
||||
"kimi-k3-1": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 32000 },
|
||||
"deepseek-v4-pro": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: true, contextWindow: 1000000, maxOutput: 50000 },
|
||||
"deepseek-v4-flash": { vision: true, reasoning: true, thinkingFormat: "openai", thinkingCanDisable: true, contextWindow: 1000000, maxOutput: 50000 },
|
||||
},
|
||||
// Qoder — upstream exposes opaque internal ids (dfmodel, kmodel, …); the
|
||||
// registry `name` is display-only and capability lookup matches on the raw
|
||||
// id, so every qoder model would fall through to DEFAULT_CAPABILITIES
|
||||
// (200K) without this map. contextWindow follows the real model family's
|
||||
// spec: the /algo/api/v2/model/list max_input_tokens under-reports some
|
||||
// windows (GLM-5.3 / Kimi-K3 / Qwen3.8-Max claim 180K but accept more).
|
||||
// max_output_tokens arrives as 0 for every model, so outputs are
|
||||
// best-guess from the real model family. Vision tags below follow the
|
||||
// upstream is_vl flag per explicit request, even though the executor
|
||||
// currently sends image_urls:null (image pass-through over the agent_chat
|
||||
// SSE protocol is unverified). reasoning:true on all of them — every model can
|
||||
// reason; the upstream is_reasoning flag only drives model_config selection.
|
||||
// thinkingFormat keeps the true-model family for documentation/UI, but
|
||||
// thinkingCanDisable:false everywhere: the executor only forwards
|
||||
// messages/tools/max_tokens, and thinking is fixed upstream via
|
||||
// modelConfig.is_reasoning — client thinking intent is dropped, so "none"
|
||||
// must never be offered as an option.
|
||||
"qoder": {
|
||||
"ultimate": { vision: true, reasoning: true, thinkingFormat: "claude-adaptive", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 128000 }, // Claude Opus 5
|
||||
"performance": { vision: true, reasoning: true, thinkingFormat: "claude-adaptive", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 128000 }, // Claude Sonnet 5
|
||||
"dmodel": { reasoning: true, thinkingFormat: "deepseek", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // DeepSeek-V4-Pro
|
||||
"dfmodel": { reasoning: true, thinkingFormat: "deepseek", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // DeepSeek-V4-Flash
|
||||
"gmodel": { reasoning: true, thinkingFormat: "zai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 128000 }, // GLM-5.3
|
||||
"gfmodel": { vision: true, reasoning: true, thinkingFormat: "zai", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 128000 }, // GLM-5.3-Flash
|
||||
"kmodel_latest": { vision: true, reasoning: true, thinkingFormat: "kimi", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // Kimi-K3
|
||||
"kmodel": { vision: true, reasoning: true, thinkingFormat: "kimi", thinkingCanDisable: false, contextWindow: 256000, maxOutput: 65536 }, // Kimi-K2.7-Code
|
||||
"mmodel": { reasoning: true, thinkingFormat: "minimax", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 512000 }, // MiniMax-M3
|
||||
"qmodel_latest": { vision: true, reasoning: true, thinkingFormat: "qwen", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // Qwen3.7-Max
|
||||
"qmodel": { vision: true, reasoning: true, thinkingFormat: "qwen", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // Qwen3.7-Plus
|
||||
"qfmodel": { vision: true, reasoning: true, thinkingFormat: "qwen", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // Qwen3.8-Flash
|
||||
"qmodel_38max": { vision: true, reasoning: true, thinkingFormat: "qwen", thinkingCanDisable: false, contextWindow: 1000000, maxOutput: 65536 }, // Qwen3.8-Max
|
||||
},
|
||||
// Poolside Laguna — OpenAI-compatible, all reasoning-capable (32K max output).
|
||||
"poolside": {
|
||||
@@ -205,6 +274,7 @@ export const PATTERN_CAPABILITIES = [
|
||||
|
||||
// ── Gemini (all 2.0+ multimodal + google_search grounding, 1M ctx) ─
|
||||
{ pattern: "*gemini*image*", caps: { vision: true, imageOutput: true, contextWindow: 1048576 } },
|
||||
{ pattern: "*gemini-3.8*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, search: true, thinkingFormat: "gemini-level", thinkingCanDisable: false, contextWindow: 1048576, maxOutput: 65536 } },
|
||||
{ pattern: "*gemini-3.7*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, search: true, thinkingFormat: "gemini-level", thinkingCanDisable: false, contextWindow: 1048576, maxOutput: 65536 } },
|
||||
{ pattern: "*gemini-3*pro*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, search: true, thinkingFormat: "gemini-level", thinkingCanDisable: false, contextWindow: 1048576, maxOutput: 65535 } },
|
||||
{ pattern: "*gemini-3*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, search: true, thinkingFormat: "gemini-level", thinkingCanDisable: false, contextWindow: 1048576, maxOutput: 65536 } },
|
||||
@@ -214,6 +284,9 @@ export const PATTERN_CAPABILITIES = [
|
||||
{ pattern: "*gemma*", caps: { vision: true, contextWindow: 128000 } },
|
||||
{ pattern: "*nanobanana*", caps: { vision: true, imageOutput: true } },
|
||||
|
||||
// ── OpenAI GPT-6.x (vision + thinking + web search) ──────────────
|
||||
{ pattern: "*gpt-6*", caps: { vision: true, reasoning: true, search: true, thinkingFormat: "openai", contextWindow: 272000, maxOutput: 128000 } },
|
||||
|
||||
// ── OpenAI GPT-5.x (vision + thinking + web search) ──────────────
|
||||
{ pattern: "*gpt-5*image*", caps: { imageOutput: true } },
|
||||
{ pattern: "*gpt-5*codex*", caps: { reasoning: true, search: true, thinkingFormat: "openai", contextWindow: 400000, maxOutput: 128000 } },
|
||||
@@ -234,6 +307,8 @@ export const PATTERN_CAPABILITIES = [
|
||||
// ── Grok (vision + Live Search) ──────────────────────────────────
|
||||
{ pattern: "*grok*image*", caps: { imageOutput: true } },
|
||||
{ pattern: "*grok-code*", caps: { reasoning: true, thinkingFormat: "openai", contextWindow: 256000 } },
|
||||
// Grok 4.6: 500k context, no text output limit (docs.x.ai/developers/grok-4-6)
|
||||
{ pattern: "*grok-4.6*", caps: { vision: true, reasoning: true, search: true, thinkingFormat: "openai", contextWindow: 500000, maxOutput: 500000 } },
|
||||
// Grok 4.5 (Grok CLI / Grok Build): 500k context per cli-chat-proxy /v1/models
|
||||
{ pattern: "*grok-4.5*", caps: { vision: true, reasoning: true, search: true, thinkingFormat: "openai", contextWindow: 500000, maxOutput: 64000 } },
|
||||
{ pattern: "*grok-4*", caps: { vision: true, reasoning: true, search: true, thinkingFormat: "openai", contextWindow: 256000 } },
|
||||
@@ -261,6 +336,10 @@ export const PATTERN_CAPABILITIES = [
|
||||
{ pattern: "*kimi*", caps: { reasoning: true, thinkingFormat: "kimi", contextWindow: 262144 } },
|
||||
|
||||
// ── GLM / Z.ai (thinking.enabled; disable via enable_thinking:false) ─
|
||||
// reasoning_effort is only read by z.ai from GLM-5.2 onward (docs.z.ai/guides/capabilities/thinking) —
|
||||
// older GLM (4.x, 5.0, 5.1, 5-turbo, 5v-turbo) ignore it, so gate it per exact version, not the "*glm-5*" catch-all.
|
||||
{ pattern: "*glm-5.3*", caps: { reasoning: true, thinkingFormat: "zai", thinkingEffortSupported: true, contextWindow: 200000, maxOutput: 128000 } },
|
||||
{ pattern: "*glm-5.2*", caps: { reasoning: true, thinkingFormat: "zai", thinkingEffortSupported: true, contextWindow: 200000, maxOutput: 128000 } },
|
||||
{ pattern: "*glm-5*", caps: { reasoning: true, thinkingFormat: "zai", contextWindow: 200000, maxOutput: 128000 } },
|
||||
{ pattern: "*glm-4.7*", caps: { reasoning: true, thinkingFormat: "zai", contextWindow: 200000, maxOutput: 128000 } },
|
||||
{ pattern: "*glm-4*", caps: { reasoning: true, thinkingFormat: "zai", contextWindow: 200000 } },
|
||||
@@ -309,6 +388,9 @@ export const PATTERN_CAPABILITIES = [
|
||||
{ pattern: "*laguna-s-2.1*", caps: { reasoning: true, thinkingFormat: "openai", contextWindow: 1000000, maxOutput: 32000 } },
|
||||
{ pattern: "*laguna*", caps: { reasoning: true, thinkingFormat: "openai", contextWindow: 200000, maxOutput: 32000 } },
|
||||
|
||||
|
||||
// ── OpenCode Free Muse Spark (multimodal text+image; OpenAI Responses reasoning supports up to xhigh) ─
|
||||
{ pattern: "*muse*spark*", caps: { vision: true, reasoning: true, thinkingFormat: "openai", contextWindow: 1048576, maxOutput: 131072 } },
|
||||
// ── Others ───────────────────────────────────────────────────────
|
||||
{ pattern: "*hunyuan*", caps: { reasoning: true, thinkingFormat: "hunyuan", contextWindow: 262144, maxOutput: 262144 } },
|
||||
{ pattern: "hy3*", caps: { reasoning: true, thinkingFormat: "hunyuan", contextWindow: 262144, maxOutput: 262144 } },
|
||||
@@ -330,6 +412,46 @@ const TRUST_UPSTREAM_VISION = new Set(["openrouter"]);
|
||||
* @param {string} model
|
||||
* @returns {object} full capabilities object
|
||||
*/
|
||||
const MODALITY_KEYS = ["vision", "pdf", "audioInput", "videoInput"];
|
||||
|
||||
// Catalog lookups, installed by the server at startup. Left as no-ops in the
|
||||
// browser bundle, where there is no file to read.
|
||||
let catalogSource = null;
|
||||
|
||||
/**
|
||||
* Install the synced catalog reader (server only).
|
||||
* @param {{ getModalities: Function, getLimits: Function } | null} source
|
||||
*/
|
||||
export function setCatalogSource(source) {
|
||||
catalogSource = source;
|
||||
}
|
||||
|
||||
// Apply the synced catalog + name heuristic on top of a table-resolved result.
|
||||
// Strictly additive: a capability already true stays true, and a false one only
|
||||
// flips when an outside source positively declares support.
|
||||
function refine(base, provider, model) {
|
||||
const result = { ...DEFAULT_CAPABILITIES, ...base };
|
||||
|
||||
if (catalogSource) {
|
||||
const modalities = catalogSource.getModalities(model);
|
||||
if (modalities) {
|
||||
for (const key of MODALITY_KEYS) {
|
||||
if (modalities[key] === true) result[key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
const limits = catalogSource.getLimits(provider, model);
|
||||
if (limits) {
|
||||
if (limits.contextWindow > 0) result.contextWindow = limits.contextWindow;
|
||||
if (limits.maxOutput > 0) result.maxOutput = limits.maxOutput;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.vision && looksLikeVisionModel(model)) result.vision = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getCapabilitiesForModel(provider, model) {
|
||||
if (!model) return { ...DEFAULT_CAPABILITIES };
|
||||
|
||||
@@ -347,16 +469,13 @@ export function getCapabilitiesForModel(provider, model) {
|
||||
if (MODEL_CAPABILITIES[baseModel]) return { ...DEFAULT_CAPABILITIES, ...MODEL_CAPABILITIES[baseModel] };
|
||||
if (MODEL_CAPABILITIES[model]) return { ...DEFAULT_CAPABILITIES, ...MODEL_CAPABILITIES[model] };
|
||||
|
||||
// 3. Pattern match (first match wins)
|
||||
// 3. Pattern match (first match wins), refined by catalog + name heuristic
|
||||
for (const { pattern, caps } of PATTERN_CAPABILITIES) {
|
||||
if (matchPattern(pattern, baseModel) || matchPattern(pattern, model)) {
|
||||
return { ...DEFAULT_CAPABILITIES, ...caps };
|
||||
return refine(caps, provider, model);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Floor (upstream-validated gateways keep vision on for unknown models)
|
||||
if (provider && TRUST_UPSTREAM_VISION.has(provider)) {
|
||||
return { ...DEFAULT_CAPABILITIES, vision: true };
|
||||
}
|
||||
return { ...DEFAULT_CAPABILITIES };
|
||||
// 4. Floor
|
||||
return refine(null, provider, model);
|
||||
}
|
||||
|
||||
72
open-sse/providers/catalogOverride.js
Normal file
72
open-sse/providers/catalogOverride.js
Normal file
@@ -0,0 +1,72 @@
|
||||
// Read side of the model catalog synced from models.dev.
|
||||
//
|
||||
// The file is the source of truth; the only thing held in memory is a parsed
|
||||
// copy dropped as soon as the file's mtime changes. getCapabilitiesForModel is
|
||||
// synchronous and runs per request, so the hot path is one stat (~1us) and the
|
||||
// parse (~0.1ms on a ~18KB file) only reruns after a sync.
|
||||
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { DATA_DIR } from "@/lib/dataDir.js";
|
||||
|
||||
export const CATALOG_FILE = path.join(DATA_DIR, "model-catalog.json");
|
||||
// Trimmed upstream catalog, read by the add-models skill (not by the router).
|
||||
export const CATALOG_RAW_FILE = path.join(DATA_DIR, "model-catalog-raw.json");
|
||||
|
||||
const EMPTY = { models: {}, providers: {} };
|
||||
let cache = EMPTY;
|
||||
let cachedMtime = -1;
|
||||
|
||||
// "zai-org/GLM-4.6V:free" -> "glm-4.6v"
|
||||
function baseId(model) {
|
||||
if (!model) return "";
|
||||
const withoutVendor = model.includes("/") ? model.split("/").pop() : model;
|
||||
return withoutVendor.toLowerCase().split(":")[0];
|
||||
}
|
||||
|
||||
function load() {
|
||||
let mtime;
|
||||
try {
|
||||
mtime = fs.statSync(CATALOG_FILE).mtimeMs;
|
||||
} catch {
|
||||
cache = EMPTY;
|
||||
cachedMtime = -1;
|
||||
return cache;
|
||||
}
|
||||
if (mtime === cachedMtime) return cache;
|
||||
|
||||
cachedMtime = mtime;
|
||||
try {
|
||||
const parsed = JSON.parse(fs.readFileSync(CATALOG_FILE, "utf8"));
|
||||
cache = { models: parsed?.models || {}, providers: parsed?.providers || {} };
|
||||
} catch {
|
||||
cache = EMPTY;
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
// Modality is a property of the model itself — any gateway serving it inherits
|
||||
// the same image/video/pdf support, so this is keyed by model id alone.
|
||||
export function getCatalogModalities(model) {
|
||||
return load().models[baseId(model)] || null;
|
||||
}
|
||||
|
||||
// Context and output limits are a property of the gateway, not the model: each
|
||||
// one truncates differently, so these stay keyed by provider + model.
|
||||
export function getCatalogLimits(provider, model) {
|
||||
const byProvider = provider && load().providers[provider];
|
||||
if (!byProvider) return null;
|
||||
return byProvider[model] || byProvider[baseId(model)] || null;
|
||||
}
|
||||
|
||||
// Force a re-read on the next lookup (called right after a sync writes the file).
|
||||
export function invalidateCatalog() {
|
||||
cachedMtime = -1;
|
||||
}
|
||||
|
||||
// Hand the reader to capabilities.js. That module is bundled into the browser
|
||||
// too, so it cannot import this file directly — the server pushes it in.
|
||||
export async function installCatalogSource() {
|
||||
const { setCatalogSource } = await import("./capabilities.js");
|
||||
setCatalogSource({ getModalities: getCatalogModalities, getLimits: getCatalogLimits });
|
||||
}
|
||||
@@ -18,3 +18,10 @@ export function withCodexReviewModels(models) {
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
export function isMuseSparkModel(modelId) {
|
||||
if (!modelId || typeof modelId !== "string") return false;
|
||||
const clean = modelId.replace(/\([^()]+\)\s*$/, "").trim();
|
||||
const base = clean.includes("/") ? clean.split("/").pop() : clean;
|
||||
return /^muse[-_]?spark(?:$|[-_:.\s])/i.test(base);
|
||||
}
|
||||
|
||||
@@ -53,10 +53,15 @@ export const MODEL_PRICING = {
|
||||
"gpt-5.6-luna": { input: 1.00, output: 6.00, cached: 0.10, reasoning: 6.00, cache_creation: 1.00 },
|
||||
"gpt-5.6-terra": { input: 2.50, output: 15.00, cached: 0.25, reasoning: 15.00, cache_creation: 2.50 },
|
||||
"gpt-5.6-sol": { input: 5.00, output: 30.00, cached: 0.50, reasoning: 30.00, cache_creation: 5.00 },
|
||||
"gpt-6-astra": { input: 5.00, output: 30.00, cached: 0.50, reasoning: 30.00, cache_creation: 5.00 },
|
||||
"o1": { input: 15.00, output: 60.00, cached: 7.50, reasoning: 90.00, cache_creation: 15.00 },
|
||||
"o1-mini": { input: 3.00, output: 12.00, cached: 1.50, reasoning: 18.00, cache_creation: 3.00 },
|
||||
|
||||
// === Gemini ===
|
||||
"gemini-3.8-flash": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||
"gemini-3.8-flash-high": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||
"gemini-3.8-flash-medium": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||
"gemini-3.8-flash-low": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||
"gemini-3.7-flash": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||
"gemini-3.7-flash-high": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||
"gemini-3.7-flash-medium": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||
@@ -260,6 +265,7 @@ export const PROVIDER_PRICING = {
|
||||
"z-ai/glm-5-turbo": { input: 1.2, output: 4.0, cached: 0.24, reasoning: 4.0 },
|
||||
"z-ai/glm-5.1": { input: 1.05, output: 3.5, cached: 0.525, reasoning: 3.5 },
|
||||
"z-ai/glm-5.2": { input: 1.4, output: 4.4, cached: 0.26, reasoning: 4.4 },
|
||||
"z-ai/glm-5.3-free": { input: 0, output: 0, cached: 0, reasoning: 0 },
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ export default {
|
||||
deprecationNotice: "RISK_NOTICE",
|
||||
},
|
||||
category: "oauth",
|
||||
serviceKinds: ["llm", "image"],
|
||||
serviceKinds: ["llm", "image", "webSearch"],
|
||||
transport: {
|
||||
baseUrls: [ANTIGRAVITY_IDE_BASE_URL],
|
||||
format: "antigravity",
|
||||
@@ -36,8 +36,7 @@ export default {
|
||||
},
|
||||
},
|
||||
usage: {
|
||||
// Discovery (quota/project) on PROD; daily host rejects these.
|
||||
quotaApiUrl: "https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels",
|
||||
quotaApiUrl: `${ANTIGRAVITY_IDE_BASE_URL}/v1internal:fetchAvailableModels`,
|
||||
loadProjectApiUrl: "https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist",
|
||||
tokenUrl: "https://oauth2.googleapis.com/token",
|
||||
},
|
||||
@@ -45,6 +44,10 @@ export default {
|
||||
clientSecret: "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",
|
||||
},
|
||||
models: [
|
||||
{ id: "gemini-3.8-flash-high", name: "Gemini 3.8 Flash (High)", upstreamModelId: "gemini-3.8-flash-high(high)" },
|
||||
{ id: "gemini-3.8-flash-medium", name: "Gemini 3.8 Flash (Medium)", upstreamModelId: "gemini-3.8-flash-medium(medium)" },
|
||||
{ id: "gemini-3.8-flash-low", name: "Gemini 3.8 Flash (Low)", upstreamModelId: "gemini-3.8-flash-low(low)" },
|
||||
{ id: "gemini-3.8-flash", name: "Gemini 3.8 Flash", upstreamModelId: "gemini-3.8-flash-medium(medium)" },
|
||||
{ id: "gemini-3.7-flash-high", name: "Gemini 3.7 Flash (High)", upstreamModelId: "gemini-3.7-flash-tiered(high)" },
|
||||
{ id: "gemini-3.7-flash-medium", name: "Gemini 3.7 Flash (Medium)", upstreamModelId: "gemini-3.7-flash-tiered(medium)" },
|
||||
{ id: "gemini-3.7-flash-low", name: "Gemini 3.7 Flash (Low)", upstreamModelId: "gemini-3.7-flash-tiered(low)" },
|
||||
@@ -82,6 +85,11 @@ export default {
|
||||
loadCodeAssistUserAgent: ANTIGRAVITY_IDE_USER_AGENT,
|
||||
refreshLeadMs: 300000,
|
||||
},
|
||||
searchViaChat: {
|
||||
defaultModel: "gemini-2.5-flash",
|
||||
endpoint: `${ANTIGRAVITY_IDE_BASE_URL}/v1internal:generateContent`,
|
||||
freeTier: "Free — Google Search grounding through an Antigravity OAuth account.",
|
||||
},
|
||||
features: {
|
||||
usage: true,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CLAUDE_CLI_SPOOF_HEADERS } from "../shared.js";
|
||||
import { CLAUDE_CLI_VERSION } from "../shared.js";
|
||||
|
||||
export default {
|
||||
id: "claude",
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
"Anthropic-Version": "2023-06-01",
|
||||
"Anthropic-Beta": "claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05,advanced-tool-use-2025-11-20,effort-2025-11-24,structured-outputs-2025-12-15,fast-mode-2026-02-01,redact-thinking-2026-02-12,token-efficient-tools-2026-03-28",
|
||||
"Anthropic-Dangerous-Direct-Browser-Access": "true",
|
||||
"User-Agent": "claude-cli/2.1.92 (external, sdk-cli)",
|
||||
"User-Agent": `claude-cli/${CLAUDE_CLI_VERSION} (external, sdk-cli)`,
|
||||
"X-App": "cli",
|
||||
"X-Stainless-Helper-Method": "stream",
|
||||
"X-Stainless-Retry-Count": "0",
|
||||
@@ -58,6 +58,7 @@ export default {
|
||||
},
|
||||
models: [
|
||||
{ id: "claude-opus-5", name: "Claude Opus 5" },
|
||||
{ id: "claude-fable-5-1", name: "Claude Fable 5.1" },
|
||||
{ id: "claude-fable-5", name: "Claude Fable 5" },
|
||||
{ id: "claude-sonnet-5", name: "Claude Sonnet 5" },
|
||||
{ id: "claude-haiku-4-5-20251001", name: "Claude 4.5 Haiku" },
|
||||
|
||||
@@ -47,19 +47,26 @@ export default {
|
||||
models: [
|
||||
{ id: "glm-5.2", name: "GLM-5.2" },
|
||||
{ id: "glm-5.1", name: "GLM-5.1" },
|
||||
{ id: "glm-5.0", name: "GLM-5.0" },
|
||||
{ id: "glm-5.0-turbo", name: "GLM-5.0-Turbo" },
|
||||
{ id: "glm-5v-turbo", name: "GLM-5v-Turbo" },
|
||||
{ id: "glm-4.7", name: "GLM-4.7" },
|
||||
{ id: "minimax-m3", name: "MiniMax-M3" },
|
||||
{ id: "minimax-m2.7", name: "MiniMax-M2.7" },
|
||||
{ id: "kimi-k2.7", name: "Kimi-K2.7-Code" },
|
||||
{ id: "kimi-k2.6", name: "Kimi-K2.6" },
|
||||
{ id: "kimi-k2.5", name: "Kimi-K2.5" },
|
||||
{ id: "hy3-preview", name: "Hy3 Preview" },
|
||||
// Catalog mirrors the server's product-config payload (the plugin fetches
|
||||
// it from copilot.tencent.com). Models the server no longer publishes are
|
||||
// removed even when the chat endpoint still answers them — the published
|
||||
// list is the contract. Drop log: glm-5.0 / glm-4.7 and hy4-preview-x
|
||||
// (endpoint returns 11102 "model service info not found"), plus
|
||||
// glm-5.0-turbo / minimax-m2.7 / kimi-k2.5 / hy3-preview /
|
||||
// deepseek-v3-2-volc (absent from the server list, though still answering
|
||||
// 200) and hy3-x (paid tier, not used here).
|
||||
// "-x" suffix = paid tier of the same model (free id rides the promo quota).
|
||||
{ id: "hy3", name: "Hy3" },
|
||||
{ id: "hy4-preview", name: "Hy4-Preview" },
|
||||
{ id: "glm-5.3", name: "GLM-5.3" },
|
||||
{ id: "glm-5.3-flash", name: "GLM-5.3-Flash" },
|
||||
{ id: "kimi-k3-1", name: "Kimi-K3" },
|
||||
{ id: "deepseek-v4-pro", name: "DeepSeek-V4-Pro" },
|
||||
{ id: "deepseek-v4-flash", name: "DeepSeek-V4-Flash" },
|
||||
{ id: "deepseek-v3-2-volc", name: "DeepSeek-V3.2" },
|
||||
],
|
||||
oauth: {
|
||||
baseUrl: "https://copilot.tencent.com",
|
||||
|
||||
@@ -45,6 +45,7 @@ export default {
|
||||
},
|
||||
},
|
||||
models: [
|
||||
{ id: "gpt-6-astra", name: "GPT 6.0 Astra" },
|
||||
{ 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" },
|
||||
@@ -59,6 +60,9 @@ export default {
|
||||
{ id: "gpt-5.4-mini-review", name: "GPT 5.4 Mini Review", upstreamModelId: "gpt-5.4-mini", quotaFamily: "review" },
|
||||
{ id: "gpt-5.3-codex-spark", name: "GPT 5.3 Codex Spark" },
|
||||
{ id: "gpt-5.3-codex-spark-review", name: "GPT 5.3 Codex Spark Review", upstreamModelId: "gpt-5.3-codex-spark", quotaFamily: "review" },
|
||||
{ id: "gpt-5.6-sol-image", name: "GPT 5.6 Sol Image", capabilities: ["text2img","edit"], params: ["size","quality","background","image_detail","output_format"], kind: "image" },
|
||||
{ id: "gpt-5.6-terra-image", name: "GPT 5.6 Terra Image", capabilities: ["text2img","edit"], params: ["size","quality","background","image_detail","output_format"], kind: "image" },
|
||||
{ id: "gpt-5.6-luna-image", name: "GPT 5.6 Luna Image", capabilities: ["text2img","edit"], params: ["size","quality","background","image_detail","output_format"], kind: "image" },
|
||||
{ id: "gpt-5.5-image", name: "GPT 5.5 Image", capabilities: ["text2img","edit"], params: ["size","quality","background","image_detail","output_format"], kind: "image" },
|
||||
{ id: "gpt-5.4-image", name: "GPT 5.4 Image", capabilities: ["text2img","edit"], params: ["size","quality","background","image_detail","output_format"], kind: "image" },
|
||||
{ id: "gpt-5.3-image", name: "GPT 5.3 Image", capabilities: ["text2img","edit"], params: ["size","quality","background","image_detail","output_format"], kind: "image" },
|
||||
|
||||
@@ -45,6 +45,7 @@ export default {
|
||||
{ id: "deepseek-v4-pro-max", name: "DeepSeek V4 Pro Max", upstreamModelId: "deepseek-v4-pro" },
|
||||
{ id: "deepseek-v4-pro-none", name: "DeepSeek V4 Pro No Thinking", upstreamModelId: "deepseek-v4-pro" },
|
||||
{ id: "deepseek-v4-flash", name: "DeepSeek V4 Flash" },
|
||||
{ id: "deepseek-v4-flash-vision-exp", name: "DeepSeek V4 Flash Vision (Exp)" },
|
||||
{ id: "deepseek-chat", name: "DeepSeek V3.2 Chat" },
|
||||
{ id: "deepseek-reasoner", name: "DeepSeek V3.2 Reasoner" },
|
||||
],
|
||||
|
||||
@@ -36,6 +36,7 @@ export default {
|
||||
},
|
||||
},
|
||||
models: [
|
||||
{ id: "gemini-3.8-flash", name: "Gemini 3.8 Flash" },
|
||||
{ id: "gemini-3.7-flash", name: "Gemini 3.7 Flash" },
|
||||
{ id: "gemini-3.6-flash", name: "Gemini 3.6 Flash" },
|
||||
{ id: "gemini-3.5-flash-lite", name: "Gemini 3.5 Flash Lite" },
|
||||
|
||||
@@ -22,10 +22,13 @@ export default {
|
||||
},
|
||||
models: [
|
||||
{ id: "glm-5.3", name: "GLM 5.3" },
|
||||
{ id: "glm-5.3-flash", name: "GLM 5.3 Flash (Vision)" },
|
||||
{ id: "glm-5.2", name: "GLM 5.2" },
|
||||
{ id: "glm-5.1", name: "GLM 5.1" },
|
||||
{ id: "glm-5-turbo", name: "GLM 5 Turbo" },
|
||||
{ id: "glm-5", name: "GLM 5" },
|
||||
{ id: "glm-4.7", name: "GLM-4.7" },
|
||||
{ id: "glm-4.6v", name: "GLM 4.6V (Vision)" },
|
||||
{ id: "glm-4.6", name: "GLM-4.6" },
|
||||
{ id: "glm-4.5-air", name: "GLM-4.5-Air" },
|
||||
],
|
||||
|
||||
@@ -46,12 +46,28 @@ export default {
|
||||
],
|
||||
models: [
|
||||
{ id: "glm-5.3", name: "GLM 5.3" },
|
||||
{ id: "glm-5.3-flash", name: "GLM 5.3 Flash (Vision)" },
|
||||
{ id: "glm-5.2", name: "GLM 5.2" },
|
||||
{ id: "glm-5.1", name: "GLM 5.1" },
|
||||
{ id: "glm-5-turbo", name: "GLM 5 Turbo" },
|
||||
{ id: "glm-5", name: "GLM 5" },
|
||||
{ id: "glm-4.7", name: "GLM 4.7" },
|
||||
{ id: "glm-4.6v", name: "GLM 4.6V (Vision)" },
|
||||
],
|
||||
serviceKinds: ["llm", "webSearch"],
|
||||
// Coding plan bundles web search on the same API key as chat.
|
||||
searchConfig: {
|
||||
baseUrl: "https://api.z.ai/api/mcp/web_search_prime/mcp",
|
||||
method: "POST",
|
||||
authType: "apikey",
|
||||
authHeader: "bearer",
|
||||
costPerQuery: 0,
|
||||
searchTypes: ["web"],
|
||||
defaultMaxResults: 5,
|
||||
maxMaxResults: 50,
|
||||
timeoutMs: 10000,
|
||||
cacheTTLMs: 300000,
|
||||
},
|
||||
features: {
|
||||
usage: true,
|
||||
usageApikey: true,
|
||||
|
||||
@@ -17,6 +17,12 @@ export default {
|
||||
transport: {
|
||||
baseUrl: "https://api.groq.com/openai/v1/chat/completions",
|
||||
validateUrl: "https://api.groq.com/openai/v1/models",
|
||||
// No dedicated quota endpoint; rate-limit info rides on x-ratelimit-*
|
||||
// response headers, always included. Reuse the models list (already
|
||||
// used as validateUrl) so reading usage never costs tokens.
|
||||
usage: {
|
||||
url: "https://api.groq.com/openai/v1/models",
|
||||
},
|
||||
},
|
||||
models: [
|
||||
{ id: "llama-3.3-70b-versatile", name: "Llama 3.3 70B" },
|
||||
@@ -34,4 +40,8 @@ export default {
|
||||
authHeader: "bearer",
|
||||
format: "openai",
|
||||
},
|
||||
features: {
|
||||
usage: true,
|
||||
usageApikey: true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -66,6 +66,7 @@ import p63 from "./nebius.js";
|
||||
import p64 from "./nvidia.js";
|
||||
import p65 from "./ollama-local.js";
|
||||
import p66 from "./ollama.js";
|
||||
import p123 from "./ollama-search.js";
|
||||
import p67 from "./openai.js";
|
||||
import p68 from "./opencode-go.js";
|
||||
import p69 from "./opencode.js";
|
||||
@@ -121,6 +122,7 @@ import p118 from "./selfhosted-tts.js";
|
||||
import p119 from "./selfhosted-embedding.js";
|
||||
import p120 from "./fish-audio.js";
|
||||
import p121 from "./alitp-intl.js";
|
||||
import p122 from "./xquik.js";
|
||||
|
||||
export default [
|
||||
p0,
|
||||
@@ -190,6 +192,7 @@ export default [
|
||||
p64,
|
||||
p65,
|
||||
p66,
|
||||
p123,
|
||||
p67,
|
||||
p68,
|
||||
p69,
|
||||
@@ -243,4 +246,5 @@ export default [
|
||||
p119,
|
||||
p120,
|
||||
p121,
|
||||
p122,
|
||||
];
|
||||
|
||||
35
open-sse/providers/registry/ollama-search.js
Normal file
35
open-sse/providers/registry/ollama-search.js
Normal file
@@ -0,0 +1,35 @@
|
||||
export default {
|
||||
id: "ollama-search",
|
||||
alias: "ollama-search",
|
||||
display: {
|
||||
name: "Ollama Search",
|
||||
icon: "cloud",
|
||||
color: "#ffffff",
|
||||
textIcon: "OL",
|
||||
website: "https://ollama.com",
|
||||
notice: {
|
||||
text: "Web search via Ollama Cloud subscription. Reuses the API key from the Ollama (chat) provider.",
|
||||
apiKeyUrl: "https://ollama.com/settings/keys",
|
||||
},
|
||||
},
|
||||
category: "apikey",
|
||||
authType: "apikey",
|
||||
authModes: ["apikey"],
|
||||
serviceKinds: ["webSearch"],
|
||||
// Credential fallback: reuses the API key registered under the `ollama`
|
||||
// chat provider — one key, chat + search.
|
||||
credentialFallback: "ollama",
|
||||
searchConfig: {
|
||||
baseUrl: "https://ollama.com/api/web_search",
|
||||
method: "POST",
|
||||
authType: "apikey",
|
||||
authHeader: "bearer",
|
||||
costPerQuery: 0,
|
||||
freeMonthlyQuota: 1000,
|
||||
searchTypes: ["web"],
|
||||
defaultMaxResults: 5,
|
||||
maxMaxResults: 10,
|
||||
timeoutMs: 10000,
|
||||
cacheTTLMs: 300000,
|
||||
},
|
||||
};
|
||||
@@ -31,7 +31,16 @@ export default {
|
||||
{ id: "qwen3.5", name: "Qwen3.5" },
|
||||
{ id: "minimax-m3", name: "MiniMax M3" },
|
||||
],
|
||||
serviceKinds: ["llm"],
|
||||
serviceKinds: ["llm", "webFetch"],
|
||||
fetchConfig: {
|
||||
baseUrl: "https://ollama.com/api/web_fetch",
|
||||
method: "POST",
|
||||
authType: "apikey",
|
||||
authHeader: "bearer",
|
||||
formats: ["markdown"],
|
||||
maxCharacters: 200000,
|
||||
timeoutMs: 30000,
|
||||
},
|
||||
features: {
|
||||
usage: true,
|
||||
usageApikey: true,
|
||||
|
||||
@@ -21,6 +21,9 @@ export default {
|
||||
transport: {
|
||||
baseUrl: "https://opencode.ai/zen/go/v1/chat/completions",
|
||||
headers: {},
|
||||
usage: {
|
||||
url: "https://opencode.ai/zen/go/v1/usage",
|
||||
},
|
||||
},
|
||||
// Multi-endpoint: pick the transport matching the client sourceFormat to skip
|
||||
// translation. Guarded per-model by `supportedFormats` (see chatCore) because
|
||||
@@ -31,12 +34,14 @@ export default {
|
||||
{ format: "openai-responses", baseUrl: "https://opencode.ai/zen/go/v1/responses", auth: { combined: true, header: "Authorization", scheme: "bearer" } },
|
||||
],
|
||||
models: [
|
||||
{ id: "glm-5.3-flash", name: "GLM 5.3 Flash (Vision)", supportedFormats: ["openai"] },
|
||||
{ id: "glm-5.2", name: "GLM 5.2", supportedFormats: ["openai"] },
|
||||
{ id: "glm-5.1", name: "GLM 5.1", 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: "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: "mimo-v2.5", name: "MiMo V2.5", supportedFormats: ["openai"] },
|
||||
{ id: "mimo-v2.5-pro", name: "MiMo V2.5 Pro", supportedFormats: ["openai"] },
|
||||
{ id: "minimax-m3", name: "MiniMax M3", supportedFormats: ["openai", "claude"] },
|
||||
@@ -45,5 +50,13 @@ export default {
|
||||
{ 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"] },
|
||||
// Muse Spark is served by /zen/go/v1/responses only — responses-only entry forces
|
||||
// chatCore past the sourceFormat-matched transports into translation (see chatCore guard).
|
||||
{ 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"] },
|
||||
],
|
||||
features: {
|
||||
usage: true,
|
||||
usageApikey: true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -19,7 +19,12 @@ export default {
|
||||
},
|
||||
noAuth: true,
|
||||
},
|
||||
models: [],
|
||||
models: [
|
||||
// Muse Spark models are served by /zen/v1/responses; the rest stay on
|
||||
// /chat/completions, so the format is declared per-model, not per-provider.
|
||||
{ id: "muse-spark-1.2-contributor-free", name: "Muse Spark 1.2 Contributor Free", targetFormat: "openai-responses" },
|
||||
{ id: "muse-spark-1.3-contributor-free", name: "Muse Spark 1.3 Contributor Free", targetFormat: "openai-responses" },
|
||||
],
|
||||
modelsFetcher: { url: "https://opencode.ai/zen/v1/models", type: "opencode-free" },
|
||||
passthroughModels: true,
|
||||
};
|
||||
|
||||
@@ -30,12 +30,15 @@ export default {
|
||||
{ id: "auto", name: "Auto" },
|
||||
{ id: "performance", name: "Performance" },
|
||||
{ id: "efficient", name: "Efficient" },
|
||||
{ id: "qmodel_preview", name: "Qwen3.8-Max-Preview" },
|
||||
{ id: "lite", name: "Lite" },
|
||||
{ id: "qmodel_38max", name: "Qwen3.8-Max" },
|
||||
{ id: "qmodel_latest", name: "Qwen3.7-Max" },
|
||||
{ id: "qmodel", name: "Qwen3.7-Plus" },
|
||||
{ id: "qfmodel", name: "Qwen3.8-Flash" },
|
||||
{ id: "kmodel_latest", name: "Kimi-K3" },
|
||||
{ id: "kmodel", name: "Kimi-K2.7-Code" },
|
||||
{ id: "gm51model", name: "GLM-5.2" },
|
||||
{ id: "gmodel", name: "GLM-5.3" },
|
||||
{ id: "gfmodel", name: "GLM-5.3-Flash" },
|
||||
{ id: "dmodel", name: "DeepSeek-V4-Pro" },
|
||||
{ id: "dfmodel", name: "DeepSeek-V4-Flash" },
|
||||
{ id: "mmodel", name: "MiniMax-M3" },
|
||||
|
||||
@@ -24,129 +24,31 @@ export default {
|
||||
validateUrl: "https://api.tokenrouter.com/v1/models",
|
||||
thinkingFormat: "tokenrouter",
|
||||
},
|
||||
// Seed snapshot from live /v1/models (120 entries). Latest catalogue is
|
||||
// Seed snapshot from live /v1/models. Latest catalogue is
|
||||
// fetched via modelsFetcher; other ids still accepted via passthroughModels.
|
||||
models: [
|
||||
{ id: "MiniMax-Hailuo-2.3", name: "Minimax Hailuo 2.3", kind: "video" },
|
||||
{ id: "MiniMax-M3", name: "Minimax M3" },
|
||||
{ id: "anthropic/claude-fable-5", name: "Claude Fable 5" },
|
||||
{ id: "anthropic/claude-haiku-4.5", name: "Claude Haiku 4.5" },
|
||||
{ id: "anthropic/claude-opus-4.5", name: "Claude Opus 4.5" },
|
||||
{ id: "anthropic/claude-opus-4.6", name: "Claude Opus 4.6" },
|
||||
{ id: "anthropic/claude-opus-4.7", name: "Claude Opus 4.7" },
|
||||
{ id: "anthropic/claude-opus-4.7-fast", name: "Claude Opus 4.7 Fast" },
|
||||
{ id: "anthropic/claude-sonnet-4.6", name: "Claude Sonnet 4.6" },
|
||||
{ id: "anthropic/claude-opus-4.8", name: "Claude Opus 4.8" },
|
||||
{ id: "anthropic/claude-opus-4.8-fast", name: "Claude Opus 4.8 Fast" },
|
||||
{ id: "anthropic/claude-opus-5", name: "Claude Opus 5" },
|
||||
{ id: "anthropic/claude-opus-5-fast", name: "Claude Opus 5 Fast" },
|
||||
{ id: "anthropic/claude-sonnet-4", name: "Claude Sonnet 4" },
|
||||
{ id: "anthropic/claude-sonnet-4.5", name: "Claude Sonnet 4.5" },
|
||||
{ id: "anthropic/claude-sonnet-4.6", name: "Claude Sonnet 4.6" },
|
||||
{ id: "anthropic/claude-sonnet-5", name: "Claude Sonnet 5" },
|
||||
{ id: "bytedance-seed/seedream-4.5", name: "Seedream 4.5", kind: "image" },
|
||||
{ id: "bytedance-seed/seedream-5.0-lite", name: "Seedream 5.0 Lite", kind: "image" },
|
||||
{ id: "bytedance-seed/seedream-5.0-pro", name: "Seedream 5.0 Pro", kind: "image" },
|
||||
{ id: "claude-haiku-4-5", name: "Claude Haiku 4 5" },
|
||||
{ id: "claude-opus-4-8-m-aws", name: "Claude Opus 4 8 M Aws" },
|
||||
{ id: "deepseek/deepseek-v3.2", name: "Deepseek V3.2" },
|
||||
{ id: "deepseek/deepseek-v4-flash", name: "Deepseek V4 Flash" },
|
||||
{ id: "deepseek/deepseek-v4-flash-0731", name: "Deepseek V4 Flash 0731" },
|
||||
{ id: "deepseek/deepseek-v4-pro", name: "Deepseek V4 Pro" },
|
||||
{ id: "ex/gpt-5.4", name: "Gpt 5.4" },
|
||||
{ id: "google/gemini-2.5-flash-image", name: "Gemini 2.5 Flash Image" },
|
||||
{ id: "google/gemini-3-flash-preview", name: "Gemini 3 Flash Preview" },
|
||||
{ id: "google/gemini-3-pro-image-preview", name: "Gemini 3 Pro Image Preview" },
|
||||
{ id: "google/gemini-3.1-flash-image-preview", name: "Gemini 3.1 Flash Image Preview" },
|
||||
{ id: "google/gemini-3.1-flash-lite-image", name: "Gemini 3.1 Flash Lite Image" },
|
||||
{ id: "google/gemini-3.1-pro-preview", name: "Gemini 3.1 Pro Preview" },
|
||||
{ id: "google/gemini-3.5-flash", name: "Gemini 3.5 Flash" },
|
||||
{ id: "google/gemini-3.5-flash-lite", name: "Gemini 3.5 Flash Lite" },
|
||||
{ id: "google/gemini-3.6-flash", name: "Gemini 3.6 Flash" },
|
||||
{ id: "google/gemini-embedding-2", name: "Gemini Embedding 2" },
|
||||
{ id: "google/gemma-4-26b-a4b-it", name: "Gemma 4 26B A4B It" },
|
||||
{ id: "happyhorse-1.0-t2v", name: "Happyhorse 1.0 T2V", kind: "video" },
|
||||
{ id: "kling-3.0-turbo", name: "Kling 3.0 Turbo", kind: "video" },
|
||||
{ id: "kling-v2-6", name: "Kling V2 6", kind: "video" },
|
||||
{ id: "kling-v3", name: "Kling V3", kind: "video" },
|
||||
{ id: "kling-v3-omni", name: "Kling V3 Omni", kind: "video" },
|
||||
{ id: "microsoft/mai-image-2.5", name: "Mai Image 2.5" },
|
||||
{ id: "minimax/minimax-m2-her", name: "Minimax M2 Her" },
|
||||
{ id: "minimax/minimax-m2.1", name: "Minimax M2.1" },
|
||||
{ id: "minimax/minimax-m2.1-highspeed", name: "Minimax M2.1 Highspeed" },
|
||||
{ id: "minimax/minimax-m2.5", name: "Minimax M2.5" },
|
||||
{ id: "minimax/minimax-m2.7", name: "Minimax M2.7" },
|
||||
{ id: "minimax/minimax-m2.7-highspeed", name: "Minimax M2.7 Highspeed" },
|
||||
{ id: "miromind/mirothinker-1-7-deepresearch", name: "Mirothinker 1 7 Deepresearch" },
|
||||
{ id: "miromind/mirothinker-1-7-deepresearch-mini", name: "Mirothinker 1 7 Deepresearch Mini" },
|
||||
{ id: "mistralai/devstral-2512", name: "Devstral 2512" },
|
||||
{ id: "mistralai/mistral-medium-3-5", name: "Mistral Medium 3 5" },
|
||||
{ id: "mistralai/mistral-small-2603", name: "Mistral Small 2603" },
|
||||
{ id: "mistralai/voxtral-small-24b-2507", name: "Voxtral Small 24B 2507" },
|
||||
{ id: "moonshotai/kimi-k2.5", name: "Kimi K2.5" },
|
||||
{ id: "moonshotai/kimi-k2.6", name: "Kimi K2.6" },
|
||||
{ id: "moonshotai/kimi-k2.7-code", name: "Kimi K2.7 Code" },
|
||||
{ id: "moonshotai/kimi-k3", name: "Kimi K3" },
|
||||
{ id: "moonshotai/kimi-k3-free", name: "Kimi K3 Free" },
|
||||
{ id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free", name: "Nemotron 3 Nano Omni 30B A3B Reasoning:Free" },
|
||||
{ id: "nvidia/nemotron-3-super-120b-a12b", name: "Nemotron 3 Super 120B A12B" },
|
||||
{ id: "openai/gpt-4o-mini", name: "Gpt 4O Mini" },
|
||||
{ id: "openai/gpt-5", name: "Gpt 5" },
|
||||
{ id: "openai/gpt-5-image", name: "Gpt 5 Image" },
|
||||
{ id: "openai/gpt-5-image-mini", name: "Gpt 5 Image Mini" },
|
||||
{ id: "openai/gpt-5-mini", name: "Gpt 5 Mini" },
|
||||
{ id: "openai/gpt-5.2", name: "Gpt 5.2" },
|
||||
{ id: "openai/gpt-5.4", name: "Gpt 5.4" },
|
||||
{ id: "openai/gpt-5.4-image-2", name: "Gpt 5.4 Image 2", kind: "image" },
|
||||
{ id: "openai/gpt-5.4-mini", name: "Gpt 5.4 Mini" },
|
||||
{ id: "openai/gpt-5.4-nano", name: "Gpt 5.4 Nano" },
|
||||
{ id: "openai/gpt-5.4-pro", name: "Gpt 5.4 Pro" },
|
||||
{ id: "openai/gpt-5.5", name: "Gpt 5.5" },
|
||||
{ id: "openai/gpt-5.5-pro", name: "Gpt 5.5 Pro" },
|
||||
{ id: "openai/gpt-5.6-luna", name: "Gpt 5.6 Luna" },
|
||||
{ id: "openai/gpt-5.6-sol", name: "Gpt 5.6 Sol" },
|
||||
{ id: "openai/gpt-5.6-terra", name: "Gpt 5.6 Terra" },
|
||||
{ id: "openai/gpt-audio", name: "Gpt Audio", kind: "audio" },
|
||||
{ id: "openai/gpt-audio-mini", name: "Gpt Audio Mini", kind: "audio" },
|
||||
{ id: "openai/gpt-oss-120b", name: "Gpt Oss 120B" },
|
||||
{ id: "google/gemini-3.5-flash", name: "Gemini 3.5 Flash" },
|
||||
{ id: "google/gemini-3.6-flash", name: "Gemini 3.6 Flash" },
|
||||
{ id: "deepseek/deepseek-v4-flash", name: "Deepseek V4 Flash" },
|
||||
{ id: "deepseek/deepseek-v4-pro", name: "Deepseek V4 Pro" },
|
||||
{ id: "qwen/qwen3-coder-next", name: "Qwen3 Coder Next" },
|
||||
{ id: "qwen/qwen3.5-122b-a10b", name: "Qwen3.5 122B A10B" },
|
||||
{ id: "qwen/qwen3.5-35b-a3b", name: "Qwen3.5 35B A3B" },
|
||||
{ id: "qwen/qwen3.5-397b-a17b", name: "Qwen3.5 397B A17B" },
|
||||
{ id: "qwen/qwen3.5-9b", name: "Qwen3.5 9B" },
|
||||
{ id: "qwen/qwen3.5-flash", name: "Qwen3.5 Flash" },
|
||||
{ id: "qwen/qwen3.5-plus-02-15", name: "Qwen3.5 Plus 02 15" },
|
||||
{ id: "qwen/qwen3.6-plus", name: "Qwen3.6 Plus" },
|
||||
{ id: "qwen/qwen3.7-max", name: "Qwen3.7 Max" },
|
||||
{ id: "qwen/qwen3.7-plus", name: "Qwen3.7 Plus" },
|
||||
{ id: "qwen/qwen3.8-max", name: "Qwen3.8 Max" },
|
||||
{ id: "qwen3.5-omni-plus", name: "Qwen3.5 Omni Plus" },
|
||||
{ id: "qwen3.6-flash", name: "Qwen3.6 Flash" },
|
||||
{ id: "sakana/fugu-ultra", name: "Fugu Ultra" },
|
||||
{ id: "seed-2-0-code-preview-260328", name: "Seed 2 0 Code Preview 260328" },
|
||||
{ id: "seed-2-0-lite-260428", name: "Seed 2 0 Lite 260428" },
|
||||
{ id: "seed-2-0-mini-260428", name: "Seed 2 0 Mini 260428" },
|
||||
{ id: "seed-2-0-pro-260328", name: "Seed 2 0 Pro 260328" },
|
||||
{ id: "stepfun/step-3.5-flash", name: "Step 3.5 Flash" },
|
||||
{ id: "stepfun/step-3.7-flash", name: "Step 3.7 Flash" },
|
||||
{ id: "tencent/hy3-preview", name: "Hy3 Preview" },
|
||||
{ id: "x-ai/grok-4.1-fast", name: "Grok 4.1 Fast" },
|
||||
{ id: "x-ai/grok-4.20-beta", name: "Grok 4.20 Beta" },
|
||||
{ id: "x-ai/grok-4.3", name: "Grok 4.3" },
|
||||
{ id: "x-ai/grok-4.5", name: "Grok 4.5" },
|
||||
{ id: "x-ai/grok-build-0.1", name: "Grok Build 0.1" },
|
||||
{ id: "xiaomi/mimo-v2-flash", name: "Mimo V2 Flash" },
|
||||
{ id: "xiaomi/mimo-v2-omni", name: "Mimo V2 Omni" },
|
||||
{ id: "xiaomi/mimo-v2-pro", name: "Mimo V2 Pro" },
|
||||
{ id: "xiaomi/mimo-v2.5", name: "Mimo V2.5" },
|
||||
{ id: "xiaomi/mimo-v2.5-pro", name: "Mimo V2.5 Pro" },
|
||||
{ id: "z-ai/glm-4.5-air", name: "Glm 4.5 Air" },
|
||||
{ id: "z-ai/glm-4.6", name: "Glm 4.6" },
|
||||
{ id: "z-ai/glm-4.6v", name: "Glm 4.6V" },
|
||||
{ id: "z-ai/glm-4.7", name: "Glm 4.7" },
|
||||
{ id: "z-ai/glm-5", name: "Glm 5" },
|
||||
{ id: "z-ai/glm-5-turbo", name: "Glm 5 Turbo" },
|
||||
{ id: "z-ai/glm-5.1", name: "Glm 5.1" },
|
||||
{ id: "moonshotai/kimi-k2.7-code", name: "Kimi K2.7 Code" },
|
||||
{ id: "moonshotai/kimi-k3-free", name: "Kimi K3 Free" },
|
||||
{ id: "z-ai/glm-5.3-free", name: "Glm 5.3 Free" },
|
||||
{ id: "z-ai/glm-5.2", name: "Glm 5.2" },
|
||||
{ id: "z-ai/glm-5-turbo", name: "Glm 5 Turbo" },
|
||||
{ id: "x-ai/grok-4.5", name: "Grok 4.5" },
|
||||
],
|
||||
serviceKinds: ["llm", "embedding", "image"],
|
||||
embeddingConfig: {
|
||||
|
||||
@@ -36,6 +36,8 @@ export default {
|
||||
},
|
||||
},
|
||||
models: [
|
||||
{ id: "grok-4.6", name: "Grok 4.6" },
|
||||
{ id: "grok-4.5", name: "Grok 4.5" },
|
||||
{ id: "grok-4", name: "Grok 4" },
|
||||
{ id: "grok-4-fast-reasoning", name: "Grok 4 Fast Reasoning" },
|
||||
{ id: "grok-code-fast-1", name: "Grok Code Fast" },
|
||||
|
||||
35
open-sse/providers/registry/xquik.js
Normal file
35
open-sse/providers/registry/xquik.js
Normal file
@@ -0,0 +1,35 @@
|
||||
export default {
|
||||
id: "xquik",
|
||||
alias: "xquik",
|
||||
display: {
|
||||
name: "Xquik",
|
||||
icon: "tag",
|
||||
color: "#5C3327",
|
||||
textIcon: "XQ",
|
||||
website: "https://docs.xquik.com/api-reference/x/search-tweets",
|
||||
notice: {
|
||||
apiKeyUrl: "https://xquik.com",
|
||||
text: "Searches public X posts. Billing uses 1 Xquik credit per returned post."
|
||||
}
|
||||
},
|
||||
category: "apikey",
|
||||
authType: "apikey",
|
||||
serviceKinds: [
|
||||
"webSearch"
|
||||
],
|
||||
searchConfig: {
|
||||
baseUrl: "https://xquik.com/api/v1/x/tweets/search",
|
||||
validateUrl: "https://xquik.com/api/v1/credits",
|
||||
method: "GET",
|
||||
authType: "apikey",
|
||||
authHeader: "x-api-key",
|
||||
searchTypes: [
|
||||
"x"
|
||||
],
|
||||
defaultMaxResults: 5,
|
||||
maxMaxResults: 100,
|
||||
timeoutMs: 10000,
|
||||
cacheTTLMs: 60000,
|
||||
creditsPerResult: 1
|
||||
}
|
||||
};
|
||||
@@ -22,6 +22,7 @@ export function mapStainlessArch() {
|
||||
|
||||
// Anthropic API version (single source — reused across claude-format providers/executors)
|
||||
export const ANTHROPIC_API_VERSION = "2023-06-01";
|
||||
export const CLAUDE_CLI_VERSION = "2.1.258";
|
||||
|
||||
// Shared Claude-compatible API headers (reused across claude-format providers)
|
||||
export const CLAUDE_API_HEADERS = {
|
||||
@@ -34,7 +35,7 @@ export const CLAUDE_CLI_SPOOF_HEADERS = {
|
||||
"Anthropic-Version": ANTHROPIC_API_VERSION,
|
||||
"Anthropic-Beta": "claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05,advanced-tool-use-2025-11-20,effort-2025-11-24,structured-outputs-2025-12-15,fast-mode-2026-02-01,redact-thinking-2026-02-12,token-efficient-tools-2026-03-28",
|
||||
"Anthropic-Dangerous-Direct-Browser-Access": "true",
|
||||
"User-Agent": "claude-cli/2.1.92 (external, sdk-cli)",
|
||||
"User-Agent": `claude-cli/${CLAUDE_CLI_VERSION} (external, sdk-cli)`,
|
||||
"X-App": "cli",
|
||||
"X-Stainless-Helper-Method": "stream",
|
||||
"X-Stainless-Retry-Count": "0",
|
||||
@@ -74,10 +75,10 @@ export const KIMI_CODING_BASE_URL = "https://api.kimi.com/coding/v1/messages";
|
||||
export const OPENAI_COMPAT_BASE = "https://api.openai.com/v1";
|
||||
export const ANTHROPIC_COMPAT_BASE = "https://api.anthropic.com/v1";
|
||||
|
||||
// Official Antigravity IDE Desktop 2.1.1 fingerprint captured from macOS arm64.
|
||||
// Official Antigravity IDE Desktop 2.11.0 fingerprint captured from macOS arm64.
|
||||
// Keep this static even when 9router runs on Linux: the provider profile is
|
||||
// intentionally matching the IDE client, not the server host.
|
||||
export const ANTIGRAVITY_IDE_VERSION = "2.1.1";
|
||||
export const ANTIGRAVITY_IDE_VERSION = "2.11.0";
|
||||
export const ANTIGRAVITY_IDE_BASE_URL = "https://daily-cloudcode-pa.googleapis.com";
|
||||
export const ANTIGRAVITY_IDE_USER_AGENT = `antigravity/ide/${ANTIGRAVITY_IDE_VERSION} darwin/arm64`;
|
||||
|
||||
|
||||
@@ -35,10 +35,23 @@ const CODEX_GPT_5_6_LEVELS = ["none", "minimal", "low", "medium", "high", "xhigh
|
||||
|
||||
// Model-name pattern overrides (glob, first match wins) — more precise than format default.
|
||||
const PATTERN_THINKING = [
|
||||
{ provider: "codex", pattern: "*gpt-6*", levels: CODEX_GPT_5_6_LEVELS },
|
||||
{ provider: "codex", pattern: "*gpt-5.6-sol*", levels: [...CODEX_GPT_5_6_LEVELS, "ultra"] },
|
||||
{ provider: "codex", pattern: "*gpt-5.6-terra*", levels: [...CODEX_GPT_5_6_LEVELS, "ultra"] },
|
||||
{ provider: "codex", pattern: "*gpt-5.6-luna*", levels: CODEX_GPT_5_6_LEVELS },
|
||||
{ pattern: "*codex*", levels: ["low", "medium", "high", "xhigh"] }, // codex cannot disable thinking
|
||||
// codebuddy-cn per-model effort sets — the server's product-config payload
|
||||
// publishes `reasoning.supportedEfforts` per model. NOTE: the chat endpoint
|
||||
// accepts any level you send (probed none/minimal/low/medium/high/xhigh/max
|
||||
// → all 200), but values outside a model's supportedEfforts are silently
|
||||
// clamped, so the declared set stays authoritative for the picker. Models
|
||||
// that publish no supportedEfforts (glm-5.1 / glm-5v-turbo / kimi-k2.x /
|
||||
// kimi-k3-1 / minimax-m3) fall through to the openai format default.
|
||||
{ provider: "codebuddy-cn", pattern: "glm-5.3*", levels: ["low", "high", "max"] },
|
||||
{ provider: "codebuddy-cn", pattern: "glm-5.2", levels: ["high", "xhigh"] },
|
||||
{ provider: "codebuddy-cn", pattern: "deepseek-v4*", levels: ["low", "high", "xhigh"] },
|
||||
{ provider: "codebuddy-cn", pattern: "hy3*", levels: ["low", "high"] },
|
||||
{ provider: "codebuddy-cn", pattern: "hy4*", levels: ["high"] },
|
||||
];
|
||||
|
||||
// Returns valid thinking levels for a model, or null when the model has no reasoning.
|
||||
|
||||
42
open-sse/providers/visionPatterns.js
Normal file
42
open-sse/providers/visionPatterns.js
Normal file
@@ -0,0 +1,42 @@
|
||||
// Name-based vision detection — last resort when neither the catalog file nor
|
||||
// the capability tables know a model. Vendors put the modality in the id
|
||||
// ("qwen3-vl-plus", "glm-4.6v", "deepseek-v4-flash-vision-exp"), so a custom or
|
||||
// freshly released model still gets image input instead of silently dropping it.
|
||||
//
|
||||
// Only ever turns vision ON. Never used to turn a declared capability off.
|
||||
|
||||
const SEP = "[-_/:.]";
|
||||
|
||||
// Image GENERATION, video generation, and non-chat models also carry these
|
||||
// words but take no image input — checked first so they can never match.
|
||||
const NOT_VISION = new RegExp(
|
||||
[
|
||||
`(^|${SEP})(image|img)(${SEP}|$)`,
|
||||
"stable-image", "gen[0-9]_image", "nanobanana", "imagine",
|
||||
"t2v", "i2v", "flux", "dall", "sdxl", "diffusion",
|
||||
"embed", "rerank", "guard", "moderation",
|
||||
"tts", "stt", "whisper", "voice", "speech", "audio",
|
||||
].join("|"),
|
||||
"i"
|
||||
);
|
||||
|
||||
// Explicit modality words, plus the "<digit>v" suffix vendors use for vision
|
||||
// variants (glm-4.6v, glm-5v-turbo). The digit-v branch requires a dotted
|
||||
// version so the never-shipped `gpt-4v` cannot match.
|
||||
const VISION_NAME = new RegExp(
|
||||
[
|
||||
`(^|${SEP})(vision|vl|vlm|multimodal|omni|visual)(${SEP}|$)`,
|
||||
`[0-9]\\.[0-9]+v(${SEP}|$)`,
|
||||
`(^|${SEP})glm-[0-9]+v(${SEP}|$)`,
|
||||
"(^|[-_/:.])(llava|pixtral|internvl|cogvlm|minicpm-v|moondream|idefics|fuyu)",
|
||||
].join("|"),
|
||||
"i"
|
||||
);
|
||||
|
||||
// Does this model id look like a vision model? Name signal only.
|
||||
export function looksLikeVisionModel(modelId) {
|
||||
if (!modelId) return false;
|
||||
const id = String(modelId).toLowerCase();
|
||||
if (NOT_VISION.test(id)) return false;
|
||||
return VISION_NAME.test(id);
|
||||
}
|
||||
Reference in New Issue
Block a user