You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Replace the native provider package model(modelID, settings) boundary with model({ id, settings, credential, defaults }). Core continues to select and refresh integration credentials, but native provider packages now own provider-specific auth lowering.
The package boundary carries a neutral key | oauth credential plus structured request defaults. Providers decide whether that credential becomes bearer auth, x-api-key, x-goog-api-key, Azure api-key, Vertex OAuth, Bedrock bearer auth, or provider-specific ambient/configured auth.
Core had package-name switches for Anthropic authToken, Vertex accessToken, and the default apiKey path. That made Core responsible for provider auth semantics and could erase the distinction between API keys and OAuth credentials.
Core passes the selected credential without interpreting its wire representation. Each provider package lowers it locally, removes competing stale auth headers where necessary, and preserves provider settings or environment fallback when no non-empty selected credential exists.
How
packages/ai/src/provider-package.ts defines the neutral credential algebra, structured model input/defaults, route-default projection, and semantic bearerAuthOption / apiKeyOrBearerAuthOption helpers.
Native provider entrypoints adopt the structured contract and keep auth behavior local across OpenAI, Anthropic, Google, Azure, Vertex, Bedrock, OpenRouter, xAI, and compatible providers.
Anthropic, Google, Azure, and Vertex remove competing key or authorization headers when switching credential modes.
Azure consumes key credential configuration for resource/base URL selection while Core retains configuration overlay and credential refresh ownership.
Vertex preserves OAuth/ADC and express-key behavior; Bedrock preserves bearer/SigV4 and ambient credential behavior.
packages/core/src/model-resolver.ts passes neutral credentials and structured defaults while retaining key configuration overlay, metadata handling, URL interpolation, selection, and refresh.
packages/core/src/aisdk-native.ts maps legacy native descriptors into provider-owned settings without moving auth lowering back into Core.
Leaves credential selection, OAuth refresh, configuration overlay, and provider enablement in Core.
Leaves provider-specific auth lowering in native AI provider packages.
Leaves Vertex service-account/ADC and Bedrock SigV4 credentials as provider settings rather than forcing them into the neutral OpenCode integration credential algebra.
No Protocol or Server HttpApi changes.
Testing
cd packages/ai && bun run test test/auth.test.ts test/provider-package.test.ts (24 passed)
cd packages/ai && bun typecheck
cd packages/core && bun run test test/model-resolver.test.ts test/aisdk-native.test.ts (58 passed)
cd packages/core && bun typecheck
bun turbo typecheck --concurrency=3 (33/33 tasks passed; also passed in the pre-push hook)
Repository-wide bun run lint still exits on the existing octal-escape error in packages/session-ui/src/v2/components/prompt-input/index.tsx:163; the changed-file lint has no errors.
Flow
flowchart LR
Integration[Integration connection] --> Core[Core selects and refreshes credential]
Catalog[Catalog model and settings] --> Resolver[Core model resolver]
Core --> Resolver
Resolver -->|neutral key or oauth credential| Package[Native provider package]
Resolver -->|structured headers body limits| Package
Package --> Auth{Provider auth lowering}
Auth -->|bearer| Bearer[Authorization header]
Auth -->|provider key| Key[Provider-specific key header]
Auth -->|ambient or configured| Ambient[ADC or SigV4]
Package --> Model[Executable LanguageModel]
AI code review — automated review for reference; please use your judgment.
packages/core/src/provider.ts:174 — this is a breaking contract change for third-party provider packages: model(modelID, settings) becomes model(input), and opencode loads arbitrary user-configured packages. An old package now receives an object where it expects a string (configure(...).chat(modelID) → chat({id,...}).id garbage), failing at runtime with confusing errors — consider feature-detecting the legacy shape (typeof arg === "string" adapter) for one release cycle, or documenting a required minimum @opencode-ai/plugin/ai version loudly at load time.
packages/core/src/model-resolver.ts:127 — configured dropped credential?.metadata: before, AI-SDK and native mapping saw { ...settings, ...metadata, ...configuration }; now only the AISDK branch merges metadata, so native packages lose integration-provided metadata (e.g. per-connection baseURL/region hints) at mapping time — if intentional, call it out; otherwise restore Provider.mergeOverlay(resolved.settings, credential?.metadata) semantics for parity.
packages/ai/src/providers/amazon-bedrock.ts:53 — the SigV4/apiKey mutual-exclusion guards only run when !input.credential; an OAuth credential combined with auth === "sigv4" now silently sets apiKey = accessToken — exactly the contradictory state the guard exists to prevent — extend the validation to the credential path (or ignore auth when a credential is supplied and say so).
packages/core/src/model-resolver.ts:238 — providerCredential treats empty-string keys/access tokens as "no credential", which re-opens the env-fallback chain — good fix for the apiKey: "" footgun, but it's a behavior change worth a line in the notes since configs that had an empty stored key will suddenly resolve differently.
packages/ai/src/providers/openai.ts:75 vs packages/core/src/aisdk-native.ts:263 — the OpenAI option allowlist now lives in two places (splitConfigOptions and openAIOptions) that must stay in lockstep with each other and with the protocol options type; drift sends a setting to route-level defaults instead of providerOptions (silently ignored server-side) depending on which entry path ran — add a shared const/type or a cross-package unit test asserting both lists are identical.
packages/ai/src/providers/anthropic.ts:34 / anthropic-compatible.ts:35 — wrapping the apiKey chain in Auth.remove("authorization") is a nice hardening against ambient/gateway-injected Bearer headers overriding x-api-key; consider noting it in the changelog since setups relying on a proxy-injected Authorization header alongside a configured apiKey will change behavior.
Nit — packages/ai/src/provider-package.ts:44 — bearerCredentialValue conflates OAuth access tokens and API keys into one string for the bearer path; fine today, but a short comment that OAuth tokens may need refresh-aware plumbing later would save future refactoring pain.
Overall: well-executed refactor — centralizing credential lowering in the providers removes a class of specifier-string branching, the structured ModelInput+Credential contract is much cleaner, and the test additions (type-level auth-option tests plus the expanded provider-package suite) are reassuring. Items 1–3 deserve attention before merge; the rest is polish. Thanks!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
This PR follows merged #43513.
Replace the native provider package
model(modelID, settings)boundary withmodel({ id, settings, credential, defaults }). Core continues to select and refresh integration credentials, but native provider packages now own provider-specific auth lowering.The package boundary carries a neutral
key | oauthcredential plus structured request defaults. Providers decide whether that credential becomes bearer auth,x-api-key,x-goog-api-key, Azureapi-key, Vertex OAuth, Bedrock bearer auth, or provider-specific ambient/configured auth.Before / After
Before
Core had package-name switches for Anthropic
authToken, VertexaccessToken, and the defaultapiKeypath. That made Core responsible for provider auth semantics and could erase the distinction between API keys and OAuth credentials.After
Core passes the selected credential without interpreting its wire representation. Each provider package lowers it locally, removes competing stale auth headers where necessary, and preserves provider settings or environment fallback when no non-empty selected credential exists.
How
packages/ai/src/provider-package.tsdefines the neutral credential algebra, structured model input/defaults, route-default projection, and semanticbearerAuthOption/apiKeyOrBearerAuthOptionhelpers.packages/core/src/model-resolver.tspasses neutral credentials and structured defaults while retaining key configuration overlay, metadata handling, URL interpolation, selection, and refresh.packages/core/src/aisdk-native.tsmaps legacy native descriptors into provider-owned settings without moving auth lowering back into Core.packages/ai/README.md,packages/ai/AGENTS.md, and the tutorial document the ownership boundary and call shape.Scope
HttpApichanges.Testing
cd packages/ai && bun run test test/auth.test.ts test/provider-package.test.ts(24 passed)cd packages/ai && bun typecheckcd packages/core && bun run test test/model-resolver.test.ts test/aisdk-native.test.ts(58 passed)cd packages/core && bun typecheckbun turbo typecheck --concurrency=3(33/33 tasks passed; also passed in the pre-push hook)bunx prettier --check $(git diff --name-only -- '*.ts' '*.md')bunx oxlint $(git diff --name-only -- '*.ts')(0 errors; warnings only)git diff --checkRepository-wide
bun run lintstill exits on the existing octal-escape error inpackages/session-ui/src/v2/components/prompt-input/index.tsx:163; the changed-file lint has no errors.Flow
flowchart LR Integration[Integration connection] --> Core[Core selects and refreshes credential] Catalog[Catalog model and settings] --> Resolver[Core model resolver] Core --> Resolver Resolver -->|neutral key or oauth credential| Package[Native provider package] Resolver -->|structured headers body limits| Package Package --> Auth{Provider auth lowering} Auth -->|bearer| Bearer[Authorization header] Auth -->|provider key| Key[Provider-specific key header] Auth -->|ambient or configured| Ambient[ADC or SigV4] Package --> Model[Executable LanguageModel]