mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-06-16 13:34:04 +08:00
4b57f7e113
- Replace the four flat env inputs with a Sonnet/Opus/Haiku role table. Each row exposes ANTHROPIC_DEFAULT_*_MODEL plus a new display name field ANTHROPIC_DEFAULT_*_MODEL_NAME, and Sonnet/Opus gain a "Declare 1M" checkbox that toggles the [1M] suffix. - Strip the [1M] context-capability marker before forwarding non-Copilot requests upstream. Copilot keeps its existing [1m]->-1m normalization. - Claude Desktop import now consumes ANTHROPIC_DEFAULT_*_MODEL_NAME as label_override, closing the Claude Code -> Claude Desktop displayName pipeline; add_route's merge logic is shared between hashmap branches. - Unify the [1M] marker as ONE_M_CONTEXT_MARKER across claude_desktop_config and proxy::model_mapper; rename the strip helper to strip_one_m_suffix_for_upstream. - Collapse useModelState's seven duplicated useState initializers and the useEffect parse block into a single parseModelsFromConfig call. - Add tests/hooks/useModelState.test.tsx and a Claude Desktop import test covering Kimi K2 -> label_override. i18n (en/ja/zh) updated.
111 lines
3.5 KiB
TypeScript
111 lines
3.5 KiB
TypeScript
import { act, renderHook } from "@testing-library/react";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
import {
|
|
hasClaudeOneMMarker,
|
|
setClaudeOneMMarker,
|
|
stripClaudeOneMMarker,
|
|
useModelState,
|
|
} from "@/components/providers/forms/hooks/useModelState";
|
|
|
|
describe("useModelState", () => {
|
|
it("hydrates role models and display names from Claude Code env", () => {
|
|
const settingsConfig = JSON.stringify({
|
|
env: {
|
|
ANTHROPIC_MODEL: "fallback-model",
|
|
ANTHROPIC_SMALL_FAST_MODEL: "legacy-small",
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: "deepseek-v4-pro",
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL_NAME: "DeepSeek V4 Pro",
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: "kimi-k2",
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL_NAME: "Kimi K2",
|
|
},
|
|
});
|
|
|
|
const { result } = renderHook(() =>
|
|
useModelState({
|
|
settingsConfig,
|
|
onConfigChange: vi.fn(),
|
|
}),
|
|
);
|
|
|
|
expect(result.current.claudeModel).toBe("fallback-model");
|
|
expect(result.current.defaultSonnetModel).toBe("deepseek-v4-pro");
|
|
expect(result.current.defaultSonnetModelName).toBe("DeepSeek V4 Pro");
|
|
expect(result.current.defaultOpusModel).toBe("kimi-k2");
|
|
expect(result.current.defaultOpusModelName).toBe("Kimi K2");
|
|
expect(result.current.defaultHaikuModel).toBe("legacy-small");
|
|
expect(result.current.defaultHaikuModelName).toBe("legacy-small");
|
|
});
|
|
|
|
it("writes and clears role display-name env fields without changing model mapping", () => {
|
|
let latestConfig = JSON.stringify({
|
|
env: {
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: "deepseek-v4-pro",
|
|
},
|
|
});
|
|
const onConfigChange = vi.fn((config: string) => {
|
|
latestConfig = config;
|
|
});
|
|
|
|
const { result } = renderHook(() =>
|
|
useModelState({
|
|
settingsConfig: latestConfig,
|
|
onConfigChange,
|
|
}),
|
|
);
|
|
|
|
act(() => {
|
|
result.current.handleModelChange(
|
|
"ANTHROPIC_DEFAULT_SONNET_MODEL_NAME",
|
|
"DeepSeek V4 Pro",
|
|
);
|
|
});
|
|
|
|
let env = JSON.parse(latestConfig).env;
|
|
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe("deepseek-v4-pro");
|
|
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL_NAME).toBe("DeepSeek V4 Pro");
|
|
|
|
act(() => {
|
|
result.current.handleModelChange(
|
|
"ANTHROPIC_DEFAULT_SONNET_MODEL_NAME",
|
|
"",
|
|
);
|
|
});
|
|
|
|
env = JSON.parse(latestConfig).env;
|
|
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe("deepseek-v4-pro");
|
|
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL_NAME).toBeUndefined();
|
|
});
|
|
|
|
it("keeps the 1M marker on request models but strips it from fallback display names", () => {
|
|
const settingsConfig = JSON.stringify({
|
|
env: {
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: "deepseek-v4-pro[1M]",
|
|
},
|
|
});
|
|
|
|
const { result } = renderHook(() =>
|
|
useModelState({
|
|
settingsConfig,
|
|
onConfigChange: vi.fn(),
|
|
}),
|
|
);
|
|
|
|
expect(result.current.defaultSonnetModel).toBe("deepseek-v4-pro[1M]");
|
|
expect(result.current.defaultSonnetModelName).toBe("deepseek-v4-pro");
|
|
});
|
|
|
|
it("normalizes Claude Code 1M markers for UI toggles", () => {
|
|
expect(hasClaudeOneMMarker("deepseek-v4-pro[1m]")).toBe(true);
|
|
expect(hasClaudeOneMMarker("deepseek-v4-pro [1M] ")).toBe(true);
|
|
expect(stripClaudeOneMMarker("deepseek-v4-pro [1M] ")).toBe(
|
|
"deepseek-v4-pro",
|
|
);
|
|
expect(setClaudeOneMMarker("deepseek-v4-pro [1M]", false)).toBe(
|
|
"deepseek-v4-pro",
|
|
);
|
|
expect(setClaudeOneMMarker("deepseek-v4-pro", true)).toBe(
|
|
"deepseek-v4-pro[1M]",
|
|
);
|
|
});
|
|
});
|