Skip to content

feat: support custom baseURL via opencode.json and ANTHROPIC_BASE_URL…#229

Open
anxjok wants to merge 1 commit into
griffinmartin:mainfrom
anxjok:feat/proxy-baseurl-support
Open

feat: support custom baseURL via opencode.json and ANTHROPIC_BASE_URL…#229
anxjok wants to merge 1 commit into
griffinmartin:mainfrom
anxjok:feat/proxy-baseurl-support

Conversation

@anxjok

@anxjok anxjok commented May 22, 2026

Copy link
Copy Markdown

Summary

Add support for configuring a custom Anthropic API base URL via opencode.json or the ANTHROPIC_BASE_URL environment variable. This enables routing Anthropic API requests through proxies, API gateways, and custom endpoints while maintaining OAuth authentication through Claude Code credentials.
Key features:

  • Configure custom base URL in opencode.json via provider.anthropic.options.baseURL
  • Fallback support via ANTHROPIC_BASE_URL environment variable
  • Priority chain: config file > environment variable > default Anthropic endpoint
  • Custom headers from provider.anthropic.options.headers are automatically forwarded (useful for authentication headers like X-Gateway-Key)
  • Fully backward compatible — existing setups continue to work without changes

Related issue

Closes #160 (FR: Anthropic API mode for e.g. CLIProxyAPI)

Testing

  • Manually tested with live proxy endpoint:
    • Requests correctly routed to proxy URL (not default API)
    • 200 OK responses received
    • Custom headers (e.g., X-Gateway-Key) forwarded correctly
    • Fallback to default endpoint when no config/env var is set
  • Priority chain validated: config > env var > default
  • All 225 tests pass (220 existing + 5 new baseURL tests):
    • Lint: 0 warnings, 0 errors
    • Build: TypeScript compilation successful
    • Test suites: 39 suites, 0 failures
  • No regression in existing functionality
    Test coverage includes:
  • Uses default baseURL when no config or env var is set
  • Uses provider.anthropic.options.baseURL from opencode.json when provided
  • Uses ANTHROPIC_BASE_URL environment variable when set (no config)
  • Prioritizes config over environment variable (correct precedence)
  • Does not double /v1 path segment (correct URL merging)

Checklist

  • PR title follows Conventional Commits (feat:)
  • make all passes locally (runs lint, build, and test)
  • Tests added or updated where applicable (5 new baseURL tests in src/index.test.ts)
  • README or docs updated where applicable (added "Custom base URL / Proxy support" section and ANTHROPIC_BASE_URL env var documentation)

… env var

- Add support for configuring custom base URL in opencode.json via provider.anthropic.options.baseURL
- Add fallback to ANTHROPIC_BASE_URL environment variable
- Maintain backward compatibility with default Anthropic API endpoint
- Priority: config > env var > default

This enables routing Anthropic API requests through proxies, API gateways, and custom endpoints while maintaining OAuth authentication through Claude Code credentials.

Features:
- Custom headers from provider.anthropic.options.headers are automatically forwarded
- Useful for authentication headers (e.g., X-Gateway-Key)
- Verified to work with proxies and load balancers

Closes: Support for proxy/gateway setups requested by users
@griffinmartin

Copy link
Copy Markdown
Owner

@greptileai

@greptile-apps

greptile-apps Bot commented Jul 25, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds support for routing Anthropic API requests through a custom base URL, configurable via provider.anthropic.options.baseURL in opencode.json or the ANTHROPIC_BASE_URL environment variable, with the config file taking precedence over the env var.

  • The core change in src/index.ts is a 4-line effectiveBaseURL resolution that is returned in the auth config object — straightforward and correct.
  • The README's new priority-list section is accurate, but the env-var table entry incorrectly states that ANTHROPIC_BASE_URL "Takes precedence over config file," which is the opposite of the actual behaviour.
  • The PR description and README both document that provider.anthropic.options.headers entries are automatically forwarded to requests, but no code in this diff reads or applies those headers — the feature is documented but not implemented.

Confidence Score: 3/5

Safe to merge for the baseURL routing itself, but ships with a documented feature (custom header forwarding) that has no implementation and a README table that misstates the priority order.

The baseURL resolution logic is correct and backward-compatible. However, the README's env-var table says the env var overrides the config file when the opposite is true, and the custom headers feature advertised in both the README and the PR description is entirely absent from the code — users who configure provider.anthropic.options.headers expecting those headers to reach their proxy will see silent failures.

Files Needing Attention: src/index.ts (missing headers forwarding implementation) and README.md (inverted priority description in the env-var table)

Important Files Changed

Filename Overview
src/index.ts Adds effectiveBaseURL resolution (config > env var > default) and returns it in the auth config object. However, provider.options?.headers — which is documented as being forwarded — is never read or applied.
README.md Documents the new feature correctly in the priority-list section but contradicts it in the env-var table, which says ANTHROPIC_BASE_URL "Takes precedence over config file" — the opposite of the actual behaviour.
src/index.test.ts Adds 5 tests covering default baseURL, config baseURL, env-var baseURL, priority order, and no-double-/v1. Tests verify the baseURL property on the returned config object; no test covers the missing headers forwarding.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[auth loader called] --> B{provider.options?.baseURL set?}
    B -- yes --> C[use config baseURL]
    B -- no --> D{ANTHROPIC_BASE_URL env var set?}
    D -- yes --> E[use env var baseURL]
    D -- no --> F[use default: https://api.anthropic.com/v1]
    C --> G[return auth config with baseURL]
    E --> G
    F --> G
    G --> H[framework builds request URL from baseURL]
    H --> I[fetch called with constructed URL]
    I --> J[buildRequestUrl — add ?beta=true if path == /v1/messages]
    J --> K[buildRequestHeaders — adds auth, beta, stainless headers]
    K --> L[fetchWithRetry]
Loading

Fix All in Cursor Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
README.md:215
**README env-var table priority is inverted**

The table entry for `ANTHROPIC_BASE_URL` says "Takes precedence over config file," but the code and the priority section above it both say the opposite: `provider.anthropic.options.baseURL` wins over the env var. A user reading only the table will believe they can override a config-file URL with the env var, try it, and find it silently doesn't work.

### Issue 2 of 3
README.md:217
The description incorrectly says the env var takes precedence over the config file. The actual priority (reflected both in the code and the priority list above the table) is config file > env var > default.

```suggestion
| `ANTHROPIC_BASE_URL`                | Custom base URL for Anthropic API requests (e.g., proxy or custom endpoint). Overridden by `provider.anthropic.options.baseURL` in `opencode.json` when both are set.                 | `https://api.anthropic.com/v1`                                                                          |
```

### Issue 3 of 3
src/index.ts:321-328
**Custom headers from `provider.options.headers` are documented but not forwarded**

The README and PR description prominently state that `provider.anthropic.options.headers` entries are "automatically forwarded to all API requests" (useful for `X-Gateway-Key` etc.). However, only `provider.options?.baseURL` is consumed here — `provider.options?.headers` is never read. `buildRequestHeaders` takes its input only from the `init` argument supplied by the framework, not from provider config headers. Any user who configures headers in `opencode.json` expecting them to reach the proxy will receive a silent failure.

Reviews (1): Last reviewed commit: "feat: support custom baseURL via opencod..." | Re-trigger Greptile

Comment thread README.md
@@ -182,6 +214,7 @@ All configurable parameters can be overridden via environment variables. If Anth

| Variable | Description | Default |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 README env-var table priority is inverted

The table entry for ANTHROPIC_BASE_URL says "Takes precedence over config file," but the code and the priority section above it both say the opposite: provider.anthropic.options.baseURL wins over the env var. A user reading only the table will believe they can override a config-file URL with the env var, try it, and find it silently doesn't work.

Prompt To Fix With AI
This is a comment left during a code review.
Path: README.md
Line: 215

Comment:
**README env-var table priority is inverted**

The table entry for `ANTHROPIC_BASE_URL` says "Takes precedence over config file," but the code and the priority section above it both say the opposite: `provider.anthropic.options.baseURL` wins over the env var. A user reading only the table will believe they can override a config-file URL with the env var, try it, and find it silently doesn't work.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Cursor Fix in Claude Code Fix in Codex

Comment thread README.md

| Variable | Description | Default |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `ANTHROPIC_BASE_URL` | Custom base URL for Anthropic API requests (e.g., proxy or custom endpoint). Takes precedence over config file. | `https://api.anthropic.com/v1` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 The description incorrectly says the env var takes precedence over the config file. The actual priority (reflected both in the code and the priority list above the table) is config file > env var > default.

Suggested change
| `ANTHROPIC_BASE_URL` | Custom base URL for Anthropic API requests (e.g., proxy or custom endpoint). Takes precedence over config file. | `https://api.anthropic.com/v1` |
| `ANTHROPIC_BASE_URL` | Custom base URL for Anthropic API requests (e.g., proxy or custom endpoint). Overridden by `provider.anthropic.options.baseURL` in `opencode.json` when both are set. | `https://api.anthropic.com/v1` |
Prompt To Fix With AI
This is a comment left during a code review.
Path: README.md
Line: 217

Comment:
The description incorrectly says the env var takes precedence over the config file. The actual priority (reflected both in the code and the priority list above the table) is config file > env var > default.

```suggestion
| `ANTHROPIC_BASE_URL`                | Custom base URL for Anthropic API requests (e.g., proxy or custom endpoint). Overridden by `provider.anthropic.options.baseURL` in `opencode.json` when both are set.                 | `https://api.anthropic.com/v1`                                                                          |
```

How can I resolve this? If you propose a fix, please make it concise.

Fix in Cursor Fix in Claude Code Fix in Codex

Comment thread src/index.ts
Comment on lines +321 to +328
const effectiveBaseURL =
provider.options?.baseURL ||
process.env.ANTHROPIC_BASE_URL ||
"https://api.anthropic.com/v1"

return {
apiKey: "",
baseURL: "https://api.anthropic.com/v1",
baseURL: effectiveBaseURL,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Custom headers from provider.options.headers are documented but not forwarded

The README and PR description prominently state that provider.anthropic.options.headers entries are "automatically forwarded to all API requests" (useful for X-Gateway-Key etc.). However, only provider.options?.baseURL is consumed here — provider.options?.headers is never read. buildRequestHeaders takes its input only from the init argument supplied by the framework, not from provider config headers. Any user who configures headers in opencode.json expecting them to reach the proxy will receive a silent failure.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/index.ts
Line: 321-328

Comment:
**Custom headers from `provider.options.headers` are documented but not forwarded**

The README and PR description prominently state that `provider.anthropic.options.headers` entries are "automatically forwarded to all API requests" (useful for `X-Gateway-Key` etc.). However, only `provider.options?.baseURL` is consumed here — `provider.options?.headers` is never read. `buildRequestHeaders` takes its input only from the `init` argument supplied by the framework, not from provider config headers. Any user who configures headers in `opencode.json` expecting them to reach the proxy will receive a silent failure.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Cursor Fix in Claude Code Fix in Codex

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.

FR: Anthropic API mode for e.g. CLIProxyAPI

2 participants