Merge branch 'main' of github.com:musistudio/claude-code-router into dev/3.1

This commit is contained in:
musistudio
2026-08-11 10:56:16 +08:00
9 changed files with 228 additions and 17 deletions
@@ -1022,12 +1022,7 @@ async function writeDurableJsonFile(
const filePath = join(directory, fileName);
const temporaryPath = join(directory, `.${fileName}-${randomUUID()}.tmp`);
await writeFile(temporaryPath, JSON.stringify(value));
const temporaryFile = await open(temporaryPath, "r");
try {
await temporaryFile.sync();
} finally {
await temporaryFile.close();
}
await syncFile(temporaryPath);
await rename(temporaryPath, filePath);
await syncDirectory(directory);
}
@@ -1049,14 +1044,7 @@ async function syncRawTracePartFiles(
throw new Error(`Raw trace part is shorter than its manifest: ${filePath}`);
}
if (syncPartFile) await syncPartFile(filePath);
else {
const handle = await open(filePath, "r");
try {
await handle.sync();
} finally {
await handle.close();
}
}
else await syncFile(filePath);
}
await syncDirectory(directory);
}
@@ -1096,14 +1084,47 @@ async function readRawTraceDeliveryState(
};
}
// Windows maps fsync to FlushFileBuffers, which requires the handle to carry
// write access: flushing a handle opened read-only fails with EPERM. Every
// file flushed here was just written by this process, so reopening it as "r+"
// keeps the barrier real on Windows instead of trading it for a tolerated
// error. POSIX accepts a read-write handle for fsync just as readily.
async function syncFile(filePath: string): Promise<void> {
const handle = await open(filePath, "r+");
try {
await handle.sync();
} finally {
await handle.close();
}
}
// Flushing a directory entry is a best-effort durability barrier: POSIX never
// required it to succeed, and platforms are free to reject the request. Linux
// and macOS answer with EINVAL/ENOTSUP/EISDIR depending on the filesystem;
// Windows rejects fsync on a directory handle with EPERM. All of those mean
// "this platform will not flush a directory", not "this spool is broken", so
// the rename that precedes the call still stands and we continue. Any other
// code (EACCES, EIO, ENOSPC, EBADF, ...) is a real storage failure and must
// keep propagating, so the caller can refuse the bundle instead of reporting a
// durability guarantee it never obtained.
const toleratedDirectorySyncErrorCodes = new Set(["EINVAL", "EISDIR", "ENOTSUP", "EPERM"]);
function isToleratedDirectorySyncError(error: unknown): boolean {
const code = nodeErrorCode(error);
return code !== undefined && toleratedDirectorySyncErrorCodes.has(code);
}
export function isToleratedDirectorySyncErrorForTest(error: unknown): boolean {
return isToleratedDirectorySyncError(error);
}
async function syncDirectory(directory: string): Promise<void> {
let handle;
try {
handle = await open(directory, "r");
await handle.sync();
} catch (error) {
const code = nodeErrorCode(error);
if (code !== "EINVAL" && code !== "ENOTSUP" && code !== "EISDIR") throw error;
if (!isToleratedDirectorySyncError(error)) throw error;
} finally {
await handle?.close().catch(() => undefined);
}
@@ -18,6 +18,12 @@ import { runApiProviderPreset } from "@ccr/core/providers/presets/runapi/index";
import { siliconFlowProviderPreset } from "@ccr/core/providers/presets/siliconflow/index";
import { teamoRouterProviderPreset } from "@ccr/core/providers/presets/teamorouter/index";
import { unity2ProviderPreset } from "@ccr/core/providers/presets/unity2/index";
import {
xiaomiMimoProviderPreset,
xiaomiMimoTokenPlanChinaProviderPreset,
xiaomiMimoTokenPlanEuropeProviderPreset,
xiaomiMimoTokenPlanSingaporeProviderPreset
} from "@ccr/core/providers/presets/xiaomi/index";
import { zaiGlobalCodingProviderPreset } from "@ccr/core/providers/presets/zai-global-coding/index";
import { zaiGlobalGeneralProviderPreset } from "@ccr/core/providers/presets/zai-global-general/index";
import { zhipuCnCodingProviderPreset } from "@ccr/core/providers/presets/zhipu-cn-coding/index";
@@ -40,6 +46,10 @@ export const providerPresets: ProviderPreset[] = [
openRouterProviderPreset,
nvidiaProviderPreset,
deepSeekProviderPreset,
xiaomiMimoProviderPreset,
xiaomiMimoTokenPlanChinaProviderPreset,
xiaomiMimoTokenPlanSingaporeProviderPreset,
xiaomiMimoTokenPlanEuropeProviderPreset,
kimiCodingProviderPreset,
zhipuCnCodingProviderPreset,
zhipuCnGeneralProviderPreset,
@@ -0,0 +1,65 @@
import { defaultProviderAccountConfig, type ProviderPreset } from "@ccr/core/providers/presets/types";
const xiaomiMimoDefaultModels = ["mimo-v2.5-pro", "mimo-v2.5"];
const xiaomiMimoWebsiteUrl = "https://platform.xiaomimimo.com/";
function createXiaomiMimoProviderPreset(input: {
aliases: string[];
anthropicBaseUrl: string;
id: string;
name: string;
openAiBaseUrl: string;
}): ProviderPreset {
return {
account: defaultProviderAccountConfig,
aliases: input.aliases,
defaultModels: xiaomiMimoDefaultModels,
endpoints: [
{
baseUrl: input.openAiBaseUrl,
label: "OpenAI",
protocols: ["openai_responses", "openai_chat_completions"]
},
{
baseUrl: input.anthropicBaseUrl,
label: "Anthropic",
protocols: ["anthropic_messages"]
}
],
id: input.id,
name: input.name,
websiteUrl: xiaomiMimoWebsiteUrl
};
}
export const xiaomiMimoProviderPreset = createXiaomiMimoProviderPreset({
aliases: ["mimo", "xiaomi", "xiaomi mimo", "小米", "小米 mimo"],
anthropicBaseUrl: "https://api.xiaomimimo.com/anthropic",
id: "xiaomi",
name: "Xiaomi MiMo",
openAiBaseUrl: "https://api.xiaomimimo.com/v1"
});
export const xiaomiMimoTokenPlanChinaProviderPreset = createXiaomiMimoProviderPreset({
aliases: ["mimo token plan china", "xiaomi token plan china", "xiaomi token plan cn"],
anthropicBaseUrl: "https://token-plan-cn.xiaomimimo.com/anthropic",
id: "xiaomi-token-plan-cn",
name: "Xiaomi Token Plan (China)",
openAiBaseUrl: "https://token-plan-cn.xiaomimimo.com/v1"
});
export const xiaomiMimoTokenPlanSingaporeProviderPreset = createXiaomiMimoProviderPreset({
aliases: ["mimo token plan singapore", "xiaomi token plan singapore", "xiaomi token plan sgp"],
anthropicBaseUrl: "https://token-plan-sgp.xiaomimimo.com/anthropic",
id: "xiaomi-token-plan-sgp",
name: "Xiaomi Token Plan (Singapore)",
openAiBaseUrl: "https://token-plan-sgp.xiaomimimo.com/v1"
});
export const xiaomiMimoTokenPlanEuropeProviderPreset = createXiaomiMimoProviderPreset({
aliases: ["mimo token plan europe", "xiaomi token plan ams", "xiaomi token plan europe"],
anthropicBaseUrl: "https://token-plan-ams.xiaomimimo.com/anthropic",
id: "xiaomi-token-plan-ams",
name: "Xiaomi Token Plan (Europe)",
openAiBaseUrl: "https://token-plan-ams.xiaomimimo.com/v1"
});
@@ -11,6 +11,7 @@ import {
applyRawTraceRequestLogPolicy,
buildRawTraceConfig,
createBodySampler,
isToleratedDirectorySyncErrorForTest,
readRawTraceRequestLogBundle,
RawTraceSynchronizer
} from "@ccr/core/observability/raw-trace-sync.ts";
@@ -874,6 +875,48 @@ test("fallback raw bundles keep unique bundle ids while sharing the logical requ
}
});
// A real directory handle cannot drive these cases: on Linux and macOS the
// fsync either succeeds or fails with a code that depends on the filesystem
// under the temp directory, and on Windows it always fails. The predicate is
// the only place where the platform-independent contract can be pinned down.
test("raw trace tolerates every directory fsync rejection a platform may return", () => {
// Node rejects fsync on a directory handle with EPERM on Windows
// (errno -4048, verified on Node 24.14.1 win32) and with EINVAL, ENOTSUP or
// EISDIR across POSIX filesystems. Flushing a directory is a best-effort
// barrier, so none of these may fail the spool.
for (const code of ["EINVAL", "EISDIR", "ENOTSUP", "EPERM"]) {
assert.equal(
isToleratedDirectorySyncErrorForTest(directorySyncError(code)),
true,
`expected a directory fsync ${code} to be tolerated`
);
}
});
test("raw trace still propagates real storage failures from a directory fsync", () => {
// The tolerated set must stay a set. If it ever degrades into a blanket
// catch, an unwritable or failing spool would be acknowledged as durable.
for (const code of ["EACCES", "EIO", "ENOSPC", "EROFS", "EBADF", "EMFILE"]) {
assert.equal(
isToleratedDirectorySyncErrorForTest(directorySyncError(code)),
false,
`expected a directory fsync ${code} to keep propagating`
);
}
assert.equal(isToleratedDirectorySyncErrorForTest(new Error("fsync failed")), false);
assert.equal(isToleratedDirectorySyncErrorForTest(directorySyncError("")), false);
assert.equal(isToleratedDirectorySyncErrorForTest(undefined), false);
});
function directorySyncError(code) {
// Shaped like the rejection Node produces for fsync on a directory handle,
// e.g. "EPERM: operation not permitted, fsync" on Windows.
const error = new Error(`${code}: directory fsync rejected, fsync`);
error.code = code;
error.syscall = "fsync";
return error;
}
function createConfig() {
const config = createDefaultAppConfig();
config.observability.requestLogs = true;
@@ -37,6 +37,12 @@ import {
import {
unity2ProviderPreset
} from "@ccr/core/providers/presets/unity2/index.ts";
import {
xiaomiMimoProviderPreset,
xiaomiMimoTokenPlanChinaProviderPreset,
xiaomiMimoTokenPlanEuropeProviderPreset,
xiaomiMimoTokenPlanSingaporeProviderPreset
} from "@ccr/core/providers/presets/xiaomi/index.ts";
const openAiPreset = {
aliases: ["OpenAI", "ChatGPT"],
@@ -140,6 +146,50 @@ test("NVIDIA preset exposes the hosted NIM OpenAI-compatible endpoint", () => {
assert.equal(providerPresetMatchesBaseUrl(nvidiaProviderPreset, "https://build.nvidia.com/models"), false);
});
test("Xiaomi MiMo presets expose official Responses, Chat, and Anthropic endpoints", () => {
const cases = [
[
xiaomiMimoProviderPreset,
"https://api.xiaomimimo.com/v1",
"https://api.xiaomimimo.com/anthropic"
],
[
xiaomiMimoTokenPlanChinaProviderPreset,
"https://token-plan-cn.xiaomimimo.com/v1",
"https://token-plan-cn.xiaomimimo.com/anthropic"
],
[
xiaomiMimoTokenPlanSingaporeProviderPreset,
"https://token-plan-sgp.xiaomimimo.com/v1",
"https://token-plan-sgp.xiaomimimo.com/anthropic"
],
[
xiaomiMimoTokenPlanEuropeProviderPreset,
"https://token-plan-ams.xiaomimimo.com/v1",
"https://token-plan-ams.xiaomimimo.com/anthropic"
]
];
for (const [preset, openAiBaseUrl, anthropicBaseUrl] of cases) {
assert.equal(providerPresets.find((candidate) => candidate.id === preset.id), preset);
assert.deepEqual(preset.defaultModels, ["mimo-v2.5-pro", "mimo-v2.5"]);
assert.deepEqual(preset.endpoints, [
{
baseUrl: openAiBaseUrl,
label: "OpenAI",
protocols: ["openai_responses", "openai_chat_completions"]
},
{
baseUrl: anthropicBaseUrl,
label: "Anthropic",
protocols: ["anthropic_messages"]
}
]);
assert.equal(providerPresetMatchesBaseUrl(preset, `${openAiBaseUrl}/responses`), true);
assert.equal(providerPresetMatchesBaseUrl(preset, `${anthropicBaseUrl}/v1/messages`), true);
}
});
test("NVIDIA preset ignores stale Responses detection and converts Codex requests to Chat Completions", () => {
const provider = {
api_base_url: "https://integrate.api.nvidia.com/v1",
Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

@@ -2128,6 +2128,10 @@ export const appCopy: Record<ResolvedLanguage, AppCopy> = {
"Kimi API (China)": "Kimi API(国内)",
"Kimi API (Global)": "Kimi API(海外)",
"Kimi Code - Coding Plan": "Kimi Code - Coding Plan",
"Xiaomi MiMo": "小米 MiMo",
"Xiaomi Token Plan (China)": "MiMo 套餐(国内)",
"Xiaomi Token Plan (Europe)": "MiMo 套餐(欧洲)",
"Xiaomi Token Plan (Singapore)": "MiMo 套餐(新加坡)",
"Zhipu AI (China)": "智谱 AI (国内)",
"Zhipu AI (China) - Coding Plan": "智谱 AI (国内) - Coding Plan",
"Zhipu AI (China) - General Endpoint": "智谱 AI (国内) - 通用端点",
@@ -62,6 +62,7 @@ import runapiProviderIconUrl from "@/assets/provider-icons/runapi.jpg";
import siliconflowProviderIconUrl from "@/assets/provider-icons/siliconflow.png";
import teamorouterProviderIconUrl from "@/assets/provider-icons/teamorouter.png";
import unity2ProviderIconUrl from "@/assets/provider-icons/unity2.jpg";
import xiaomiMimoProviderIconUrl from "@/assets/provider-icons/xiaomi-mimo.png";
import zaiGlobalCodingProviderIconUrl from "@/assets/provider-icons/zai-global-coding.svg";
import zaiGlobalGeneralProviderIconUrl from "@/assets/provider-icons/zai-global-general.svg";
import zhipuCnCodingProviderIconUrl from "@/assets/provider-icons/zhipu-cn-coding.png";
@@ -389,6 +390,10 @@ export const providerPresetIconUrls: Record<string, string> = {
siliconflow: siliconflowProviderIconUrl,
teamorouter: teamorouterProviderIconUrl,
unity2: unity2ProviderIconUrl,
xiaomi: xiaomiMimoProviderIconUrl,
"xiaomi-token-plan-ams": xiaomiMimoProviderIconUrl,
"xiaomi-token-plan-cn": xiaomiMimoProviderIconUrl,
"xiaomi-token-plan-sgp": xiaomiMimoProviderIconUrl,
"zai-global-coding": zaiGlobalCodingProviderIconUrl,
"zai-global-general": zaiGlobalGeneralProviderIconUrl,
"zhipu-cn-coding": zhipuCnCodingProviderIconUrl,
+14 -1
View File
@@ -7,6 +7,7 @@ import { geminiProviderPreset } from "@ccr/core/providers/presets/gemini/index.t
import { minimaxChinaProviderPreset } from "@ccr/core/providers/presets/minimax/index.ts";
import { moonshotGlobalProviderPreset } from "@ccr/core/providers/presets/moonshot/index.ts";
import { qiniuAiProviderPreset } from "@ccr/core/providers/presets/qiniu-ai/index.ts";
import { xiaomiMimoProviderPreset } from "@ccr/core/providers/presets/xiaomi/index.ts";
import { AddProviderDialog, AddProviderForm, ProviderConnectivityCheckDialog, ProvidersView, uniqueProviderProbeProtocolRows } from "@ccr/ui/pages/home/components/providers.tsx";
import {
applyProviderProbeResult,
@@ -1266,7 +1267,7 @@ test("provider deep link config saves anthropic probe prefix as capability URL",
});
test("provider display icon prefers custom icons and falls back to preset icons", () => {
setProviderPresets([geminiProviderPreset, minimaxChinaProviderPreset]);
setProviderPresets([geminiProviderPreset, minimaxChinaProviderPreset, xiaomiMimoProviderPreset]);
assert.equal(
providerDisplayIcon({
@@ -1296,6 +1297,18 @@ test("provider display icon prefers custom icons and falls back to preset icons"
}),
providerPresetIconUrls["minimax-cn"]
);
assert.equal(
providerDisplayIcon({
api_base_url: "https://api.xiaomimimo.com/v1",
models: [],
name: "Xiaomi MiMo",
type: "openai_responses"
}),
providerPresetIconUrls.xiaomi
);
assert.equal(providerPresetIconUrls["xiaomi-token-plan-cn"], providerPresetIconUrls.xiaomi);
assert.equal(providerPresetIconUrls["xiaomi-token-plan-sgp"], providerPresetIconUrls.xiaomi);
assert.equal(providerPresetIconUrls["xiaomi-token-plan-ams"], providerPresetIconUrls.xiaomi);
assert.equal(
providerDisplayIcon({
api_base_url: "https://cli-chat-proxy.grok.com/v1",