feat: 新增模型管理功能(供应商 + 模型 CRUD)

- 新增 providers/models 数据库表、迁移和数据访问层
- 新增 15 个后端 API 路由(供应商/模型 CRUD + 连通性测试)
- 新增 AI 服务层(registry.ts: buildProviderRegistry + testProviderConnection)
- 新增前端模型管理页面(Tabs: 供应商/模型,含表格、表单、工具栏)
- 新增前端 hooks(use-providers, use-models)
- 新增共享类型和 MODEL_CAPABILITIES 常量
- 新增 10 个测试文件(66 个测试用例,4 个因 bun test ESM 兼容问题待修复)
- 更新开发文档(architecture, backend, frontend)
- 附带 apply-review 修复:统一错误响应、提取共享常量、清理重复测试

注意:registry.test.ts 中 4 个测试因 bun test 无法解析
createProviderRegistry ESM 导出而失败,详情见 context.md
This commit is contained in:
2026-05-29 12:40:10 +08:00
parent 2ea4bd4410
commit 933c2133f0
56 changed files with 4706 additions and 9 deletions

View File

@@ -75,6 +75,7 @@
| ------------------- | -------------------------------------------------------------------- |
| `src/server/` | Bun 后端代码,不能 import src/web/HTML import 集成除外 |
| `src/server/db/` | SQLite 数据库模块,包含 schema、connection、migration 和 data access |
| `src/server/ai/` | AI Provider Registry 构建与连接测试 |
| `src/web/` | React 前端,不能 import src/server/ 运行时实现 |
| `src/shared/` | 前后端共享 TypeScript 类型 |
| `scripts/` | 独立运行脚本,可 import 项目源码 |

View File

@@ -18,6 +18,11 @@ src/
load-migrations.ts 从文件系统加载 migration SQL
migrate.ts migration 执行器(备份 + 事务应用)
projects.ts 项目数据访问函数
providers.ts 供应商数据访问函数
models.ts 模型数据访问函数
ai/ AI 服务层
types.ts AI 配置类型定义
registry.ts AI Provider Registry 构建与连接测试
dev.ts 开发模式启动入口
main.ts 生产模式启动入口
server.ts HTTP server 启动工厂Bun.serve routes 声明式路由)
@@ -27,6 +32,8 @@ src/
logger.ts 结构化日志(基于 pino + pino-roll
version.ts 运行时版本号读取
routes/ API 路由处理器
providers/ 供应商 CRUD 路由
models/ 模型 CRUD 路由
shared/
api.ts 前后端共享 TypeScript 类型定义
app.ts 应用全局常量name、title、subtitle、description
@@ -37,6 +44,7 @@ src/
routes.tsx 路由配置
styles.css 全局样式
pages/ 页面组件
models/ 模型管理页面
components/ UI 组件
hooks/ React Hooks
utils/ 前端工具函数
@@ -93,6 +101,7 @@ Request
| `src/server/server.ts` | Bun HTTP server 和 routes 注册 |
| `src/server/routes/` | API handler按端点拆分 |
| `src/server/db/` | SQLite 连接、schema、migration 和 data access |
| `src/server/ai/` | AI Provider Registry 构建与连接测试 |
| `src/server/config/` | 配置解析模块types、variables、schema |
| `src/web/` | React 前端 |
| `src/shared/api.ts` | 前后端共享 API 类型 |

View File

@@ -62,7 +62,36 @@ middleware.ts 提供 API 参数校验函数:
### 数据访问
`src/server/db/projects.ts` 提供项目数据访问函数,输入输出使用 `src/shared/api.ts` 的类型。函数内部使用 Drizzle query builder 包装 `bun:sqlite` Database。
`src/server/db/projects.ts` 提供项目数据访问函数,`src/server/db/providers.ts` 提供供应商数据访问函数,`src/server/db/models.ts` 提供模型数据访问函数。输入输出使用 `src/shared/api.ts` 的类型。函数内部使用 Drizzle query builder 包装 `bun:sqlite` Database。
## AI 服务层
`src/server/ai/` 提供 AI Provider Registry 构建与连接测试能力。
### 类型定义
`src/server/ai/types.ts` 定义 AI 配置类型:
- `AIProviderConfig` — 供应商配置name、type、baseUrl、apiKey
- `AIModelConfig` — 模型配置providerId、modelId、capabilities
- `AIRegistryConfig` — Registry 构建配置providers、models
### Registry 构建
`src/server/ai/registry.ts` 提供:
- `buildProviderRegistry(db)` — 从 DB 查询启用的供应商,构建 Vercel AI SDK Provider Registry
- `testProviderConnection(config)` — 使用 generateText 测试供应商连接
每次 AI 调用时从 DB 查询 providers构建 registry 后通过 `registry.languageModel('providerId:modelId')` 获取模型实例。不使用缓存层。
### 支持的供应商类型
| type | AI SDK factory |
| ------------------- | --------------------------------------------------- |
| `openai` | `createOpenAI({ apiKey, baseURL })` |
| `anthropic` | `createAnthropic({ apiKey, baseURL })` |
| `openai-compatible` | `createOpenAICompatible({ name, apiKey, baseURL })` |
## 类型规范

View File

@@ -122,12 +122,12 @@ token 和 CSS 变量规则:
前端提供两个入口外壳,共享通用 Console Shell 组件:
- **Admin管理台**`src/web/consoles/admin/AdminConsoleLayout.tsx`,菜单配置在 `menu.tsx`,路由 `/``/projects`
- **Admin管理台**`src/web/consoles/admin/AdminConsoleLayout.tsx`,菜单配置在 `menu.tsx`,路由 `/``/projects``/models`
- **Workbench工作台**`src/web/consoles/workbench/WorkbenchProjectGate.tsx``WorkbenchConsoleLayout.tsx`,菜单配置和路由构造在 `routes.ts`,路由 `/workbench/:projectId`
通用 Console Shell`src/web/components/ConsoleShell/ConsoleShell.tsx`)包含 Layout、Header、Sider、Content、主题切换、版本展示和侧边栏折叠状态由 Admin 和 Workbench 复用。Header 显示品牌名、版本号和控制台标题Admin 显示"管理台"Workbench 显示"工作台 · 项目名")。
Sidebar`src/web/components/Sidebar/index.tsx`)是纯展示/导航组件,通过 `menuItems` props 接收菜单配置由调用方决定菜单内容和路径。Admin 传入静态路径 `/``/projects`Workbench 通过 route builder`buildWorkbenchPath`)将相对菜单路径拼成 `/workbench/:projectId` 的子路径。
Sidebar`src/web/components/Sidebar/index.tsx`)是纯展示/导航组件,通过 `menuItems` props 接收菜单配置由调用方决定菜单内容和路径。Admin 传入静态路径 `/``/projects``/models`Workbench 通过 route builder`buildWorkbenchPath`)将相对菜单路径拼成 `/workbench/:projectId` 的子路径。
Workbench 项目上下文通过 `ProjectContext` 提供,在 `WorkbenchProjectGate` 中从 URL path param 读取 `projectId`,通过 `useProject(projectId)` 加载项目,仅 active 项目渲染工作台布局,不存在或 archived 项目显示"项目不存在或不可访问"。