From 2b49fe6a25a3d1bba592a9430b230f247b3408bc Mon Sep 17 00:00:00 2001 From: lzt404 <2596933790@qq.com> Date: Sun, 4 Oct 2026 16:44:28 +0800 Subject: [PATCH] feat: refine usage views and add Codex system prompt editing - Brighten usage subpages with consistent surfaces and text contrast - Show reasoning effort by default and migrate saved column settings - Hide HTTP method prefixes and tighten request table spacing - Support custom Codex system prompts and synchronize instruction templates - Add a clear button to plugin search - Update localization, mocks, and regression tests --- src-tauri/src/codex_catalog.rs | 1 + src-tauri/src/codex_catalog/customizations.rs | 28 +++++- src/i18n/ja.ts | 3 + src/i18n/locales/en.ts | 3 + src/i18n/locales/zh-CN.ts | 3 + src/mocks/browserMockRuntime.ts | 1 + src/pages/CodexModelCatalogDialog.tsx | 1 + src/pages/PluginsPage.css | 13 ++- src/pages/PluginsPage.tsx | 13 ++- src/pages/UsageEventsView.css | 2 +- src/pages/UsageEventsView.tsx | 42 +++++--- src/services/codexModelCatalog.ts | 3 + src/styles.css | 5 + src/styles/index.css | 1 + src/styles/usage-subpages.css | 99 +++++++++++++++++++ tests/codexModelCatalog.test.ts | 9 ++ tests/fixtures/usage-response-model.tsx | 6 +- tests/plugins-ui.cjs | 20 ++++ tests/usage-response-model-ui.cjs | 3 + 19 files changed, 233 insertions(+), 23 deletions(-) create mode 100644 src/styles/usage-subpages.css diff --git a/src-tauri/src/codex_catalog.rs b/src-tauri/src/codex_catalog.rs index f8823d5..e398b7d 100644 --- a/src-tauri/src/codex_catalog.rs +++ b/src-tauri/src/codex_catalog.rs @@ -494,6 +494,7 @@ fn prepare_catalog_with_customizations( } for entry in &mut entries { + entry.value.insert("supports_parallel_tool_calls".to_string(), Value::Bool(true)); customizations::apply_customizations(&mut entry.value, customizations)?; } diff --git a/src-tauri/src/codex_catalog/customizations.rs b/src-tauri/src/codex_catalog/customizations.rs index 1f90fc1..37a51f8 100644 --- a/src-tauri/src/codex_catalog/customizations.rs +++ b/src-tauri/src/codex_catalog/customizations.rs @@ -6,9 +6,10 @@ use std::path::Path; pub(super) type ModelCustomizations = BTreeMap>; -pub(super) const EDITABLE_FIELDS: [&str; 11] = [ +pub(super) const EDITABLE_FIELDS: [&str; 12] = [ "display_name", "description", + "base_instructions", "context_window", "max_context_window", "effective_context_window_percent", @@ -78,6 +79,11 @@ fn editable_configuration(model: &Map) -> Map { } fn validate_configuration(model: &Map) -> Result<(), String> { + if let Some(value) = model.get("base_instructions") { + if !value.as_str().is_some_and(|text| !text.trim().is_empty()) { + return Err("System prompt must be non-empty text".to_string()); + } + } for field in model.keys() { if !EDITABLE_FIELDS.contains(&field.as_str()) { return Err(format!("Model field {field} cannot be modified")); @@ -198,6 +204,17 @@ pub(super) fn apply_customizations( let slug = string_value(model, "slug"); if let Some(customization) = customizations.get(&normalize_id(&slug)) { model.extend(customization.clone()); + // Codex clients can prefer the message template over base_instructions. + // Keep both paths consistent when the user replaces the system prompt. + if let Some(prompt) = customization.get("base_instructions") { + let messages = model.entry("model_messages".to_string()) + .or_insert_with(|| Value::Object(Map::new())); + if !messages.is_object() { + *messages = Value::Object(Map::new()); + } + messages.as_object_mut().unwrap() + .insert("instructions_template".to_string(), prompt.clone()); + } validate_configuration(&editable_configuration(model)) .map_err(|error| format!("Invalid custom configuration for model {slug}: {error}"))?; enable_fast_mode(model); @@ -417,6 +434,10 @@ mod tests { let runtime_models = vec![runtime_model("third-party-model")]; let snapshot = snapshot_for_state(&runtime_models, &state).unwrap(); let mut configuration = snapshot.models[0].configuration.clone(); + assert_eq!(configuration["supports_parallel_tool_calls"], true); + let prompt = "请用中文回答。\nPreserve whitespace and newlines.\n"; + configuration.insert("base_instructions".to_string(), serde_json::json!(prompt)); + configuration.insert("supports_parallel_tool_calls".to_string(), Value::Bool(false)); configuration.insert("context_window".to_string(), serde_json::json!(131_072)); configuration.insert("max_context_window".to_string(), serde_json::json!(262_144)); let path = temporary_path(); @@ -446,6 +467,9 @@ mod tests { .unwrap(); let generated: Value = serde_json::from_str(&generated.json).unwrap(); assert_eq!(generated["models"][0]["context_window"], 131_072); + assert_eq!(generated["models"][0]["base_instructions"], prompt); + assert_eq!(generated["models"][0]["model_messages"]["instructions_template"], prompt); + assert_eq!(generated["models"][0]["supports_parallel_tool_calls"], false); assert_eq!(generated["models"][0]["max_context_window"], 262_144); let loaded = decode_customizations(&std::fs::read(&path).unwrap()).unwrap(); @@ -465,6 +489,8 @@ mod tests { ) .unwrap(); assert!(!restored.models[0].customized); + assert_eq!(restored.models[0].configuration["supports_parallel_tool_calls"], true); + assert_eq!(restored.models[0].configuration["base_instructions"], restored.models[0].defaults["base_instructions"]); assert!(state.customizations.is_empty()); let persisted: Value = serde_json::from_slice(&std::fs::read(&path).unwrap()).unwrap(); assert_eq!(persisted["models"], serde_json::json!({})); diff --git a/src/i18n/ja.ts b/src/i18n/ja.ts index 223f6a5..ca1b8a1 100644 --- a/src/i18n/ja.ts +++ b/src/i18n/ja.ts @@ -351,6 +351,9 @@ export const jaOverrides = { 'agents.catalog.image': '画像', 'agents.catalog.visible': 'Codex のモデル一覧に表示', 'agents.catalog.parallel': '並列ツール呼び出しを許可', + 'agents.catalog.systemPrompt': 'システムプロンプト', + 'agents.catalog.systemPromptHint': 'このモデルの既定のシステムプロンプトを置き換え、保存時に Codex モデル一覧へ同期します。モデルのリセットで元に戻せます。', + 'agents.catalog.invalidPrompt': 'システムプロンプトは空にできません。', 'agents.catalog.capabilityHint': 'Fast は常に選択可能です。推論・画像・ツール機能の動作は上流モデルの対応状況によります。', 'agents.catalog.resetModel': 'このモデルの既定値に戻す', 'agents.catalog.resetAll': 'すべて既定値に戻す', diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index d65aaa8..7fdc9ed 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -300,6 +300,9 @@ export const en: Record = { 'agents.catalog.image': 'Image', 'agents.catalog.visible': 'Show in the Codex model list', 'agents.catalog.parallel': 'Allow parallel tool calls', + 'agents.catalog.systemPrompt': 'System prompt', + 'agents.catalog.systemPromptHint': 'Replaces this model’s default system prompt and syncs to the Codex model list when saved. Use “Reset model” to restore it.', + 'agents.catalog.invalidPrompt': 'System prompt cannot be empty.', 'agents.catalog.capabilityHint': 'Fast is always available. Reasoning, image and tool capabilities depend on the upstream model.', 'agents.catalog.resetModel': 'Restore model defaults', 'agents.catalog.resetAll': 'Restore all defaults', diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index ee9a660..853e875 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -299,6 +299,9 @@ export const zhCN = { 'agents.catalog.image': '图片', 'agents.catalog.visible': '在 Codex 模型列表中显示', 'agents.catalog.parallel': '允许并行工具调用', + 'agents.catalog.systemPrompt': '系统提示词', + 'agents.catalog.systemPromptHint': '替换当前模型的默认系统提示词,保存后同步到 Codex 模型列表。可通过“恢复此模型默认值”还原。', + 'agents.catalog.invalidPrompt': '系统提示词不能为空。', 'agents.catalog.capabilityHint': 'Fast 始终可选;思考等级、图片与工具能力是否生效取决于上游模型。', 'agents.catalog.resetModel': '恢复此模型默认值', 'agents.catalog.resetAll': '全部恢复默认值', diff --git a/src/mocks/browserMockRuntime.ts b/src/mocks/browserMockRuntime.ts index 50fe0da..de70290 100644 --- a/src/mocks/browserMockRuntime.ts +++ b/src/mocks/browserMockRuntime.ts @@ -585,6 +585,7 @@ function createState(scenario: BrowserMockScenario) { input_modalities: ['text', 'image'], visibility: 'list', supports_parallel_tool_calls: true, + base_instructions: 'You are Codex, a coding assistant.', }; return { slug, diff --git a/src/pages/CodexModelCatalogDialog.tsx b/src/pages/CodexModelCatalogDialog.tsx index 75c0f0f..ac03dd7 100644 --- a/src/pages/CodexModelCatalogDialog.tsx +++ b/src/pages/CodexModelCatalogDialog.tsx @@ -283,6 +283,7 @@ export function CodexModelCatalogDialog({ onClose, onSaved }: CodexModelCatalogD +