feat: unified provider resolver with protocol-based dispatch

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>
This commit is contained in:
7418andClaude Opus 4.6 committed 2026-03-09 20:30:35 +08:00
1 parent 4dc787c4a4
commit f76e4747cd
21 files changed
+2932 -344

No files matched your search

@@ -0,0 +1,56 @@
# Provider Resolver Refactor
**Status:** Complete (Phase 1–5)
**Scope:** Provider system unification — resolve "主聊天能用、旁路功能失效" structural issue
## Problem
- `ApiProvider` mixes protocol/vendor/auth/model-mapping into one flat structure
- `claude-client` and `text-generator` are 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 definitions
- `src/lib/provider-resolver.ts` — unified provider/model resolution for all consumers
### Phase 2: DB migration
- Add `protocol`, `headers_json`, `env_overrides_json`, `role_models_json` to `api_providers`
- Create `provider_models` table
- Migrate existing data (provider_type → protocol, extra_env → env_overrides_json)
### Phase 3: Consumer refactoring
- `claude-client.ts` → use resolver's `toClaudeCodeEnv()`
- `text-generator.ts` → use resolver's `toAiSdkConfig()`
- `route.ts`, `conversation-engine.ts`, `onboarding`, `checkin`, `plan` → use shared resolver
### Phase 4: UI update
- `ProviderManager.tsx` presets → reference catalog
- `ProviderForm.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