fix(agents): sync Kimi and Grok context windows with CPA core
This commit is contained in:
1 parent
b312b904a2
commit
51ea7fd69f
11 files changed
+218
-37
No files matched your search
@@ -688,7 +688,7 @@ pub(crate) async fn fetch_prepared_agent_models(
|
||||
prepare_codex_agent_models(&runtime_models)
|
||||
} else {
|
||||
let mut models = fetch_agent_models(config.port, api_key).await?;
|
||||
if client == AgentClient::ZCode {
|
||||
if agent_uses_cpa_runtime_context_windows(client) {
|
||||
let runtime_models = fetch_codex_runtime_models(config.port, api_key).await?;
|
||||
codex_catalog::merge_runtime_context_windows(&mut models, &runtime_models);
|
||||
}
|
||||
@@ -714,6 +714,13 @@ pub(crate) async fn fetch_prepared_agent_models(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn agent_uses_cpa_runtime_context_windows(client: AgentClient) -> bool {
|
||||
matches!(
|
||||
client,
|
||||
AgentClient::ZCode | AgentClient::KimiCode | AgentClient::GrokBuild
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_claude_desktop_model_mappings(
|
||||
client: AgentClient,
|
||||
models: &[AgentModelOption],
|
||||
|
||||
@@ -525,6 +525,10 @@ pub(crate) fn build_claude_agent_config(
|
||||
CLAUDE_CODE_MAX_CONTEXT_TOKENS_ENV.to_string(),
|
||||
serde_json::Value::String(max_context_tokens.to_string()),
|
||||
);
|
||||
env.insert(
|
||||
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY_ENV.to_string(),
|
||||
serde_json::Value::String("1".to_string()),
|
||||
);
|
||||
env.insert(
|
||||
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE_ENV.to_string(),
|
||||
serde_json::Value::String(mappings.auto_compact_pct.to_string()),
|
||||
@@ -922,6 +926,7 @@ pub(crate) fn remove_claude_code_managed_configuration(
|
||||
"ANTHROPIC_DEFAULT_SONNET_MODEL",
|
||||
"ANTHROPIC_DEFAULT_OPUS_MODEL",
|
||||
"ANTHROPIC_DEFAULT_FABLE_MODEL",
|
||||
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY_ENV,
|
||||
CLAUDE_CODE_MAX_CONTEXT_TOKENS_ENV,
|
||||
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE_ENV,
|
||||
DISABLE_AUTO_COMPACT_ENV,
|
||||
@@ -1582,6 +1587,7 @@ pub(crate) fn build_restored_claude_code_config(
|
||||
"ANTHROPIC_DEFAULT_SONNET_MODEL",
|
||||
"ANTHROPIC_DEFAULT_OPUS_MODEL",
|
||||
"ANTHROPIC_DEFAULT_FABLE_MODEL",
|
||||
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY_ENV,
|
||||
CLAUDE_CODE_MAX_CONTEXT_TOKENS_ENV,
|
||||
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE_ENV,
|
||||
DISABLE_AUTO_COMPACT_ENV,
|
||||
|
||||
@@ -368,6 +368,7 @@ pub(crate) fn inspect_pi_provider_status(
|
||||
config_exists,
|
||||
config_valid,
|
||||
configured,
|
||||
configuration_synchronized: configured,
|
||||
current_model: current_model.clone(),
|
||||
oauth_configuration: false,
|
||||
modification_enabled: configured,
|
||||
@@ -849,6 +850,7 @@ pub(crate) fn inspect_agent_config(
|
||||
warnings.push(message.clone());
|
||||
}
|
||||
let modification = inspect_agent_application(client, home);
|
||||
let configuration_synchronized = agent_configuration_is_synchronized(client, home, configured);
|
||||
warnings.extend(modification.warnings.iter().cloned());
|
||||
|
||||
AgentConfigStatus {
|
||||
@@ -865,6 +867,7 @@ pub(crate) fn inspect_agent_config(
|
||||
config_exists,
|
||||
config_valid,
|
||||
configured,
|
||||
configuration_synchronized,
|
||||
current_model,
|
||||
oauth_configuration,
|
||||
modification_enabled: modification.enabled,
|
||||
@@ -880,6 +883,23 @@ pub(crate) fn inspect_agent_config(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn agent_configuration_is_synchronized(
|
||||
client: AgentClient,
|
||||
home: &Path,
|
||||
configured: bool,
|
||||
) -> bool {
|
||||
if !configured {
|
||||
return false;
|
||||
}
|
||||
if !matches!(client, AgentClient::KimiCode | AgentClient::GrokBuild) {
|
||||
return true;
|
||||
}
|
||||
load_agent_applied_state(client, home)
|
||||
.ok()
|
||||
.flatten()
|
||||
.is_some_and(|state| state.configuration_revision >= AGENT_CONFIGURATION_REVISION)
|
||||
}
|
||||
|
||||
pub(crate) fn inspect_agent_application(
|
||||
client: AgentClient,
|
||||
home: &Path,
|
||||
@@ -2063,7 +2083,11 @@ pub(crate) fn inspect_claude_agent_config(
|
||||
&& env
|
||||
.and_then(|env| env.get("ANTHROPIC_AUTH_TOKEN"))
|
||||
.and_then(serde_json::Value::as_str)
|
||||
== Some(api_key);
|
||||
== Some(api_key)
|
||||
&& env
|
||||
.and_then(|env| env.get(CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY_ENV))
|
||||
.and_then(serde_json::Value::as_str)
|
||||
== Some("1");
|
||||
let model = env
|
||||
.and_then(|env| env.get("ANTHROPIC_MODEL"))
|
||||
.and_then(serde_json::Value::as_str)
|
||||
|
||||
@@ -161,6 +161,7 @@ pub(crate) fn recover_codex_applied_state_from_backups(
|
||||
version: AGENT_APPLIED_STATE_VERSION,
|
||||
client: AgentClient::Codex.id().to_string(),
|
||||
model,
|
||||
configuration_revision: AGENT_CONFIGURATION_REVISION,
|
||||
claude_desktop_model_mappings: None,
|
||||
backup_files,
|
||||
updated_at_unix: SystemTime::now()
|
||||
@@ -284,6 +285,7 @@ pub(crate) fn load_agent_applied_state(
|
||||
version: AGENT_APPLIED_STATE_VERSION,
|
||||
client: client.id().to_string(),
|
||||
model: record.model,
|
||||
configuration_revision: 0,
|
||||
claude_desktop_model_mappings: None,
|
||||
backup_files,
|
||||
updated_at_unix: SystemTime::now()
|
||||
@@ -1485,6 +1487,7 @@ pub(crate) fn commit_agent_configuration(
|
||||
version: AGENT_APPLIED_STATE_VERSION,
|
||||
client: client.id().to_string(),
|
||||
model: model.to_string(),
|
||||
configuration_revision: AGENT_CONFIGURATION_REVISION,
|
||||
claude_desktop_model_mappings: (client == AgentClient::ClaudeDesktop)
|
||||
.then(|| claude_desktop_model_mappings.cloned())
|
||||
.flatten(),
|
||||
|
||||
@@ -159,6 +159,8 @@ const MANAGED_CLAUDE_HAIKU_ALIAS_DISPLAY_NAME: &str =
|
||||
const DEFAULT_CLAUDE_CONTEXT_WINDOW: u64 = 200_000;
|
||||
const CLAUDE_DESKTOP_EXTENDED_CONTEXT_WINDOW: u64 = 1_000_000;
|
||||
const CLAUDE_CODE_MAX_CONTEXT_TOKENS_ENV: &str = "CLAUDE_CODE_MAX_CONTEXT_TOKENS";
|
||||
const CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY_ENV: &str =
|
||||
"CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY";
|
||||
const CLAUDE_AUTOCOMPACT_PCT_OVERRIDE_ENV: &str = "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE";
|
||||
const DISABLE_AUTO_COMPACT_ENV: &str = "DISABLE_AUTO_COMPACT";
|
||||
const DEFAULT_CLAUDE_AUTO_COMPACT_PCT: u8 = 90;
|
||||
@@ -171,6 +173,7 @@ const MODEL_ALIAS_CONFIG_SECTIONS: &[&str] = &[
|
||||
const LEGACY_AGENT_MODIFICATION_STATE_VERSION: u8 = 1;
|
||||
const AGENT_MODIFICATION_STATE_VERSION: u8 = 2;
|
||||
const AGENT_APPLIED_STATE_VERSION: u8 = 4;
|
||||
const AGENT_CONFIGURATION_REVISION: u8 = 1;
|
||||
const AGENT_PHASE_APPLYING: &str = "applying";
|
||||
const AGENT_PHASE_ACTIVE: &str = "active";
|
||||
const AGENT_PHASE_RESTORING: &str = "restoring";
|
||||
@@ -768,6 +771,7 @@ struct AgentConfigStatus {
|
||||
config_exists: bool,
|
||||
config_valid: bool,
|
||||
configured: bool,
|
||||
configuration_synchronized: bool,
|
||||
current_model: Option<String>,
|
||||
oauth_configuration: bool,
|
||||
modification_enabled: bool,
|
||||
@@ -951,6 +955,8 @@ struct AgentAppliedState {
|
||||
version: u8,
|
||||
client: String,
|
||||
model: String,
|
||||
#[serde(default)]
|
||||
configuration_revision: u8,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
claude_desktop_model_mappings: Option<ClaudeDesktopModelMappings>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
|
||||
@@ -22,6 +22,10 @@ fn claude_agent_config_preserves_existing_fields() {
|
||||
assert_eq!(value["env"]["ANTHROPIC_BASE_URL"], "http://127.0.0.1:8317");
|
||||
assert_eq!(value["env"]["ANTHROPIC_AUTH_TOKEN"], DEFAULT_API_KEY);
|
||||
assert_eq!(value["env"]["ANTHROPIC_MODEL"], "claude-test");
|
||||
assert_eq!(
|
||||
value["env"][CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY_ENV],
|
||||
"1"
|
||||
);
|
||||
assert_eq!(value["env"][CLAUDE_CODE_MAX_CONTEXT_TOKENS_ENV], "200000");
|
||||
assert_eq!(value["env"][CLAUDE_AUTOCOMPACT_PCT_OVERRIDE_ENV], "90");
|
||||
assert!(value["env"].get(DISABLE_AUTO_COMPACT_ENV).is_none());
|
||||
@@ -44,6 +48,7 @@ fn claude_code_inspection_normalizes_legacy_1m_suffix() {
|
||||
"env": {
|
||||
"ANTHROPIC_BASE_URL": "http://127.0.0.1:8317",
|
||||
"ANTHROPIC_AUTH_TOKEN": "test-key",
|
||||
"CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY": "1",
|
||||
"ANTHROPIC_MODEL": "deepseek-v4-pro[1m]",
|
||||
"ANTHROPIC_DEFAULT_OPUS_MODEL": "deepseek-v4-pro[1m]",
|
||||
"ANTHROPIC_DEFAULT_SONNET_MODEL": "deepseek-v4-pro[1m]",
|
||||
@@ -71,6 +76,30 @@ fn claude_code_inspection_normalizes_legacy_1m_suffix() {
|
||||
fs::remove_dir_all(directory).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn claude_code_requires_gateway_model_discovery_to_be_enabled() {
|
||||
let directory = agent_test_home("claude-code-gateway-model-discovery");
|
||||
let path = directory.join("settings.json");
|
||||
fs::write(
|
||||
&path,
|
||||
r#"{
|
||||
"env": {
|
||||
"ANTHROPIC_BASE_URL": "http://127.0.0.1:8317",
|
||||
"ANTHROPIC_AUTH_TOKEN": "test-key",
|
||||
"ANTHROPIC_MODEL": "gpt-test",
|
||||
"CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY": "0"
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (configured, model) = inspect_claude_agent_config(&path, 8317, "test-key").unwrap();
|
||||
|
||||
assert!(!configured);
|
||||
assert_eq!(model.as_deref(), Some("gpt-test"));
|
||||
fs::remove_dir_all(directory).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn claude_mapping_legacy_json_defaults_1m_preferences_off() {
|
||||
let mappings: ClaudeDesktopModelMappings =
|
||||
@@ -762,7 +791,9 @@ fn kimi_code_config_preserves_existing_tables_and_uses_openai_provider() {
|
||||
let home = agent_test_home("kimi-code-agent-config");
|
||||
let path = home.join(".kimi-code/config.toml");
|
||||
fs::create_dir_all(path.parent().unwrap()).unwrap();
|
||||
let models = test_agent_models(&["gpt-test", "deepseek-test"]);
|
||||
let mut models = test_agent_models(&["gpt-test", "deepseek-test"]);
|
||||
models[0].context_window = Some(1_048_576);
|
||||
models[1].context_window = Some(131_072);
|
||||
let rendered = build_kimi_code_agent_config(
|
||||
Some(
|
||||
r#"theme = "dark"
|
||||
@@ -806,6 +837,14 @@ model = "model"
|
||||
.as_str(),
|
||||
Some("tool_use")
|
||||
);
|
||||
assert_eq!(
|
||||
value["models"]["cpa-gui/gpt-test"]["max_context_size"].as_integer(),
|
||||
Some(1_048_576)
|
||||
);
|
||||
assert_eq!(
|
||||
value["models"]["cpa-gui/deepseek-test"]["max_context_size"].as_integer(),
|
||||
Some(131_072)
|
||||
);
|
||||
assert_eq!(
|
||||
inspect_kimi_code_agent_config(&path, 8317, DEFAULT_API_KEY).unwrap(),
|
||||
(true, Some("gpt-test".to_string()))
|
||||
@@ -818,7 +857,9 @@ fn grok_build_config_preserves_existing_models_and_uses_chat_completions() {
|
||||
let home = agent_test_home("grok-build-agent-config");
|
||||
let path = home.join(".grok/config.toml");
|
||||
fs::create_dir_all(path.parent().unwrap()).unwrap();
|
||||
let models = test_agent_models(&["gpt-test", "deepseek-test"]);
|
||||
let mut models = test_agent_models(&["gpt-test", "deepseek-test"]);
|
||||
models[0].context_window = Some(1_048_576);
|
||||
models[1].context_window = Some(131_072);
|
||||
let rendered = build_grok_build_agent_config(
|
||||
Some(
|
||||
r#"theme = "dark"
|
||||
@@ -858,6 +899,14 @@ api_key = "other-key"
|
||||
value["model"]["cpa-gui/gpt-test"]["api_backend"].as_str(),
|
||||
Some("chat_completions")
|
||||
);
|
||||
assert_eq!(
|
||||
value["model"]["cpa-gui/gpt-test"]["context_window"].as_integer(),
|
||||
Some(1_048_576)
|
||||
);
|
||||
assert_eq!(
|
||||
value["model"]["cpa-gui/deepseek-test"]["context_window"].as_integer(),
|
||||
Some(131_072)
|
||||
);
|
||||
assert_eq!(
|
||||
inspect_grok_build_agent_config(&path, 8317, DEFAULT_API_KEY).unwrap(),
|
||||
(true, Some("gpt-test".to_string()))
|
||||
@@ -1077,6 +1126,28 @@ fn agent_model_list_parser_exposes_aliases_as_selectable_model_ids() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kimi_grok_and_zcode_use_cpa_runtime_context_windows() {
|
||||
for client in [
|
||||
AgentClient::KimiCode,
|
||||
AgentClient::GrokBuild,
|
||||
AgentClient::ZCode,
|
||||
] {
|
||||
assert!(agent_uses_cpa_runtime_context_windows(client));
|
||||
}
|
||||
for client in [
|
||||
AgentClient::ClaudeCode,
|
||||
AgentClient::ClaudeDesktop,
|
||||
AgentClient::Codex,
|
||||
AgentClient::OpenCode,
|
||||
AgentClient::OpenClaw,
|
||||
AgentClient::Hermes,
|
||||
AgentClient::DeepSeekHarness,
|
||||
] {
|
||||
assert!(!agent_uses_cpa_runtime_context_windows(client));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn claude_model_lists_mark_yaml_aliases_when_api_returns_only_model_ids() {
|
||||
let mut models = test_agent_models(&[
|
||||
|
||||
@@ -453,6 +453,7 @@ fn zcode_legacy_single_file_state_upgrades_and_restores_cli_config() {
|
||||
version: AGENT_APPLIED_STATE_VERSION,
|
||||
client: AgentClient::ZCode.id().to_string(),
|
||||
model: "gpt-one".to_string(),
|
||||
configuration_revision: 0,
|
||||
claude_desktop_model_mappings: None,
|
||||
backup_files: vec![AgentAppliedBackupFile {
|
||||
path: paths[0].clone(),
|
||||
@@ -489,9 +490,37 @@ fn zcode_legacy_single_file_state_upgrades_and_restores_cli_config() {
|
||||
fs::remove_dir_all(home).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kimi_and_grok_legacy_states_require_context_catalog_resynchronization() {
|
||||
for client in [AgentClient::KimiCode, AgentClient::GrokBuild] {
|
||||
let home = agent_test_home(&format!("{}-context-revision", client.id()));
|
||||
let paths = agent_config_paths(client, &home);
|
||||
let state_path = agent_state_path(&paths).unwrap();
|
||||
fs::create_dir_all(state_path.parent().unwrap()).unwrap();
|
||||
let mut state = AgentAppliedState {
|
||||
version: AGENT_APPLIED_STATE_VERSION,
|
||||
client: client.id().to_string(),
|
||||
model: "gpt-test".to_string(),
|
||||
configuration_revision: 0,
|
||||
claude_desktop_model_mappings: None,
|
||||
backup_files: Vec::new(),
|
||||
updated_at_unix: 1,
|
||||
};
|
||||
write_agent_applied_state(&state_path, &state).unwrap();
|
||||
|
||||
assert!(!agent_configuration_is_synchronized(client, &home, true));
|
||||
|
||||
state.configuration_revision = AGENT_CONFIGURATION_REVISION;
|
||||
write_agent_applied_state(&state_path, &state).unwrap();
|
||||
assert!(agent_configuration_is_synchronized(client, &home, true));
|
||||
assert!(!agent_configuration_is_synchronized(client, &home, false));
|
||||
fs::remove_dir_all(home).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn session_merge_preserves_runtime_fields_for_other_agent_formats() {
|
||||
let claude_original = r#"{"env":{"KEEP_ENV":"original"},"keep":"claude"}"#;
|
||||
let claude_original = r#"{"env":{"KEEP_ENV":"original","CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY":"0"},"keep":"claude"}"#;
|
||||
let claude_managed = build_claude_agent_config(
|
||||
Some(claude_original),
|
||||
"http://127.0.0.1:8317",
|
||||
@@ -516,6 +545,10 @@ fn session_merge_preserves_runtime_fields_for_other_agent_formats() {
|
||||
assert_eq!(claude["runtimeAdded"], true);
|
||||
assert_eq!(claude["env"]["RUNTIME_ENV"], "keep");
|
||||
assert_eq!(claude["env"]["KEEP_ENV"], "original");
|
||||
assert_eq!(
|
||||
claude["env"][CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY_ENV],
|
||||
"0"
|
||||
);
|
||||
assert!(claude["env"].get("ANTHROPIC_BASE_URL").is_none());
|
||||
assert!(claude.get("model").is_none());
|
||||
|
||||
@@ -735,6 +768,7 @@ fn legacy_codex_single_file_state_remains_restorable() {
|
||||
version: AGENT_APPLIED_STATE_VERSION,
|
||||
client: AgentClient::Codex.id().to_string(),
|
||||
model: "gpt-test".to_string(),
|
||||
configuration_revision: AGENT_CONFIGURATION_REVISION,
|
||||
claude_desktop_model_mappings: None,
|
||||
backup_files: vec![AgentAppliedBackupFile {
|
||||
path: path.clone(),
|
||||
@@ -799,6 +833,7 @@ fn claude_desktop_version_three_state_can_be_closed_safely() {
|
||||
version: 3,
|
||||
client: AgentClient::ClaudeDesktop.id().to_string(),
|
||||
model: "gpt-test".to_string(),
|
||||
configuration_revision: 0,
|
||||
claude_desktop_model_mappings: None,
|
||||
backup_files: Vec::new(),
|
||||
updated_at_unix: 1,
|
||||
@@ -930,6 +965,7 @@ fn applied_state_rejects_backup_paths_outside_the_managed_config_set() {
|
||||
version: AGENT_APPLIED_STATE_VERSION,
|
||||
client: AgentClient::OpenCode.id().to_string(),
|
||||
model: "gpt-test".to_string(),
|
||||
configuration_revision: AGENT_CONFIGURATION_REVISION,
|
||||
claude_desktop_model_mappings: None,
|
||||
backup_files: vec![AgentAppliedBackupFile {
|
||||
path: path.clone(),
|
||||
@@ -966,6 +1002,7 @@ fn missing_session_backup_is_detected_before_any_file_is_restored() {
|
||||
version: AGENT_APPLIED_STATE_VERSION,
|
||||
client: AgentClient::Codex.id().to_string(),
|
||||
model: "gpt-test".to_string(),
|
||||
configuration_revision: AGENT_CONFIGURATION_REVISION,
|
||||
claude_desktop_model_mappings: None,
|
||||
backup_files: vec![
|
||||
AgentAppliedBackupFile {
|
||||
@@ -1003,6 +1040,7 @@ fn version_three_cleanup_covers_every_non_desktop_agent_format() {
|
||||
version: 3,
|
||||
client: client.id().to_string(),
|
||||
model: "gpt-test".to_string(),
|
||||
configuration_revision: 0,
|
||||
claude_desktop_model_mappings: None,
|
||||
backup_files: Vec::new(),
|
||||
updated_at_unix: 1,
|
||||
@@ -1017,6 +1055,7 @@ fn version_three_cleanup_covers_every_non_desktop_agent_format() {
|
||||
"ANTHROPIC_BASE_URL": "http://127.0.0.1:8317",
|
||||
"ANTHROPIC_API_KEY": "secret",
|
||||
"ANTHROPIC_AUTH_TOKEN": "secret",
|
||||
"CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY": "1",
|
||||
"ANTHROPIC_MODEL": "gpt-test",
|
||||
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "gpt-test",
|
||||
"KEEP_ENV": "yes"
|
||||
@@ -1039,6 +1078,9 @@ fn version_three_cleanup_covers_every_non_desktop_agent_format() {
|
||||
serde_json::from_str(&fs::read_to_string(&claude_path).unwrap()).unwrap();
|
||||
assert!(claude.get("model").is_none());
|
||||
assert!(claude["env"].get("ANTHROPIC_BASE_URL").is_none());
|
||||
assert!(claude["env"]
|
||||
.get(CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY_ENV)
|
||||
.is_none());
|
||||
assert_eq!(claude["env"]["KEEP_ENV"], "yes");
|
||||
assert_eq!(claude["keep"], "claude");
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
+33
-31
@@ -32,6 +32,7 @@ import kimiIcon from '../assets/icons/kimi-light.svg';
|
||||
import openclawIcon from '../assets/icons/openclaw.svg';
|
||||
import opencodeIcon from '../assets/icons/opencode.svg';
|
||||
import piIcon from '../assets/icons/pi-logo-on-light.svg';
|
||||
import zcodeIcon from '../assets/icons/zcode.png';
|
||||
import {
|
||||
agentModelAlias,
|
||||
filterAgentModels,
|
||||
@@ -79,6 +80,7 @@ type AgentConfigStatus = {
|
||||
pluginVersion: string | null;
|
||||
configValid: boolean;
|
||||
configured: boolean;
|
||||
configurationSynchronized: boolean;
|
||||
currentModel: string | null;
|
||||
oauthConfiguration: boolean;
|
||||
modificationEnabled: boolean;
|
||||
@@ -205,12 +207,42 @@ const agentDefinitions: AgentDefinition[] = [
|
||||
icon: codexIcon,
|
||||
descriptionKey: 'agents.description.codex',
|
||||
},
|
||||
{
|
||||
id: 'deepseek-harness',
|
||||
name: 'DeepSeek Harness',
|
||||
icon: deepseekIcon,
|
||||
descriptionKey: 'agents.description.deepseekHarness',
|
||||
},
|
||||
{
|
||||
id: 'opencode',
|
||||
name: 'OpenCode',
|
||||
icon: opencodeIcon,
|
||||
descriptionKey: 'agents.description.opencode',
|
||||
},
|
||||
{
|
||||
id: 'pi',
|
||||
name: 'Pi',
|
||||
icon: piIcon,
|
||||
descriptionKey: 'agents.description.pi',
|
||||
},
|
||||
{
|
||||
id: 'grok-build',
|
||||
name: 'Grok Build',
|
||||
icon: grokIcon,
|
||||
descriptionKey: 'agents.description.grokBuild',
|
||||
},
|
||||
{
|
||||
id: 'zcode',
|
||||
name: 'ZCode',
|
||||
icon: zcodeIcon,
|
||||
descriptionKey: 'agents.description.zcode',
|
||||
},
|
||||
{
|
||||
id: 'kimi-code',
|
||||
name: 'Kimi Code',
|
||||
icon: kimiIcon,
|
||||
descriptionKey: 'agents.description.kimiCode',
|
||||
},
|
||||
{
|
||||
id: 'openclaw',
|
||||
name: 'OpenClaw',
|
||||
@@ -223,36 +255,6 @@ const agentDefinitions: AgentDefinition[] = [
|
||||
icon: hermesIcon,
|
||||
descriptionKey: 'agents.description.hermes',
|
||||
},
|
||||
{
|
||||
id: 'deepseek-harness',
|
||||
name: 'DeepSeek Harness',
|
||||
icon: deepseekIcon,
|
||||
descriptionKey: 'agents.description.deepseekHarness',
|
||||
},
|
||||
{
|
||||
id: 'zcode',
|
||||
name: 'ZCode',
|
||||
Icon: Bot,
|
||||
descriptionKey: 'agents.description.zcode',
|
||||
},
|
||||
{
|
||||
id: 'kimi-code',
|
||||
name: 'Kimi Code',
|
||||
icon: kimiIcon,
|
||||
descriptionKey: 'agents.description.kimiCode',
|
||||
},
|
||||
{
|
||||
id: 'grok-build',
|
||||
name: 'Grok Build',
|
||||
icon: grokIcon,
|
||||
descriptionKey: 'agents.description.grokBuild',
|
||||
},
|
||||
{
|
||||
id: 'pi',
|
||||
name: 'Pi',
|
||||
icon: piIcon,
|
||||
descriptionKey: 'agents.description.pi',
|
||||
},
|
||||
];
|
||||
|
||||
const agentSubpages: AgentSubpageDefinition[] = [
|
||||
@@ -885,7 +887,7 @@ export function AgentsPage() {
|
||||
const configurationAction = resolveAgentConfigurationAction({
|
||||
client: selected,
|
||||
modificationState: activeStatus?.modificationState ?? 'unconfigured',
|
||||
configurationSynchronized: Boolean(activeStatus?.configured),
|
||||
configurationSynchronized: Boolean(activeStatus?.configurationSynchronized),
|
||||
selectedModel,
|
||||
appliedModel,
|
||||
oauthConfiguration,
|
||||
|
||||
@@ -93,7 +93,10 @@ export function resolveAgentConfigurationAction({
|
||||
}: ResolveAgentConfigurationActionOptions): AgentConfigurationAction {
|
||||
if (modificationState !== 'applied') return 'apply';
|
||||
if (client === 'pi') return 'close';
|
||||
if (client === 'zcode' && !configurationSynchronized) return 'update';
|
||||
if (
|
||||
(client === 'zcode' || client === 'kimi-code' || client === 'grok-build')
|
||||
&& !configurationSynchronized
|
||||
) return 'update';
|
||||
|
||||
const modelChanged = client === 'claude-code' || client === 'claude-desktop'
|
||||
? !sameAgentModelMappings(modelMappings, appliedModelMappings)
|
||||
|
||||
@@ -175,6 +175,23 @@ describe('agent configuration update action', () => {
|
||||
})).toBe('update');
|
||||
});
|
||||
|
||||
test.each<AgentConfigurationClientId>(['kimi-code', 'grok-build'])(
|
||||
'%s updates an applied configuration whose CPA context catalog is stale',
|
||||
(client) => {
|
||||
expect(resolveAgentConfigurationAction({
|
||||
client,
|
||||
modificationState: 'applied',
|
||||
configurationSynchronized: false,
|
||||
selectedModel: 'model-a',
|
||||
appliedModel: 'model-a',
|
||||
oauthConfiguration: false,
|
||||
appliedOauthConfiguration: false,
|
||||
modelMappings: { opus: '', sonnet: '', haiku: '' },
|
||||
appliedModelMappings: { opus: '', sonnet: '', haiku: '' },
|
||||
})).toBe('update');
|
||||
},
|
||||
);
|
||||
|
||||
test('Codex also updates when only OAuth configuration changes', () => {
|
||||
expect(resolveAgentConfigurationAction({
|
||||
client: 'codex',
|
||||
|
||||
Reference in new issue
Block a user