fix(codex): infer image capability for generated catalogs and resync takeover live on save

Mapped GPT models were rejected by Codex clients with "model does not
support image inputs". Two root causes:

- Catalog entries for native-Responses/Anthropic providers cloned a
  template whose input_modalities defaulted to ["text"], so every mapped
  model was advertised text-only. model_catalog_json replaces Codex's
  built-in model table wholesale, and both the TUI and the IDE extension
  block images pre-send when the current model is found without "image".
- Editing the current Codex provider during proxy takeover only refreshed
  the DB backup, so removing the mapping left a stale model_catalog_json
  pointer (and its text-only catalog file) active in live config.

Changes:

- New shared model_capabilities module: explicit row declaration first,
  then a confirmed text-only registry (exact tail match only — prefix
  matching removed, variants enumerated so future -vl/-vision models fail
  open), everything else unknown.
- Catalog generation writes input_modalities from that inference for all
  tool profiles: unknown models fail open to ["text","image"]; only
  confirmed text-only models are advertised as ["text"], giving users a
  clear client-side prompt instead of silent image stripping.
- Live catalog reverse-import collapses modalities that match current
  inference, so registry corrections are not frozen into hidden row
  overrides and the rectifier's heuristic opt-out keeps working.
- Saving the current Codex provider while takeover owns live now
  re-projects the live config (mirrors the hot-switch path), so mapping
  edits and removals take effect immediately.
- Media rectifier delegates to the shared module; its preflight toggle is
  documented (4 locales) as proxy-request-only, never affecting catalog
  capability declarations.
This commit is contained in:
Jason
2026-07-13 16:27:51 +08:00
parent 618723b42f
commit ac52c851bf
14 changed files with 627 additions and 193 deletions
+3 -2
View File
@@ -80,8 +80,9 @@ function modelCatalog(
displayName?: string;
contextWindow?: number;
// Native Responses (direct) overrides for the generated
// model-catalogs.json; omit to inherit the native template defaults
// (supports_parallel_tool_calls=false, input_modalities=["text"]).
// model-catalogs.json. Omitted input modalities are inferred by the
// backend: confirmed text-only models stay text-only; everything else
// defaults to text+image.
supportsParallelToolCalls?: boolean;
inputModalities?: string[];
// Vendor's OFFICIAL base_instructions; omit to inherit the neutral
+2 -2
View File
@@ -382,8 +382,8 @@
"thinkingBudgetDescription": "When an Anthropic-type provider returns budget_tokens constraint errors (such as at least 1024), automatically normalizes thinking to enabled, sets thinking budget to 32000, and raises max_tokens to 64000 if needed, then retries once",
"mediaFallback": "Unsupported Image Fallback",
"mediaFallbackDescription": "When a provider does not support image input (it declares text-only capability, or the upstream returns an unsupported-image error), automatically replaces image blocks with an [Unsupported Image] marker so the conversation is not interrupted",
"mediaHeuristic": "Heuristic Text-Only Model Detection",
"mediaHeuristicDescription": "Predictively strips images before sending based on a built-in model-name list. When off, only the declared-text-only and upstream-error fallback paths remain, preventing the built-in list from misclassifying a multimodal model as text-only and silently dropping images"
"mediaHeuristic": "Text-Only Model Preflight",
"mediaHeuristicDescription": "Before sending, strips images for models in the built-in confirmed text-only registry. Turning this off only disables the proxy's registry-based preflight; declared text-only handling and upstream-error fallback remain, and Codex model-catalog capability declarations are unchanged"
},
"optimizer": {
"title": "Bedrock Request Optimizer",
+2 -2
View File
@@ -382,8 +382,8 @@
"thinkingBudgetDescription": "Anthropic タイプのプロバイダーが budget_tokens 制約エラー(例: 1024 以上)を返した場合、thinking を enabled に正規化し、thinking 予算を 32000 に設定し、必要に応じて max_tokens を 64000 に引き上げて 1 回リトライします",
"mediaFallback": "非対応画像フォールバック",
"mediaFallbackDescription": "プロバイダーが画像入力に対応していない場合(テキストのみの能力が宣言されている、または上流が画像非対応エラーを返した場合)、画像ブロックを [Unsupported Image] マーカーに自動置換し、会話を中断させません",
"mediaHeuristic": "ヒューリスティックなテキスト専用モデル判定",
"mediaHeuristicDescription": "送信前に内蔵モデル名リストに基づいて画像を予測的に削除します。オフにすると「宣言済みテキスト専用」と「上流エラー時のフォールバック」のみが残り、内蔵リストがマルチモーダルモデルをテキスト専用と誤判定して画像を静かに削除するのを防ぎます"
"mediaHeuristic": "テキスト専用モデルの事前判定",
"mediaHeuristicDescription": "送信前に内蔵の確認済みテキスト専用モデル登録に基づいて画像を除します。オフにしても無効になるのはプロキシの登録ベース事前処理だけで、宣言済みテキスト専用モデルの処理と上流エラー時のフォールバックは残り、Codex モデルカタログの能力宣言は変わりません"
},
"optimizer": {
"title": "Bedrock リクエストオプティマイザー",
+2 -2
View File
@@ -382,8 +382,8 @@
"thinkingBudgetDescription": "當 Anthropic 類型供應商回傳 budget_tokens 限制錯誤(如至少 1024)時,自動將 thinking 規範為 enabled,並將 budget 設為 32000,同時在需要時將 max_tokens 設為 64000,然後重試一次",
"mediaFallback": "不支援圖片降級",
"mediaFallbackDescription": "當供應商不支援圖片輸入時(已宣告純文字能力,或上游回傳不支援圖片的錯誤),自動將圖片區塊替換為 [Unsupported Image] 標記,使對話不中斷",
"mediaHeuristic": "啟發式純文字模型辨識",
"mediaHeuristicDescription": "傳送前依內建模型名稱清單預測性地移除圖片。關閉後僅保留「已宣告純文字」與「上游錯誤兜底」兩條事實驅動路徑,避免內建清單將多模態模型誤判為純文字而靜默丟失圖片"
"mediaHeuristic": "純文字模型預判",
"mediaHeuristicDescription": "傳送前依內建的已確認純文字模型登錄表移除圖片。關閉只會停用代理的登錄表預判;已宣告純文字模型的處理與上游錯誤兜底仍會保留,且不會改變 Codex 模型目錄的能力宣告"
},
"optimizer": {
"title": "Bedrock 請求最佳化工具",
+2 -2
View File
@@ -382,8 +382,8 @@
"thinkingBudgetDescription": "当 Anthropic 类型供应商返回 budget_tokens 约束错误(如至少 1024)时,自动将 thinking 规范为 enabled 并将 budget 设为 32000,同时在需要时将 max_tokens 设为 64000,然后重试一次",
"mediaFallback": "不支持图片降级",
"mediaFallbackDescription": "当供应商不支持图片输入时(已声明纯文本能力,或上游返回不支持图片的错误),自动将图片块替换为 [Unsupported Image] 标记,使对话不中断",
"mediaHeuristic": "启发式纯文本模型识别",
"mediaHeuristicDescription": "发送前按内置模型名列表预测性剥离图片。关闭后仅保留「已声明纯文本」与「上游报错兜底」两条事实驱动路径,避免内置列表把多模态模型误判为纯文本而静默丢图"
"mediaHeuristic": "纯文本模型预判",
"mediaHeuristicDescription": "发送前根据内置的已确认纯文本模型注册表剥离图片。关闭仅停用代理的注册表预判;已声明纯文本模型的处理和上游报错兜底仍保留,且不会改变 Codex 模型目录的能力声明"
},
"optimizer": {
"title": "Bedrock 请求优化器",
+3 -3
View File
@@ -260,9 +260,9 @@ export interface CodexCatalogModel {
model: string;
displayName?: string;
contextWindow?: string | number;
// Native Responses (direct) profile overrides for the generated
// model-catalogs.json. Ignored by the chat/proxy profile.
// e.g. MiniMax: supportsParallelToolCalls=true, inputModalities=["text","image"].
// Hidden provider capability metadata for the generated model catalog.
// supportsParallelToolCalls is native-profile-only; inputModalities wins over
// automatic text-only model detection for every profile.
supportsParallelToolCalls?: boolean;
inputModalities?: string[];
// Vendor's OFFICIAL base_instructions (model identity / system preamble).