dsh-connect-agnes-token-plan 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +386 -0
- package/LICENSE +21 -0
- package/README.md +110 -0
- package/THIRD_PARTY_NOTICES.md +23 -0
- package/client.js +3921 -0
- package/cordis.patch.yml +147 -0
- package/lib/agnescode-llm-adapter-DDvQ-xvK.js +135 -0
- package/lib/agnescode-models-CUcL9UwK.js +713 -0
- package/lib/host-config-BNGgm_j7.js +456 -0
- package/lib/index.js +7648 -0
- package/lib/llm-adapter-qvvVg7Gb.js +168 -0
- package/lib/llm-error-fix-DQUng8AL.js +247 -0
- package/lib/llm-models-CRYZmwHg.js +1070 -0
- package/lib/raccoon-llm-adapter-n6ZdIdvk.js +143 -0
- package/lib/raccoon-models-DV1sQN4n.js +491 -0
- package/package.json +90 -0
- package/screenshots.json +4 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
# 更新日志(Changelog)
|
|
2
|
+
|
|
3
|
+
本文件只记**公开行为变化**(新增能力、破坏性改动、重要修复)。实现细节、重构与测试加固请直接看 `git log`。
|
|
4
|
+
|
|
5
|
+
## [0.5.0] — 2026-10-01
|
|
6
|
+
|
|
7
|
+
**独立仓库首次发布**:新包名 `dsh-connect-agnes-token-plan` 首次上 npm。全面更名并切换登录线(Agnes 一跳登录),额度模型改为账号级四窗口,新增视频生成 agent 工具与第三上游 AgnesCode。
|
|
8
|
+
|
|
9
|
+
> **版本号说明**:0.4.4 从未发布到 npm(原 0.4.4 章节内容并入本节);旧包名 `dsh-connect-sensenova-token-plan` 由兄弟插件独立维护,已发至 0.4.5。
|
|
10
|
+
|
|
11
|
+
### 全面更名 + 登录线切换(迁移主线)
|
|
12
|
+
|
|
13
|
+
- **包名 / provider / 工具 / Key 引用全切 Agnes**:`dsh-connect-agnes-token-plan`、provider `agnes-token-plan`、agent 工具 `agnes_draw_image`、Key 引用 `AGNES_TOKEN_PLAN_API_KEY`、控制台 `platform-backend.agnes-ai.cn` / 推理 `api.agnes-ai.cn`。
|
|
14
|
+
- **登录改为一跳邮箱+密码**:`POST {consoleBase}/api/user/login`——Agnes 无 OIDC / 无 refresh token,令牌失效即**重登一次**(重登是唯一的续期路径);密码明文 JSON 仅走 TLS、不落盘,`AGNES_PASSWORD` 是唯一持久来源。
|
|
15
|
+
- **登录节流按平台声明窗口照单全收**:`Retry-After` 头与消息里的时间文案(中英文)都解析为等待窗口,绝不自行截短;平台未声明才回退本地指数退避。
|
|
16
|
+
- 随迁移退役的 OIDC 模块与测试已删除(`sensenova-auth.ts` / `sensenova-crypto.ts` / `test/auth.test.mjs`)。
|
|
17
|
+
|
|
18
|
+
### 额度模型:账号级四窗口(不再计算「剩余」)
|
|
19
|
+
|
|
20
|
+
- Agnes 不发布 per-pool 余额,只在滑动窗口上封顶四个维度(5h 请求 / 周请求 / 日图 / 日视频),控制台只给上限与**累计**用量——`limit − total` 无人能负责,所以面板头条从「剩余」换成「限额」,累计用量单独一行(宁少一个数,也不发明一个)。
|
|
21
|
+
- 控制台未连接时不再整页只剩登录表单;额度正常显示时不再误挂「需要重新登录」。
|
|
22
|
+
|
|
23
|
+
### 视频生成 agent 工具(可选,默认关)
|
|
24
|
+
|
|
25
|
+
与出图对称新增 `agnes_video_generate`:面板开关 + 「建任务→轮询→取 url」状态机(`VIDEO_MAX_POLLS` 防呆、无 30s 冷却门)。
|
|
26
|
+
|
|
27
|
+
- **V2.0 参数体系**:`width`/`height`/`num_frames`(8n+1)/`frame_rate`;2.5 家族进 `video25ModelIds` 单独上报、不进对话选择器。
|
|
28
|
+
- **2.5 系列补齐(秒数制)**:`buildVideoBody25`(`seconds` 4–12 / `size` 720P·960P·2K / `aspect_ratio` 白名单 + `image`/`keyframes` → media、flash 收敛仅 720P 且 reference ≤5)双家族分派,互斥字段永不同时发给同一模型;`pickVideoModel` 认全量视频模型、目录无 V2.0 时回落到第一个 2.5 模型;帧数字段自动换算(`121@24fps → 5s`)、`negative_prompt` 不转发给 2.5;面板候选含 2.5、文案改为「已支持、自动换算」。
|
|
29
|
+
- **双向混发防护 + 错误点名实际模型**:`buildVideoBody` 只解构 V2.0 字段,所以 2.5 专有字段(`seconds`/`size`/`aspect_ratio`/`mode`/`keyframes`)发到 V2.0 模型原先是**静默丢弃**——agent 以为拿到 10 秒 2K、实际拿到 5 秒 720P 且无任何信号。现在 `defineVideoTool` 在分派前拒掉这个组合(`VIDEO25_ONLY_FIELDS`),报错逐字段点名并给出修法;反向(V2.0 帧数字段 → 2.5 模型)仍走换算,保留「不判断家族也能出片」的退路。2.5 家族的每个校验错误经 `video25ErrorContext()` 带上**实际解析到的模型 id 与所属体系**(`模型 agnes-video-2.5-flash(2.5 秒数制):无效的 seconds 3:须为 4–12 的整数秒`),此前只说「2.5 系列」,得回读 catalog 才知道打到的是哪个模型。
|
|
30
|
+
- **工具描述与文档修正**:描述里不完整的 id `2.5-flash` 补全为 `agnes-video-2.5-flash`(避免 agent 照抄后白跑一次 400)并写明反向混发会被拒;README 与 `AGNES-API.md` 头部「只覆盖 V2.0 参数体系、2.5 不选」的过期表述改为双体系都覆盖;`API.md`「认不出的 id 退回自动选择」与实现不符(显式 `model` 原样直传、不查目录,只面板偏好 `videoModelId` 才查目录后回落),已改正并注明两条 id 的校验强度差异。
|
|
31
|
+
|
|
32
|
+
### 第三个上游:AgnesCode tab(可选,默认关)
|
|
33
|
+
|
|
34
|
+
- **本机登录态采集**(workbuddy 族先例):微信登录发生在 AgnesCode 桌面 App 里,插件只读 App 的 os_crypt 加密会话文件(DPAPI + AES-256-GCM,注入式可离线测),探测失败按五档逐文件分诊(`file_missing` / `no_key` / `decrypt_failed` / `no_token` / `untrusted_base`)。
|
|
35
|
+
- 独立 provider `sensenova-agnescode`:接口 base **按账号跟随**会话文件且钉死在 Agnes 域名族;无刷新端点(JWT 约 28 天),续期 = 重开桌面 App 后「检测本机登录态」。
|
|
36
|
+
- 独立凭据引用 `AGNESCODE_CREDENTIAL`(引用值而非私有 kind)、独立 switch-store / publisher,与主注册零耦合;`reasoning:false`(thinking 线路未证实)、memberOnly 标记不隐藏(红线 7 精神)。
|
|
37
|
+
- 契约探针(ROADMAP §6.3):CN BFF OpenAI 兼容、28 天 JWT、独立积分池、本机会话文件解密链已验证。
|
|
38
|
+
|
|
39
|
+
### 出图与其它修复
|
|
40
|
+
|
|
41
|
+
- 出图 `n` 硬限为 1、补全 `ratio`/`image`/`return_base64`(live probe 确认 size 2K/4K 常量与 extra_body 全接受);出图模型识别补齐名称兜底(结构化模态判定 + 名称双链统一);出图描述与成功 hint 修复。
|
|
42
|
+
- 浏览器不再把保存的控制台账号自动填进模型搜索框;sk-(免费版)与 cpk-(Token Plan)密钥前缀提示区分。
|
|
43
|
+
- 渐进式 checkJs 类型校验(激活既有 JSDoc 防静默漂移)。
|
|
44
|
+
- e2e 扩至 59 项实跑;全量离线门禁 + build-gate + e2e 绿。
|
|
45
|
+
|
|
46
|
+
## [0.4.3] — 2026-10-01
|
|
47
|
+
|
|
48
|
+
第二个上游(小浣熊)、面板从侧边栏归位到 Plugins 页、模型花名册重排,外加一批「状态翻成某个值后操作入口跟着消失」的可见性修复。
|
|
49
|
+
|
|
50
|
+
> **版本号说明**:0.4.1 与 0.4.2 都**未发布到 npm**(registry 上仍是 0.4.0)。本版把自 0.4.1 以来的全部改动一次收敛为 0.4.3,0.4.2 不再单独发布。
|
|
51
|
+
|
|
52
|
+
### 第二个上游:小浣熊 tab(微信扫码登录 + 独立 provider)
|
|
53
|
+
|
|
54
|
+
`ROADMAP §6.1` 的「第二上游」落地:接入 `xiaohuanxiong.com` 网关,与 Token Plan 积分池**相互独立**,全程 opt-in。
|
|
55
|
+
|
|
56
|
+
- **面板第三个 tab「小浣熊」**(`src/client/raccoon-tab.ts`):开关、微信扫码登录、积分余额、模型花名册四块。文案中英双语(`raccoon.*` 17 键)。
|
|
57
|
+
- **Host 半边 peer-free 协议层**(`src/host/raccoon.ts`):扫码登录走查、信封解析(成功判据是 `code === 0`,用普通 `Number` 比较——共享的 `num` 助手会把 `0` 当假值拒掉)、一次性 refresh-token 轮换、余额与目录读取、两态思考档位映射。
|
|
58
|
+
- **凭据走 DSH 凭据服务**(`src/host/raccoon-store.ts`):存的是凭据服务引用而非明文;轮换后的新 pair 在续期时**回写**——这正是与「读桌面端文件」路线相比唯一能站住的地方。
|
|
59
|
+
- **开关按 profile 分段**(`src/host/raccoon-switch-store.ts`):与 provider/draw 同一套文件-backed 纪律。
|
|
60
|
+
- **第二个独立 publisher**(`src/host/raccoon-publish.ts` + `raccoon-llm-adapter.ts`):与 Token Plan 的注册完全隔离,小浣熊侧怎么折腾都churn 不到主注册。
|
|
61
|
+
- **自包含 QR 编码器**(`src/client/qr.ts`,455 行,零外部依赖):byte mode、纠错等级 M、v1–10,登录 URL 直接在面板内编码成图。
|
|
62
|
+
- **测试**:`test/raccoon.test.mjs`(离线,覆盖协议、两个 store、描述符映射、publisher 状态机、QR 编码器、开关 store),已进 `npm test` 与 CI offline 档。
|
|
63
|
+
|
|
64
|
+
**小浣熊上线后连修四轮**(每条都是「面板看起来正常、实际不可用」):
|
|
65
|
+
|
|
66
|
+
- **QR 编码器产出的矩阵没有任何解码器读得出来**:用 jsQR(`qrcode-decoder` 同款纯 JS 引擎)做解码验证时发现,首版从 v1 到 v10 全部解码失败——尽管套件里每一条结构断言都是绿的。五个缺陷全是绘制顺序或码表错误,最典型的是**定位图形(timing)画在三个 finder 之后**,把 finder 内部的第 6 行/列擦成黑白条纹;timing 必须先画,finder 后画才能覆盖。
|
|
67
|
+
- **扫码确认时「正在等待」不可见**:进行中的那次扫码对 tab 不可见。
|
|
68
|
+
- **QR 要等下一轮 60s 轮询才出现**:登录入口像没反应。
|
|
69
|
+
- **`fontSize` / `marginTop` 泄漏成 DOM 属性而非样式**:样式静默失效。
|
|
70
|
+
- **扫码登录拿到的昵称没存**:面板无法称呼用户,补存后正常问候。
|
|
71
|
+
- **小浣熊的积分倍率没进模型选择器**:面板花名册显示的 ×0.75 / free / ×0.2,在选择器里看不到(pi-ai 没有计费元数据通道,选择器只渲染名字)。倍率改挂进显示名——`GLM-5.3(×0.75)`、`SenseNova 6.8 Flash(free)`,倍率 1 保持裸名。两处同源,不会打架。
|
|
72
|
+
|
|
73
|
+
### 面板从侧边栏归位到 Plugins 页
|
|
74
|
+
|
|
75
|
+
- **去掉 `sidebar.panellist` 与 `main` 槽位注册**,只留 `plugins.bundle.config`:面板改为 Plugins 页内的**内联卡片**,不再占侧边栏一行(`src/client/panel-page.ts`、`src/client/index.ts`)。同时摘掉 layout 服务依赖与 onClose 按钮(Plugins 页自己管导航),`PanelPage` 的 `onClose` 改为按传入与否决定渲染。
|
|
76
|
+
- 这解决了「装了 5 个 connect 插件 = 侧边栏 5 行噪音」的问题,与 workbuddy 的形态对齐。
|
|
77
|
+
|
|
78
|
+
### 小浣熊模型列表:行形态与 Token Plan 花名册对齐
|
|
79
|
+
|
|
80
|
+
原来每个模型只有「名字 + 一个 English 徽章」,参数行整块缺席,读起来像个半成品。数据其实**早就在手上**——网关的目录行带 `context_window` / `max_output_tokens`,`fetchRaccoonCatalog` 自首个版本就归一化了这两个字段,`raccoonRoster` 也一路保留着,只有这个渲染组件把它们丢了:
|
|
81
|
+
|
|
82
|
+
- **补上参数行**:「256K 上下文 · 最大输出 64K」,复用 Token Plan 花名册的 `S.modelMeta` 与同两条文案模板(`llm.contextBadge` / `llm.metaOutput`)。目录没声明该字段时**不画这一段**(`num()` 对缺失值返回 `undefined`,不兜底编数)——面板只引述平台真给的东西。
|
|
83
|
+
- **倍率改为独立 chip**(`S.modelRate`,与 Token Plan 同款),`0` 显示 `free` 而不是 `×0`(零倍率是对模型的事实陈述,不是一个为零的费率);新增 `raccoon.free` 键补齐 i18n。
|
|
84
|
+
- **倍率 tooltip 不复用 `llm.rosterRateTitle`**:那句话写的是「积分消耗**伪**倍率(自定义对比用,**非官方**)」,因为 Token Plan 的倍率确实是操作者在插件里配的;而小浣熊的倍率是**网关目录直接声明的字段**,借那句 tooltip 等于给真数据贴上"编的"标签。新增 `raccoon.rateTitle`「网关目录声明的积分倍率(0 为免费)」,并加断言钉住别再用错。
|
|
85
|
+
- **`· vision` 硬编码英文改为 `llm.rosterVision`「可看图」徽章**,靠右对齐——原先那个 `" · vision"` 是拼在倍率徽章里的中文字典里的英文裸串,既没走 i18n 也没走统一徽章样式。
|
|
86
|
+
- **给列表一个框**(新增 `S.modelPanel`):与同 tab 里「已登录」块(`S.card`)同级的容器。行的分隔线样式**不变**——仓库既有原则是「section card 持有唯一的框、行不重画框」,缺的是列表这一层的容器,不是给每行描边。
|
|
87
|
+
|
|
88
|
+
`test/render.test.mjs` 补 5 条断言(150 → 155):参数行在有字段时出现、在没字段时不出现为空行、费率 chip 渲染、free 不带 `×0`,以及**思考档位必须缺席**——该 provider 注册的是 `reasoning: false`(pi-ai 发不出网关唯一有效的 `extra_body.thinking`),照抄 Token Plan 那行「思考 关闭/低/中/高」等于承诺一个 DSH 选择器永远不会给的档位。均做过「删参数行 / 填入思考档位 → 红 → 还原 → 绿」验证。
|
|
89
|
+
|
|
90
|
+
### 「接入 API」tab:卡片改名、重排、默认展开
|
|
91
|
+
|
|
92
|
+
按「你为什么来这」而不是按依赖排序,三张卡全部改名 / 换位置(`src/client/panel-page.ts`、`src/client/i18n.ts`):
|
|
93
|
+
|
|
94
|
+
- **「提供方注册与模型推送」改名「语言模型」**(`llm.providerTitle`,en: `Language models`),并移到**第一位**、默认展开。
|
|
95
|
+
- **「出图工具」第二位**,默认展开。两张功能卡都是用户进这个 tab 的理由;收起的卡把自己的开关藏起来,读起来像「这个功能没反应」。
|
|
96
|
+
- **「API Key」移到最后**并保持默认收起——它是前两张卡的**前置条件**,由它们指回来,而不是被配置的对象;卡内是密钥输入框,也不该是默认铺开的那一屏。
|
|
97
|
+
|
|
98
|
+
同时修掉一处被这次重排坑到的文案漂移:`llm.rosterEmpty` 原写「在**上方**保存一次 API Key」,而它所指引的 API Key 卡已经换到**下方**——方向词在换序后必然指错,改为直接点名「API Key」卡片(中英两侧同步;`draw.off`、`llm.noKey` 那两处「上方」指的是**同卡片内**的开关与输入框,不跨卡,保持不变)。
|
|
99
|
+
|
|
100
|
+
`test/panel.test.mjs` 补三条断言把这次的决定钉住:三张卡的渲染顺序、默认展开集合、跨卡指引必须点卡片名而非方向词(均做过「故意改回旧序 / 改回 false → 红 → 还原 → 绿」验证)。
|
|
101
|
+
|
|
102
|
+
### 截图与市场清单对齐(`docs` 门禁新增检查 11)
|
|
103
|
+
|
|
104
|
+
重截截图时文件名从 `panel-credit-pools.png` / `panel-provider-setup.png` 换了新名,磁盘与 git 都已同步,**唯独 `screenshots.json` 仍指着两个已删掉的旧文件**——工作树干净、构建通过、其余检查全绿,**没有任何东西在报错**,而它是市场页取图的唯一依据,推上去就是图裂。
|
|
105
|
+
|
|
106
|
+
- **清单对齐当前两张**:`assets/panel-credit.png`(「积分额度」tab)、`assets/panel-API-provider.png`(「接入 API」tab);「小浣熊」那张待补。
|
|
107
|
+
- **`docs.test.mjs` 新增检查 11**:清单声明的每条路径必须**真实存在于磁盘**、是图片扩展名、条目数 1–8、且为仓库根相对路径。三种破坏实测红过再还原复验绿(换回旧名 / `..` 逃逸 / 拿 `README.md` 当条目)。
|
|
108
|
+
- **`PITFALLS` 新增 §26**(条目数 25 → 26,三处引用由门禁当场抓出并同步):**清单类文件(`.json` / `.yml` / `.toml`)不是文档,但同样是契约**——改资产名前先问「还有谁按名字引用它」;本仓库按名字引用 `assets/` 的机器消费方只有 `screenshots.json` 一处,正是「只有一处 + 又不叫 `.md`」让它成了盲区。
|
|
109
|
+
- **`CONTRIBUTING` §8** 那句「重截并推送后截图自动生效(**文件名不变**)」已修正:它藏了个未言明的前提——**改名就必须同步清单**,而这次恰恰是换了名。
|
|
110
|
+
|
|
111
|
+
### 模型花名册重排(WorkBuddy 形态)
|
|
112
|
+
|
|
113
|
+
- **行去卡内框、改用分隔线**:`modelRow` 由横向 flex 行改为纵向列(头行 + 缩进的参数行),新增 `modelRowHead` 包裹头行;徽章只标 notable 态(删「纯文本」徽章、补「额度耗尽」徽章)。工具行计数成组右置,批量按钮 32px 与搜索框等高。
|
|
114
|
+
- **每行只留会变的 per-model 事实**:参数段从「上下文 · 最大输出 · 默认思考强度」改为**本模型实际可选档位**——「思考 关闭/低/中/高/极高[/最高]」,由 Host 新导出的 `supportedThinkingLevels` 按 pi-ai `getSupportedThinkingLevels` 同一规则过滤(与 DSH 选择器同源),glm-5.2 独显「最高」。provider 级常数(默认思考强度)收进花名册头部只说一次(`llm.rosterThinkingDefault`),**删掉逐行重复的恒定默认档**——用户锐评「恒定默认档逐行重复=噪音」,该反模式已记入 `docs/IMPROVEMENTS.md` §7。
|
|
115
|
+
- **`tokenSize` 修正 1049k → 1M**:千整走十进制、纯二进制走 1024、≥1M 归 M。Host 侧新增 `maxOutputLength` 投影(`0` = 未声明则整段不画,绝不猜)。
|
|
116
|
+
- **`matchMultiplier` 单一匹配器**:趋势行 ×N 与花名册 ×N 同源同值,两处显示不可能不一致。
|
|
117
|
+
|
|
118
|
+
### 出图行的渲染回归修复
|
|
119
|
+
|
|
120
|
+
- **出图行把名字与徽章摞成了竖排**:`modelRow` 在花名册重排时改为纵向列并新增 `modelRowHead`,但当时只迁移了 `model-picker.ts`;`provider-controls.ts` 的 `DrawSwitch` 与 `raccoon-tab.ts` 仍是旧标记——`label` 与徽章成了纵向列的直接子元素,于是堆叠,且 `modelName` 的 `flex: 0 1 auto` 被压到近乎零宽。现两处都补上 `modelRowHead` 包裹(与 `ModelRoster` 同一契约)。
|
|
121
|
+
- **回归守卫**:`test/render.test.mjs` G6 组改为真正挂载 `DrawSwitch` 并断言行是列形态、没有任何一行把名字/徽章留在 `modelRowHead` 之外、每行恰好 3 个头行;`ModelRoster` 与 `RaccoonRoster` 共用同一组断言并带**非空性检查**(此前「0 行也算通过」的真空通过正是这次回归溜走的原因)。为让渲染套件能挂载,`raccoon-tab.ts` 把内联花名册抽成无 hook 的导出组件 `RaccoonRoster`。
|
|
122
|
+
- **出图选择器的两处显示修复**:勾选态不再叠在开关上;目录为空时说明原因(而不是留白);自动选择且未钉模型时徽章点名实际生效的模型;出图块在自动选择时也下发(此前只在钉死模型时下发)。
|
|
123
|
+
|
|
124
|
+
### 面板注册引导双向化
|
|
125
|
+
|
|
126
|
+
- 账号表单标题下与 API Key 表单底部的官网链接**两种状态都显示**:无账号时「前往官网注册」,已有账号时「前往官网管理额度 / 获取 API Key」(新键 `auth.portalHint`,中英双语;URL 入 `const.ts`)。
|
|
127
|
+
|
|
128
|
+
### 思考档位收敛到「实测过 200 才画」(面板不再过度承诺 low/medium/xhigh)
|
|
129
|
+
|
|
130
|
+
面板花名册每行原来把 `low/medium/xhigh` 对**所有**商汤模型都画出来,但冻结契约表
|
|
131
|
+
`test/baselines/sensenova-contract.json` 里 `xhigh` 只实测过 deepseek-v4-flash(200)、
|
|
132
|
+
`max` 只实测过 glm-5.2(200),`low`/`medium` 对任何模型都**从未实测**(代码依据只是
|
|
133
|
+
平台 400 报错文案里出现过这两个词,而 [SENSENOVA-API.md §7.6](docs/SENSENOVA-API.md)
|
|
134
|
+
明说那串列表是**并集**、各模型支持面不同)——用户点了某家不支持的档就可能 400。
|
|
135
|
+
现把 `thinkingLevelMapFor` 改为**逐模型门控**(新常量 `PROBED_EFFORT`,数据抄自同一张
|
|
136
|
+
冻结契约,覆盖 low/medium/high/xhigh/max 五格):`high`(平台默认,全家族实测过)保持
|
|
137
|
+
开,`xhigh` 只对 deepseek-v4-flash 开,`max` 只对 glm-5.2 开;未收录模型默认全关。
|
|
138
|
+
|
|
139
|
+
**2026-09-30 探针补测后**:`test/live-contract.mjs` 扩了 `reasoning_effort:low/medium`
|
|
140
|
+
探针(2s 退避;429 记 INDEFINITE 不当判读——限流是节奏问题不是参数拒绝,只有 4xx 才
|
|
141
|
+
算"不支持"的负证据)。首跑实锤 200 的格子:sensenova-6.8-flash-lite(low+medium)、
|
|
142
|
+
**deepseek-v4-flash(low+medium,你原问的那行——低中档平台真支持)**、glm-5.2(low+medium)、
|
|
143
|
+
deepseek-flash(medium)、kimi-k3(medium)→ 这些格已翻 `true`,对应面板行放出低/中档。
|
|
144
|
+
仍 INDEFINITE 的(429 rpm 窗口,非 400,保持关、重跑再翻):deepseek-v4-pro 的 low+medium、
|
|
145
|
+
deepseek-flash 的 low、kimi-k3 的 low。
|
|
146
|
+
|
|
147
|
+
测试同步:`contract` §2 加逐模型 low/medium 断言(读契约表,`true`→开、`indefinite`/`false`→关)、
|
|
148
|
+
`provider` §1(v4-flash/glm-5.2/flash-lite 的 low+medium 开、INDEFINITE 格关)、`retry` §5、
|
|
149
|
+
`routes` Q2、`render` G4(v4-flash 那行 = 关闭/低/中/高/极高)。文档同步:`API.md` 样例
|
|
150
|
+
行与字段注记、`IMPROVEMENTS.md` §7 修订、本条。
|
|
151
|
+
|
|
152
|
+
### 可见性修复三连:登录态常显 + provider 注册 pending 态 + 小浣熊错误不再被开关藏起
|
|
153
|
+
|
|
154
|
+
同族问题——「状态翻成某个值后,操作入口/错误行跟着消失,用户拿不到重入路」:
|
|
155
|
+
|
|
156
|
+
- **登录态与账号编辑器无条件可见**(中间态不再是死路):此前「连接商汤控制台」区卡只在 `hasAccount || needsAccount` 时出现——中间态(已点过「清除账号」、grant 仍在静默续期)下整卡消失,要等 refresh_token 彻底失效才重新拿到重输入口。现改为**只要快照携带 auth 块就常显**,积分额度页底部永远有该卡(默认折叠、一键展开):随时可核对登录态、重输账号改指仍有效的 grant、或再清一次账号。头部「需要重新登录」chip 的 tooltip 在 Host 没给 reason 时回落 guidance 文案,不再留空白。
|
|
157
|
+
- **provider 注册 pending 态**:开关已开、服务在、无 error,但注册没落地时,原文案谎报「未注册——勾选上方开关」(指向已勾选的开关);新增 `llm.registeredPending` 直说 pending。同时修分支序:具体失败(providerError)优先于能力缺失(noService),两者同时成立时不再吞错误。
|
|
158
|
+
- **小浣熊 tab 注册状态行不再被开关门控**:providerError 原来只在 `enabled === true` 时渲染,开关一关报错就消失;现 `state !== null` 即渲染,失败行与开关解耦。
|
|
159
|
+
- **构建修复**:`qr.ts` 内 8 处 `x?.y = v`(可选链左值赋值)是解析错误,tsdown 直接挂掉——改为先索引后赋值。
|
|
160
|
+
- **测试**:`test/panel.test.mjs` B2 组翻转(中间态/死 grant 态都钉 `canManageAccount === true`);`panel-decision.js` 镜像同步去门控;`render.test.mjs` 新增 pending 态与 error 优先序 2 项 pin。
|
|
161
|
+
|
|
162
|
+
### 修复:全新安装时面板只剩「连接 Agnes 控制台」,连 tab 栏都不渲染
|
|
163
|
+
|
|
164
|
+
上报现象:全新装好插件打开面板,看不到三个 tab,整页只有一个登录表单——**API Key tab 和小浣熊 tab 也一起消失了**,尽管它们一个根本不读控制台、一个连的是另一个上游。
|
|
165
|
+
|
|
166
|
+
根因是**结构性设计缺陷,不是移植失误**(源版同样存在):控制台探针 `overview` 被当作**唯一致命源**,失败即整个快照走 `ok:false`;客户端又把 tab 栏放在 `data` 分支里,于是「控制台没登录」这一件事把三个互相独立的模块全埋了。这正是 `AGENTS.md` 模块独立性不变量禁止的形状。
|
|
167
|
+
|
|
168
|
+
两层修复 + 一条诚实性补丁:
|
|
169
|
+
|
|
170
|
+
- **Host(`snapshot-aggregate.ts`)**:`overview` 从致命源降级为五个可降级源之一(`soft()`),新增 `quota.consoleConnected`;失败原因(`not_configured` / `auth_error` / `console_error`)走 `quota.error.code`。它仍**串行先取**——401 时先换新令牌,后面批量才拿活令牌出门(`test/routes.test.mjs` B 组的「死令牌只被出示一次」仍是绿的)。
|
|
171
|
+
- **客户端(`panel-page.ts`)**:tab 栏从 `data` 分支提到顶层,**第一帧就渲染**;`data === null` 时登录表单变成额度 tab 的**内容**而不是整页。控制台未连接时额度 tab 内点名原因,并一次性自动展开账号卡(用 `useRef` + `useEffect`,因为 `open` 是受控 prop,写成 `open: openSections.account || needsSetup` 会让卡片再也收不起来)。
|
|
172
|
+
- **诚实性补丁**:`quota.totals` 在读不到时是 **`null`,不是零值块**。`parseUsageOverview(null)` 的每个计数器都经 `countOf` 落到 `0`,直接渲染会把一次读取失败伪装成「0 次请求 / 0 token」——把失败变成测量。面板本就有 `null` → 「暂未读到」的分支,所以这一条只改 Host 侧。
|
|
173
|
+
- **顺带暴露的副作用**:未登录的 Host 现在也会去取**公开套餐目录**(它是控制台静默时唯一还剩的额度内容),`test/wiring.test.mjs` 此前从未 stub 过它,已补。
|
|
174
|
+
- **测试**:`routes` +8、`wiring` +2、`e2e` +2、`render` +2(含「第一帧就带三个 tab」的回归);`docs/API.md` / `ARCHITECTURE.md` §3 §5 同步。客户端两个 tab 的行为未变,只是重新可达。
|
|
175
|
+
|
|
176
|
+
**上线实测又挖出一个缺口(同日补)**:重启 web 后快照确实变成 `ok:true` / `consoleConnected:false` / `totals:null`,但 `quota.error.code` 是 **`login_rejected`**——而 `GUIDANCE_BY_CODE` 只覆盖了 5 个码。根因是这次降级的连带效应:`AUTH_FAILURE_CODES` 里 13 个码现在**都能**以 `quota.error.code` 抵达面板(以前它们只会变成整份 `ok:false`,面板只读顶层 `code`),表却没跟着长。后果是面板退化成泛泛的「控制台未连接」,丢掉「账号需要重新输入」这个唯一有用的信息。
|
|
177
|
+
|
|
178
|
+
- `GUIDANCE_BY_CODE` 补齐到 `AUTH_FAILURE_CODES ∪ NO_LOGIN_CODES` 全覆盖:令牌侧(`auth_error` / `jwt_expired` / `no_refresh_token` / `refresh_rejected` + 四个已死的 OIDC 期码)统一给「令牌失效,重登一次」;账号侧 `not_configured` / `missing_credentials` 给「还没配账号」;四种凭据拒绝**复用表单自己的文案**(`auth.badCredentials` / `auth.locked` / `auth.rateLimited` / `auth.verification`)——它们的下一步动作各不相同(重输 / 等解锁 / 等限频 / 完成人工验证),塌成一句「登录失败」会对其中三种给出错误建议。
|
|
179
|
+
- **补上反向检查**(`test/panel.test.mjs`):此前只断言「表里的 key 都是真码」,现在同时断言「能抵达面板的码都有文案」。缺的正是这一半,而且是被线上抓到的,不是被测试抓到的。
|
|
180
|
+
|
|
181
|
+
### 修复:浏览器把保存的商汤账号填进模型搜索框
|
|
182
|
+
|
|
183
|
+
上报现象:密码管理器把 SenseNova 控制台的账号自动填进插件的输入框,**连「接入 API」tab 的模型搜索框也被塞了账号**,看着像浏览器按关键词猜中了什么。
|
|
184
|
+
|
|
185
|
+
**不是关键词,是我们主动声明的,而且同 origin 上还有第二个一模一样的表单**:
|
|
186
|
+
|
|
187
|
+
- 两个插件(`dsh-connect-sensenova-token-plan` 与 `dsh-connect-agnes-token-plan`)同时装在 `profiles/web` 的 bundles 里,注册进同一个 slot、由同一个 `http://127.0.0.1:3080` 提供——浏览器按 origin 存密码,分不清谁是谁。
|
|
188
|
+
- 两个插件的表单语义逐行相同(`<form>` + `autocomplete="username"` + `type="password"` + `current-password`),正是 Chromium 文档里的标准登录表单形状。
|
|
189
|
+
- API Key 那个 `<form>` 只有密码字段、**没有用户名字段**。Chromium 自己的文档要求这种拆分布局必须在密码表单里放一个含用户名的字段(可 CSS 隐藏),否则它会自己去找——它挑中了同页唯一既无 `autocomplete` 又无 `name` 的文本输入框,也就是模型搜索框。
|
|
190
|
+
|
|
191
|
+
修法:给模型搜索框加 `autoComplete="off"` 与 `name="model-search"`。**账号表单的 `username`/`current-password` 语义刻意保留**(浏览器记住 Agnes 账号是想要的能力),本次只堵「去表单外找用户名」这条路径。
|
|
192
|
+
|
|
193
|
+
- `render.test.mjs` 新增 I2 组:渲染全部 7 个可能含输入框的组件,断言每个可填文本输入框要么 `autoComplete="off"`、要么声明凭据角色,并把「唯一声明凭据角色的是账号表单」钉死。该检查实测会红再复绿。
|
|
194
|
+
- 机制与证据写进 `docs/PITFALLS.md` §27(同 origin 多插件会把这一点放大成「凭据互相串门」)。
|
|
195
|
+
|
|
196
|
+
### 修复:额度已经正常显示,头部却一直挂「需要重新登录」
|
|
197
|
+
|
|
198
|
+
上线后看到的第二处「状态不落地」:面板头部 chip 说「需要重新登录」,下面额度、用量、套餐**全都正常**——数据是真的,chip 是假的,而且不会自愈,要重启 Host 才消失。
|
|
199
|
+
|
|
200
|
+
- **根因**:`state.lastError` 由 `getToken()` 的 `acquire()` 路径写入、也由那条路径清除,但 `getToken()` 在缓存令牌仍然新鲜时会**提前 return**,根本不进 `acquire()`;而面板上的手动登录是**直接存令牌**的,从不经过 `acquire()`。一次失败的自动重登写上这个字符串,用户手动登录成功后节流记录被清了、**这个字符串没清**,新令牌又足够新鲜——清除路径再也不会跑到。
|
|
201
|
+
- **修法**:不逐个写入点补清除,而是把上报钉在结果上——`state()` 里 `error: isFresh(stored) ? null : …`。`auth.error` 的契约是「面板该向用户要账号」,持有一个控制台没拒绝过的令牌时就不存在当前错误。
|
|
202
|
+
- **同族**:`AccountForm` 的「已保存并登录,正在读取额度…」也从不落地(`saved` 只被「清除账号」复位),改由父组件传 `hasSnapshot` 门控——独立表单照旧显示,面板内嵌不再显示。**这条没有测试覆盖**(测试替身的 `useState` 只返回初值,进不去 `saved`),是记录在案的缺口。
|
|
203
|
+
- **测试**:`store.test.mjs` 8c 组补两处断言(parked 期间必须报错、改正之后必须不报),实测会红并精确报出用户看到的那句原文,再还原复绿;冻结基线零漂移。机制写进 `docs/PITFALLS.md` §28。
|
|
204
|
+
|
|
205
|
+
### 运维诊断 doctor(PITFALLS §22 的欠账)
|
|
206
|
+
|
|
207
|
+
回答「这台机器的 provider / 出图开关到底开没开」——此前唯一答案在一个 JSON 状态文件里,不在任何配置文件、任何路由、任何 CLI。
|
|
208
|
+
|
|
209
|
+
- **新增 `src/host/doctor.ts`(peer-free 纯读层)+ `tools/doctor.mjs` CLI**:读 `$DSH_HOME/state/<name>/` 与每个 `<profile>/<name>/` 下的 `provider.json` / `draw.json` / `catalog.json`,报「面板保存值 > 部署默认值」的生效开关、模型允许清单、以及「文件存在但读不成」时**点名**是哪个文件(损坏/外来版本不会静默变空)。`npm run doctor`(人读)/ `npm run doctor:json`(机器读)。
|
|
210
|
+
- 与「大统一」定位对齐:单点入口必须可查,doctor 是第一条查询通道;它不写任何文件、不碰凭据,只在磁盘上读,Host 没起也能跑。
|
|
211
|
+
- **测试**:`test/doctor.test.mjs`(23 项,离线门禁)——三套 payload 解析器的「损坏/外来版本读作未设」方向、profile 分段与 shared 布局互不误认、干净机器/损坏文件的人读文案;进 `npm test` 与 CI offline 档。
|
|
212
|
+
|
|
213
|
+
### 边界裁定:第二上游正式纳入界内(不变量 3 修订)
|
|
214
|
+
|
|
215
|
+
Token Plan 与小浣熊同为商汤旗下产品线,`sensenova` 这个名头名副其实,第二上游不再是「待定方向的破例」。
|
|
216
|
+
|
|
217
|
+
- **`ARCHITECTURE.md` §5 不变量 3 修订**:划线依据从「只吸收与商汤 **Key/账号线**强相关的能力」改为「只吸收与**商汤(SenseTime)产品线**强相关的能力」。原划法按 Key 域名 / 认证域划线,会把同一厂商的姐妹产品线误判到界外——第二上游由此从「撞边界、须先定方向」变为**界内**。另两条不变量(opt-in 默认关、凭据红线)不变。
|
|
218
|
+
- **新增 §5.5** 记录裁定本身,**三条独立举证**而非印象:中证网 2026-07-19(U1 Pro 能力「在**商汤旗下的**产业级 AI『小浣熊』及 Seko 中已得到深度验证」)、商汤官方稿件 2026-09-21(「**商汤小浣熊 Raccoon Work**」由商汤科技打造)、以及本仓库既有措辞(ROADMAP §6.1 早写着「接入**商汤小浣熊**桌面 App 模型」——边界这次才承认,事实一直在那儿)。
|
|
219
|
+
- **它与 Token Plan 的确切关系**(后来人据此判断还能不能再放宽):**同一厂商、不同产品线、认证域互不相通、积分口径互不算**。所以实现上必须继续是独立凭据 / 独立 publisher / 独立 provider id——共享任何一样都等于把两条产品线焊死。它是**第二上游**,与 §6.1.1 判死的**第二登录路径**不是同一件事。
|
|
220
|
+
- **防止口子被开成无限大**:本次放宽只覆盖「同一厂商下的产品线」,**跨厂商聚合**(codearts 那类一套形态融 N 家)依旧在界外。以后每纳入一条新产品线必须同时落三条——① 外部可核的厂商举证;② 与 Token Plan 的具体关系,尤其是积分与认证域是否通用;③ 齐全后才允许以 opt-in 默认关的形态进入树干。缺一条就退回 publisher 隔离那条路。
|
|
221
|
+
- **同步**:`ROADMAP.md` §6.1.1 的「须先定方向——不默认吸收」改为**方向已定**;`AGENTS.md` 第三条事实改为「同属商汤旗下,但认证域不相通」。§6.1.1 判死第二**登录路径**的两次复测结论**不变**——它与「第二上游属不属界内」不是同一件事,别混为一谈。
|
|
222
|
+
|
|
223
|
+
### 第二上游补复测 + 文档追平(一次自审掀开的三处「文档与代码分头走路」)
|
|
224
|
+
|
|
225
|
+
- **README 不再说谎**(它进 npm 的 `files` 白名单,是用户装完后读到的唯一说明书):此前 ① **零处**提到当期头条特性——第三个 tab「小浣熊」;② 三处仍写「侧边栏」,而代码早已迁到 Plugins 页,第 31 行「打开侧边栏「积分面板」」会让人**找不到入口**(操作级失效,不是文字洁癖);③ 仍挂着「面板**只读**」的承诺,而它已经能注册推理通道、挂出图工具、写 DSH settings。三处全部改正,并补齐「出图工具」与「第二个上游:小浣熊」两个真正的能力小节(含 provider id `sensenova-raccoon`、工具挂载需重启的事实)。
|
|
226
|
+
- **`cordis.patch.yml` 头注释的同类漂移**:第 3 行同款地写着 "sidebar panel",同样进 npm 包,一并改掉。
|
|
227
|
+
- **第二上游的网关契约补复测**(新增 `docs/ROADMAP.md` §6.1.2):2026-10-01 的四次无凭据只读请求——本插件实际依赖的 `/model_catalog` 与 `/chat/completions` 均回 `401 authorization_empty_error`(已抵鉴权层,路由健在);09-30 记录里那个 404 的是参考件 `dsh-raccoon-work` 的 `/models`,**本插件不使用**。此前据前缀相同就判「实现的常量正是被标注 404 的那份清单」属**误判,已更正**。附带教训收进 PITFALLS §24。
|
|
228
|
+
- **护栏:`docs.test.mjs` 新增两条语义检查**——原有的全是形式校验(链接 / 表格去重 / 行数上限),对面「文档断言的事是否与代码一致」毫无感知:
|
|
229
|
+
- **检查 9**:README 必须覆盖面板的每一个 tab。tab 名单从 `panel-page.ts` 的 `activeTab` 联合类型派生、文案从 `i18n.ts` 的 `tab.<id>` 派生,**不写死任何名字**,于是「加 tab 忘了告诉用户」和「改 tab 名不跟」都必然红。
|
|
230
|
+
- **检查 10**:README 与 `cordis.patch.yml` 声称的 UI 位置必须与 `src/client/*.ts` 实际注册的槽位一致。
|
|
231
|
+
- 两条都做过「故意破坏 → 必须红 → 还原 → 复绿」的双向验证(删光「小浣熊」精确报出 `raccoon(面板文案「小浣熊」)`;改回事故原文报「声称面板在侧边栏但没有 sidebar 槽位注册」)。
|
|
232
|
+
- **PITFALLS 新增 §24(GET 探活会误判)与 §25(形式门禁全绿 ≠ 文档说实话)**,总数 23 → 25;三处散落的过期引用(`README.md` / `AGENTS.md` / `docs/README.md`)同步——这批数字正是由新门禁当场揪出来的。
|
|
233
|
+
|
|
234
|
+
### 文档修正:撤销 ROADMAP §0 被证伪的前提
|
|
235
|
+
|
|
236
|
+
- [ROADMAP.md](docs/ROADMAP.md) §0 与 §2 引言原写「本插件已是双 profile 的 `agent-default-model`——即这台机器的**默认推理通道**,故障域已升级为推理可用性」。该论断 2026-09-29 已被 [IMPROVEMENTS.md](docs/IMPROVEMENTS.md) §1.2 撤销(`agent-default-model` 是宿主的选择记录服务,原引用不可复现),但 ROADMAP 未同步。现改为「**能力事实**:可注册 provider `sensenova-token-plan`;是否默认通道由 profile 与用户模型选择决定;一旦某 profile 选它作默认,故障域才从面板升级为推理可用性(条件性爆炸半径)」。两份文档不再正面矛盾。
|
|
237
|
+
|
|
238
|
+
### 文档与仓库纪律
|
|
239
|
+
|
|
240
|
+
- **消灭「离线 N 套件」数字漂移源**:文档不再背书套件数量与枚举(`AGENTS.md` 曾写十七套件、`DSH-PLUGIN.md` 曾列 17 项清单,raccoon/doctor 套件加入后双双过期)——套件清单与链的唯一事实源收敛到 `package.json scripts.test`(已有 `package.test.mjs` 钉磁盘 ↔ 链 ↔ CI 一致性),文档只指事实源不复制数字。
|
|
241
|
+
- **现状模块引用 `.js` → `.ts` 全量对齐**(64 处 / 9 文件):只改「现状引用」,保留「历史动作 / 研究档案 / 产物 / 外部」四类原文。
|
|
242
|
+
|
|
243
|
+
### 仓库结构规范化:src/ 全源码,lib/ 纯产物
|
|
244
|
+
|
|
245
|
+
- 全部源码收敛到 `src/`(`src/host/*.ts` 27 个 Host 模块 + `src/client/*.ts` Client 半边);`lib/` 与根 `client.js` 降为纯构建产物并加入 `.gitignore`——删掉后 `npm run build` 一条命令从源码完整重建。
|
|
246
|
+
- 对外行为无变化:`main`/`exports` 指向不变(`./lib/index.js`、`./client: ./client.js`),`files` 白名单同步,`npm publish` 经 `prepack` 自动构建;`exports` 收敛为 `.` 与 `./client` 两个子路径。
|
|
247
|
+
|
|
248
|
+
### 模态判定地基(modality.ts):出图 / 视频模型识别统一为单一出处
|
|
249
|
+
|
|
250
|
+
出图工具认不出模型的根因是「模态判定」两路分家、又都没拿到字段:Agnes 网关的 `/v1/models` 条目只带 `id/object/created/owned_by/supported_endpoint_types`,**没有任何模态字段**(真机确证 2026-10-01)。同一缺失让两个判定朝相反方向失手——`isImageGenModel` 严格方向(缺字段 = 不是出图模型)导致 `agnes_draw_image` 选不出候选,面板报「暂无出图模型」;`isChatModel` 宽松方向(缺字段 = 对话)把 4 个 image/video 模型全挂进对话选择器,一选就 400「是 image 模型,请使用 /v1/images/generations」。
|
|
251
|
+
|
|
252
|
+
- **新增 `src/host/modality.ts` 作为模态判定的唯一出处**,三级解析:`output_modalities` 字段优先(平台补字段即自动生效)→ `agnes-image-*` / `agnes-video-*` 名称段兜底(只匹配完整段,不重蹈 `dsh-draw-router` 的 `/u1-fast/i` 子串漏判)→ 默认 `text`。`isImageGenModel` 与 `isChatModel` 改为共用这一个函数,矛盾由构造消除而非靠约定维持。
|
|
253
|
+
- **真实目录验证**:出图候选 0 → 2(自动选中 `agnes-image-2.1-flash`);对话名单 7 → 3。出图端点本身无需改动——真机实测 `POST /v1/images/generations` 返回 `data[0].url`,与 `parseDrawResponse` 已对齐。
|
|
254
|
+
- **文档更正**:`AGNES-API.md` §7.1 原先把 SenseNova 字段名误列为 Agnes 字段;新增 §7.5 记录图片同步 / 视频异步端点形状(`POST /v1/video/generations` 建任务、`GET /v1/videos/generations` 查任务)。`ARCHITECTURE.md` §5.4 记录「结构化判定」前提在 Agnes 上的反转。
|
|
255
|
+
- **测试**:`test/draw.test.mjs` 58 → 67,`test/provider.test.mjs` 201 → 205。
|
|
256
|
+
|
|
257
|
+
### 出图工具面板开关(drawEnabled)
|
|
258
|
+
|
|
259
|
+
与 provider 开关同机制的「面板开关 + 立即生效」,出图吸收(§5.4 接法 B)不再需要改配置重启:
|
|
260
|
+
|
|
261
|
+
- **面板新增「出图工具」卡片**(`client.js` 的 `DrawSwitch` 控件):勾选保存后写入插件私有状态文件 `$DSH_HOME/state/<plugin>/draw.json`,与 `provider-store.js` 走完全相同的完整性纪律。优先级:面板保存值 > `cordis.patch.yml` 的 `drawEnabled`;从未动过面板的部署,行为与 `false` 一致。
|
|
262
|
+
- **新增 `POST /api/<name>/draw` 路由**(`routes.js`):与 `/provider` 同一信任形状(同源围栏 + 4 KB body 上限),`{ enabled: true|false }` 或 `{ forget: true }`。
|
|
263
|
+
- **快照 `llm.drawEnabled` / `llm.drawSource`**:`snapshot-aggregate.js` 在 llm 块里回显出图开关的生效值与来源,面板无需单独调 `/draw` 就能读到当前状态。
|
|
264
|
+
- **`lifecycle.js` 的 `registerDrawTool` 改读生效值**:不再直接读 `settings.drawEnabled`,而是「面板保存值 ?? 配置默认值」。工具的实际挂载/缺席发生在**下一个 Host 启动**时(agent tools 没有 unregister 语义),开关值本身是立即生效的。
|
|
265
|
+
- **测试**:`test/provider.test.mjs` 新增 draw-store 纯逻辑组(归一、读写、版本拒绝、损坏忽略、forget);`test/routes.test.mjs` 新增 R 组(8 项,覆盖 GET/POST/forget/跨域围栏/跨 remount 持久化/配置回退);`test/wiring.test.mjs` 路由计数从 5 更新为 6。
|
|
266
|
+
|
|
267
|
+
### 视频工具面板开关(videoEnabled):V2.0 单体系,异步任务制
|
|
268
|
+
|
|
269
|
+
与出图对称,新增可选的视频生成 agent 工具(默认关),接入全链路与出图共用同一套纪律:
|
|
270
|
+
|
|
271
|
+
- **面板新增「视频工具」卡片**(`client.js` 的 `VideoSwitch` 控件):与 `DrawSwitch` 共用同一私有 `ToolSwitch` 体,保证两个工具的降级阶梯与状态不可能分叉。勾选保存写入 `$DSH_HOME/state/<plugin>/video.json`,优先级:面板保存值 > `cordis.patch.yml` 的 `videoEnabled`。
|
|
272
|
+
- **新增 `POST /api/<name>/video` 路由**(`routes.js`):与 `/draw` 共用同一处理器 `registerToolSwitchRoute`,区别只在闭包捕获的 store 与请求体键名(`drawModelId` / `videoModelId`)——键名承重,写错会让两工具静默共用一个模型;`test/routes.test.mjs` 组 S 专门钉隔离。
|
|
273
|
+
- **Host 半边 `src/host/video.ts`(V2.0 单体系,不无脑移植上游)**:走 `POST {apiBase}/videos` 建任务 → 轮询 `{host}/agnesapi` → 取 `url` 的完整状态机;`VIDEO_MAX_POLLS = 1000` 防时钟不前进时空转;**刻意不设 30s 冷却门**(协议往返延迟已远宽于冷却窗口,且一次视频尝试分钟级、共用视频限频池)。`buildVideoBody` 对非法显式值**抛错而非夹取**(夹取帧数会静默改变视频时长,分钟级生成后才发现)。
|
|
274
|
+
- **只覆盖 V2.0 参数体系**(`width`/`height`/`num_frames`(须 8n+1)/`frame_rate`/`seed`/`negative_prompt`/`image`),与 2.5 系列(`mode`/`seconds`/`size`/`aspect_ratio`)互斥;`pickVideoModel` 只在 V2.0 家族选,2.5 进 `video25ModelIds` 单独上报面板说明,不进对话选择器。
|
|
275
|
+
- **快照新增视频键**:`llm.videoEnabled` / `videoSource` / `videoModel` / `videoCandidateCount` / `videoCandidateIds` / `video25ModelIds`;`progress: 0` 走 `parseVideoQuery` 直接 `Number()` 读取(不能用坚持正值的 `num()`,否则合法 0% 被读成缺失)。
|
|
276
|
+
- **配套配置**:`cordis.patch.yml` 新增 `videoEnabled` / `videoModelId` / `videoTimeoutMs`(≥30000) / `videoWidth`(1152) / `videoHeight`(768) / `videoNumFrames`(121) / `videoFrameRate`(24) 七项;`src/host/types.ts` 的 `HostDeps` 补 `videoFetch`。
|
|
277
|
+
- **文档**:`AGNES-API.md` §7.5 整段重写为 V2.0 请求体字段与校验规则;`API.md` 补快照视频键与 `/video` 路由;`SETUP.md` 补 7 个视频配置字段;`PROVIDER-HOT-RELOAD.md` 新增 §8;`ARCHITECTURE.md` §5.4 补「视频吸收」;`README.md` 补视频工具段;`PITFALLS.md` 新增 §29(两站凭据不互通)/ §30(视频异步任务制)/ §31(`progress:0` 不能用 `num()`)。
|
|
278
|
+
- **测试**:`test/video.test.mjs`(89 项,peer-free)覆盖 V2.0 请求体校验、V2.0+2.5 混合目录的候选过滤与自动选型、开关隔离;`test/routes.test.mjs` 组 S(10 项)覆盖视频开关读写、跨工具键名隔离、各自 store 隔离;`test/render.test.mjs` 组 G10 覆盖 `VideoSwitch` 渲染;`test/doctor.test.mjs` 覆盖 `video.json` 解析与隔离;`test/wiring.test.mjs` 路由计数 7 → 8。
|
|
279
|
+
|
|
280
|
+
### 面板视觉打磨
|
|
281
|
+
|
|
282
|
+
几处「不报错、但会误导或压平层级」的显示。
|
|
283
|
+
|
|
284
|
+
- **每模型消耗柱状图补图例**:柱子按「最高消耗者」归一化,top 模型永远填满轨道——它回答的是「谁在烧积分」,但满格会被误读成「这个模型快触顶」。卡片底部补一行说明「柱长按最高消耗相对显示,非占总额度比例」,图表不再靠省略说谎。
|
|
285
|
+
- **返赠余额从药丸改为指标数字**:`返赠余额 327,904` 此前裹在与「通用池/专属池」同款的圆角药丸里,一个大数字被压成和静态类型标签同等权重的装饰。改为卡头右侧的 tabular 数字,读作可花余额指标。
|
|
286
|
+
- **注册成功不再常驻绿色**:「已向 DSH 注册提供方…」是静止常态,长期亮 `state-success-primary` 会让人误以为刚发生了好事。收敛为中性次要文字,绿色只留给「已保存」这类瞬时反馈。
|
|
287
|
+
- **去掉最内层子卡的冗余边框**:section 卡→池卡→双子窗三层等宽 `border-l1` 互相抵消、压平层级。最内层子窗改为纯靠更深的背景面(layer-2)浮起,边框只留两层。
|
|
288
|
+
- **API Key 字段标题去重**:「模型接入(API Key)」区块头与卡内输入框标签原本同名重复,标签改为「API Key」。
|
|
289
|
+
- **品牌色锚定商汤紫**:去掉 shell 跟随层,3 个品牌强调点直接锚定 SenseNova 紫;活动 tab 与非活动 tab 使用同一套基础样式。
|
|
290
|
+
|
|
291
|
+
## [0.4.1] — 2026-09-29
|
|
292
|
+
|
|
293
|
+
面板前端修复:几处「看起来对、实际错」的显示,加两处让操作直接失效的 bug。
|
|
294
|
+
|
|
295
|
+
- **每周额度重置时间误显示为当天**:5 小时与每周两个窗口共用同一个时间格式化器,而它只吐 `HH:MM`——每周窗口的 `reset_at` 是几天后的绝对时刻,日期被吞掉,读作「重置 18:10」,像是当天 18 点发生。新增 `when()`:今天保持紧凑 `HH:MM`,跨天带 `MM-DD`。返赠到期一直用的是 `clockLong`(带日期),只有重置时间漏了。
|
|
296
|
+
- **模型选择器「全选」会清空已选模型**:`ModelPicker.bulk` 把 `{id, name, vision}` 行数组传给只接受字符串的 `allowListFor`,`rosterIds` 过滤后恒为空 → 无论点「全选」还是「全不选」都返回 `[HIDE_ALL_MODELS]`,保存即清空模型列表。逻辑提成纯函数 `bulkModelsIn`,调用点显式转 id。
|
|
297
|
+
- **选择器单个模型无法勾选**:`ModelRoster` 的 checkbox 只有 `checked` 没有 `onChange`,实际只读——配合上一条,整块选择器不可用。
|
|
298
|
+
- **轮询竞态**:前一轮请求未返回时定时器又触发一轮,慢的那次会后发先至、覆盖新数据,用量条肉眼可见地往回跳。每次 `load` 递增 generation,过期响应直接丢弃,并用 `AbortController` 取消被取代的请求(不只是忽略结果)。后台标签停掉轮询,切回时立即刷新一次。
|
|
299
|
+
- **控制台不可读时给出可行动的文案**:`console_error` 一直被挡在登录表单之外(`FORM_EXCLUDED_CODES`),但 `GUIDANCE_BY_CODE` 没有这个键,用户只看到裸错误串、暗示永久故障——现在提示「通常下一次自动刷新即可恢复」。HTTP 401/403 不再只显 `读取失败:HTTP 401`,改为按令牌失效处理并保持登录表单可达。
|
|
300
|
+
- **暗色主题状态色静默失效**:三处主题变量前缀写成 `--dsh-alias-*`(不存在的变量名),「已耗尽」红标与「已保存」绿字失效;官方 UI 一律 `--dsw-alias-*`。
|
|
301
|
+
- **可访问性**:错误类 7 处 `role="alert"`、状态类 5 处 `role="status"`(此前屏幕阅读器听不到任何失败原因);QuotaCard 的 `aria-valuenow` 与可见百分比统一为一位小数;模型搜索框补 `aria-label`;两处 tooltip 不再裸露 `{balance}` / `{selected}` 占位符。
|
|
302
|
+
|
|
303
|
+
## [0.4.0] — 2026-09-29
|
|
304
|
+
|
|
305
|
+
出图吸收(大统一 §5.4 接法 B):本插件可以给 agent 提供商汤出图能力了。
|
|
306
|
+
|
|
307
|
+
- **新增 agent 工具 `sensenova_draw_image`**(opt-in,配置 `drawEnabled: false` 默认关):POST `{apiBase}/images/generations`,鉴权用面板「模型接入」保存的 `SENSENOVA_API_KEY` 引用(每次调用现取,轮换 Key 无需重启)。
|
|
308
|
+
- **出图模型识别用结构化字段,不用名字正则**:从 catalog 的 `output_modalities` 判定(与 chat 清单的排除逻辑互为反向,两份清单不可能矛盾)。社区同类 `dsh-draw-router` 的名字正则会漏掉 `sensenova-u1.5-lite`,本实现不会(对照见 `docs/ARCHITECTURE.md` §5.4)。
|
|
309
|
+
- **429 分诊与失败冷却**:出图失败时区分「配额不足(别盲重试)」与「限频(等再试)」;失败后 30s 冷却,防止 agent 在耗尽的共享池上打转。
|
|
310
|
+
- **修复 429 误判纠正(chat 路径)**:peer 的 `classifyPiAiError` 先跑 `isQuotaExceededError`,命中面过宽——商汤限频 429 体里带 `rate budget` / `credits` 字眼时会被抢判成 `QUOTA`,导致本应退避重试的限频被按"配额耗尽"快速失败、且模型被面板静默下线(呈现"额度已用尽")。新增 `llm-error-fix.js`:在 `llm-adapter.js` 用 Proxy 包裹 `PiAiAdapter` 的流出口,把这类"误判的限频 QUOTA"在出流前纠正回 `RATE_LIMIT`(保留原 message),真配额耗尽与已限频原样放行。`test/error-fix.test.mjs`(24 项,peer-free)覆盖。详见 ROADMAP §3 的纠偏注记。
|
|
311
|
+
- **降级同型**:无 tools 服务的 Host、peer 加载失败、注册被拒——工具静默缺席,面板与 provider 不受影响;快照契约零改动(14 键不变)。
|
|
312
|
+
- 配套:`drawModelId`(首选模型)与 `drawTimeoutMs`(默认 120s)两个配置;`test/draw.test.mjs`(56 项,peer-free)。
|
|
313
|
+
|
|
314
|
+
## [0.3.4] — 2026-09-29
|
|
315
|
+
|
|
316
|
+
429 自愈与「清单自带识别」:Token Plan 池额度耗尽时,模型不再发出必失败的请求。
|
|
317
|
+
|
|
318
|
+
- **provider 级重试策略**(`llm-retry.js` → `resolveRetryPolicy` 显式配置):配额耗尽(`QUOTA`/`ACCOUNT_QUOTA`)**不重试、快速失败**;限频(`RATE_LIMIT`)按退避重试。候选路由在共享额度池上空转只会延长冷却窗口,故刻意不对配额做重试(对应上文「不做多 Key 池」)。
|
|
319
|
+
- **清单自带识别**:某模型所属额度池耗尽(`remaining <= 0`)时,该模型从 DSH 模型选择器移除(不再发出必 429 的请求);面板花名册则**保留**该模型并以 `available:false` / `quotaExhausted:true` 标记、灰色显示原因,用户可知「为什么这个模型不见了」。
|
|
320
|
+
- **额度跨越零点自动重注册**:快照用 `quotaSignature` 去抖,仅在额度状态变化时才触发一次 `publishProvider` 重建(受 `PiAiAdapter` 对 profiles Map 引用记忆化约束,这是唯一生效路径),无需重启 Host。
|
|
321
|
+
- **快照 `llm` 块新增** `quotaBlockedModelIds`;`models` 每行新增 `available` / `quotaExhausted` 字段,供面板渲染。
|
|
322
|
+
|
|
323
|
+
## [0.3.3] — 2026-09-29
|
|
324
|
+
|
|
325
|
+
**安全姿态收紧:控制台密码不再落盘**(破坏性改动——老用户升级后需重新登录一次的情况见下)。
|
|
326
|
+
|
|
327
|
+
- **密码默认不写入任何文件**:此前 `saveAccount` 会把面板输入的密码原样存进 DSH 凭据服务(`~/.dsh/.credentials.yaml`,owner-only 的明文 YAML)。本版改为只保存**账号 + access/refresh token**;密码仅在登录瞬间于内存中使用,用完即弃。
|
|
328
|
+
- **`SENSENOVA_PASSWORD` 环境变量是密码唯一的持久来源**(显式 opt-in):放在环境里,refresh_token 失效后可自动重登,与旧行为一致;不放,则 refresh 失效时面板要求重新输入一次(README「登录失败怎么办」早已承诺此路径)。
|
|
329
|
+
- **旧版残留自动清除**:凭据服务里已存的 `SENSENOVA_PASSWORD` 引用在首次接触时被移除(一次性清扫),明文密码不会继续留在磁盘上。
|
|
330
|
+
- 行为影响:**升级后若当前 refresh_token 仍有效,完全无感**(续期照常);仅在 refresh_token 已失效、且依赖"密码存在凭据服务里自动重登"的场景下,会多一次手动输入。
|
|
331
|
+
- `state().hasAccount` 语义微调:现在按"已保存的账号名"判定(不再要求密码可用),面板的「清除账号」入口在密码缺失时仍然可用。
|
|
332
|
+
|
|
333
|
+
## [0.3.2] — 2026-09-29
|
|
334
|
+
|
|
335
|
+
面板新增「模型允许清单」:可以**勾选具体哪些模型推送进 DSH 的模型列表**,不再只能全推或全不推。
|
|
336
|
+
|
|
337
|
+
- **面板新增模型选择器**(「模型接入(API Key)」区):列出本 Key 目录下每个模型(带名称与可看图标记),逐条勾选;支持搜索过滤、可见项全选/全取消、实时计数,编辑先落草稿,点保存才写入。
|
|
338
|
+
- **新增路由** `POST /api/<name>/models`(同源围栏 + body 上限 + 500 项上限,与账号/api-key/provider 路由同一信任形状):`POST { enabledModelIds: string[] }` 替换允许清单,**同一请求内**重新发布 provider,面板不用等下一次轮询。设计理由见 [docs/PROVIDER-HOT-RELOAD.md](docs/PROVIDER-HOT-RELOAD.md) §6。
|
|
339
|
+
- **清单语义**:`[]` = 不过滤,全部推送;非空 = 严格允许清单,只推列出的模型;`["__hide_all__"]` = 一个都不推送(表达「临时全部收起」,空数组已表示「未筛选」,需要独立写法)。
|
|
340
|
+
- **快照 `llm` 块新增两个字段**:`models`(整份可选目录:`id` / `name` / `vision`,**不受**过滤影响,面板据此画可勾选项)、`enabledModelIds`(当前生效的允许清单)。
|
|
341
|
+
- **`modelCount` / `visionCount` 改为按清单过滤后计数**——它们描述的是「实际注册了多少」,而不是目录有多大。0.3.1 及以前清单恒为空,数值不变。
|
|
342
|
+
- 清单存在与 catalog 同一份私有状态文件 `state/<name>/catalog.json` 的 `enabledModelIds` 字段(版本与原子写纪律不变),重启即恢复。
|
|
343
|
+
- `POST /api/<name>/api-key` 的 `forget` 语义不变,但它会连带清掉勾选记录:换一个 Key 就是一份新的、未勾选的目录。
|
|
344
|
+
- 补记:`package.json` 的 `version` 在 0.3.1 时漏改(一直是 0.3.0),本次一并补齐到 0.3.2。
|
|
345
|
+
|
|
346
|
+
## [0.3.1] — 2026-09-28
|
|
347
|
+
|
|
348
|
+
提供方注册开关热生效([docs/PROVIDER-HOT-RELOAD.md](docs/PROVIDER-HOT-RELOAD.md)):
|
|
349
|
+
|
|
350
|
+
- **面板新增真开关**:「模型接入(API Key)」区可直接勾选「向 DSH 注册 SenseNova 提供方」,保存到插件私有状态文件并在**同一请求内**重新发布 provider——立即生效,无需改配置、无需重启 Host。
|
|
351
|
+
- **新增路由** `GET/POST /api/<name>/provider`(同源围栏 + body 上限,与账号/api-key 路由同一信任形状):`POST { enabled: boolean }` 切换开关,GET 回显生效值、来源与注册状态。
|
|
352
|
+
- **优先级**:面板保存过的值 > `cordis.patch.yml` 的 `registerProvider`(后者降级为部署默认)。未触碰面板的部署行为与 0.3.0 完全一致。
|
|
353
|
+
- **快照 `llm` 块新增 `registerSource`**(`"panel"` / `"config"`);`registerProvider` 改为回显生效值。
|
|
354
|
+
- 开关状态存 `state/<name>/provider.json`(新模块 `provider-store.js`,版本化 + 原子写 + 损坏即读作未设置,与 `catalog-store`/`throttle-store` 同一完整性纪律)。
|
|
355
|
+
|
|
356
|
+
## [0.3.0] — 2026-09-28
|
|
357
|
+
|
|
358
|
+
第三步「一条龙」:本插件可**直接注册 SenseNova LLM provider**,不再需要手写 `llm-pi-ai` patch 行(opt-in,默认关闭)。
|
|
359
|
+
|
|
360
|
+
- **面板新增「模型接入(API Key)」区**:粘贴 `sk-` Key 即保存为 DSH 凭据服务引用 `SENSENOVA_API_KEY`(与手写 provider 读取同一引用名),支持显示/隐藏、保存、清除;环境变量 `SENSENOVA_API_KEY` 仍作兜底,清除面板引用不会动环境变量;任何接口响应只回「有无/来源」去密状态,不回显 Key。
|
|
361
|
+
- **新增配置 `registerProvider`(默认 `false`)**:开启后 Host 以 provider id `sensenova-token-plan` 直连 `apiBase`(默认 `https://token.sensenova.cn/v1`)注册 OpenAI 兼容适配器(`ctx.llm.registerAdapter` + `registerConfigurableProviders`),模型列表由 `/v1/models` catalog 自动构建并广播刷新;vision 模型自动带图片输入,无需手填 `imageModelIds`。
|
|
362
|
+
- **catalog 与模型勾选清单存插件私有状态文件** `$DSH_HOME/state/<name>/catalog.json`(原子写、损坏即忽略),不写 dsh 配置;重启后、首次轮询前即凭缓存完成注册。
|
|
363
|
+
- **快照新增 `llm` 块**:`hasApiKey` / `keySource` / `ephemeral` / `registerProvider` / `llmAvailable` / `providerRegistered` / `providerId` / `modelCount` / `visionCount`(成功响应顶层键 13 → 14)。
|
|
364
|
+
- **新增路由** `GET/POST /api/<name>/api-key`(同源围栏 + 4 KB body 上限,与账号路由一致)。
|
|
365
|
+
- 无 `llm` 服务或 peer 加载失败时面板与额度轮询照常工作,provider 静默缺席并在快照里带进去密错误原因。
|
|
366
|
+
- **peer 解析**:`@earendil-works/pi-ai` / `@deepseek-ai/dsh-llm` / `@deepseek-ai/dsh-llm-pi-ai` 进 `peerDependencies`。它们由 Host 发行,npm 装进 profile 的插件能顺着 `profiles/node_modules` 解析到;**开发期 symlink/junction 进 profile 的检出解析不到**(Node 会把链接解成 realpath),表现为面板一直说「provider 缺席」而离线套件全绿——修法与现象见 PITFALLS §16。
|
|
367
|
+
- e2e 现在会真开 `registerProvider` 并断言注册成功(含目录 / vision / 去密状态),并像离线套件一样从子进程环境里剥掉 `SENSENOVA_*`(PITFALLS §17)。
|
|
368
|
+
- Host 侧改动需**完全退出 DSH(含托盘)后重启**生效。
|
|
369
|
+
|
|
370
|
+
## [0.2.0] — 2026-09-28
|
|
371
|
+
|
|
372
|
+
文档与合规加固(无对外行为变化,纯质量与一致性工作):
|
|
373
|
+
|
|
374
|
+
- **文档职责归位**:根 `README.md` 从 ~243 行瘦身到 ~128 行,只留索引与快速上手;重复的「认证」章节、配置/节流/测试表格、文件表已删除或下沉。
|
|
375
|
+
- `docs/SETUP.md`:新增「环境隔离(web 优先,桌面端后置)」说明与「常见信号与处置」表。
|
|
376
|
+
- `docs/TESTING.md`:吸收原 README 独占的开发轶事(test:live 边界、读写隔离、凭据双钉、store 守卫),并补 `docs.test.mjs` 一行职责;测试套件说明由「九套件」更正为「十套件」。
|
|
377
|
+
- `docs/DSH-PLUGIN.md`:移除写死的测试计数,教学快照 caveat 与 `files` 数组同步到真实 `package.json`。
|
|
378
|
+
- `docs/ARCHITECTURE.md` / `docs/CONTRIBUTING.md`:把 host 外路径(`~/.dsh/profiles/desktop/cordis.patch.yml`)标注为「仓库外」,示例提交信息改为中文。
|
|
379
|
+
- **文档一致性门禁**(新增 `test/docs.test.mjs`,已纳入 `npm test` 十套件与 CI):内部链接可解析、同一张表格不跨文件重复、根 README 行数上限、DSH-PLUGIN 教学快照与 `package.json` 同步、`API.md` 快照示例与声明契约键集一致。
|
|
380
|
+
- **许可证与第三方合规**:新增 `LICENSE`(MIT,Copyright (c) 2026 eghrhegpe)与 `THIRD_PARTY_NOTICES.md`(致谢 dsh-connect-qoder 文档范式、connect 家族设计对齐、上游接口参考实现);二者进入 `files` 打包清单。
|
|
381
|
+
- **上游关系澄清**:各文档补 `shaobingtongzhi/sensenova-usage-dashboard` GitHub 参考链接;如实记录本地 `upstream/` 副本当前不含 `.git`(设计态为独立仓库,恢复命令见 `docs/ARCHITECTURE.md` §1)。
|
|
382
|
+
- **首次发布 npm**:`dsh-connect-sensenova-token-plan@0.2.0`(无 scope、公开);`package.json` 移除 `private: true` 并补 `repository` 字段指回 GitHub 仓,市场列表可自动关联下载量。
|
|
383
|
+
|
|
384
|
+
## [0.1.x] 及之前 — 未发布
|
|
385
|
+
|
|
386
|
+
早期提交(最新见 `git log`,本机无 git tag):实现 OIDC+PKCE 登录、密码 JWE 封包、`refresh_token` 静默续期、登录节流分类、双窗口(5h/7d)用量面板、趋势与返赠明细、视觉第二步 opt-in 写入本插件 settings。具体条目以提交历史为准,本文件不再补列。
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 eghrhegpe
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# dsh-connect-agnes-token-plan
|
|
2
|
+
|
|
3
|
+
Agnes 接入的 DSH **Plugins 页**插件卡**全家桶**(四个 tab):① **积分额度** tab——登录一次 Agnes 控制台,实时查看四类额度窗口与账号累计用量,令牌失效自动重登,之后无需再管;② **接入 API** tab——把 Agnes 模型注册为 DSH provider,参与对话与出图;③ **小浣熊** tab(可选、默认关)——微信扫码接入第二个上游 `xiaohuanxiong.com`;④ **AgnesCode** tab(可选、默认关)——读取本机 AgnesCode 桌面端登录态接入第三个上游。三条上游凭据相互独立。此外 429 自愈在后台生效:限频被误判为"额度耗尽"时在 Host 侧纠正回退避重试,模型不会无端消失。
|
|
4
|
+
|
|
5
|
+
## 功能
|
|
6
|
+
|
|
7
|
+
Agnes 的 Token Plan **按窗口限流**,不是积分余额——账号级四个维度各有上限,用超了只能等窗口滚过:
|
|
8
|
+
|
|
9
|
+
| 维度 | 上限字段 | 窗口 |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| 模型请求 | `concurrency_limit` | `concurrency_window_h`(各档均为 5 小时) |
|
|
12
|
+
| 每周请求 | `text_weekly_limit` | 168 小时 |
|
|
13
|
+
| 生图 | `image_daily_limit` | 24 小时 |
|
|
14
|
+
| 视频 | `video_daily_limit` | 24 小时 |
|
|
15
|
+
|
|
16
|
+
这个面板把数字搬进 DSH 的 Plugins 页,写代码时不用切网页就能盯住:
|
|
17
|
+
|
|
18
|
+
- **额度上限**:四个窗口的上限与周期(平台只给上限,不给窗口内已用量——面板**不替平台做减法**,理由见下)
|
|
19
|
+
- **账号累计用量**:控制台口径的累计请求 / 文本 Token / 生图 / 视频秒数 / 活跃天数,以及近 N 天的分桶柱图
|
|
20
|
+
- **套餐对比**:平台**公开**的套餐目录(六档:入门版 / 专业版 / 高级版 × 月付 / 年付),无需登录即可读,用来回答"升级能买到什么"
|
|
21
|
+
- **模型清单**:当前 Key 实际能调哪些模型,其中哪些能看图(按平台 `input_modalities` 判定,不靠名字猜)
|
|
22
|
+
- **可选接入**:把 Agnes 模型接进 DSH 对话,思考强度可选;并可注册出图 / 视频工具
|
|
23
|
+
- **第二个上游(默认关)**:面板「小浣熊」tab 微信扫码接入 `xiaohuanxiong.com`,独立凭据、独立 provider,与 Token Plan 互不干涉
|
|
24
|
+
- **第三个上游(默认关)**:面板「AgnesCode」tab 读取本机 AgnesCode 桌面端的登录态,独立 provider 与独立积分池
|
|
25
|
+
|
|
26
|
+
面板**不代你操作账务**:不改套餐、不代扣额度、不碰 Key 明文;数据来自 Agnes 控制台自己的 API,与网页控制台口径一致。真正会「动」的四部分——注册 provider、挂出图工具、接第二个上游、接 AgnesCode——全部 opt-in 且**默认关闭**,不打开时插件退化为纯信息展示。
|
|
27
|
+
|
|
28
|
+
**注册 provider 时**(面板开关打开),插件把 Agnes 模型接进 DSH 的对话模型选择器,并在 Host 侧纠正 peer 对限频 429 的误判(Agnes 把速率上限错命名为 `quota_exceeded_error`,会被判成额度耗尽而不重试)——限频真正退避重试,模型不再无端 "消失"。
|
|
29
|
+
|
|
30
|
+
## 安装
|
|
31
|
+
|
|
32
|
+
1. 在 DSH「插件」页搜索 `dsh-connect-agnes-token-plan` 点击安装,或运行:
|
|
33
|
+
|
|
34
|
+
```powershell
|
|
35
|
+
dsh plugin --profile web add dsh-connect-agnes-token-plan # Web 端
|
|
36
|
+
dsh plugin --profile desktop add dsh-connect-agnes-token-plan # 桌面端
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
2. **完全退出 DSH(含托盘)再启动**。
|
|
40
|
+
|
|
41
|
+
## 快速开始
|
|
42
|
+
|
|
43
|
+
1. 打开 DSH 的 **Plugins 页**,找到 `dsh-connect-agnes-token-plan` 的插件卡(面板是页内的内联卡片,**不在侧边栏**)。
|
|
44
|
+
2. 在「积分额度」tab 点「连接 Agnes 控制台」,填一次账号和密码,点登录。
|
|
45
|
+
3. 之后令牌失效会自动重登(Agnes 不发 refresh token,续期的唯一路径就是重登一次),无需再操作。
|
|
46
|
+
|
|
47
|
+
登录失败时表单会直接显示 Agnes 返回的原因;密码错误属于**凭据型拒绝**,面板**绝不自动重试**(Agnes 有失败次数锁定),只有你主动点「登录」才会再发一次。想清除账号,用面板底部的按钮。
|
|
48
|
+
|
|
49
|
+
## 它是怎么工作的
|
|
50
|
+
|
|
51
|
+
登录原理一句话:Host 在后台向 `{consoleBase}/api/user/login` 发**一次**账号密码 POST 换取 access token(Agnes 没有 OIDC 跳转、没有 refresh token),令牌过期或被拒时用同一路径**重登一次**;面板打开时才轮询一个只读本地路由,关掉即停。协议细节(一跳登录、密码明文过 TLS 与「不落盘」纪律、防锁号节流)见 [docs/AUTH.md](docs/AUTH.md),接口契约见 [docs/AGNES-API.md](docs/AGNES-API.md)。
|
|
52
|
+
|
|
53
|
+
**为什么不显示「剩余」**:Agnes 控制台只提供**累计**用量(`/api/usage/overview`)与**分桶**用量(`/api/usage/series`),滚动窗口内的已用量拿不到。`上限 − 累计` 是个跨周期的减法,算出来的数没人能负责,所以面板把「上限」与「累计」作为两个独立事实并排显示,并明说它们不可相减。
|
|
54
|
+
|
|
55
|
+
## 把 Agnes 模型接进 DSH(可选)
|
|
56
|
+
|
|
57
|
+
「接入 API」tab 的三张卡按"你为什么来这"排序,而不是按依赖排序:**语言模型**(注册 provider + 勾选推送哪些模型)、**出图工具**——两张都在最前且默认展开;**API Key** 收在最后(默认收起),它是前两张卡的前置条件,由它们指回来。
|
|
58
|
+
|
|
59
|
+
在「API Key」卡里粘贴 API Key 保存(免费版 `sk-` 或 Token Plan `cpk-` 皆可):Host 即以 `agnes-token-plan` 之名注册 OpenAI 兼容 provider,模型列表随 `/v1/models` 自动刷新、可看图模型自动带图片输入,还能在「语言模型」卡勾选具体要推送哪些模型。Key 只进 DSH 凭据(引用名 `AGNES_TOKEN_PLAN_API_KEY`)、面板永不回显。开关与勾选都在面板热生效,无需重启。细节见 [docs/SETUP.md](docs/SETUP.md) §3 与 [docs/PROVIDER-HOT-RELOAD.md](docs/PROVIDER-HOT-RELOAD.md)。
|
|
60
|
+
|
|
61
|
+
> **免费版与付费 Token Plan 共用同一个 API Key 输入框**:免费版发的 `sk-` 密钥只能调免费全模态模型;付费 Token Plan 发的 `cpk-` 密钥消耗四窗口额度(即「积分额度」tab 读到的上限)。两者都能在此粘贴,本插件不做前缀限制。
|
|
62
|
+
|
|
63
|
+
## 出图工具(可选,默认关)
|
|
64
|
+
|
|
65
|
+
面板「出图工具」卡(在「语言模型」下方,默认展开)打开开关后,Host 给 agent 注册工具 `agnes_draw_image`(首选模型由 `drawModelId` 指定),鉴权走同一把 `AGNES_TOKEN_PLAN_API_KEY`。出图模型优先按 catalog 的 `output_modalities` 结构化判定,该字段缺失时退回模型名里的 `image` 段(Agnes 网关不返回这个字段,名字兜底才是实际命中的路径)。注意:工具的实际挂载 / 缺席发生在**下一次 Host 启动**(agent tools 没有 unregister 语义),开关值本身立即生效。
|
|
66
|
+
|
|
67
|
+
## 视频工具(可选,默认关)
|
|
68
|
+
|
|
69
|
+
面板「视频工具」卡(在「出图工具」下方,默认展开)打开开关后,Host 给 agent 注册工具 `agnes_video_generate`(首选模型由 `videoModelId` 指定),鉴权同样走 `AGNES_TOKEN_PLAN_API_KEY`。与出图**不同**的是协议:图片一次请求同步返回,视频是**异步任务制**——建任务后轮询到完成。**V2.0 与 2.5 两个参数体系都覆盖**,工具按选中模型分派请求体:V2.0(`agnes-video-v2.0`)走 `width`/`height`/`num_frames`/`frame_rate`,2.5(`agnes-video-2.5` / `agnes-video-2.5-flash`)走 `mode`/`seconds`/`size`/`aspect_ratio`。两套字段互斥、永不同时发给同一模型,但处理是**不对称**的:V2.0 帧数字段发到 2.5 模型会被换算成最接近的整秒(`121 @ 24fps → 5s`),保留「不判断家族也能出片」的退路;反过来,2.5 专有字段发到 V2.0 模型会**当场报错并给出修法**——工具不会静默丢弃,丢弃等于让你以为拿到 10 秒 2K、实际拿到 5 秒 720P。自动选择优先 V2.0,目录里没有 V2.0 时回落第一个 2.5 模型;面板仍会把 2.5 家族单独点名。协议细节与校验规则见 [docs/AGNES-API.md](docs/AGNES-API.md) §7.5。
|
|
70
|
+
|
|
71
|
+
## 第二个上游:小浣熊(可选,默认关)
|
|
72
|
+
|
|
73
|
+
面板「小浣熊」tab 用微信扫码登录 `xiaohuanxiong.com`,并以 provider id `sensenova-raccoon`(显示名 SenseNova Raccoon)注册**独立** provider。登录后显示积分余额与模型清单,每个模型带**上下文窗口 / 最大输出**与积分倍率(`free` / `×0.75` 这类,由网关目录声明;目录没给就不显示,不猜)。它与 Token Plan 同属**商汤(SenseTime)旗下**的两条产品线,所以放在同一个插件里顺理成章;但两者的**认证域与额度口径互不相通**(那边是独立积分余额,这边是四个限流窗口),凭据也各走一套——它不是 Token Plan 的第二条登录路径,实测依据见 [docs/ROADMAP.md](docs/ROADMAP.md) §6.1.1。
|
|
74
|
+
|
|
75
|
+
## 第三个上游:AgnesCode(可选,默认关)
|
|
76
|
+
|
|
77
|
+
面板「AgnesCode」tab 接的是 **AgnesCode 桌面端**的登录态:微信扫码发生在桌面 App 里,本插件只**读取** App 留在本机的加密会话文件(Chromium os_crypt,密钥经系统 DPAPI 解封,全程内存使用、不落盘不显示;解出的凭据随后存入 DSH 凭据服务,与账号密码同一纪律),并以 provider id `sensenova-agnescode`(显示名 SenseNova AgnesCode)注册**独立** provider。它的接口地址写在会话文件里、**按账号跟随**(钉死在 Agnes 域名族内,地址不对就拒绝使用);显示的积分是**订阅池**口径(时效 + 永久),模型清单带「会员」标记(会员门槛是账号状态,不是模型不存在,所以标记而不隐藏)。检测不到登录态时,面板逐条列出**探测过哪些文件、各自为什么没成**——「没装 App」「解不开密」「会话里没有令牌」是三种不同的处理方式,不会笼统叫你重新登录。JWT 有效期约 28 天,过期后开一次桌面 App 再点「检测本机登录态」即可;协议探针记录见 [docs/ROADMAP.md](docs/ROADMAP.md) §6.3。
|
|
78
|
+
|
|
79
|
+
## 运维诊断:这台机器现在挂没挂 provider?
|
|
80
|
+
|
|
81
|
+
provider / 出图开关的生效值存在插件私有状态文件里(`$DSH_HOME/state/<name>/`),不在任何配置或路由上——查"到底开没开"用 doctor,它只读状态文件、不碰凭据,Host 没起也能跑:
|
|
82
|
+
|
|
83
|
+
```powershell
|
|
84
|
+
npm run doctor # 人读:每个 profile 的 provider / draw / video / raccoon / agnescode 开关与模型清单
|
|
85
|
+
npm run doctor:json # 机器读:JSON(可进你的巡检 / 工单脚本)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 文档
|
|
89
|
+
|
|
90
|
+
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) — 架构与数据流
|
|
91
|
+
- [docs/SETUP.md](docs/SETUP.md) — 配置字段、改动后重启、常见信号
|
|
92
|
+
- [docs/AUTH.md](docs/AUTH.md) — 登录 / 重登 / 节流设计
|
|
93
|
+
- [docs/API.md](docs/API.md) — 路由与控制台端点
|
|
94
|
+
- [docs/AGNES-API.md](docs/AGNES-API.md) — Agnes 接口全集(控制台额度侧 + 推理侧)
|
|
95
|
+
- [docs/TESTING.md](docs/TESTING.md) — 测试体系
|
|
96
|
+
- [docs/PITFALLS.md](docs/PITFALLS.md) — 真实踩坑(31 条)
|
|
97
|
+
- [CHANGELOG.md](CHANGELOG.md) — 版本变化
|
|
98
|
+
|
|
99
|
+
AI 协作会话请先读 [AGENTS.md](AGENTS.md)。
|
|
100
|
+
|
|
101
|
+
## 诚实声明
|
|
102
|
+
|
|
103
|
+
- 面板显示的是**控制台自己的口径**,与网页控制台一致;`GET /v1/models` 只区分权限,不计费也不占推理额度;
|
|
104
|
+
- 窗口内的「已用量」平台不提供,所以面板**不显示「剩余」**——上限与累计是两个不同周期的独立事实;
|
|
105
|
+
- 令牌被拒时面板明确提示重新登录,而不是静默显示旧数据;
|
|
106
|
+
- 凭据(账号、access token)只经 DSH 凭据服务保存,**密码不落盘**;本插件不写任何明文凭据文件或调试日志。
|
|
107
|
+
|
|
108
|
+
## 许可证
|
|
109
|
+
|
|
110
|
+
MIT License(Copyright (c) 2026 eghrhegpe),全文见 [LICENSE](LICENSE);第三方依赖与合规说明见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# 第三方致谢与合规(Third-Party Notices)
|
|
2
|
+
|
|
3
|
+
## 致谢
|
|
4
|
+
|
|
5
|
+
- **文档范式**:参照本地 `~/.dsh/fork/dsh-connect-qoder` 的 README——「这是一个 DSH 插件、如何被加载、bundle 结构」的完整讲述方式(见 `docs/DSH-PLUGIN.md`);
|
|
6
|
+
- **架构对齐**:provider settings 设计对齐 DSH connect 家族(`dsh-connect-trae` / `dsh-connect-workbuddy` / `llm-qoder`,`imageModelIds` 等见 `docs/ARCHITECTURE.md` §5.1);
|
|
7
|
+
- **接口参考实现**:`upstream/`——[shaobingtongzhi/sensenova-usage-dashboard](https://github.com/shaobingtongzhi/sensenova-usage-dashboard)(Python 桌面工具),是 `.gitignore` 忽略、不随本仓库提交的本地容纳目录;本插件构建期与运行期均不依赖它、不进包,仅本地对照(见 `docs/ARCHITECTURE.md` §1)。其算法细节(登录 OIDC 流、密码 JWE 封包、用量接口解析)已被吸收进 `docs/SENSENOVA-API.md` 与本插件的 Node 实现。
|
|
8
|
+
|
|
9
|
+
以上均为**设计 / 文档 / 接口层面的参照,无代码复制**,不构成许可证约束下的再分发。
|
|
10
|
+
|
|
11
|
+
## 随包第三方依赖
|
|
12
|
+
|
|
13
|
+
`package.json` 的 `files` 打包清单(由 `test/package.test.mjs` 的 import 闭包检查钉住)**不包含任何第三方代码**:
|
|
14
|
+
|
|
15
|
+
- `peerDependencies`(`react`、`@deepseek-ai/dsh`、`@deepseek-ai/dsh-credentials`)由 DSH Host 运行时在运行期提供,不随本插件安装或打包(见 `docs/DSH-PLUGIN.md` §2);测试基建 `test/peer-roots.mjs` 就地解析它们,不引入新依赖;
|
|
16
|
+
- `react` 为 MIT 许可;`@deepseek-ai/*` 属 DSH 运行时发行物,其许可证以 DSH 官方发行版为准;
|
|
17
|
+
- `LICENSE` 与本文随包携带,但均为本项目自身文档。
|
|
18
|
+
|
|
19
|
+
引入新的第三方外部依赖或复用其他项目代码时,请同步更新本文件并遵守对应许可证要求。
|
|
20
|
+
|
|
21
|
+
## 许可证
|
|
22
|
+
|
|
23
|
+
本项目采用 MIT 许可证,版权归属:Copyright (c) 2026 eghrhegpe。全文见 [LICENSE](./LICENSE)。
|