mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 12:44:18 +08:00
feat(proxy): session-based prompt_cache_key routing for Codex Chat bridge
Codex always sends prompt_cache_key in its Responses requests, but the Responses -> Chat Completions conversion dropped it, breaking session cache affinity on upstreams that route by key (e.g. Kimi Coding). - Re-inject prompt_cache_key after conversion in the forwarder: an explicit client key wins, otherwise a client-provided session ID; generated per-request UUIDs are never sent upstream. - Provider-aware gating: "auto" enables only known-compatible upstreams (api.openai.com, api.kimi.com/coding) because strict gateways reject unknown fields with HTTP 400 (e.g. Fireworks); an advanced Auto/Enabled/Disabled override is available on the Codex form in all four locales. - Kimi For Coding preset opts in explicitly.
This commit is contained in:
@@ -40,6 +40,7 @@ import type {
|
||||
CodexApiFormat,
|
||||
CodexCatalogModel,
|
||||
CodexChatReasoning,
|
||||
PromptCacheRoutingMode,
|
||||
ProviderCategory,
|
||||
} from "@/types";
|
||||
|
||||
@@ -89,6 +90,8 @@ interface CodexFormFieldsProps {
|
||||
onMaxOutputTokensChange: (value: string) => void;
|
||||
codexChatReasoning?: CodexChatReasoning;
|
||||
onCodexChatReasoningChange?: (value: CodexChatReasoning) => void;
|
||||
promptCacheRouting: PromptCacheRoutingMode;
|
||||
onPromptCacheRoutingChange: (value: PromptCacheRoutingMode) => void;
|
||||
|
||||
// Model Catalog
|
||||
catalogModels?: CodexCatalogModel[];
|
||||
@@ -182,6 +185,8 @@ export function CodexFormFields({
|
||||
onMaxOutputTokensChange,
|
||||
codexChatReasoning = {},
|
||||
onCodexChatReasoningChange,
|
||||
promptCacheRouting,
|
||||
onPromptCacheRoutingChange,
|
||||
catalogModels = [],
|
||||
onCatalogModelsChange,
|
||||
speedTestEndpoints,
|
||||
@@ -229,6 +234,7 @@ export function CodexFormFields({
|
||||
isAnthropicFormat ||
|
||||
supportsThinking ||
|
||||
supportsEffort ||
|
||||
promptCacheRouting !== "auto" ||
|
||||
!!maxOutputTokens;
|
||||
const [advancedExpanded, setAdvancedExpanded] = useState(hasAnyAdvancedValue);
|
||||
|
||||
@@ -716,6 +722,49 @@ export function CodexFormFields({
|
||||
shouldShowSpeedTest && "border-t border-border-default pt-3",
|
||||
)}
|
||||
>
|
||||
<div className="space-y-2">
|
||||
<FormLabel>
|
||||
{t("codexConfig.promptCacheRoutingLabel", {
|
||||
defaultValue: "提示词缓存路由",
|
||||
})}
|
||||
</FormLabel>
|
||||
<Select
|
||||
value={promptCacheRouting}
|
||||
onValueChange={(value) =>
|
||||
onPromptCacheRoutingChange(
|
||||
value as PromptCacheRoutingMode,
|
||||
)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="auto">
|
||||
{t("codexConfig.promptCacheRoutingAuto", {
|
||||
defaultValue: "自动(推荐)",
|
||||
})}
|
||||
</SelectItem>
|
||||
<SelectItem value="enabled">
|
||||
{t("codexConfig.promptCacheRoutingEnabled", {
|
||||
defaultValue: "开启",
|
||||
})}
|
||||
</SelectItem>
|
||||
<SelectItem value="disabled">
|
||||
{t("codexConfig.promptCacheRoutingDisabled", {
|
||||
defaultValue: "关闭",
|
||||
})}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-xs leading-relaxed text-muted-foreground">
|
||||
{t("codexConfig.promptCacheRoutingHint", {
|
||||
defaultValue:
|
||||
"自动模式仅对已确认兼容的上游发送 prompt_cache_key;开启可用于其他兼容网关,关闭可避免严格网关因未知字段返回 400。只使用客户端提供的稳定会话 ID。",
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<FormLabel>
|
||||
{t("codexConfig.reasoningGroupTitle", {
|
||||
|
||||
@@ -21,6 +21,7 @@ import type {
|
||||
CodexApiFormat,
|
||||
CodexCatalogModel,
|
||||
CodexChatReasoning,
|
||||
PromptCacheRoutingMode,
|
||||
ClaudeApiKeyField,
|
||||
} from "@/types";
|
||||
import {
|
||||
@@ -357,6 +358,7 @@ function ProviderFormFull({
|
||||
),
|
||||
});
|
||||
setCodexChatReasoning(initialData?.meta?.codexChatReasoning ?? {});
|
||||
setPromptCacheRouting(initialData?.meta?.promptCacheRouting ?? "auto");
|
||||
setCustomUserAgent(initialData?.meta?.customUserAgent ?? "");
|
||||
setLocalProxyHeadersOverride(
|
||||
formatRequestOverrideObject(
|
||||
@@ -529,6 +531,10 @@ function ProviderFormFull({
|
||||
useState<CodexChatReasoning>(
|
||||
() => initialData?.meta?.codexChatReasoning ?? {},
|
||||
);
|
||||
const [promptCacheRouting, setPromptCacheRouting] =
|
||||
useState<PromptCacheRoutingMode>(
|
||||
() => initialData?.meta?.promptCacheRouting ?? "auto",
|
||||
);
|
||||
const [customUserAgent, setCustomUserAgent] = useState<string>(
|
||||
() => initialData?.meta?.customUserAgent ?? "",
|
||||
);
|
||||
@@ -632,6 +638,7 @@ function ProviderFormFull({
|
||||
const template = getCodexCustomTemplate();
|
||||
resetCodexConfig(template.auth, template.config);
|
||||
setCodexChatReasoning({});
|
||||
setPromptCacheRouting("auto");
|
||||
}
|
||||
}, [appId, initialData, selectedPresetId, resetCodexConfig]);
|
||||
|
||||
@@ -1485,6 +1492,13 @@ function ProviderFormFull({
|
||||
localCodexApiFormat === "openai_chat"
|
||||
? normalizeCodexChatReasoningForSave(codexChatReasoning)
|
||||
: undefined,
|
||||
promptCacheRouting:
|
||||
appId === "codex" &&
|
||||
category !== "official" &&
|
||||
localCodexApiFormat === "openai_chat" &&
|
||||
promptCacheRouting !== "auto"
|
||||
? promptCacheRouting
|
||||
: undefined,
|
||||
customUserAgent:
|
||||
(appId === "claude" || appId === "codex") && category !== "official"
|
||||
? customUserAgent.trim() || undefined
|
||||
@@ -1651,6 +1665,7 @@ function ProviderFormFull({
|
||||
const template = getCodexCustomTemplate();
|
||||
resetCodexConfig(template.auth, template.config);
|
||||
setCodexChatReasoning({});
|
||||
setPromptCacheRouting("auto");
|
||||
setLocalCodexApiFormat(
|
||||
codexApiFormatFromWireApi(extractCodexWireApi(template.config)) ??
|
||||
"openai_responses",
|
||||
@@ -1692,6 +1707,7 @@ function ProviderFormFull({
|
||||
|
||||
resetCodexConfig(auth, config, preset.modelCatalog ?? []);
|
||||
setCodexChatReasoning(preset.codexChatReasoning ?? {});
|
||||
setPromptCacheRouting(preset.promptCacheRouting ?? "auto");
|
||||
setLocalCodexApiFormat(
|
||||
preset.apiFormat ??
|
||||
codexApiFormatFromWireApi(extractCodexWireApi(config)) ??
|
||||
@@ -2182,6 +2198,8 @@ function ProviderFormFull({
|
||||
onMaxOutputTokensChange={setLocalCodexMaxOutputTokens}
|
||||
codexChatReasoning={codexChatReasoning}
|
||||
onCodexChatReasoningChange={setCodexChatReasoning}
|
||||
promptCacheRouting={promptCacheRouting}
|
||||
onPromptCacheRoutingChange={setPromptCacheRouting}
|
||||
catalogModels={codexCatalogModels}
|
||||
onCatalogModelsChange={setCodexCatalogModels}
|
||||
speedTestEndpoints={speedTestEndpoints}
|
||||
|
||||
Reference in New Issue
Block a user