Initial TrueGrowth source import
This commit is contained in:
116
openspec/changes/add-runtime-model-discovery/design.md
Normal file
116
openspec/changes/add-runtime-model-discovery/design.md
Normal file
@@ -0,0 +1,116 @@
|
||||
## Context
|
||||
|
||||
设置页已经保存 `gemini.apiKey` 与 `gemini.baseUrl`,但模型选择器仍然依赖静态模型表。
|
||||
动态发现模型会影响设置页、AI 输入栏、图片生成弹窗、视频生成弹窗等多个入口,因此需要抽成独立的运行时模型发现层,而不是在单个组件内临时请求。
|
||||
|
||||
`/v1/models` 的返回结构在不同兼容平台上通常接近 OpenAI:
|
||||
|
||||
- `data[].id`
|
||||
- `data[].owned_by`
|
||||
- `data[].supported_endpoint_types`(部分平台特有)
|
||||
|
||||
但项目内部展示和筛选依赖 `ModelConfig`:
|
||||
|
||||
- `type`: `image | video | text`
|
||||
- `vendor`: 固定枚举
|
||||
- `label/shortLabel/shortCode/description`
|
||||
|
||||
因此本次设计的关键不只是“拉取模型”,而是“把远端模型转成项目内部可消费的运行时模型配置”。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
- Goals:
|
||||
- 支持通过当前 `Base URL + API Key` 拉取兼容服务的模型列表
|
||||
- 兼容 `https://host` 与 `https://host/v1` 两种 Base URL 输入
|
||||
- 产出图片、视频、文本三类运行时模型列表,供多个模型选择器共用
|
||||
- 基于厂商名称分组展示动态模型
|
||||
- 获取失败时可回退到静态模型列表,不影响现有功能
|
||||
- Non-Goals:
|
||||
- 不替换已有静态模型定义文件中的全部元数据
|
||||
- 不为所有第三方平台实现完全准确的模型类型识别
|
||||
- 不在本次变更中改造价格、额度、健康状态等其它模型元数据来源
|
||||
|
||||
## Decisions
|
||||
|
||||
- Decision: 新增运行时模型发现模块
|
||||
- 提供:
|
||||
- Base URL 归一化
|
||||
- `/v1/models` 请求
|
||||
- 响应解析
|
||||
- 动态 `ModelConfig` 适配
|
||||
- 内存态/持久态缓存
|
||||
- 理由:
|
||||
- 设置页、AI 输入栏和图片/视频弹窗都需要同一份发现结果
|
||||
- 避免每个组件重复实现一套拉取和分类逻辑
|
||||
|
||||
- Decision: 用“显式同步按钮”触发模型发现
|
||||
- 设置页在 `API Key` / `Base URL` 输入区域附近提供“获取模型”或“同步模型”操作
|
||||
- 理由:
|
||||
- 避免用户输入过程中频繁请求
|
||||
- 易于呈现加载态、错误态和刷新结果
|
||||
|
||||
- Decision: 动态模型继续适配为 `ModelConfig`
|
||||
- 对外仍然给 `ModelDropdown` 传 `ModelConfig[]`
|
||||
- 理由:
|
||||
- 最小化对选择器 UI 的侵入
|
||||
- 可复用现有 vendor tabs、搜索、高亮和选择交互
|
||||
|
||||
- Decision: 动态模型分类采用“端点类型优先,模型 ID 关键字兜底”
|
||||
- 预期规则:
|
||||
- 视频:
|
||||
- `supported_endpoint_types` 包含视频异步端点
|
||||
- 或模型 ID 命中 `veo` / `sora` / `kling` / `video` / `seedance` / `t2v` / `i2v`
|
||||
- 图片:
|
||||
- `supported_endpoint_types` 包含 `generate` / `edit` / `banana` 类图片端点
|
||||
- 或模型 ID 命中 `image` / `banana` / `flux` / `mj` / `seedream` / `gpt-image`
|
||||
- 其余默认归为文本
|
||||
- 理由:
|
||||
- live 返回里并没有稳定的 `type` 字段
|
||||
- 仅靠 `owned_by` 不足以判断类型
|
||||
|
||||
- Decision: 厂商分类采用“owned_by 映射优先,模型 ID 关键字回退”
|
||||
- 预期映射:
|
||||
- `openai` -> `GPT`
|
||||
- `vertex-ai` -> `GEMINI` 或 `GOOGLE`,优先根据模型 ID 是否以 `gemini` 开头判断
|
||||
- `volcengine` / `doubao-video` -> `DOUBAO`
|
||||
- `custom` -> 基于模型 ID 关键字映射到 `GEMINI` / `FLUX` / `MIDJOURNEY` / `SORA` / `VEO` / `GPT`
|
||||
- 未命中时新增 `OTHER` 分组或回退为一个现有兜底分组
|
||||
- 理由:
|
||||
- live 数据里的 `owned_by=custom` 占比不低,不能直接作为展示厂商
|
||||
|
||||
- Decision: 动态模型发现失败时回退静态模型表
|
||||
- 获取失败、401、非 JSON、空列表等情况下,不清空现有可选模型
|
||||
- 理由:
|
||||
- 保证已有默认体验不受影响
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- 风险:不同聚合服务返回的 `/v1/models` 结构不完全一致
|
||||
- Mitigation:
|
||||
- 解析时做字段存在性保护
|
||||
- 只依赖 `id`,其余字段尽量可选
|
||||
|
||||
- 风险:模型类型推断不完全准确
|
||||
- Mitigation:
|
||||
- 分类规则集中在单一适配器,便于后续补关键字
|
||||
- 保留手工输入模型 ID 的能力
|
||||
|
||||
- 风险:动态模型缺少静态元数据,影响短标签、默认参数、健康状态
|
||||
- Mitigation:
|
||||
- 未命中静态表时生成保守默认值
|
||||
- 若动态模型 ID 命中已有静态模型,则优先复用静态配置中的 `shortCode`、默认参数和标签
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 新增运行时模型发现与适配模块
|
||||
2. 在设置页引入“同步模型”入口和状态提示
|
||||
3. 将设置页三个模型选择器切到运行时列表优先
|
||||
4. 将 AI 输入栏、图片弹窗、视频弹窗改成读取同一份运行时列表
|
||||
5. 保持默认模型与现有存量设置兼容
|
||||
6. 补最小测试和手工验证
|
||||
|
||||
## Open Questions
|
||||
|
||||
- 是否需要把动态发现结果持久化到 localStorage,以便刷新后保留上次同步结果
|
||||
- 未知厂商是否新增 `OTHER` vendor 枚举,还是暂时回退到 `GOOGLE/GPT` 等已有分组
|
||||
- 文本模型是否需要排除 embedding / rerank 等非聊天模型
|
||||
42
openspec/changes/add-runtime-model-discovery/proposal.md
Normal file
42
openspec/changes/add-runtime-model-discovery/proposal.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Change: 基于 Base URL 和 API Key 动态发现模型列表
|
||||
|
||||
## Why
|
||||
|
||||
当前设置页中的 `API Key` 和 `Base URL` 只负责保存配置,图片、视频、文本模型选择器仍然完全依赖静态常量表。
|
||||
这导致当用户接入一个新的兼容服务商时,无法像 Cherry Studio、Chatbox 等客户端一样直接通过 `/v1/models` 自动发现可用模型,也无法按服务商分类浏览返回的模型。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 为设置页增加“根据当前 Base URL + API Key 获取模型列表”的能力
|
||||
- 新增运行时模型发现与缓存层,统一产出图片、视频、文本三类动态模型列表
|
||||
- 基于 `/v1/models` 返回中的 `id`、`owned_by`、`supported_endpoint_types` 对模型做类型和厂商分类
|
||||
- 让设置页和现有模型选择器优先使用动态模型列表;当发现失败或未配置时回退到静态模型表
|
||||
- 保留现有手输模型 ID 的兼容能力,不阻断自定义模型使用
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs:
|
||||
- `runtime-model-discovery`
|
||||
- Affected code:
|
||||
- `packages/drawnix/src/components/settings-dialog/settings-dialog.tsx`
|
||||
- `packages/drawnix/src/components/ai-input-bar/ModelDropdown.tsx`
|
||||
- `packages/drawnix/src/components/ai-input-bar/AIInputBar.tsx`
|
||||
- `packages/drawnix/src/components/ttd-dialog/ai-image-generation.tsx`
|
||||
- `packages/drawnix/src/components/ttd-dialog/ai-video-generation.tsx`
|
||||
- `packages/drawnix/src/constants/model-config.ts`
|
||||
- `packages/drawnix/src/utils/settings-manager.ts`
|
||||
- `packages/drawnix/src/utils/` 下新增模型发现/归类模块
|
||||
|
||||
## Analysis
|
||||
|
||||
基于 `2026-03-12` 的实测:
|
||||
|
||||
- `https://api.tu-zi.com/v1/models` 在携带有效 Bearer Token 时会返回标准模型列表,结构为 `{"data":[...], "object":"list", "success":true}`
|
||||
- `https://api.tu-zi.com/models` 不返回 JSON,而是返回站点 HTML,因此实现必须显式归一化到 `/v1/models`
|
||||
- 当前设置页默认保存的是 `https://api.tu-zi.com/v1`,但用户需求描述的是“基础 base URL”,因此发现逻辑需要兼容 `https://host` 和 `https://host/v1` 两种输入
|
||||
- 返回字段中没有现成的“模型类型”和“厂商中文名”,需要在前端做一层适配:
|
||||
- 模型类型:由 `supported_endpoint_types`、模型 ID 关键字共同推断
|
||||
- 厂商分类:由 `owned_by` 优先映射,必要时再回退到模型 ID 前缀/关键字映射
|
||||
- 现有 `ModelDropdown` 和 `VendorTabPanel` 强依赖静态 `ModelConfig.vendor` 枚举,因此动态模型不能直接透传接口原始字段,必须先转换成内部 `ModelConfig`
|
||||
|
||||
本次变更默认采用“显式触发同步”而不是“输入时自动请求”的交互,以避免设置弹窗在键入过程中频繁发起网络请求。
|
||||
@@ -0,0 +1,84 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Discover Models From Base URL And API Key
|
||||
|
||||
The system SHALL allow users to fetch a provider's available model list using the currently entered Base URL and API key.
|
||||
|
||||
#### Scenario: Normalize root base URL before discovery
|
||||
- **GIVEN** the user enters a provider root URL such as `https://api.tu-zi.com`
|
||||
- **WHEN** the system performs model discovery
|
||||
- **THEN** the request SHALL be sent to the normalized models endpoint under `/v1/models`
|
||||
|
||||
#### Scenario: Normalize v1 base URL before discovery
|
||||
- **GIVEN** the user enters a Base URL such as `https://api.tu-zi.com/v1`
|
||||
- **WHEN** the system performs model discovery
|
||||
- **THEN** the request SHALL be sent to the models endpoint under the same API namespace
|
||||
|
||||
#### Scenario: Surface discovery failure without breaking existing settings
|
||||
- **GIVEN** the current Base URL or API key cannot fetch a valid model list
|
||||
- **WHEN** the discovery request fails, returns non-JSON, or returns an empty list
|
||||
- **THEN** the user SHALL receive a visible failure message
|
||||
- **AND** the existing static model list fallback SHALL remain available
|
||||
|
||||
### Requirement: Adapt Remote Models To Runtime Model Config
|
||||
|
||||
Remote model list items SHALL be converted into the internal model configuration format used by model selectors.
|
||||
|
||||
#### Scenario: Reuse static metadata for known models
|
||||
- **GIVEN** a discovered model ID matches an existing static model definition
|
||||
- **WHEN** the runtime model config is built
|
||||
- **THEN** the system SHALL reuse the known short code, tags, and default parameters when available
|
||||
|
||||
#### Scenario: Create safe defaults for unknown models
|
||||
- **GIVEN** a discovered model ID does not match any static model definition
|
||||
- **WHEN** the runtime model config is built
|
||||
- **THEN** the system SHALL still expose that model as selectable
|
||||
- **AND** assign safe fallback values for display label, short code, and description
|
||||
|
||||
### Requirement: Classify Discovered Models By Type
|
||||
|
||||
The system SHALL classify discovered models into image, video, or text groups for the corresponding selectors.
|
||||
|
||||
#### Scenario: Classify video models from endpoint hints
|
||||
- **GIVEN** a discovered model exposes video-oriented endpoint types or video-specific model identifiers
|
||||
- **WHEN** the runtime model config is built
|
||||
- **THEN** the model SHALL appear in the video model selector
|
||||
|
||||
#### Scenario: Classify image models from endpoint hints
|
||||
- **GIVEN** a discovered model exposes image-oriented endpoint types or image-specific model identifiers
|
||||
- **WHEN** the runtime model config is built
|
||||
- **THEN** the model SHALL appear in the image model selector
|
||||
|
||||
#### Scenario: Default non-image non-video models to text
|
||||
- **GIVEN** a discovered model does not match image or video classification rules
|
||||
- **WHEN** the runtime model config is built
|
||||
- **THEN** the model SHALL appear in the text model selector
|
||||
|
||||
### Requirement: Group Discovered Models By Provider Vendor
|
||||
|
||||
The system SHALL present discovered models under provider vendor groupings compatible with the existing model dropdown vendor tabs.
|
||||
|
||||
#### Scenario: Use provider ownership as primary vendor hint
|
||||
- **GIVEN** a discovered model includes a recognized `owned_by` value
|
||||
- **WHEN** the runtime model config is built
|
||||
- **THEN** the model SHALL be assigned to the mapped vendor group for dropdown display
|
||||
|
||||
#### Scenario: Fallback to model identifier for custom ownership
|
||||
- **GIVEN** a discovered model uses a generic or custom `owned_by` value
|
||||
- **WHEN** the runtime model config is built
|
||||
- **THEN** the system SHALL infer the vendor from model identifier keywords when possible
|
||||
|
||||
### Requirement: Reuse Runtime Model Lists Across Selectors
|
||||
|
||||
All model selectors that currently depend on static model lists SHALL prefer the discovered runtime model lists when available.
|
||||
|
||||
#### Scenario: Settings dialog uses discovered lists
|
||||
- **GIVEN** model discovery has completed successfully
|
||||
- **WHEN** the user opens the settings dialog
|
||||
- **THEN** the image, video, and text model selectors SHALL use the discovered runtime lists first
|
||||
|
||||
#### Scenario: Generation entry points use discovered lists
|
||||
- **GIVEN** model discovery has completed successfully
|
||||
- **WHEN** the user opens the AI input bar or generation dialogs
|
||||
- **THEN** those selectors SHALL use the same discovered runtime lists
|
||||
- **AND** continue to work with saved model IDs from settings
|
||||
29
openspec/changes/add-runtime-model-discovery/tasks.md
Normal file
29
openspec/changes/add-runtime-model-discovery/tasks.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Tasks: 动态模型发现与分类
|
||||
|
||||
## 1. 发现链路
|
||||
|
||||
- [ ] 1.1 新增 Base URL 归一化逻辑,兼容 `https://host` 与 `https://host/v1`
|
||||
- [ ] 1.2 新增 `/v1/models` 请求封装,支持 Bearer Token、错误解析和非 JSON 保护
|
||||
- [ ] 1.3 为模型发现结果增加内存态和持久态缓存
|
||||
|
||||
## 2. 模型适配
|
||||
|
||||
- [ ] 2.1 将远端模型列表适配为项目内部 `ModelConfig[]`
|
||||
- [ ] 2.2 基于 `owned_by`、`supported_endpoint_types` 和模型 ID 完成厂商分类
|
||||
- [ ] 2.3 基于端点类型和模型 ID 完成图片/视频/文本分类
|
||||
- [ ] 2.4 对已知静态模型复用现有 `shortCode`、默认参数和标签
|
||||
- [ ] 2.5 为未知模型生成保守默认配置,保持可搜索、可选择、可保存
|
||||
|
||||
## 3. UI 接入
|
||||
|
||||
- [ ] 3.1 在设置页增加“同步模型”操作和加载/成功/失败提示
|
||||
- [ ] 3.2 设置页的图片、视频、文本模型选择器优先使用动态模型列表
|
||||
- [ ] 3.3 AI 输入栏、图片生成弹窗、视频生成弹窗复用同一份动态模型列表
|
||||
- [ ] 3.4 获取失败或无结果时回退到静态模型列表,不阻断当前使用
|
||||
|
||||
## 4. 验证
|
||||
|
||||
- [ ] 4.1 使用 `https://api.tu-zi.com` 的 live `/v1/models` 返回验证模型发现与分类结果
|
||||
- [ ] 4.2 验证动态发现后可正确保存并重新读取三个模型设置
|
||||
- [ ] 4.3 验证未知模型仍可手动输入并保存
|
||||
- [ ] 4.4 补充最小测试或手工验证记录
|
||||
Reference in New Issue
Block a user