feat(cliproxyapi): support multiple OpenCode API keys - #2331
Conversation
|
Warning Indent Zero is shutting down on August 7th. Please migrate over to Indent 2.0 to continue getting PR reviews.
|
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe OpenCode provider now supports multiple comma-separated API keys. Startup rendering trims, deduplicates, escapes, and converts keys into YAML entries, with fallback to the legacy singular variable. Documentation and shell tests cover the behavior. ChangesOpenCode API-key pool
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Environment
participant render_opencode_api_key_entries
participant OpenCodeTemplates
participant CLIProxyAPI
Environment->>render_opencode_api_key_entries: provide comma-separated API keys
render_opencode_api_key_entries->>render_opencode_api_key_entries: trim, deduplicate, and escape keys
render_opencode_api_key_entries->>OpenCodeTemplates: replace __OPENCODE_API_KEY_ENTRIES__
OpenCodeTemplates->>CLIProxyAPI: generate api-key-entries configuration
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
spec/cliproxyapi_spec.sh (1)
286-310: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd runtime assertions for the complete key-pool contract.
The test at lines 296-303 passes if
first-keyoccurs more than once. The test suite also does not set both variables to verify that plural keys exclude the legacy key. Add runtime cases for plural precedence, an empty pool, and exact deduplicated output.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@spec/cliproxyapi_spec.sh` around lines 286 - 310, Extend the runtime key-pool specs around the plural-key rendering tests to assert exact deduplicated output rather than merely checking key presence. Add cases verifying non-empty OPENCODE_API_KEYS takes precedence over OPENCODE_API_KEY, both variables empty produce an empty pool, and repeated or blank plural entries render exactly once with no legacy key included; preserve the existing success and placeholder assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@spec/cliproxyapi_spec.sh`:
- Around line 286-310: Extend the runtime key-pool specs around the plural-key
rendering tests to assert exact deduplicated output rather than merely checking
key presence. Add cases verifying non-empty OPENCODE_API_KEYS takes precedence
over OPENCODE_API_KEY, both variables empty produce an empty pool, and repeated
or blank plural entries render exactly once with no legacy key included;
preserve the existing success and placeholder assertions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 126aa59e-d6db-4a80-bb4f-5ce8bf1a6f05
📒 Files selected for processing (6)
.env.exampleconfig/cliproxyapi/config.template.yamlconfig/cliproxyapi/config.tpl.yamlhome-manager/services/cliproxyapi/README.mdhome-manager/services/cliproxyapi/scripts/start.shspec/cliproxyapi_spec.sh
| done | ||
|
|
||
| while IFS= read -r line || [ -n "$line" ]; do | ||
| if [ "$line" != " __OPENCODE_API_KEY_ENTRIES__" ]; then |
There was a problem hiding this comment.
Brittle placeholder matching: [ "$line" != " __OPENCODE_API_KEY_ENTRIES__" ] requires exactly 4 leading spaces and no trailing whitespace. If someone edits config.template.yaml/config.tpl.yaml and changes the indent (or an editor adds trailing whitespace), the placeholder passes through untouched and ends up in the rendered config.yaml, producing invalid YAML that cliproxyapi will refuse to load. Consider matching with a regex that tolerates surrounding whitespace, e.g. if [[ "$line" =~ ^[[:space:]]*__OPENCODE_API_KEY_ENTRIES__[[:space:]]*$ ]], and preserve the captured leading indent when emitting the block.
| fi | ||
|
|
||
| if [ "${#api_keys[@]}" -eq 0 ]; then | ||
| printf '%s\n' ' api-key-entries: []' |
There was a problem hiding this comment.
Empty-pool behavior change: Previously, if OPENCODE_API_KEY was unset, the sed substitution rendered - api-key: "" — cliproxyapi still saw one (bogus) entry and loaded the provider. With this change, an unconfigured environment now yields api-key-entries: []. If cliproxyapi requires ≥1 entry per provider, the opencode provider will fail to load entirely, which is a silent regression. Worth confirming against the cliproxyapi config validator; if it does reject empty lists, either preserve the empty-string fallback or skip the provider block when no keys are configured.
There was a problem hiding this comment.
2 issues found across 6 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="config/cliproxyapi/config.template.yaml">
<violation number="1" location="config/cliproxyapi/config.template.yaml:137">
P3: This file is installed twice by config/cliproxyapi/default.nix — as the render template AND as `~/.cli-proxy-api/config.example.yaml` consumed by CLIProxy's object-backed config bootstrap. The new placeholder line is only expanded by `render_opencode_api_key_entries` in start.sh when producing config.yaml; in the example copy it is never substituted, so the opencode provider there silently loses its `api-key-entries` block (replaced by a literal `__OPENCODE_API_KEY_ENTRIES__` null key) where previously it carried an `api-key-entries` entry. Consider rendering/expanding the placeholder from the shared source, or giving the example config its own opencode `api-key-entries` block.</violation>
</file>
<file name="home-manager/services/cliproxyapi/scripts/start.sh">
<violation number="1" location="home-manager/services/cliproxyapi/scripts/start.sh:45">
P3: The placeholder match is a hardcoded, indentation-sensitive literal (` __OPENCODE_API_KEY_ENTRIES__`) that must stay byte-for-byte in sync between start.sh and both config template files. If the template indentation is ever adjusted, the placeholder will silently pass through into the generated config.yaml instead of being replaced, and the service will ship an invalid/placeholder config without any failure being raised at generation time. A small guard (e.g., echo a warning and abort if the placeholder remains in the output) would make this coupling self-checking.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| base-url: "https://opencode.ai/zen/go/v1" | ||
| api-key-entries: | ||
| - api-key: "__OPENCODE_API_KEY__" | ||
| __OPENCODE_API_KEY_ENTRIES__ |
There was a problem hiding this comment.
P3: This file is installed twice by config/cliproxyapi/default.nix — as the render template AND as ~/.cli-proxy-api/config.example.yaml consumed by CLIProxy's object-backed config bootstrap. The new placeholder line is only expanded by render_opencode_api_key_entries in start.sh when producing config.yaml; in the example copy it is never substituted, so the opencode provider there silently loses its api-key-entries block (replaced by a literal __OPENCODE_API_KEY_ENTRIES__ null key) where previously it carried an api-key-entries entry. Consider rendering/expanding the placeholder from the shared source, or giving the example config its own opencode api-key-entries block.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At config/cliproxyapi/config.template.yaml, line 137:
<comment>This file is installed twice by config/cliproxyapi/default.nix — as the render template AND as `~/.cli-proxy-api/config.example.yaml` consumed by CLIProxy's object-backed config bootstrap. The new placeholder line is only expanded by `render_opencode_api_key_entries` in start.sh when producing config.yaml; in the example copy it is never substituted, so the opencode provider there silently loses its `api-key-entries` block (replaced by a literal `__OPENCODE_API_KEY_ENTRIES__` null key) where previously it carried an `api-key-entries` entry. Consider rendering/expanding the placeholder from the shared source, or giving the example config its own opencode `api-key-entries` block.</comment>
<file context>
@@ -134,8 +134,7 @@ openai-compatibility:
base-url: "https://opencode.ai/zen/go/v1"
- api-key-entries:
- - api-key: "__OPENCODE_API_KEY__"
+ __OPENCODE_API_KEY_ENTRIES__
models:
- name: "deepseek-v4-pro"
</file context>
| done | ||
|
|
||
| while IFS= read -r line || [ -n "$line" ]; do | ||
| if [ "$line" != " __OPENCODE_API_KEY_ENTRIES__" ]; then |
There was a problem hiding this comment.
P3: The placeholder match is a hardcoded, indentation-sensitive literal ( __OPENCODE_API_KEY_ENTRIES__) that must stay byte-for-byte in sync between start.sh and both config template files. If the template indentation is ever adjusted, the placeholder will silently pass through into the generated config.yaml instead of being replaced, and the service will ship an invalid/placeholder config without any failure being raised at generation time. A small guard (e.g., echo a warning and abort if the placeholder remains in the output) would make this coupling self-checking.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/services/cliproxyapi/scripts/start.sh, line 45:
<comment>The placeholder match is a hardcoded, indentation-sensitive literal (` __OPENCODE_API_KEY_ENTRIES__`) that must stay byte-for-byte in sync between start.sh and both config template files. If the template indentation is ever adjusted, the placeholder will silently pass through into the generated config.yaml instead of being replaced, and the service will ship an invalid/placeholder config without any failure being raised at generation time. A small guard (e.g., echo a warning and abort if the placeholder remains in the output) would make this coupling self-checking.</comment>
<file context>
@@ -16,6 +16,51 @@ MANAGEMENT_PASSWORD="${CLIPROXY_MANAGEMENT_PASSWORD:-}"
+ done
+
+ while IFS= read -r line || [ -n "$line" ]; do
+ if [ "$line" != " __OPENCODE_API_KEY_ENTRIES__" ]; then
+ printf '%s\n' "$line"
+ continue
</file context>
Summary
OPENCODE_API_KEYSas a comma-separated credential pool for the existing OpenCode Go endpointOPENCODE_API_KEYas the backward-compatible fallbackValidation
shellspec spec/cliproxyapi_spec.sh spec/llm_update_spec.sh(87 examples)make shell-test(2,037 ShellSpec + 454 Fish tests)make shell-lintmake build(Galactica Darwin configuration)Summary by cubic
Adds multi-key support for the OpenCode Go provider in
cliproxyapiviaOPENCODE_API_KEYS, rendering a safe YAML token pool with no temp secret files. Also repairs shell/format checks to stabilize CI.New Features
OPENCODE_API_KEYSsupports a comma-separated pool; trims blanks, dedupes, YAML-quotes keys, and rendersapi-key-entriesor[]. Takes precedence over legacyOPENCODE_API_KEY.__OPENCODE_API_KEY_ENTRIES__for theopencodeprovider and render inline instart.sh(no temp files).Bug Fixes
Written for commit 326439e. Summary will update on new commits.