Problem
All 18 provider loaders live as inline async functions inside a single CUSTOM_LOADERS record in provider.ts (lines 84-595, ~511 lines). Adding or modifying a provider means editing this monolithic file, which:
- Increases merge conflict risk
- Makes individual providers hard to test in isolation
- Inflates cognitive load when working on a single provider
- Diverges from upstream's modular architecture
Current providers in CUSTOM_LOADERS
| # |
Provider |
Lines |
Complexity |
| 1 |
anthropic |
85-131 |
High — OAuth, subscription, API key, beta headers |
| 2 |
cyberstrike |
132-153 |
Medium — auto-filter paid models, public fallback |
| 3 |
openai |
154-162 |
Low |
| 4 |
github-copilot |
163-172 |
Low — responses/chat routing |
| 5 |
github-copilot-enterprise |
173-182 |
Low |
| 6 |
azure |
183-195 |
Low — responses/chat routing |
| 7 |
azure-cognitive-services |
196-211 |
Low |
| 8 |
amazon-bedrock |
212-371 |
Very high — AWS credential chain, cross-region, profiles |
| 9 |
openrouter |
372-382 |
Low — headers only |
| 10 |
vercel |
383-393 |
Low — headers only |
| 11 |
google-vertex |
394-418 |
Medium — ADC, project/location resolution |
| 12 |
google-vertex-anthropic |
419-446 |
Medium — regional endpoints |
| 13 |
sap-ai-core |
447-470 |
Medium — AICORE_SERVICE_KEY parsing |
| 14 |
zenmux |
471-481 |
Low — headers only |
| 15 |
gitlab |
482-523 |
Medium — OAuth/API, feature flags |
| 16 |
cloudflare-workers-ai |
524-546 |
Medium — account ID resolution |
| 17 |
cloudflare-ai-gateway |
547-584 |
Medium — unified API format |
| 18 |
cerebras |
585-595 |
Low — header only |
Proposal
Refactor to per-provider files under src/provider/loaders/, mirroring upstream's modular plugin approach:
src/provider/
├── provider.ts # core loading logic, imports loaders
├── loaders/
│ ├── index.ts # re-exports all loaders as CUSTOM_LOADERS record
│ ├── anthropic.ts
│ ├── amazon-bedrock.ts
│ ├── google-vertex.ts
│ ├── google-vertex-anthropic.ts
│ ├── gitlab.ts
│ ├── cloudflare-workers-ai.ts
│ ├── cloudflare-ai-gateway.ts
│ ├── sap-ai-core.ts
│ ├── openrouter.ts # (could group simple header-only loaders)
│ └── ...
Each loader file exports a single async function matching the current CustomLoader type signature. The loaders/index.ts assembles them into the CUSTOM_LOADERS record — zero change to the consumer API.
Suggested phases
- Extract complex providers first —
amazon-bedrock (160 lines), anthropic, google-vertex*, gitlab, cloudflare-*
- Group simple header-only providers —
openrouter, vercel, zenmux, cerebras could share a utility
- Add per-provider tests — currently untestable in isolation
- Align type with upstream's
PluginV2.define() if applicable
Upstream reference
Upstream (anomalyco/opencode) uses a granular plugin architecture at packages/core/src/plugin/provider/ with PluginV2.define(), typed event hooks (catalog.transform, aisdk.sdk, aisdk.language), and Effect-based composition.
We don't need to adopt Effect or the full plugin system — the goal is file-level separation while keeping the existing CustomLoader interface.
Non-goals
- Changing the provider loading flow (6-step process stays)
- Adopting Effect or upstream's full plugin system
- Breaking the
CustomLoader type contract
Problem
All 18 provider loaders live as inline async functions inside a single
CUSTOM_LOADERSrecord inprovider.ts(lines 84-595, ~511 lines). Adding or modifying a provider means editing this monolithic file, which:Current providers in CUSTOM_LOADERS
anthropiccyberstrikeopenaigithub-copilotgithub-copilot-enterpriseazureazure-cognitive-servicesamazon-bedrockopenroutervercelgoogle-vertexgoogle-vertex-anthropicsap-ai-corezenmuxgitlabcloudflare-workers-aicloudflare-ai-gatewaycerebrasProposal
Refactor to per-provider files under
src/provider/loaders/, mirroring upstream's modular plugin approach:Each loader file exports a single async function matching the current
CustomLoadertype signature. Theloaders/index.tsassembles them into theCUSTOM_LOADERSrecord — zero change to the consumer API.Suggested phases
amazon-bedrock(160 lines),anthropic,google-vertex*,gitlab,cloudflare-*openrouter,vercel,zenmux,cerebrascould share a utilityPluginV2.define()if applicableUpstream reference
Upstream (
anomalyco/opencode) uses a granular plugin architecture atpackages/core/src/plugin/provider/withPluginV2.define(), typed event hooks (catalog.transform,aisdk.sdk,aisdk.language), and Effect-based composition.We don't need to adopt Effect or the full plugin system — the goal is file-level separation while keeping the existing
CustomLoaderinterface.Non-goals
CustomLoadertype contract