mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-03 11:01:22 +08:00
feat: adaptive reasoning detection for Codex Chat providers
Auto-detect each Chat-routed Codex provider's reasoning interface from
its name, base URL, and model, then inject the matching thinking
parameter without manual configuration:
- Platform-first inference (OpenRouter, SiliconFlow) overrides model
rules, since the same model exposes different reasoning controls
depending on the hosting platform.
- Effort tiers are forwarded only to providers that support them
(DeepSeek, OpenRouter, and StepFun's step-3.5-flash-2603); on/off-only
providers (Kimi, GLM, Qwen, MiniMax, MiMo, SiliconFlow) drop the level
instead of sending a field the upstream rejects.
- OpenRouter uses the native reasoning:{effort} object, clamps max to
xhigh (its enum has no max), and forwards an explicit effort:"none" so
reasoning can be turned off.
- StepFun falls back to inference so per-model effort support is honored
(the static preset would have forced effort on step-3.5-flash too).
Includes the Codex provider-form reasoning controls, i18n strings
(zh/en/ja), and response-side reasoning extraction.
This commit is contained in:
@@ -16,6 +16,7 @@ import type {
|
||||
ClaudeApiFormat,
|
||||
CodexApiFormat,
|
||||
CodexCatalogModel,
|
||||
CodexChatReasoning,
|
||||
ClaudeApiKeyField,
|
||||
} from "@/types";
|
||||
import {
|
||||
@@ -174,6 +175,41 @@ export const normalizeCodexCatalogModelsForSave = (
|
||||
return normalized;
|
||||
};
|
||||
|
||||
const normalizeCodexChatReasoningForSave = (
|
||||
value?: CodexChatReasoning,
|
||||
): CodexChatReasoning | undefined => {
|
||||
const supportsEffort = value?.supportsEffort === true;
|
||||
const supportsThinking = value?.supportsThinking === true || supportsEffort;
|
||||
const hasExplicitConfig = value && Object.keys(value).length > 0;
|
||||
|
||||
if (!supportsThinking && !supportsEffort) {
|
||||
return hasExplicitConfig
|
||||
? {
|
||||
supportsThinking: false,
|
||||
supportsEffort: false,
|
||||
thinkingParam: "none",
|
||||
effortParam: "none",
|
||||
outputFormat: value?.outputFormat ?? "auto",
|
||||
}
|
||||
: undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
supportsThinking,
|
||||
supportsEffort,
|
||||
thinkingParam: supportsThinking
|
||||
? (value?.thinkingParam ?? "thinking")
|
||||
: "none",
|
||||
effortParam: supportsEffort
|
||||
? (value?.effortParam ?? "reasoning_effort")
|
||||
: "none",
|
||||
effortValueMode: supportsEffort
|
||||
? (value?.effortValueMode ?? "passthrough")
|
||||
: undefined,
|
||||
outputFormat: value?.outputFormat ?? "auto",
|
||||
};
|
||||
};
|
||||
|
||||
export interface ProviderFormProps {
|
||||
appId: AppId;
|
||||
providerId?: string;
|
||||
@@ -316,6 +352,7 @@ function ProviderFormFull({
|
||||
initialData?.meta?.pricingModelSource,
|
||||
),
|
||||
});
|
||||
setCodexChatReasoning(initialData?.meta?.codexChatReasoning ?? {});
|
||||
}, [appId, initialData, supportsFullUrl]);
|
||||
|
||||
const defaultValues: ProviderFormData = useMemo(
|
||||
@@ -466,6 +503,10 @@ function ProviderFormFull({
|
||||
const [codexFastMode, setCodexFastMode] = useState<boolean>(
|
||||
() => initialData?.meta?.codexFastMode ?? false,
|
||||
);
|
||||
const [codexChatReasoning, setCodexChatReasoning] =
|
||||
useState<CodexChatReasoning>(
|
||||
() => initialData?.meta?.codexChatReasoning ?? {},
|
||||
);
|
||||
|
||||
const {
|
||||
codexAuth,
|
||||
@@ -530,6 +571,7 @@ function ProviderFormFull({
|
||||
if (appId === "codex" && !initialData && selectedPresetId === "custom") {
|
||||
const template = getCodexCustomTemplate();
|
||||
resetCodexConfig(template.auth, template.config);
|
||||
setCodexChatReasoning({});
|
||||
}
|
||||
}, [appId, initialData, selectedPresetId, resetCodexConfig]);
|
||||
|
||||
@@ -1336,6 +1378,12 @@ function ProviderFormFull({
|
||||
? selectedGitHubAccountId
|
||||
: undefined,
|
||||
codexFastMode: isCodexOauthProvider ? codexFastMode : undefined,
|
||||
codexChatReasoning:
|
||||
appId === "codex" &&
|
||||
category !== "official" &&
|
||||
localCodexApiFormat === "openai_chat"
|
||||
? normalizeCodexChatReasoningForSave(codexChatReasoning)
|
||||
: undefined,
|
||||
testConfig: testConfig.enabled ? testConfig : undefined,
|
||||
costMultiplier: pricingConfig.enabled
|
||||
? pricingConfig.costMultiplier
|
||||
@@ -1473,6 +1521,7 @@ function ProviderFormFull({
|
||||
if (appId === "codex") {
|
||||
const template = getCodexCustomTemplate();
|
||||
resetCodexConfig(template.auth, template.config);
|
||||
setCodexChatReasoning({});
|
||||
setLocalCodexApiFormat(
|
||||
codexApiFormatFromWireApi(extractCodexWireApi(template.config)) ??
|
||||
"openai_responses",
|
||||
@@ -1513,6 +1562,7 @@ function ProviderFormFull({
|
||||
const config = preset.config ?? "";
|
||||
|
||||
resetCodexConfig(auth, config, preset.modelCatalog ?? []);
|
||||
setCodexChatReasoning(preset.codexChatReasoning ?? {});
|
||||
setLocalCodexApiFormat(
|
||||
preset.apiFormat ??
|
||||
codexApiFormatFromWireApi(extractCodexWireApi(config)) ??
|
||||
@@ -1984,6 +2034,8 @@ function ProviderFormFull({
|
||||
onAutoSelectChange={setEndpointAutoSelect}
|
||||
apiFormat={localCodexApiFormat}
|
||||
onApiFormatChange={handleCodexApiFormatChange}
|
||||
codexChatReasoning={codexChatReasoning}
|
||||
onCodexChatReasoningChange={setCodexChatReasoning}
|
||||
catalogModels={codexCatalogModels}
|
||||
onCatalogModelsChange={setCodexCatalogModels}
|
||||
speedTestEndpoints={speedTestEndpoints}
|
||||
|
||||
Reference in New Issue
Block a user