feat(llm): provider packages own model request construction#35212
Open
kitlangton wants to merge 5 commits into
Open
feat(llm): provider packages own model request construction#35212kitlangton wants to merge 5 commits into
kitlangton wants to merge 5 commits into
Conversation
Provider packages in @opencode-ai/llm/providers/* now implement a uniform ProviderPackage contract: model(modelID, settings) => Model. SessionRunnerModel becomes provider-agnostic: it resolves a package specifier, folds catalog settings, credentials, and transport overlays into one Settings object, and delegates request construction to the package. - llm: add ProviderPackage (Settings, Definition, define), flat model(id, config) constructors on the openai-responses, anthropic-messages, and openai-compatible-chat protocols, contract-shaped model exports on the openai, anthropic, and openai-compatible providers, and a new providers/openai/codex entry point that targets the ChatGPT codex backend and sets the chatgpt-account-id header from settings.accountID. - schema: Provider.Native gains optional package. - core: SessionRunnerModel loads packages through a static built-in map (dynamic import for foreign specifiers) and applies one settings fold; the ChatGPT conditional is deleted from the runner. The OpenAI plugin's catalog transform now assigns the codex package to eligible models when a ChatGPT connection is active, alongside the existing eligibility and cost rewrites. - llm schema: hoist ToolResultValue union out of its Object.assign self reference; the previous shape only typechecked under lucky check ordering and broke under core's typecheck with the new import graph. Closes #34765
…outes
Provider packages are now the only module-level model constructors; the
protocol-level model wrappers added earlier on this branch had one call
site each and duplicated the Settings vocabulary, so packages call
route.with(...).model({id}) directly. Deletes provider facades with no
importers outside llm tests; configure stays for V1 native-request.
The catalog treated any native model api with empty settings and no url as a placeholder inheriting the provider api, which stomped plugin-assigned native packages (ChatGPT codex retargeting) back to aisdk. A native api carrying a package is explicitly targeted and now survives projection.
Replace the codex-substring heuristic with the empirically verified allow/disallow lists plus the >5.4 version rule; the ChatGPT backend rejects models like gpt-5.3-codex that the substring rule admitted.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
Makes
SessionRunnerModelprovider-agnostic. Provider packages under@opencode-ai/llm/providers/*implement a uniform contract:The runner resolves a package specifier from the catalog api, folds
api.settings, credentials, and transport overlays (headers/body/limits) into oneSettingsobject, and callsmodule.model(id, settings). All provider knowledge (routes, auth shapes, backend quirks) lives in the packages.ChatGPT / Codex (#34765)
The temporary runner seam is gone. The codex backend is now just a per-API entry point of the openai provider,
@opencode-ai/llm/providers/openai/codex, selected by the OpenAI plugin's existing catalog transform when a ChatGPT connection is active (same transform that already handles eligibility and zero cost). The plugin writescredential.metadata.accountID; the runner folds OAuth metadata into settings; the codex package sets the backend URL andchatgpt-account-idheader. The runner has no provider conditionals left.Changes
ProviderPackagecontract (Settings,Definition,define); flatmodel(id, config)constructors on the openai-responses / anthropic-messages / openai-compatible-chat protocols; contract-shapedmodelexports on openai, anthropic, openai-compatible providers; newproviders/openai/codex; explicit exports-map entries.Provider.Nativegains optionalpackage(client + sdk types regenerated).import()with shape validation for foreign specifiers); one settings fold with explicit precedence (credential > config; key metadata → body as before, OAuth metadata → settings, never the body); legacyaisdkcatalog entries dispatch through the same map, preserving behavior.ToolResultValuewas self-referential throughObject.assignand only typechecked under lucky check ordering; hoisted the union so core's typecheck passes with the new import graph.Notes
Direction follows the native provider package work in #33689/#34462, rebuilt on current
devso the ChatGPT routing lands provider-owned rather than as a runner seam. The generic AI SDK adapter for arbitraryaisdkpackages is deliberately out of scope (follow-up).Verification
bun typecheck: llm, core, schema, client ✓bun run test: llm 329 pass; core session-runner + plugin + model suites 362 pass ✓chatgpt-account-idheader with/without accountID); plugin assigns codex package + zero cost to eligible models, disables ineligible ✓