A ModelProvider over Anthropic’s own SDK. It is the only package in the
copilot allowed to import a vendor SDK.
Install
npm install @orthacms/copilot-provider-anthropicConfigure
# .env
COPILOT_ENABLED=true
# setting it registers the backend
ANTHROPIC_API_KEY=sk-ant-...
COPILOT_ANTHROPIC_MODELS=claude-opus-5,claude-sonnet-5,claude-haiku-4-5
# optional gateway / proxy
ANTHROPIC_BASE_URL=| Variable | Default | Notes |
|---|---|---|
ANTHROPIC_API_KEY | unset | Unset = no claude in the picker at all |
COPILOT_ANTHROPIC_MODELS | reference: claude-opus-5,claude-sonnet-5,claude-haiku-4-5; generated app: claude-sonnet-5 | First is the default |
ANTHROPIC_BASE_URL | unset | Reference server only. In a generated app, add baseUrl to config/copilot-anthropic.ts |
The reference server, apps/server/config/copilot.ts:
const anthropicApiKey = readEnv('ANTHROPIC_API_KEY');
claude: when(anthropicApiKey, () =>
defined({
apiKey: anthropicApiKey as string,
models: readList(
'COPILOT_ANTHROPIC_MODELS',
'claude-opus-5,claude-sonnet-5,claude-haiku-4-5'
),
baseUrl: readEnv('ANTHROPIC_BASE_URL')
})
),A generated app has the same in config/copilot-anthropic.ts:
import type { AnthropicProviderConfig } from '@orthacms/copilot-provider-anthropic';
import { readEnv, readList } from '@orthacms/utils-server';
export function anthropicProvider(): AnthropicProviderConfig | undefined {
const apiKey = readEnv('ANTHROPIC_API_KEY');
if (!apiKey) return undefined;
return { apiKey, models: readList('COPILOT_ANTHROPIC_MODELS', 'claude-sonnet-5') };
}All options
AnthropicProviderConfig:
| Option | Default | Notes |
|---|---|---|
apiKey | required | Never leaves the server |
models | required | Non-empty. First is the default |
baseUrl | Anthropic API | Gateway, proxy or regional endpoint |
effort | API default (high) | low | medium | high | xhigh | max |
maxRetries | SDK’s 2 | On 429, 5xx, connection errors |
timeoutMs | SDK’s 10 minutes | Per request |
promptCaching | true | Turn off only for a gateway that rejects cache_control |
Register
// apps/server/src/plugins.ts
import { createAnthropicProvider } from '@orthacms/copilot-provider-anthropic';
const { claude } = config.plugins.copilot.providers;
CopilotPlugin({
providers: claude
? [{ name: 'claude', provider: createAnthropicProvider(claude) }]
: [],
config: config.plugins.copilot
});Or with options that have no variable:
createAnthropicProvider({
apiKey: process.env.ANTHROPIC_API_KEY!,
models: ['claude-sonnet-5', 'claude-haiku-4-5'],
effort: 'medium',
timeoutMs: 120_000
});Verify
curl -s -b cookies.txt http://localhost:3000/api/copilot/models
# {"items":[{"provider":"claude","model":"claude-opus-5"},
# {"provider":"claude","model":"claude-sonnet-5"}, ...]}No claude rows means the key was not read. Sign-in and a streamed run are
shown on the copilot page.
Behaviour worth knowing
- Unknown model = error, no request. A run naming a model outside
modelsfails withUnknownModelError. It never falls back to the default. - Lazy client. The SDK client is built on first use, so an unused adapter never fails a boot.
- Capabilities are probed from the Models API and cached per model. If the probe fails: 200,000-token context, 8,192 output tokens, vision and tool calling. A failed probe is not cached.
- No
thinkingconfig is sent and no sampling parameters. Useeffort. - Prompt caching: one breakpoint at the end of the system prompt, up to three rolling through the conversation.