From f9fbd19a542abbcc08f78aa4b5b7ecc7cc46e018 Mon Sep 17 00:00:00 2001 From: Shun Kakinoki Date: Thu, 23 Apr 2026 11:23:39 +0800 Subject: [PATCH 1/2] Add gpt-image and qwen cliproxy provider config Co-authored-by: Codex --- config/cliproxyapi/config.template.yaml | 18 ++++++++++++++++-- config/cliproxyapi/config.tpl.yaml | 18 ++++++++++++++++-- home-manager/services/cliproxyapi/README.md | 2 ++ .../services/cliproxyapi/scripts/start.sh | 2 ++ models.json | 1 + spec/cliproxyapi_spec.sh | 10 ++++++++++ 6 files changed, 47 insertions(+), 4 deletions(-) diff --git a/config/cliproxyapi/config.template.yaml b/config/cliproxyapi/config.template.yaml index 3e98430b9..37476f87d 100644 --- a/config/cliproxyapi/config.template.yaml +++ b/config/cliproxyapi/config.template.yaml @@ -88,6 +88,8 @@ openai-compatibility: models: - name: "openrouter/free" alias: "free" + - name: "openai/gpt-5.4-image-2" + alias: "gpt-image-2" - name: "@preset/glm-4-7" alias: "glm-4.7" - name: "google/gemma-4-27b-it" @@ -108,6 +110,13 @@ openai-compatibility: models: - name: "kimi-2.6" alias: "kimi-2.6" + - name: "qwen" + base-url: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1" + api-key-entries: + - api-key: "__QWEN_API_KEY__" + models: + - name: "qwen3.6-plus" + alias: "qwen3.6-plus" - name: "opencode" base-url: "https://opencode.ai/zen/go/v1" api-key-entries: @@ -117,8 +126,13 @@ openai-compatibility: alias: "minimax-m2.7" - name: "kimi-2.6" alias: "kimi-2.6" - - name: "qwen3.6-plus" - alias: "qwen3.6-plus" + - name: "openai" + base-url: "https://api.openai.com/v1" + api-key-entries: + - api-key: "__OPENAI_API_KEY__" + models: + - name: "gpt-image-2" + alias: "gpt-image-2" # payload: # Optional payload configuration # default: # Default rules only set parameters when they are missing in the payload. # - models: diff --git a/config/cliproxyapi/config.tpl.yaml b/config/cliproxyapi/config.tpl.yaml index eb8fde04b..ef8cdcf55 100644 --- a/config/cliproxyapi/config.tpl.yaml +++ b/config/cliproxyapi/config.tpl.yaml @@ -88,6 +88,8 @@ openai-compatibility: models: - name: "openrouter/free" alias: "free" + - name: "openai/gpt-5.4-image-2" + alias: "__GPT_IMAGE__" - name: "@preset/__GLM_NONDOT__" alias: "__GLM__" - name: "google/__GEMMA__" @@ -108,6 +110,13 @@ openai-compatibility: models: - name: "__KIMI__" alias: "__KIMI__" + - name: "qwen" + base-url: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1" + api-key-entries: + - api-key: "__QWEN_API_KEY__" + models: + - name: "__QWEN__" + alias: "__QWEN__" - name: "opencode" base-url: "https://opencode.ai/zen/go/v1" api-key-entries: @@ -117,8 +126,13 @@ openai-compatibility: alias: "__MINIMAX__" - name: "__KIMI__" alias: "__KIMI__" - - name: "__QWEN__" - alias: "__QWEN__" + - name: "openai" + base-url: "https://api.openai.com/v1" + api-key-entries: + - api-key: "__OPENAI_API_KEY__" + models: + - name: "__GPT_IMAGE__" + alias: "__GPT_IMAGE__" # payload: # Optional payload configuration # default: # Default rules only set parameters when they are missing in the payload. # - models: diff --git a/home-manager/services/cliproxyapi/README.md b/home-manager/services/cliproxyapi/README.md index 5820cad47..68843ce3e 100644 --- a/home-manager/services/cliproxyapi/README.md +++ b/home-manager/services/cliproxyapi/README.md @@ -97,6 +97,8 @@ OBJECTSTORE_SECRET_KEY="..." # Service Config CLIPROXY_MANAGEMENT_PASSWORD="..." OPENROUTER_API_KEY="sk-or-v1-..." +OPENAI_API_KEY="sk-..." +QWEN_API_KEY="sk-..." ``` ## Usage diff --git a/home-manager/services/cliproxyapi/scripts/start.sh b/home-manager/services/cliproxyapi/scripts/start.sh index b151e9a97..5cbb938d2 100755 --- a/home-manager/services/cliproxyapi/scripts/start.sh +++ b/home-manager/services/cliproxyapi/scripts/start.sh @@ -33,8 +33,10 @@ fi if [ -f "$TEMPLATE" ]; then @sed@ \ -e "s|__OPENROUTER_API_KEY__|${OPENROUTER_API_KEY:-}|g" \ + -e "s|__OPENAI_API_KEY__|${OPENAI_API_KEY:-}|g" \ -e "s|__CLIPROXY_MANAGEMENT_PASSWORD__|${CLIPROXY_MANAGEMENT_PASSWORD:-}|g" \ -e "s|__ZAI_API_KEY__|${ZAI_API_KEY:-}|g" \ + -e "s|__QWEN_API_KEY__|${QWEN_API_KEY:-${DASHSCOPE_API_KEY:-}}|g" \ -e "s|__OPENCODE_API_KEY__|${OPENCODE_API_KEY:-}|g" \ -e "s|__AMP_UPSTREAM_API_KEY__|${AMP_UPSTREAM_API_KEY:-}|g" \ -e "s|__OPENCODE_API_KEY__|${OPENCODE_API_KEY:-}|g" \ diff --git a/models.json b/models.json index 79261ef11..a9e814c9c 100644 --- a/models.json +++ b/models.json @@ -5,6 +5,7 @@ "gpt": "gpt-5.4", "gpt-codex": "gpt-5.3-codex", "gpt-codex-spark": "gpt-5.3-codex-spark", + "gpt-image": "gpt-image-2", "gpt-mini": "gpt-5.4-mini", "gpt-nano": "gpt-5.4-nano", "gemini-pro": "gemini-3.1-pro-preview", diff --git a/spec/cliproxyapi_spec.sh b/spec/cliproxyapi_spec.sh index 5b74374ac..eac2146b1 100644 --- a/spec/cliproxyapi_spec.sh +++ b/spec/cliproxyapi_spec.sh @@ -13,12 +13,16 @@ setup() { # Create template config cat >"$TEMP_HOME/.cli-proxy-api/config.template.yaml" <<'YAML' api_key: __OPENROUTER_API_KEY__ +openai_api_key: __OPENAI_API_KEY__ +qwen_api_key: __QWEN_API_KEY__ management_password: __CLIPROXY_MANAGEMENT_PASSWORD__ YAML # Create .env file cat >"$TEMP_HOME/dotfiles/.env" <<'ENV' OPENROUTER_API_KEY=test_openrouter_key +OPENAI_API_KEY=test_openai_key +QWEN_API_KEY=test_qwen_key CLIPROXY_MANAGEMENT_PASSWORD=test_mgmt_password ENV } @@ -60,10 +64,14 @@ TEMPLATE="$CONFIG_DIR/config.template.yaml" CONFIG="$CONFIG_DIR/config.yaml" OPENROUTER_API_KEY="test_key" +OPENAI_API_KEY="test_openai_key" +QWEN_API_KEY="test_qwen_key" CLIPROXY_MANAGEMENT_PASSWORD="test_pass" if [ -f "$TEMPLATE" ]; then sed -e "s|__OPENROUTER_API_KEY__|${OPENROUTER_API_KEY:-}|g" \ + -e "s|__OPENAI_API_KEY__|${OPENAI_API_KEY:-}|g" \ + -e "s|__QWEN_API_KEY__|${QWEN_API_KEY:-}|g" \ -e "s|__CLIPROXY_MANAGEMENT_PASSWORD__|${CLIPROXY_MANAGEMENT_PASSWORD:-}|g" \ "$TEMPLATE" >"$CONFIG" fi @@ -73,6 +81,8 @@ chmod +x "$TEMP_HOME/test_config.sh" When run bash -c "HOME='$TEMP_HOME' bash '$TEMP_HOME/test_config.sh'" The output should include 'api_key: test_key' +The output should include 'openai_api_key: test_openai_key' +The output should include 'qwen_api_key: test_qwen_key' The output should include 'management_password: test_pass' The status should be success End From 3b5a024af8d5474417485aa2f85c4f54eaa0dee4 Mon Sep 17 00:00:00 2001 From: Shun Kakinoki Date: Thu, 23 Apr 2026 11:27:51 +0800 Subject: [PATCH 2/2] Generate provider-specific model overrides Co-authored-by: Codex --- config/cliproxyapi/config.tpl.yaml | 2 +- scripts/llm-update.sh | 12 +++++++++ spec/llm_update_spec.sh | 39 ++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/config/cliproxyapi/config.tpl.yaml b/config/cliproxyapi/config.tpl.yaml index ef8cdcf55..25fc701c2 100644 --- a/config/cliproxyapi/config.tpl.yaml +++ b/config/cliproxyapi/config.tpl.yaml @@ -88,7 +88,7 @@ openai-compatibility: models: - name: "openrouter/free" alias: "free" - - name: "openai/gpt-5.4-image-2" + - name: "__GPT_IMAGE_OPENROUTER__" alias: "__GPT_IMAGE__" - name: "@preset/__GLM_NONDOT__" alias: "__GLM__" diff --git a/scripts/llm-update.sh b/scripts/llm-update.sh index b9d98f767..604ab80fd 100755 --- a/scripts/llm-update.sh +++ b/scripts/llm-update.sh @@ -25,6 +25,14 @@ require_command sed require_command mktemp require_command mv +add_model_override() { + local key="$1" + local suffix="$2" + local value="$3" + local placeholder="__$(echo "${key}-${suffix}" | tr 'a-z-' 'A-Z_')__" + sed_args+=(-e "s|${placeholder}|${value}|g") +} + # jq function: derive display name from a model ID # claude-opus-4.6 → "Claude Opus 4.6", claude-sonnet-4.5-20250929 → "Claude Sonnet 4.5" # shellcheck disable=SC2016 @@ -69,6 +77,10 @@ while IFS=$'\t' read -r key value pretty nondot; do sed_args+=(-e "s|${placeholder}|${value}|g") done <<<"$model_rows" +# Provider-specific upstream slugs that intentionally differ from the canonical +# alias stored in models.json. +add_model_override "gpt-image" "openrouter" "openai/gpt-5.4-image-2" + # Template → output pairs declare -A TEMPLATES=( ["config/aichat/config.tpl.yaml"]=config/aichat/config.yaml diff --git a/spec/llm_update_spec.sh b/spec/llm_update_spec.sh index 7f121911c..4124c8827 100644 --- a/spec/llm_update_spec.sh +++ b/spec/llm_update_spec.sh @@ -124,6 +124,45 @@ It 'generates NONDOT variant placeholders' When run bash -c "grep '_NONDOT__' '$SCRIPT'" The output should include '_NONDOT__' End + +It 'supports provider-specific override placeholders' +When run bash -c "grep 'add_model_override' '$SCRIPT'" +The output should include 'add_model_override' +The output should include 'gpt-image' +The output should include 'openrouter' +End +End + +Describe 'provider-specific override resolution' +setup_provider_override_fixture() { + TEMP_ROOT=$(mktemp -d) + + mkdir -p "$TEMP_ROOT/scripts" "$TEMP_ROOT/config/cliproxyapi" + cp -f "$SCRIPT" "$TEMP_ROOT/scripts/llm-update.sh" + cp -f "$PWD/models.json" "$TEMP_ROOT/models.json" + + cat >"$TEMP_ROOT/config/cliproxyapi/config.tpl.yaml" <<'EOF' +openai-compatibility: + - name: "openrouter" + models: + - name: "__GPT_IMAGE_OPENROUTER__" + alias: "__GPT_IMAGE__" +EOF +} + +cleanup_provider_override_fixture() { + rm -rf "$TEMP_ROOT" +} + +Before 'setup_provider_override_fixture' +After 'cleanup_provider_override_fixture' + +It 'replaces provider-specific placeholders in generated configs' +When run bash -c "cd '$TEMP_ROOT' && bash scripts/llm-update.sh >/dev/null && cat config/cliproxyapi/config.template.yaml" +The output should include 'openai/gpt-5.4-image-2' +The output should include 'gpt-image-2' +The output should not include '__GPT_IMAGE_OPENROUTER__' +End End Describe 'failure handling'