Skip to content

Commit 3702aa2

Browse files
committed
spec
1 parent 12bc377 commit 3702aa2

22 files changed

Lines changed: 1267 additions & 254 deletions

README.md

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Electron 桌面应用,用于集中管理 LLM 供应商与模型配置:支持
44

55
## 主要功能
66

7-
- 多供应商、多模型管理:新增、编辑、删除、复制、折叠/展开、拖拽排序
7+
- 多供应商、多模型管理:新增、编辑、删除、折叠/展开、拖拽排序;列表内可复制 API Key
88
- 模型测试:单模型测试与批量「测试选中模型」
99
- 模型参数:支持记录与探测 Context Window、Max Tokens 等(见 `ModelParams`
1010
- 从远端拉取模型列表(按供应商配置请求,结果在弹窗中展示与选用)
@@ -29,13 +29,9 @@ Electron 桌面应用,用于集中管理 LLM 供应商与模型配置:支持
2929
5. 备份或迁移配置:使用 **导出 JSON** / **导入 JSON**
3030
6. 列表较长时可用 **折叠全部** / **展开全部**;用 **全选** 快速选中全部模型。
3131

32-
## JSON 导入冲突处理
32+
## JSON 导入
3333

34-
当当前已有配置且导入文件也包含配置时,应用会提示:
35-
36-
- **合并导入**:按 `provider.id` 合并;同一 Provider 内按 `model.id` 合并(同 ID 以导入内容为准)
37-
- **覆盖导入**:用导入文件替换当前全部配置
38-
- **取消**:不执行本次导入
34+
导入 JSON 会解析文件(支持顶层数组或带 `providers` 字段的对象),经标准化后**替换**当前全部配置并保存。详细约定见 [specs/06-json-config-import-export.md](specs/06-json-config-import-export.md)。若后续产品增加「合并导入」等交互,以实现与文档更新为准。
3935

4036
## 支持导出的应用 / 形式
4137

@@ -59,14 +55,16 @@ Electron 桌面应用,用于集中管理 LLM 供应商与模型配置:支持
5955

6056
## 本地开发
6157

58+
> 约束:本仓库以 `specs/` 作为**产品行为的唯一真源(source of truth)**。任何功能、交互、导出格式、边界条件的变更,必须同步更新 Specs;否则视为变更未完成。
59+
6260
### 技术栈
6361

6462
- **运行时:** Electron(主进程 + 预加载脚本)
6563
- **构建:** [electron-vite](https://electron-vite.org/),输出至 `dist/`
6664
- **界面:** React 19、TypeScript、Tailwind CSS
6765
- **组件:** Radix UI 对话框 / 气泡 / 提示等,配合 `class-variance-authority``tailwind-merge`
6866
- **交互:** `@dnd-kit` 实现供应商与模型的拖拽排序
69-
- **主进程能力:** 通过 IPC 读写配置、HTTP 探测、打开外链、在终端执行命令、在浏览器中执行脚本等(通道定义见 `src/shared/ipc.ts`
67+
- **主进程能力:** 提供本地持久化、网络请求、打开外链、终端执行、浏览器脚本执行等桌面能力(具体行为以 `specs` 为准
7068

7169
### 前置要求
7270

@@ -79,24 +77,47 @@ Electron 桌面应用,用于集中管理 LLM 供应商与模型配置:支持
7977
npm install
8078
```
8179

82-
### 启动
80+
### 开发模式(推荐,热重载)
8381

8482
```bash
85-
npm start
83+
npm run dev
8684
```
8785

88-
(预览构建产物,开发前需先 `npm run build`
86+
### 启动(预览构建产物)
8987

90-
### 开发模式(热重载)
88+
当你希望用“构建后的产物”验证打包前行为时:
9189

9290
```bash
93-
npm run dev
91+
npm run build
92+
npm start
93+
```
94+
95+
### 构建与打包(本地)
96+
97+
```bash
98+
npm run build
99+
npm run dist
94100
```
95101

96102
### 文档
97103

104+
- 产品行为说明(Specs 索引):[specs/README.md](specs/README.md)
98105
- Harness 自动化测试:[docs/HARNESS.md](docs/HARNESS.md)
99106

107+
### 变更规范(必须遵守)
108+
109+
当你修改任何产品行为(包括但不限于:表单自动填充、导入/导出规则、测试判定、远端模型列表映射、外部动作确认策略、UI 禁用态/文案/状态机),必须同时完成以下事项:
110+
111+
- **更新 Specs**:修改或新增对应的 `specs/*.md`,确保规则、触发点、边界条件与验收口径同步。
112+
- **更新索引与交叉引用**:若新增/拆分文档,更新 `specs/README.md` 的文档地图与引用。
113+
- **对齐对外文档**:若用户可见流程变化,更新本 `README.md` 的“使用流程 / JSON 导入 / 支持导出应用”等章节。
114+
115+
推荐在提交前自检:
116+
117+
- 变更涉及 Provider/Model/Preset/Selection/Export 语义时,Specs 是否能让新同事“只看文档就实现同等行为”?
118+
- 是否新增了用户可见的边界条件或风险(例如外部执行)但未写入 Specs?
119+
- 是否出现“实现已变但 Specs 仍描述旧行为”的不一致?
120+
100121
### 发布桌面安装包(GitHub Release)
101122

102123
已配置 `electron-vite` + `electron-builder` + GitHub Actions:

specs/00-overview.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# LLM 模型 API 管理器:产品总览(Overview)
2+
3+
**文档性质**:面向产品、设计与沟通的**行为与范围**说明;不替代交互稿。
4+
**完整索引**[README](README.md)
5+
6+
**专项索引**[主列表与选择](01-provider-model-list.md) · [供应商与模型表单](02-provider-model-dialogs.md) · [连通性测试](03-model-connectivity-test.md) · [远端模型列表](04-remote-model-list.md) · [导出与外部动作](05-export-and-external-actions.md) · [JSON 备份与导入](06-json-config-import-export.md) · [内置预设](07-builtin-presets.md)
7+
8+
**实现相关补充**[数据与持久化](08-data-model-and-persistence.md) · [运行环境能力边界](09-electron-shell-and-ipc.md) · [Preset 归并说明](10-preset-and-form-algorithms.md) · [网络交互语义](11-http-check-and-remote-model-list.md) · [导出内容契约](12-export-system.md) · [状态与工作流](13-application-state-and-workflows.md) · [界面清单](14-ui-specification.md)
9+
10+
---
11+
12+
## 1. 产品目标与定位
13+
14+
帮助用户在**本地**集中管理多家 **Provider(供应商)** 及其 **Model(模型)**,完成一条清晰闭环:
15+
16+
1. 维护连接信息与模型清单
17+
2. 验证模型在当前 Endpoint 上是否可用
18+
3. 将选中模型**导出**到常用 AI 工具(环境变量、命令行、**Deep Link**、说明文档等)
19+
4.**JSON** 做备份与迁移
20+
21+
定位是**本地配置中控台**:低门槛、可迁移、可导出;****提供云端托管、账号体系或多端实时同步。
22+
23+
---
24+
25+
## 2. 目标用户与典型场景
26+
27+
- **谁会用**:多客户端/多工具的开发者、需要在机器间或同事间传递「可复现配置」的人。
28+
- **典型用法**:为不同供应商配置 **Base URL****Endpoint****API Key**;勾选模型做批量测试或导出;换机时备份/恢复 JSON;从供应商侧枚举模型后挑选加入本地列表。
29+
30+
---
31+
32+
## 3. 核心概念(产品语言)
33+
34+
| 概念(英文优先) | 含义 |
35+
|------------------|------|
36+
| **Provider** | 一家 API 服务入口:接口族(OpenAI-compatible / Anthropic-compatible)、**Base URL****Endpoint**、可选官网与密钥、以及下属 **Model** 列表。 |
37+
| **Model** | 隶属于某一 Provider:模型标识、展示名、可选能力参数(如上下文长度、输出上限、推理/多模态等),以及最近一次**测试结果**(成功/失败、时间、可读错误摘要)。 |
38+
| **Preset** | 应用内置或随版本提供的建议项,用于减少手填(供应商档、模型档、常见 URL 片段等)。 |
39+
| **Selection** | 用户在主列表中勾选的一组 **Model**,用于批量测试与导出。 |
40+
| **Export** | 将当前 **Selection** 转为某一目标工具所需的文本或可执行说明;可能包含多条内容块,供复制或触发系统能力(打开链接、终端执行等)。 |
41+
42+
数据语义与持久化策略见 [08-data-model-and-persistence.md](08-data-model-and-persistence.md)
43+
44+
---
45+
46+
## 4. 能力地图(What we ship)
47+
48+
- **配置与列表**:多 Provider、多 Model;编辑、删除;列表内排序与折叠;与表单中的 **Preset** 协同降低录入成本(详见 [01](01-provider-model-list.md)[02](02-provider-model-dialogs.md)[14](14-ui-specification.md))。
49+
- **连通性测试**:按供应商连接信息发起探测,结果回写到模型行(详见 [03](03-model-connectivity-test.md)[11](11-http-check-and-remote-model-list.md))。
50+
- **远端模型列表**:拉取候选并在弹窗中筛选、勾选后加入本地(详见 [04](04-remote-model-list.md))。
51+
- **导出**:多种目标形态,支持预览与复制;部分形态调起系统能力(详见 [05](05-export-and-external-actions.md)[12](12-export-system.md))。
52+
- **JSON**:整库导出为带版本与时间戳的备份文件;导入替换工作集(详见 [06](06-json-config-import-export.md)[08](08-data-model-and-persistence.md))。
53+
54+
---
55+
56+
## 5. 数据与安全边界(产品承诺)
57+
58+
- 配置保存在**本机**;应用使用用户填写的密钥仅用于本地发起的检测与生成导出内容,****向业务方云端上传用户配置。
59+
- 终端执行、Deep Link、浏览器脚本等风险见 [05](05-export-and-external-actions.md)[09](09-electron-shell-and-ipc.md)
60+
61+
---
62+
63+
## 6. 体验与错误处理原则
64+
65+
网络失败、格式错误、外部调起失败等,应通过明确提示或可读的模型行状态呈现;**导入 JSON** 的健壮性要求见 [06](06-json-config-import-export.md)。具体文案与控件形态由交互稿与实现迭代。

specs/01-provider-model-list.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# 主列表:Selection、折叠与排序
2+
3+
**文档性质**:描述主界面 **Provider** 卡片与 **Model** 行的**用户可感知行为**;表单与 Preset 逻辑见 [02](02-provider-model-dialogs.md)**控件级清单**[14-ui-specification.md](14-ui-specification.md)
4+
5+
---
6+
7+
## 1. Selection(选中范围)
8+
9+
- **粒度**:以单条 **Model** 为选中单位;同一 Provider 下可多选。
10+
- ****:由 “Provider ID + Model ID” 组合而成(见 [08](08-data-model-and-persistence.md))。
11+
- **全选 / 清空**:工具栏 checkbox;展示 **indeterminate** 当 0<N<总数。
12+
- **按 Provider 批量选**:行头复选框选中或取消该 Provider 下全部 **Model**;支持 **indeterminate**
13+
- **删除 Provider 或 Model 后****清空当前 Selection**(避免索引错位)。
14+
- **工具栏****测试选中模型****导出选中模型****无选中项时 disabled**;展示「已选 N 项」。
15+
16+
---
17+
18+
## 2. 折叠与展开
19+
20+
- 每个 **Provider** 可独立折叠/展开其 **Model** 列表。
21+
- **稳定键**:优先使用 Provider ID;若 Provider ID 为空,则回退为当前列表位置键。
22+
- 支持 **折叠全部 / 展开全部**
23+
- **批量测试**:开始前自动**展开**所有「含有选中 Model」的 Provider 卡片,便于看结果。
24+
25+
---
26+
27+
## 3. 排序
28+
29+
- **Provider****Model**(各 Provider 内)均支持 **拖拽**;顺序持久化。
30+
- 排序不改变 **Model ID** 语义;若导出顺序与列表遍历顺序一致,则以列表顺序为准。
31+
32+
---
33+
34+
## 4. 列表展示与操作
35+
36+
- **Base URL / Endpoint**:只读展示,文本可选中复制。
37+
- **API Key****脱敏**展示 + **复制完整密钥** 按钮(无密钥时禁用)。
38+
- **官网**:若填写,标题可点击跳转;用户输入未带协议时按常见网址方式补全(见 [13](13-application-state-and-workflows.md))。
39+
- **操作**:加载远端模型列表、添加模型、编辑供应商、删除供应商、单模型测试、编辑/删除模型、拖拽排序。
40+
- **复制**:列表区无「复制整条 Provider」;**复制 API Key** 见上。
41+
42+
---
43+
44+
## 5. 与配置持久化的关系
45+
46+
列表即当前工作集视图;结构性变更后需立即保存(见 [08](08-data-model-and-persistence.md)[13](13-application-state-and-workflows.md))。

specs/02-provider-model-dialogs.md

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# 供应商与模型表单:Preset 与自动填充
2+
3+
**文档性质**:描述「添加/编辑 **Provider**」与「添加/编辑 **Model**」时,**什么会被自动带出****什么必须尊重用户已填内容**;供产品验收与需求变更对照。
4+
5+
---
6+
7+
## 1. 术语(概念英文名优先)
8+
9+
| 用户可见说法 | 概念(英文) | 说明 |
10+
|--------------|--------------|------|
11+
| 供应商标识 | **Provider ID** | 唯一标识一条 Provider。 |
12+
| 供应商展示名 | **Display name** | 仅展示。 |
13+
| 接口类型 | **API type** | OpenAI-compatible 与 Anthropic-compatible 二选一。 |
14+
| 服务根地址 / 路径 | **Base URL** / **Endpoint** | 共同决定实际请求落点;二者组合为完整 **Service URL**(产品表述可用「完整 URL」)。 |
15+
| 官网 | **Website** | 可选。 |
16+
| 密钥 | **API Key** | 可选;用于检测与部分请求。 |
17+
| 模型标识 / 展示名 | **Model ID** / **Model display name** | 模型在列表与导出中的主键与展示。 |
18+
| 能力与参数 | **Model params**(如上下文长度、输出上限、推理、输入类型等) | 可选扩展信息。 |
19+
20+
---
21+
22+
## 2. Preset 从哪来、起什么作用
23+
24+
- **Provider preset**:按供应商给出的默认展示名,以及**按 API type 分组的**默认 **Base URL / Endpoint**
25+
- **Model preset**:按模型给出的建议展示名与常见能力字段。
26+
- **历史复用**:用户曾在本地保存过的 **Model ID** 也可进入候选,便于跨项目复用标识。
27+
- **URL 片段建议**:常见 **Base URL****Endpoint** 片段来自内置汇总与 Preset 去重合并,供下拉快速选择。
28+
29+
以上均服务于**降低首次配置成本**;不替代用户对真实服务端点的确认责任。
30+
31+
---
32+
33+
## 3. Provider 表单行为
34+
35+
### 3.1 打开时
36+
37+
- **新建**:空表或默认值;****在标识为空时「猜一整张供应商」。
38+
- **编辑**:与已保存记录一致。
39+
40+
### 3.2 自动填充的匹配键(核心规则)
41+
42+
**Provider** 一侧,凡是根据 **Provider preset** 写入 **Base URL / Endpoint**(以及必要时 **API type**)时,逻辑都建立在两个键上:
43+
44+
1. **Provider ID**:在预设目录中命中哪一条供应商(或判定无命中)。
45+
2. **API type**:在已命中的那条预设里,选用**哪一组**默认连接信息——**必须优先对应当前界面上已选择的 API type**
46+
47+
直观表述:**同一 Provider ID 下,OpenAI-compatible 与 Anthropic-compatible 可以对应不同的 Base URL / Endpoint**;自动填充时不是只「认供应商名」,而是 **Provider ID + API type** 一起决定填哪一组 **Base URL / Endpoint**。若预设里只为某一种 API type 配了连接信息,则只在用户当前选中该 type(或回落到预设中的第一组可用连接)时写入,避免把另一类型的地址套到当前类型上。
48+
49+
**Website****API Key** 不因上述自动填充被覆盖,除非用户自行编辑。
50+
51+
---
52+
53+
### 3.3 Provider ID 输入框失焦(且标识非空)
54+
55+
- **无匹配 Preset**:只补**展示名**(由标识格式推导可读名称),****自动写入 **Base URL / Endpoint****API type**
56+
- **有匹配 Preset**
57+
- 写入 Preset 中的**展示名**
58+
- **Base URL / Endpoint**(及必要时 **API type**):在预设里查找与**失焦瞬间界面上已选择的 API type** 一致的那一组默认连接;若该 type 在预设中有独立配置,则使用这一组;若预设未按 type 拆分、或该 type 没有单独一组,则使用预设中的**第一组**默认连接(前提是该组为「有效连接」,见第 6 节)。
59+
- 若预设中**没有任何一组有效连接**(见第 6 节):****补展示名,**不得****Base URL / Endpoint** 写成空串去覆盖用户已填内容,也**不得**在无有效依据时乱改 **API type**
60+
61+
---
62+
63+
### 3.4 从下拉列表点选某条预设供应商
64+
65+
**3.3 失焦** 规则一致:以**点选瞬间界面上已选择的 API type** 为准,去命中 **Provider ID** 对应预设里「该 API type 下的一组 **Base URL / Endpoint**」;若无该 type 的独立配置,则按预设内约定回落到第一组有效连接。
66+
**Website** / **API Key** 仍不因点选而被动覆盖。
67+
68+
---
69+
70+
### 3.5 用户切换 API type(两种接口互切)
71+
72+
- 界面上的 **API type** 立即变为用户新选的一种。
73+
- **仅当**当前 **Provider ID** 在预设中存在,且预设里**存在与新选 API type 对应的一组「有效」默认连接**时,才用这一组去更新 **Base URL / Endpoint**
74+
- 若预设**没有**为新选的 API type 配置连接,或该组为无效空连接:则**只更新 API type**,用户已填的 **Base URL / Endpoint 保持不变**(不得用空预设行覆盖)。
75+
76+
---
77+
78+
### 3.6 Base URL / Endpoint 的其它来源
79+
80+
这两项没有独立于上述规则的「再算一遍」逻辑;其余来源仅为:**用户手输**、或 **URL 片段建议**下拉(由内置汇总与 Preset 合并而来)。二者拼成完整 **Service URL**
81+
82+
---
83+
84+
## 4. Model 表单行为
85+
86+
### 4.1 打开时
87+
88+
- **新建**:不预填模型标识与参数。
89+
- **编辑**:与已保存一致。
90+
91+
### 4.2 模型 ID 候选如何排序
92+
93+
- 若能将当前 Provider 与某条 **Provider preset** 对上号:优先展示**同一供应商生态**下的 **Model preset**,其余排在后面。
94+
- 对不上:按内置顺序展示全部 **Model preset**
95+
- 候选中同时包含:**排序后的 Preset 模型 ID****本地已出现过的、未被子列表覆盖的**历史 **Model ID**
96+
97+
### 4.3 何时触发自动填充
98+
99+
- **失焦**:在「当前排序下的 Preset 列表」中匹配第一个与输入一致的模型,用于补全。
100+
- **从下拉点选一项**:仅对该项做匹配;若无对应 Preset,只更新 **Model ID** 本身。
101+
102+
### 4.4 自动填充的尊重原则
103+
104+
- **展示名**:仅在用户未填写时,用 Preset 补全;已填写则不覆盖。
105+
- **能力参数**:在保留用户已填项的前提下,用 Preset 中有值的项**补空或补强**;Preset 无值的项不强行覆盖。
106+
- **无数**:不改动其它字段。
107+
108+
---
109+
110+
## 5. 保存时
111+
112+
保存只做必填校验与写入当前表单;**不会**在保存瞬间再次合并 Preset。自动填充只发生在编辑过程中的输入、选择与切换。
113+
114+
**保存 Model 时**:新建或编辑保存后,该条模型的**连通性测试状态会重置为待测**`pending`),并**清空**上次测试时间与信息(见 [08-data-model-and-persistence.md](08-data-model-and-persistence.md) §10)。
115+
116+
---
117+
118+
## 6. 产品规则:有效连接与防误伤(与第 3 节配套)
119+
120+
第 3.3–3.5 中凡提到「有效连接」「不得用空串覆盖」处,均以下列定义为准;验收时应与第 3 节一起覆盖。
121+
122+
下列规则用于避免「清空用户已填」或「API type 与连接信息不一致」的体验问题。
123+
124+
**何谓「一组有效的连接默认值」**
125+
Preset 里某一 API type 对应的一行:在去掉首尾空白后,**Base URL 与 Endpoint 至少一端非空**,才视为有效;全空白不算有效。
126+
127+
**当 Preset 没有任何有效连接默认值时**
128+
只能补展示名(或无 Preset 时的标识推导名),**不得**写入或清空 **API type / Base URL / Endpoint** 中的任一项为「空串占位」。
129+
130+
**当用户选的 API type 在 Preset 里对应行无效,但其它类型有有效行时**
131+
**不得**自动改用其它类型的连接信息来「凑数」,否则会造成 **API type** 与用户意图不一致;此时应退化为**只保证展示名类字段**
132+
133+
**切换 API type 时**
134+
仅当新类型在 Preset 中存在**有效**默认连接时,才覆盖 **Base URL / Endpoint**;否则保留用户当前填写。
135+
136+
---
137+
138+
## 7. 文档维护
139+
140+
若线上行为与本文冲突,应以**已发布产品行为**为准,并回写本文与相关需求说明。

0 commit comments

Comments
 (0)