Skip to content

fix(wrap): route OpenCode custom OpenAI-compatible upstreams - #3110

Closed
Parideboy wants to merge 1 commit into
headroomlabs-ai:mainfrom
Parideboy:fix/3107-opencode-openai-api-url
Closed

fix(wrap): route OpenCode custom OpenAI-compatible upstreams#3110
Parideboy wants to merge 1 commit into
headroomlabs-ai:mainfrom
Parideboy:fix/3107-opencode-openai-api-url

Conversation

@Parideboy

@Parideboy Parideboy commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Description

headroom wrap opencode always forwards OpenAI-shaped traffic to https://api.openai.com/v1, with no flag or env var to point it at a third-party OpenAI-compatible provider. A user who configures OpenCode for DeepSeek and then runs headroom wrap opencode gets their requests silently forwarded to OpenAI instead, which rejects the DeepSeek key with an HTTP 401 error. Making this worse, docs/content/docs/opencode-deepseek.mdx explicitly told users not to use headroom wrap at all for this case, leaving no documented path for DeepSeek users through wrap opencode.

The proxy-side plumbing to support a custom upstream already exists and is already used by other wrap subcommands (vibe, grok hardcode their own upstream URLs through the same _ensure_proxy(openai_api_url=...) path). This PR exposes it as a user-settable --openai-api-url option on opencode(), following the same pattern as the open sibling PR #3018 (fix(wrap): route Cline custom upstreams), and updates the docs so DeepSeek users have a working wrap opencode path.

Closes #3107

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Performance improvement
  • Code refactoring (no functional changes)

Changes Made

  • headroom/cli/wrap.py: add --openai-api-url option to opencode(), thread it into the _ensure_proxy(...) call, and reject combining it with --copilot-subscription (the two pick different, incompatible upstream-selection strategies), matching the file's existing incompatible-flag validation pattern.
  • tests/test_cli/test_wrap_opencode.py: four new tests covering the flag being forwarded, the None default when omitted, its presence in --help (and absence from wrap codex --help), and the conflict with --copilot-subscription failing fast before any proxy work.
  • docs/content/docs/opencode.mdx: document the new flag in the Options block, with a cross-link to the DeepSeek guide.
  • docs/content/docs/opencode-deepseek.mdx: rewrite the "Models appear but requests fail" troubleshooting section and the "What's NOT in this guide" bullet, which previously told readers not to use headroom wrap at all, to instead document --openai-api-url as the supported fix/shortcut.

Testing

  • Unit tests pass (pytest)
  • Linting passes (ruff check .)
  • Type checking passes (mypy headroom)
  • New tests added for new functionality
  • Manual testing performed

Test Output

$ .venv/Scripts/python -m pytest tests/test_cli/test_wrap_opencode.py -v
...
tests/test_cli/test_wrap_opencode.py::test_wrap_opencode_with_openai_api_url PASSED
tests/test_cli/test_wrap_opencode.py::test_wrap_opencode_without_openai_api_url_defaults_to_none PASSED
tests/test_cli/test_wrap_opencode.py::test_wrap_opencode_help_lists_openai_api_url PASSED
tests/test_cli/test_wrap_opencode.py::test_wrap_opencode_openai_api_url_conflicts_with_copilot_subscription PASSED
...
44 passed in 6.32s

$ ruff check headroom/cli/wrap.py tests/test_cli/test_wrap_opencode.py
All checks passed!

$ ruff format --check headroom/cli/wrap.py tests/test_cli/test_wrap_opencode.py
2 files already formatted

$ .venv/Scripts/mypy headroom --ignore-missing-imports
Success: no issues found in 522 source files

$ .venv/Scripts/headroom.exe wrap opencode --openai-api-url https://api.deepseek.com/v1 --copilot-subscription
Error: --copilot-subscription cannot be combined with --openai-api-url because the Copilot subscription flow already selects its own upstream API URL.
(exit code 1, no proxy started)

Real Behavior Proof

  • Environment: Windows 11, Python 3.13.11, project .venv (mypy 1.19.1, pytest 9.0.3, ruff 0.15.17), local editable install of headroom
  • Exact command / steps: .venv/Scripts/headroom.exe wrap opencode --help to confirm the flag is listed; .venv/Scripts/headroom.exe wrap opencode --openai-api-url https://api.deepseek.com/v1 --copilot-subscription to confirm the conflict check fires before any proxy/config work
  • Observed result: --help output lists --openai-api-url URL with the full help text; the conflicting-flags command exits 1 with the new ClickException message and does not start a proxy or touch OpenCode's config
  • Not tested: an actual end-to-end request through a running proxy to api.deepseek.com (would require a real DeepSeek API key and a running OpenCode install); this PR only adds the CLI plumbing, the underlying _ensure_proxy/proxy-side forwarding of openai_api_url is pre-existing and already covered by other wrap subcommands' tests

Runtime Rollout Safety

  • Rollout-managed feature(s): none; this is a plain CLI option with no feature flag or rollout channel
  • Minimum rollout channel: n/a
  • Stable/default behavior changed: no; omitting --openai-api-url preserves the exact prior behavior (upstream defaults to OpenAI, or to the Copilot subscription URL when --copilot-subscription is set)
  • Kill switch / disable path: n/a; simply not passing --openai-api-url reverts to prior behavior
  • Unsafe override required: no
  • Qualification impact: none; no changes to compression, pricing, or tokenizer logic
  • Rollback path: revert this commit; no data migration or state to unwind

Review Readiness

  • I have performed a self-review
  • This PR is ready for human review

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I did not edit CHANGELOG.md — it is generated by release-please from my Conventional Commit PR title (a CI guard enforces this)

Additional Notes

Coordination: this touches a different section of headroom/cli/wrap.py (OpenCode, ~line 7203) than the open sibling PR #3018 (Cline, ~line 6564), which fixes the identical class of bug for wrap cline. No textual conflict expected between the two, but line numbers may shift if #3018 merges first.

…mlabs-ai#3107)

`headroom wrap opencode` always forwarded OpenAI-shaped traffic to
api.openai.com with no way to point it at a third-party provider like
DeepSeek, so a DeepSeek-configured OpenCode session got its requests
silently sent to OpenAI and rejected with an HTTP 401 error. Add
--openai-api-url to opencode() (mirroring the plumbing already used by
proxy/vibe/grok) and reject combining it with --copilot-subscription,
since the two pick different upstream-selection strategies. Also
update the OpenCode docs, which told DeepSeek users not to use
`headroom wrap` at all, to document the new flag as the supported path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

PR governance

This PR follows the template and is marked ready for human review.

@github-actions github-actions Bot added the status: ready for review Pull request body is complete and the author marked it ready for human review label Aug 18, 2026
@codecov-commenter

codecov-commenter commented Aug 18, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@JerrettDavis JerrettDavis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This implementation looks internally coherent, but it substantially overlaps #3125 and the two changes should not both merge independently. #3125 also adds the canonical OPENAI_TARGET_API_URL environment variable and broader user guidance; this PR usefully updates the canonical docs/opencode.mdx page. I recommend consolidating that documentation addition into the selected implementation (likely #3125) and closing the duplicate, rather than landing both.

@Parideboy

Copy link
Copy Markdown
Contributor Author

Agreed with @JerrettDavis#3125 fixes the same bug (#3107) and is more complete: it also adds the OPENAI_TARGET_API_URL env var (mirroring headroom proxy) and a broader opencode-deepseek.mdx rewrite, plus a README.md footnote. It's already approved and green, so no reason to land both.

Closing this one in favor of #3125. One thing worth carrying over: this PR also updated docs/content/docs/opencode.mdx (the canonical OpenCode integration page) to document the new flag, and #3125 doesn't touch that file. I've left a comment on #3125 with that diff in case it's useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: ready for review Pull request body is complete and the author marked it ready for human review

Projects

None yet

3 participants