Extract provider resolution logic into two new modules: - provider-catalog.ts: vendor presets, default model catalogs, protocol definitions - provider-resolver.ts: unified resolution for all consumers (Claude SDK, AI SDK, model listing) DB migration: - Add protocol, headers_json, env_overrides_json, role_models_json columns to api_providers - Create provider_models table for per-provider model catalog Consumer refactoring: - claude-client.ts: replace inline env-building with toClaudeCodeEnv() - text-generator.ts: replace inline config with toAiSdkConfig() - conversation-engine.ts, onboarding, checkin, plan routes: use shared resolveProvider() - /api/providers/models: read from catalog + provider_models table UI improvements: - Merge confusing "Custom API (Anthropic-compatible)" into "Anthropic Third-party API" - Add 3-field model name mapping (sonnet/opus/haiku) in advanced options - ProviderForm.tsx: support new fields (protocol, env_overrides, role_models) Bug fixes: - Protect auth credentials from being deleted by legacy extra_env empty-string overrides - Fix env var names: ANTHROPIC_DEFAULT_SONNET → ANTHROPIC_DEFAULT_SONNET_MODEL (SDK convention) Tests: 229/229 passed. Verified with aiberm (no mapping) and pipellm (with mapping). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2.6 KiB
2.6 KiB
Provider Resolver Refactor
Status: Complete (Phase 1–5) Scope: Provider system unification — resolve "主聊天能用、旁路功能失效" structural issue
Problem
ApiProvidermixes protocol/vendor/auth/model-mapping into one flat structureclaude-clientandtext-generatorare two independent provider resolution chains- GLM/Kimi/MiniMax/Volcengine/Bailian are Anthropic-compatible but built as
custom(OpenAI-compatible in text-generator) - Model listing relies on hardcoded base_url → model label mapping
- Bridge/chat/onboarding/checkin/plan have divergent provider resolution
- No contract tests
Solution
Phase 1: Core modules
src/lib/provider-catalog.ts— vendor presets, default model catalogs, protocol definitionssrc/lib/provider-resolver.ts— unified provider/model resolution for all consumers
Phase 2: DB migration
- Add
protocol,headers_json,env_overrides_json,role_models_jsontoapi_providers - Create
provider_modelstable - Migrate existing data (provider_type → protocol, extra_env → env_overrides_json)
Phase 3: Consumer refactoring
claude-client.ts→ use resolver'stoClaudeCodeEnv()text-generator.ts→ use resolver'stoAiSdkConfig()route.ts,conversation-engine.ts,onboarding,checkin,plan→ use shared resolver
Phase 4: UI update
ProviderManager.tsxpresets → reference catalogProviderForm.tsx→ protocol selector instead of provider_type/api/providers/models→ read from catalog + provider_models
Phase 5: Tests
- Provider resolver contract tests
- Entry point consistency tests
- Preset protocol validation
- Regression tests (env cleanup, bind semantics)
Decision Log
| Date | Decision | Rationale |
|---|---|---|
| 2026-03-09 | Add fields to existing table, not new system | Minimize migration risk, preserve existing data |
| 2026-03-09 | Protocol-based dispatch instead of brand-name | Matches actual API behavior, extensible |
| 2026-03-09 | Merge custom-anthropic into anthropic-thirdparty | Remove user confusion between two nearly identical presets |
| 2026-03-09 | Auth env keys protected from envOverrides deletion | Legacy extra_env placeholders ({"ANTHROPIC_AUTH_TOKEN":""}) were deleting freshly-injected credentials |
| 2026-03-09 | Env var names use _MODEL suffix |
Claude Code SDK expects ANTHROPIC_DEFAULT_SONNET_MODEL, not ANTHROPIC_DEFAULT_SONNET |
Verification
- aiberm (no model mapping): ✅ responded "OK claude-sonnet-4-6"
- pipellm (with sonnet/opus/haiku mapping): ✅ responded "OK claude-sonnet-4-6"
- Unit tests: 229/229 passed