release: bump version to 0.62.0
Some checks failed
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / delivery (push) Has been cancelled
release / images (push) Has been cancelled

This commit is contained in:
linkong
2026-05-21 01:37:32 +08:00
parent 5c65ee24d6
commit fbca381512
138 changed files with 21303 additions and 5721 deletions

View File

@@ -0,0 +1,182 @@
# AI Provider OpenClaw-Style Routing Plan
Last updated: 2026-05-20
## Summary
Planet 的 AI Provider 路由要从“运行时识别特殊 provider / 特殊模型”收敛到 OpenClaw 风格的配置驱动模型:模型引用、协议、鉴权、轻量探测、真实调用和模型级例外都由 provider catalog / preset / runtime metadata 描述,运行时只解释这些元数据,不再散落 `if provider == ... and model == ...` 这类硬编码。
这份计划覆盖 Admin Next 的 Provider 配置体验、backend settings API、`aiprovider` 适配服务和未来模型目录同步方式。目标是让 OpenCode Go、MiniMax、DeepSeek、OpenAI-compatible、Anthropic-compatible、Ollama、OpenRouter / One API 类代理都能用同一套规则扩展。
## Background
当前实现已经完成了两步临时修正:
- OpenCode Go 模型目录不再使用普通 Zen free 列表,而是使用 `https://opencode.ai/zen/go/v1/models`
- `minimax-m2.7` / `minimax-m2.5` 的协议例外已从 `aiprovider` 运行逻辑移到 `model_provider_apis` 元数据中。
但整体还没有完全达到 OpenClaw 式结构。OpenClaw 的关键思想是:
- 模型引用使用 `provider/model`,由 provider 前缀确定 runtime provider。
- provider 插件或 catalog 拥有 `normalizeModelId``normalizeTransport``normalizeConfig``prepareRuntimeAuth``createStreamFn` 等 provider 行为。
- 主推理循环不认识具体模型名,只使用解析后的 provider config、transport 和 request adapter。
- 上游网关能自己路由时,尽量透传 provider routing metadata不在本地复制上游逻辑。
Planet 不需要完整复制 OpenClaw 插件系统,但需要学习它的边界划分。
## Design Principles
- Provider catalog 是路由事实来源runtime 不是。
- 模型级协议例外必须是 metadata例如 `model_provider_apis`,不能是 Python set / if 分支。
- 轻量连通性测试只验证网络、鉴权和模型目录,不发真实 prompt。
- 真实模型调用只发生在 Playground、AI brief、分析任务等明确需要生成的路径。
- 保存配置不自动设为默认,不自动触发连接测试;保存、设默认、测试三种按钮职责分离。
- 目录刷新使用增量合并语义:发现新模型,标记旧模型 stale不直接删除用户选择或自定义模型。
- 如果 provider 不提供可靠 `/models`,可以用内置 preset 确认已知模型,但 UI 必须说清楚这是 preset confirmation不是假装 provider 返回了目录。
## Target Data Model
Provider preset / runtime config 应逐步收敛为类似结构:
```json
{
"provider": "opencode-go",
"label": "OpenCode Go",
"default_transport": "openai-completions",
"base_url": "https://opencode.ai/zen/go/v1",
"auth": {
"type": "bearer",
"api_key_env": "OPENCODE_GO_API_KEY"
},
"models": [
{
"id": "glm-5.1",
"label": "GLM 5.1",
"transport": "openai-completions",
"context_window": null,
"capabilities": ["text"]
},
{
"id": "minimax-m2.7",
"label": "MiniMax M2.7",
"transport": "anthropic-messages",
"capabilities": ["text", "reasoning"]
}
],
"discovery": {
"type": "openai-models",
"url": "https://opencode.ai/zen/go/v1/models",
"auth": "provider-api-key"
}
}
```
Runtime 选择规则:
1. 解析 provider。
2. 解析 model。
3.`models[].transport` 找模型级 transport。
4. 若没有模型级 transport使用 provider `default_transport`
5. 将解析结果传给 `aiprovider`
6. `aiprovider` 只按 `transport` 组装请求,不认识 provider 专属模型名。
## Implementation Plan
### Phase 1: Stabilize Current Metadata Path
- Keep `model_provider_apis` as the immediate compatibility bridge.
- Ensure `_provider_defaults()` includes provider metadata such as `model_provider_apis`.
- Ensure `_runtime_config_from_ai_payload()` sends the resolved metadata through `AIProviderClient`.
- Ensure `AIProviderClient` forwards metadata to `aiprovider` with a structured header.
- Ensure `aiprovider.ProviderService` reads model metadata and resolves `provider_api = model_provider_apis[model] ?? provider_api`.
- Add tests proving `aiprovider` does not contain provider/model-specific literals for routing decisions.
### Phase 2: Replace `model_provider_apis` With Structured Model Catalog
- Extend `backend/app/services/llm_provider_catalog.py` preset shape with `models_metadata`.
- Preserve old `models` as a compatibility list for the UI.
- Add helpers:
- `get_provider_model_metadata(provider, model)`
- `resolve_provider_transport(provider_config, model)`
- `merge_discovered_models(existing, discovered)`
- Return both `models` and `models_metadata` from refresh endpoints.
- Admin Next should render model labels, capabilities and transport hints from metadata.
### Phase 3: Provider Discovery And Incremental Sync
- Add provider discovery descriptors:
- OpenAI-compatible `/models`
- Anthropic-compatible no-models / preset-confirmed path
- Ollama `/api/tags`
- OpenCode Go `/zen/go/v1/models`
- OpenRouter / One API passthrough model discovery
- Add incremental merge behavior:
- New discovered model: add.
- Existing discovered model: update `last_seen_at`, metadata.
- Missing discovered model: mark `stale`, do not delete.
- User custom model: keep unless explicitly removed.
- Surface discovery source in Admin Next: `实时发现 / 内置预设 / 用户自定义 / 已过期`.
### Phase 4: Transport Adapters
- Replace provider-specific request decisions with adapter descriptors:
- `openai-completions`
- `anthropic-messages`
- `ollama-generate`
- future `openai-responses`
- future `gemini-generate-content`
- Each adapter owns:
- path
- auth header format
- request body transform
- response text extraction
- reasoning/thinking block extraction
- models endpoint strategy
- `ProviderService.analyze()` should select adapter by resolved transport and call the adapter.
### Phase 5: Admin Next UX
- Model provider page should show:
- provider status tag
- default model tag
- source tag: env / runtime / preset / discovered
- model list with transport/capability hint
- separate buttons for save, set default, refresh model catalog, lightweight test
- The connect plug button remains lightweight.
- Full generation test lives only in Playground or a clearly named “试运行” action.
- If lightweight test falls back to preset confirmation, toast must say so explicitly.
## TODO
- [ ] Add `models_metadata` to provider presets and refresh responses.
- [ ] Add runtime resolver helper for provider/model transport selection.
- [ ] Remove any remaining provider/model-specific literals from `aiprovider` runtime routing.
- [ ] Add tests that `opencode-go/minimax-m2.7` resolves through metadata, not through runtime hardcode.
- [ ] Add tests for lightweight connectivity:
- [ ] 401 / 403 fail as auth error.
- [ ] 404 with known preset model passes as preset-confirmed.
- [ ] `/models` missing alias passes only when preset contains the alias.
- [ ] unknown model fails.
- [ ] Add discovery descriptors for OpenCode Go, OpenAI-compatible, Anthropic-compatible, Ollama, OpenRouter / One API.
- [ ] Add incremental model catalog merge semantics with stale marking.
- [ ] Update Admin Next model list to show model source, transport and capability.
- [ ] Keep save / set default / lightweight test / full test as separate actions.
- [ ] Document the final provider catalog schema in technical docs after implementation.
## Current Acceptance Criteria
- No runtime routing branch may depend on concrete model names like `minimax-m2.7`.
- OpenCode Go model refresh must not use the ordinary Zen free-model endpoint.
- Lightweight connect must not call `analyze()` or consume generation quota.
- Saving a provider must not automatically set it as default.
- Provider UI must distinguish configured key, fallback key, preset model and live-discovered model.
## Related Files
- `backend/app/services/llm_provider_catalog.py`
- `backend/app/api/v1/settings.py`
- `backend/app/services/ai_client.py`
- `aiprovider/main.py`
- `aiprovider/provider_service.py`
- `frontend/src/admin-next/pages/PlainResourcePages.tsx`
- `docs/plans/admin-next-parity-audit-closeout-plan.md`