Skip to content

docs(opencode): fix the generated OpenCode provider config - #90

Merged
tristantelleb merged 3 commits into
mainfrom
docs/opencode-integration-fixes
Aug 11, 2026
Merged

docs(opencode): fix the generated OpenCode provider config#90
tristantelleb merged 3 commits into
mainfrom
docs/opencode-integration-fixes

Conversation

@tristantelleb

@tristantelleb tristantelleb commented Aug 11, 2026

Copy link
Copy Markdown
Member

The OpenCode page's generator script wrote a config that OpenCode loads but can't fully use, and the setup steps pointed at a script that was never linked.

Everything below was tested end-to-end against opencode 1.18.16 with a real Eden AI key, in a sandboxed HOME — not just read off the schema. Test method is at the bottom.

Config generator

Issue Verified effect Fix
No limit emitted OpenCode's own /config/providers reports limit: {context: 0, output: 0} for every model — it has no idea how big any context window is. Emit limit.context from context_length, limit.output capped at OpenCode's 32k OUTPUT_TOKEN_MAX. Now reports the real values (e.g. gpt-5-mini 400000, gemini-3.6-flash 1048576).
No modalities / attachment Both default false. Loaded state showed attachment: False, input: {text: true, image: false, pdf: false} on models that do support images. unsupportedParts() then replaces any attached image/PDF with the literal text ERROR: Cannot read "x.png" (this model does not support image input). Emit both. Eden AI's file modality maps to OpenCode's pdf. Loaded state now matches the catalog exactly.
Reasoning read only from supports_reasoning That key is absent on ~120 catalog entries that are reasoning models (capabilities.reasoning.mandatory: true). Check both signals: 471 models now flagged, vs fewer before.
cost built by dropping falsy values Latent, not currently triggered. The schema requires both input and output (additionalProperties: false), so a model priced 0 on exactly one side would emit an invalid object. No model in today's catalog does that, so nothing is broken right now. Always emit both; add cache_read / cache_write when present.
Wrote the whole opencode.json Clobbered any existing global config. Merge. Verified: a pre-existing config keeping theme, autoupdate, model, mcp and a second custom provider came through untouched, with edenai added alongside.

Two things I got wrong in my first pass and have corrected here:

  • I claimed missing limit gives reasoning models a negative thinking budget. It does not on this path — ProviderTransform.variants() for @ai-sdk/openai-compatible returns reasoningEffort strings and never touches limit.output. The budget math is on the Anthropic/Bedrock npm paths. limit is still worth emitting for context tracking, but not for that reason.
  • tool_call was never a bug: it defaults to true. The config now states it explicitly, which is tidier, not a fix.

per_million was already correct — OpenCode divides by 1e6 when computing spend.

Page

  • The script had no filename before python gen_opencode_config.py, and "Download the script" linked nowhere. Now: save as gen_opencode_config.py, with a pip install requests step.
  • Added Prerequisites and Troubleshooting, matching codex-cli.mdx and openclaw.mdx.
  • Added the missing "pick a model" step, with the model key form.
  • Corrected the unknown-model troubleshooting entry: a mistyped model ID surfaces as a generic UnknownError, not the Model not found: string I first wrote.
  • Documented {env:EDENAI_API_KEY} as an alternative to /connect, plus the curl/brew install options.

Verification

Sandboxed HOME, opencode-ai@1.18.16 installed from npm, script run verbatim as extracted from the published page.

  • Generated config validates against https://opencode.ai/config.json (jsonschema) — 681 function-calling models, all 681 listed by opencode models.
  • Live completions through Eden AI: anthropic/claude-sonnet-latest, openai/gpt-5-mini, google/gemini-3.6-flash, and together_ai/meta-models/Muse-Glimmer-30B (a 3-segment ID — confirms parseModel splits on the first slash only).
  • Tool calling works: the model called its read tool and returned the file's contents.
  • Step 3 (/connect) verified: "Eden AI" is present in the list the TUI connect dialog renders (GET /providerall, source: config). Storing the key the way /connect does (PUT /auth/edenaiauth.json) and running with no env var and no apiKey in config produced a working completion.
  • The {env:EDENAI_API_KEY} tip works — that's how most of the runs above were authenticated.
  • The model default key works: opencode run with no --model used edenai/anthropic/claude-sonnet-latest.
  • Windows config path confirmed: OpenCode reads %USERPROFILE%\.config\opencode\opencode.json.
  • The troubleshooting one-liner runs and prints ['edenai'].
  • The snippet passes the docs snippet extractor (staging base URL, exit 0).

Not tested: the curl and brew install lines (Windows host); both are quoted from OpenCode's own install docs.

🤖 Generated with Claude Code

The generator script produced model entries that OpenCode could not fully
use, and the setup steps referenced a script that was never linked.

Config generator:
- Emit `limit` (context/output). Without it OpenCode records context 0, so
  the TUI cannot track context usage or trigger compaction, and reasoning
  models get a negative thinking budget.
- Always emit both `cost.input` and `cost.output`; the config schema
  requires both, and the old dict comprehension dropped either when the
  price was 0 or absent.
- Emit `tool_call`, `modalities` and `attachment`. Modalities default to
  false, which silently disabled image/file attachments on vision models.
  Eden AI's `file` modality is mapped to OpenCode's `pdf`.
- Detect reasoning from `capabilities.reasoning.mandatory` as well as
  `supports_reasoning`, which is absent on ~120 catalog entries.
- Merge into an existing `opencode.json` instead of overwriting the whole
  global config.

Page:
- Give the script a filename before the run command and add the
  `pip install requests` step.
- Add Prerequisites and Troubleshooting sections, matching the other
  integration pages.
- Document choosing a model: `/models`, or the `model` key as
  `edenai/<full-eden-model-id>` (OpenCode splits on the first slash only,
  so multi-slash IDs work).
- Document the `{env:EDENAI_API_KEY}` alternative to `/connect`, and the
  curl/brew install options.

Verified: generated config validates against https://opencode.ai/config.json
(681 models from the live catalog); the snippet runs clean under the docs
snippet extractor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mintlify

mintlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
edenai 🟢 Ready View Preview Aug 11, 2026, 7:58 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@tristantelleb, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 25 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: adaf7a8b-5978-4614-aa3a-5b8e086aec2d

📥 Commits

Reviewing files that changed from the base of the PR and between 3fcdefd and 541db9b.

📒 Files selected for processing (1)
  • v3/integrations/opencode.mdx

Walkthrough

The OpenCode integration guide adds installation methods, expanded setup instructions, and updated configuration generation. The generator now preserves settings, applies model metadata and limits, filters unsupported models, and handles missing API data. The guide also adds model selection, refresh, and troubleshooting guidance.

Changes

OpenCode integration

Layer / File(s) Summary
Installation and configuration generation
v3/integrations/opencode.mdx
The guide adds npm, curl, and Homebrew installation paths. The generator uses request timeouts, filters models without function calling, emits model metadata, caps output tokens, and preserves existing configuration.
Provider connection and model selection
v3/integrations/opencode.mdx
The guide documents API-key environment variables, model selection, default model syntax, nested model IDs, model refresh, and troubleshooting steps.
Guide metadata and next steps
v3/integrations/opencode.mdx
The modification timestamp is updated, and the Next Steps section links to Codex CLI.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • edenai/docs#89: Updates the same OpenCode integration documentation with configuration and model/provider validation changes.

Poem

A rabbit hops through config lines,
With fresh model caps and clearer signs.
Existing settings stay in place,
New provider steps improve the chase.
“Binky!” says Bun, “the guide is bright—”
OpenCode now starts just right.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the OpenCode provider configuration fix, which is the main change in the pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/opencode-integration-fixes

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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.

Inline comments:
In `@v3/integrations/opencode.mdx`:
- Around line 122-129: Update the provider configuration generation to preserve
existing provider.edenai.options, including options.apiKey, when rebuilding the
Eden AI entry. Merge the existing options into the generated options and then
explicitly set baseURL to BASE_URL, while leaving the other provider fields and
model_entries behavior unchanged.
- Around line 101-104: Update the cache price checks in the pricing
configuration logic to test whether each value is None rather than relying on
truthiness, so zero-valued cache_read_input_token_cost and
cache_creation_input_token_cost values are converted and emitted. Preserve the
existing per_million conversion and cost assignments.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b6ed27c-0343-48fe-840b-d5210107b876

📥 Commits

Reviewing files that changed from the base of the PR and between 446dbd8 and 3fcdefd.

📒 Files selected for processing (1)
  • v3/integrations/opencode.mdx

Comment on lines +101 to +104
if pricing.get("cache_read_input_token_cost"):
cost["cache_read"] = per_million(pricing["cache_read_input_token_cost"])
if pricing.get("cache_creation_input_token_cost"):
cost["cache_write"] = per_million(pricing["cache_creation_input_token_cost"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Emit zero-valued cache prices.

Lines 101 and 103 treat a cache price of 0 as unavailable. A zero price is an explicit value. The generated configuration then omits cache metadata despite the stated requirement to include cache costs when available.

Test for None instead of truthiness.

Proposed fix
-    if pricing.get("cache_read_input_token_cost"):
+    if pricing.get("cache_read_input_token_cost") is not None:
         cost["cache_read"] = per_million(pricing["cache_read_input_token_cost"])
-    if pricing.get("cache_creation_input_token_cost"):
+    if pricing.get("cache_creation_input_token_cost") is not None:
         cost["cache_write"] = per_million(pricing["cache_creation_input_token_cost"])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if pricing.get("cache_read_input_token_cost"):
cost["cache_read"] = per_million(pricing["cache_read_input_token_cost"])
if pricing.get("cache_creation_input_token_cost"):
cost["cache_write"] = per_million(pricing["cache_creation_input_token_cost"])
if pricing.get("cache_read_input_token_cost") is not None:
cost["cache_read"] = per_million(pricing["cache_read_input_token_cost"])
if pricing.get("cache_creation_input_token_cost") is not None:
cost["cache_write"] = per_million(pricing["cache_creation_input_token_cost"])
🤖 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 `@v3/integrations/opencode.mdx` around lines 101 - 104, Update the cache price
checks in the pricing configuration logic to test whether each value is None
rather than relying on truthiness, so zero-valued cache_read_input_token_cost
and cache_creation_input_token_cost values are converted and emitted. Preserve
the existing per_million conversion and cost assignments.

Comment on lines +122 to +129
config = json.loads(output.read_text()) if output.exists() else {}
config["$schema"] = "https://opencode.ai/config.json"
config.setdefault("provider", {})["edenai"] = {
"npm": "@ai-sdk/openai-compatible",
"name": "Eden AI",
"options": {"baseURL": BASE_URL},
"models": model_entries,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve existing Eden AI authentication options.

Line 124 replaces the complete provider.edenai object. A later refresh deletes the options.apiKey setting documented on Line 143. Requests then lose environment-variable authentication.

Merge existing edenai.options into the generated options. Set baseURL explicitly after the merge.

Proposed fix
 config = json.loads(output.read_text()) if output.exists() else {}
 config["$schema"] = "https://opencode.ai/config.json"
-config.setdefault("provider", {})["edenai"] = {
+provider = config.setdefault("provider", {})
+edenai_options = provider.get("edenai", {}).get("options", {})
+provider["edenai"] = {
     "npm": "`@ai-sdk/openai-compatible`",
     "name": "Eden AI",
-    "options": {"baseURL": BASE_URL},
+    "options": {**edenai_options, "baseURL": BASE_URL},
     "models": model_entries,
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
config = json.loads(output.read_text()) if output.exists() else {}
config["$schema"] = "https://opencode.ai/config.json"
config.setdefault("provider", {})["edenai"] = {
"npm": "@ai-sdk/openai-compatible",
"name": "Eden AI",
"options": {"baseURL": BASE_URL},
"models": model_entries,
}
config = json.loads(output.read_text()) if output.exists() else {}
config["$schema"] = "https://opencode.ai/config.json"
provider = config.setdefault("provider", {})
edenai_options = provider.get("edenai", {}).get("options", {})
provider["edenai"] = {
"npm": "`@ai-sdk/openai-compatible`",
"name": "Eden AI",
"options": {**edenai_options, "baseURL": BASE_URL},
"models": model_entries,
}
🧰 Tools
🪛 GitHub Check: Mintlify Validation (edenai) - vale-spellcheck

[warning] 128-128: v3/integrations/opencode.mdx#L128
Did you really mean 'model_entries'?

🤖 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 `@v3/integrations/opencode.mdx` around lines 122 - 129, Update the provider
configuration generation to preserve existing provider.edenai.options, including
options.apiKey, when rebuilding the Eden AI entry. Merge the existing options
into the generated options and then explicitly set baseURL to BASE_URL, while
leaving the other provider fields and model_entries behavior unchanged.

Tested against opencode 1.18.16 with a real Eden AI key: a mistyped model
reference surfaces as a generic UnknownError, not the "Model not found:
edenai/..." string the section quoted. Describe the symptom users actually
see and point at `opencode models` for the exact IDs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tristantelleb
tristantelleb merged commit c483a56 into main Aug 11, 2026
5 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant