mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-10-26 01:34:51 +08:00
fix(codex): stop aggregated sessions from compacting on the previous provider
In aggregation mode the route provider's catalog rows kept their template comp_hash (official GPT mirrors carry "3000") while Stack member rows used "cc-switch". Switching a session between the two made Codex run a pre-turn compaction with the previous model; when that provider was out of quota the compaction failed, custom providers get no retry with the current model, and every later turn hit the same provider again. Third-party route rows in the merged catalog now share the Stack comp_hash, which also unsticks sessions already stuck this way. The official route keeps its native rows: Codex retries with the current model there and the official compaction semantics stay intact. Closes #8485
This commit is contained in:
1 parent
273d166b2f
commit
8a0eddb0f0
2 files changed
+28
-11
No files matched your search
@@ -2530,10 +2530,15 @@ pub(crate) enum CodexStackRoute<'a> {
|
||||
},
|
||||
}
|
||||
|
||||
/// 合并目录里 Stack 行统一的 `comp_hash`。Codex 在一个会话记下的值变了时会压缩一次;
|
||||
/// 模板带来的值会随来源漂移(DeepSeek 官方目录是 "3000",从 Codex 缓存克隆的 gpt-5.5
|
||||
/// 跟着缓存变),固定值才稳定。路由那家的行不改:它的值要和名单为空时的目录一致,否则
|
||||
/// 加进第一家、移除最后一家都会让路由上的会话恢复时被压缩一次。
|
||||
/// 合并目录里 Stack 行统一的 `comp_hash`。Codex 在一个会话记下的值变了时,会先用**上一个
|
||||
/// 模型**压缩一次(codex-rs `maybe_run_previous_model_inline_compact`);模板带来的值会随
|
||||
/// 来源漂移(DeepSeek 官方目录是 "3000",镜像官方的 GPT 行也是),固定值才稳定。
|
||||
///
|
||||
/// 第三方路由那家的行也写这个值:否则在它和 Stack 行之间切换都要先用上一家压缩,上一家
|
||||
/// 不可用(额度用完)时压缩失败,而自定义供应商不会改用当前模型重试,会话从此每轮都卡在
|
||||
/// 上一家(#8485)。代价是加进第一家、移除最后一家时,路由上原本带值的会话会用路由那家
|
||||
/// 自己的模型压缩一次。官方路由的原生行不改:失败时 Codex 会改用当前模型重试,官方的
|
||||
/// 压缩语义也要保留。
|
||||
const CODEX_STACK_COMP_HASH: &str = "cc-switch";
|
||||
|
||||
/// Stack 名单非空时的模型目录:路由那家的行在前,各 Stack 供应商的行按名单顺序在后,
|
||||
@@ -2549,7 +2554,15 @@ pub(crate) fn plan_codex_stack_catalog(
|
||||
classic_subagents: bool,
|
||||
) -> Result<Value, AppError> {
|
||||
let mut entries = match route {
|
||||
CodexStackRoute::ThirdParty(row) => codex_stack_third_party_rows(&row)?,
|
||||
CodexStackRoute::ThirdParty(row) => {
|
||||
let mut rows = codex_stack_third_party_rows(&row)?;
|
||||
for entry in &mut rows {
|
||||
if let Some(obj) = entry.as_object_mut() {
|
||||
obj.insert("comp_hash".to_string(), json!(CODEX_STACK_COMP_HASH));
|
||||
}
|
||||
}
|
||||
rows
|
||||
}
|
||||
CodexStackRoute::Official {
|
||||
mut native,
|
||||
config_text,
|
||||
@@ -2634,7 +2647,7 @@ pub(crate) fn plan_codex_stack_catalog(
|
||||
/// `config.toml` 里 `[features] multi_agent_v2 = true` 比目录优先,这时写了也不生效。
|
||||
const CODEX_CLASSIC_SUBAGENTS: &str = "v1";
|
||||
|
||||
/// 一家第三方供应商在合并目录里的行(`comp_hash` 保持模板的值)。
|
||||
/// 一家第三方供应商在合并目录里的行(`comp_hash` 保持模板的值,由调用方统一改写)。
|
||||
pub(crate) fn codex_stack_third_party_rows(
|
||||
row: &CodexCatalogRow<'_>,
|
||||
) -> Result<Vec<Value>, AppError> {
|
||||
@@ -5781,8 +5794,11 @@ wire_api = "responses"
|
||||
assert_eq!(models, vec!["deepseek/deepseek-v4"]);
|
||||
}
|
||||
|
||||
/// #8485:第三方路由那家的行和 Stack 行同一个 `comp_hash`,两者之间切换时 Codex 不会先
|
||||
/// 用上一家压缩(上一家额度用完时压缩失败,会话每轮都卡在上一家)。名单为空时的目录
|
||||
/// 仍是模板的值。
|
||||
#[test]
|
||||
fn the_route_rows_keep_the_comp_hash_they_have_without_stack_models() {
|
||||
fn third_party_route_rows_share_the_stack_comp_hash() {
|
||||
let route_settings =
|
||||
json!({ "modelCatalog": { "models": [{ "model": "deepseek-v4-pro" }] } });
|
||||
let route_text = "model_provider = \"deepseek\"\nmodel = \"deepseek-v4-pro\"\n\
|
||||
@@ -5814,9 +5830,10 @@ wire_api = "responses"
|
||||
.unwrap();
|
||||
let models = stacked["models"].as_array().unwrap();
|
||||
assert_eq!(models[0]["slug"], "deepseek-v4-pro");
|
||||
assert_eq!(models[0]["comp_hash"], plain["models"][0]["comp_hash"]);
|
||||
assert_eq!(models[1]["slug"], "ccs-ds/deepseek-v4-pro");
|
||||
assert_eq!(models[1]["comp_hash"], "cc-switch");
|
||||
for model in models {
|
||||
assert_eq!(model["comp_hash"], "cc-switch", "{}", model["slug"]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -6987,8 +6987,8 @@ model_provider = "c"
|
||||
assert_eq!(route["priority"], 1);
|
||||
assert_eq!(route["context_window"], 200000);
|
||||
assert_eq!(route["auto_compact_token_limit"], 150000);
|
||||
// 路由那家的行保持模板的值(这里模板没有),加进第一家不会让路由上的会话被压缩。
|
||||
assert_eq!(route["comp_hash"], Value::Null);
|
||||
// 第三方路由那家的行和 Stack 行同一个值,互相切换不会先用上一家压缩(#8485)。
|
||||
assert_eq!(route["comp_hash"], "cc-switch");
|
||||
assert_eq!(stacked["priority"], 2);
|
||||
assert_eq!(stacked["display_name"], "DeepSeek V4 Pro(DEEPSEEK)");
|
||||
// DeepSeek 官方目录的 "3000" 不带过来,窗口按它自己的行算。
|
||||
|
||||
Reference in new issue
Block a user