Iostream-Li's picture
Add files using upload-large-folder tool
5871090 verified
import { config } from "./config";
export type AdapterId =
| "anthropic"
| "openai"
| "gemini"
| "deepseek"
| "kimi"
| "zhipu"
| "minimax"
| "qwen"
| "codex-cli";
/**
* Provider source bucket — every model declares which call paths can
* serve it. Availability is now a per-source check rather than a global
* profile gate, so e.g. MiniMax/Kimi work whether or not the hosted
* Replit integrations are configured. `DOATLAS_PROFILE` is downgraded
* to a *preference filter* in `listModels` (it controls ordering /
* default model picking, not whether a configured key works).
*/
export type ModelSource =
| "replit-integration"
| "byok-direct"
| "china-direct";
export interface ModelInfo {
id: string;
name: string;
provider: string;
description: string;
context_length: number;
capabilities: Array<"text" | "vision" | "tools" | "streaming">;
pricing: { input_per_1k: number; output_per_1k: number };
default: boolean;
available: boolean;
// Internal routing hints (not exposed to client).
tier: "S" | "A";
adapter: AdapterId;
upstreamModel: string;
/**
* Source buckets this model can be served from. The first matching
* bucket with credentials wins; we never try to fall through to a
* different source mid-call.
*/
sources: ModelSource[];
}
const ALL_MODELS: ModelInfo[] = [
// -- S tier (旗舰) --
{
id: "mdl_claude-sonnet-4-6",
name: "DoAtlas Pro",
provider: "DoAtlas",
description:
"旗舰研究模型,深度推理与代码能力最强,适合复杂文献综述、机制推理与多步分析。",
context_length: 200_000,
capabilities: ["text", "vision", "tools", "streaming"],
pricing: { input_per_1k: 0, output_per_1k: 0 },
default: false,
available: false,
tier: "S",
adapter: "anthropic",
upstreamModel: "claude-sonnet-4-6",
sources: ["replit-integration", "byok-direct"],
},
{
id: "mdl_gpt-5_2",
name: "DoAtlas Pro X",
provider: "DoAtlas",
description:
"多模态旗舰模型,视觉与文本兼顾,适合图表解读、影像分析与通用研究问答。",
context_length: 128_000,
capabilities: ["text", "vision", "tools", "streaming"],
pricing: { input_per_1k: 0, output_per_1k: 0 },
default: false,
available: false,
tier: "S",
adapter: "openai",
upstreamModel: "gpt-5.2",
sources: ["replit-integration", "byok-direct"],
},
{
id: "mdl_gemini-2_5-pro",
name: "DoAtlas Vision",
provider: "DoAtlas",
description:
"Gemini 2.5 Pro 多模态旗舰,超长上下文与图表理解,适合长文档解析与多模态研究问答。",
context_length: 1_000_000,
capabilities: ["text", "vision", "tools", "streaming"],
pricing: { input_per_1k: 0, output_per_1k: 0 },
default: false,
available: false,
tier: "S",
adapter: "gemini",
upstreamModel: "gemini-2.5-pro",
sources: ["replit-integration", "byok-direct"],
},
{
id: "mdl_deepseek-r1",
name: "DoAtlas Reason Pro",
provider: "DoAtlas",
description:
"DeepSeek R1 推理模型,专注链式推理与数学/科学论证,适合机制假设与复杂证据综合。",
context_length: 128_000,
capabilities: ["text", "tools", "streaming"],
pricing: { input_per_1k: 0, output_per_1k: 0 },
default: false,
available: false,
tier: "S",
adapter: "deepseek",
upstreamModel: "deepseek-reasoner",
sources: ["china-direct"],
},
{
id: "mdl_codex-cli",
name: "DoAtlas Code",
provider: "DoAtlas Local",
description:
"本地代码助手,运行在你自己的机器上,可读写本地文件与执行命令;需在本地部署中配置。",
context_length: 200_000,
capabilities: ["text", "tools", "streaming"],
pricing: { input_per_1k: 0, output_per_1k: 0 },
default: false,
available: false,
tier: "S",
adapter: "codex-cli",
upstreamModel: "codex-cli",
sources: ["byok-direct"],
},
// -- A tier (通用) --
{
id: "mdl_glm-4_6",
name: "DoAtlas Air",
provider: "DoAtlas",
description:
"智谱 GLM-4 系列,长上下文 128k,响应快速,适合日常问答与长文本处理。",
context_length: 131_072,
capabilities: ["text", "tools", "streaming"],
pricing: { input_per_1k: 0, output_per_1k: 0 },
default: false,
available: false,
tier: "A",
adapter: "zhipu",
upstreamModel: "glm-4-plus",
sources: ["china-direct"],
},
{
id: "mdl_minimax-m2",
name: "DoAtlas Search",
provider: "DoAtlas",
description:
"MiniMax M2 智能体模型,配合统一 web_search 工具实现实时联网检索,适合需要最新资料的研究问答。",
context_length: 200_000,
capabilities: ["text", "tools", "streaming"],
pricing: { input_per_1k: 0, output_per_1k: 0 },
default: false,
available: false,
tier: "A",
adapter: "minimax",
upstreamModel: "MiniMax-M2.7-highspeed",
sources: ["china-direct"],
},
{
id: "mdl_deepseek-v3",
name: "DoAtlas Chat",
provider: "DoAtlas",
description:
"DeepSeek V3 通用对话模型,性价比高,适合日常问答与代码补全。",
context_length: 128_000,
capabilities: ["text", "tools", "streaming"],
pricing: { input_per_1k: 0, output_per_1k: 0 },
default: false,
available: false,
tier: "A",
adapter: "deepseek",
upstreamModel: "deepseek-chat",
sources: ["china-direct"],
},
{
id: "mdl_kimi-k2",
name: "DoAtlas Long",
provider: "DoAtlas",
description:
"Kimi 长文本模型,超长上下文与文档检索能力强,适合大文档/多 PDF 阅读。",
context_length: 256_000,
capabilities: ["text", "tools", "streaming"],
pricing: { input_per_1k: 0, output_per_1k: 0 },
default: false,
available: false,
tier: "A",
adapter: "kimi",
upstreamModel: "kimi-k2-0905-preview",
sources: ["china-direct"],
},
{
id: "mdl_qwen-max",
name: "DoAtlas Bilingual",
provider: "DoAtlas",
description:
"通义千问 Max 双语通用模型,中英推理与工具调用稳定,适合中文研究场景。",
context_length: 131_072,
capabilities: ["text", "tools", "streaming"],
pricing: { input_per_1k: 0, output_per_1k: 0 },
default: false,
available: false,
tier: "A",
adapter: "qwen",
upstreamModel: "qwen-max",
sources: ["china-direct"],
},
{
id: "mdl_gemini-2_5-flash",
name: "DoAtlas Vision Lite",
provider: "DoAtlas",
description:
"Gemini 2.5 Flash 轻量多模态模型,速度快、成本低,适合实时问答与轻量视觉任务。",
context_length: 1_000_000,
capabilities: ["text", "vision", "tools", "streaming"],
pricing: { input_per_1k: 0, output_per_1k: 0 },
default: false,
available: false,
tier: "A",
adapter: "gemini",
upstreamModel: "gemini-2.5-flash",
sources: ["replit-integration", "byok-direct"],
},
];
/**
* Adapter-by-source availability table. A model is available when at
* least one of its declared sources has credentials configured.
*/
function sourceAvailable(adapter: AdapterId, source: ModelSource): boolean {
switch (adapter) {
case "anthropic":
if (source === "replit-integration") return config.hasAnthropicCloud;
if (source === "byok-direct") return config.hasAnthropicDirect;
return false;
case "openai":
if (source === "replit-integration") return config.hasOpenAICloud;
if (source === "byok-direct") return config.hasOpenAIDirect;
return false;
case "gemini":
if (source === "replit-integration") return config.hasGeminiCloud;
if (source === "byok-direct") return config.hasGeminiDirect;
return false;
case "deepseek":
return source === "china-direct" && config.hasDeepseek;
case "kimi":
return source === "china-direct" && config.hasKimi;
case "zhipu":
return source === "china-direct" && config.hasZhipu;
case "minimax":
return source === "china-direct" && config.hasMinimax;
case "qwen":
return source === "china-direct" && config.hasQwen;
case "codex-cli":
return source === "byok-direct" && config.hasCodexCli;
default:
return false;
}
}
function isAvailable(m: ModelInfo): boolean {
return m.sources.some((s) => sourceAvailable(m.adapter, s));
}
/**
* Return the source actually used to call this model. The first
* configured source from the model's `sources` list wins.
*/
export function resolveSource(m: ModelInfo): ModelSource | null {
for (const s of m.sources) {
if (sourceAvailable(m.adapter, s)) return s;
}
return null;
}
export function listModels(): ModelInfo[] {
const profile = config.profile;
const out = ALL_MODELS.map((m) => ({
...m,
available: isAvailable(m),
}));
// Profile is now a preference filter for default selection only.
// "cloud" prefers replit-integration/byok-direct models; "local"
// accepts everything that's available.
const preferCloud = profile === "cloud";
const candidates = preferCloud
? out.filter(
(m) =>
m.available &&
m.sources.some((s) => s === "replit-integration" || s === "byok-direct"),
)
: out.filter((m) => m.available);
const first = candidates[0] ?? out.find((m) => m.available);
if (first) {
const target = out.find((m) => m.id === first.id);
if (target) target.default = true;
}
return out;
}
export function findModel(id: string | null | undefined): ModelInfo | null {
if (!id) return null;
return listModels().find((m) => m.id === id) ?? null;
}
export function pickDefaultModel(): ModelInfo | null {
return listModels().find((m) => m.default) ?? null;
}
export function publicModel(m: ModelInfo) {
// Strip internal routing fields.
const { tier: _t, adapter: _a, upstreamModel: _u, sources: _s, ...pub } = m;
return pub;
}