dsh-connect-agnes-token-plan 0.9.0 → 0.10.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 +16 -0
- package/README.md +56 -45
- package/assets/panel-AgnesCode.png +0 -0
- package/client.js +140 -32
- package/lib/{agnescode-llm-adapter-BrButArh.js → agnescode-llm-adapter-j7S1OMDU.js} +2 -2
- package/lib/{agnescode-models-DBsK6xeK.js → agnescode-models-BMNUJaIy.js} +61 -13
- package/lib/index.js +27 -7
- package/lib/{llm-adapter-D2Igtn0s.js → llm-adapter-iKICEhY6.js} +1 -1
- package/lib/{llm-models-CLnHQAqK.js → llm-models-Bep2p7Tp.js} +22 -1
- package/package.json +1 -1
- package/screenshots.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
本文件只记**公开行为变化**(新增能力、破坏性改动、重要修复)。实现细节、重构与测试加固请直接看 `git log`。
|
|
4
4
|
|
|
5
|
+
## [0.10.0] — 2026-10-04
|
|
6
|
+
|
|
7
|
+
### AgnesCode 目录改读 `/v2/models`:模型名带上平台真实的积分倍率与促销标
|
|
8
|
+
|
|
9
|
+
- **目录端点从 `/v1/models` 换到 `{origin}/v2/models`**:两者是同一 host 上的**两条不同目录**,不是同一份数据——v1 只有 8 行且**不带任何按模型价格**,v2 有 9 行且其中 8 行带平台自己的 `points_cost_multiplier`。桌面端一直读 v2,这就是它的选择器能显示 `1.20x` / `1.85x` 而本插件此前什么都不显示的原因。此前的结论「AgnesCode 不存在按模型倍率」**是错的**,根因是端点选错(详见 `docs/ROADMAP.md` §6.3.1「倍率字段正记」)。
|
|
10
|
+
- **模型显示名带上倍率 `Name · xNN.NN`**:pi-ai 的 descriptor 没有承载计费的字段(`cost` 是每 token 美元,本网关是积分制),所以倍率走**显示名**——这是 DSH 选择器唯一会渲染的表面。拼写沿用兄弟插件 `dsh-connect-sensenova-token-plan` 与 WorkBuddy 自有选择器既有的 `· x` 形态,**不引入第二套约定**。
|
|
11
|
+
- **`0` 是已公布的价格(免费),不是缺失读数**:`×0.00` 与「未声明」是两件事,前者照常显示、后者才不画。为此新增 `numZeroOk()`——仓库既有的 `num()` / `numOrNull()` 都以 `> 0` 为准,直接复用会把「免费」静默变成「没读到」。
|
|
12
|
+
- **面板花名册新增促销标芯片**(`display_label`,如 `限时七折`):用桌面端同款蓝底配色,与中性灰底的「会员」徽章刻意区分——一个是**平台定价事实**,一个是**账号状态**。平台在**每一行**都放这个键、未促销的值为空串,因此判据是「非空才画」,而不是「键存在就画」。
|
|
13
|
+
- **`auto` 行排除**:v2 多出的 `auto` 是路由别名而非模型(无价格、无厂商),按 id 显式排除;判据不取「没有倍率」,以免平台给它定价后它悄悄回到花名册。
|
|
14
|
+
- **会员门槛字段随端点迁移**(`is_member_only` 布尔 → `allowed_subscription` 列表):映射规则为「列表非空即会员」,已对 v1 逐行核对 **8/8 一致**,属**重新编码**而非重新解释。
|
|
15
|
+
- **修:改价不触发重注册**(`catalogSignature` 现纳入倍率)。签名原先只编码 `id:vision`,而倍率已进显示名——`glm-5.2` 从 `1.85` 改到 `9.99` 时签名**完全相同**,选择器会一直显示旧倍率。平台在促销边界上确实会改价(`glm-5.2` 当前带 `限时七折`),所以这是会真实发生的路径。**操作者手填的伪倍率仍不触发重注册**(它在签名之后才挂上),原裁定不变。
|
|
16
|
+
- **修:AgnesCode tab 在文档隐藏时停止轮询**(与 `PanelPage` 对齐),不再在后台空转。
|
|
17
|
+
- **修:`render.test.mjs` 的午夜 flake**:`now + 1h` 在 23:00 之后跨到次日,而断言仍要求「同日」的裸时钟——每天 23:00–00:00 之间该门禁固定转红 1 项。改为按构造恒为当天的时刻。详见 `docs/PITFALLS.md` §48(与 §41「护栏的存活守卫自己漏了平台假设」同族,这次漏的是**时间**假设)。
|
|
18
|
+
- **文档**:`docs/AGNES-API.md` §7.3 记入「单次 chat 请求图像上限 4 张」的 400 实测(官方文档未公示该上限);`docs/PITFALLS.md` 新增 §48(午夜 flake)与 §49(`num()` 把「免费」塌成「未声明」)。
|
|
19
|
+
- 影响面:`src/host/{agnescode.ts, agnescode-models.ts, provider-publish.ts, util.ts, routes/agnescode.ts}`、`src/client/{agnescode-tab.ts, wire.ts, styles.ts, i18n.ts}`、`test/{agnescode, publish-core, render, live-agnescode}`、`docs/{ROADMAP, AGNES-API, PITFALLS, TESTING}`。
|
|
20
|
+
|
|
5
21
|
## [0.9.0] — 2026-10-03
|
|
6
22
|
|
|
7
23
|
### UI:开关统一为项目品牌色,积分额度拆成三张卡片
|
package/README.md
CHANGED
|
@@ -1,77 +1,89 @@
|
|
|
1
1
|
# dsh-connect-agnes-token-plan
|
|
2
2
|
|
|
3
|
-
Agnes
|
|
3
|
+
把 Agnes 接进 DSH 的 **Plugins 页**插件卡。**DSH** 即 **DeepSeek Harness**;**Agnes** 是商汤科技的模型平台(本插件对接其控制台 API 与推理 API)。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> **第一次读这个仓库?先看这三句。**
|
|
6
|
+
>
|
|
7
|
+
> 1. **这是给 DeepSeek Harness 用的插件**,不是独立应用;所有入口都在 DSH 的 Plugins 页那张卡上(三个 tab,见下)。
|
|
8
|
+
> 2. **三种「红」是正常的,不是回归**:① `store/routes/wiring.test.mjs` 等 peer 套件报 `cannot resolve the peer dependency` —— 那是 DSH runtime 自带的包不在本仓库,属环境问题,先查 `test/peer-roots.mjs`;② 没装 `dsh` CLI 时 e2e 会 SKIP,属预期;③ 若在 **23:00–00:00** 之间单独跑 `render.test.mjs` 报红,那是历史上的午夜窗口缺陷(已修,见 [docs/PITFALLS.md](docs/PITFALLS.md) §48),升级到含该修复的版本即消失。
|
|
9
|
+
> 3. **见到「奇怪」的写法先别定罪**——本仓多数刻意的取舍都在 [docs/PITFALLS.md](docs/PITFALLS.md) / [docs/ADR.md](docs/ADR.md) 有明文出处。**动手前先 grep 一遍 docs/**。
|
|
10
|
+
>
|
|
11
|
+
> 协作会话的完整纪律见 [AGENTS.md](AGENTS.md)。
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
- **积分额度**——登录一次,实时查看积分余额、额度窗口与每模型消耗,令牌自动续期,之后无需再管;
|
|
14
|
+
- **接入 API**——把爱思模型注册为 DSH provider,参与对话、出图与出视频;
|
|
15
|
+
- **Agnescode**——上游限流较宽松的另一条爱思办公产品线,独立账号、独立积分。
|
|
8
16
|
|
|
9
|
-
|
|
10
|
-
|---|---|---|
|
|
11
|
-
| 模型请求 | `concurrency_limit` | `concurrency_window_h`(各档均为 5 小时) |
|
|
12
|
-
| 每周请求 | `text_weekly_limit` | 168 小时 |
|
|
13
|
-
| 生图 | `image_daily_limit` | 24 小时 |
|
|
14
|
-
| 视频 | `video_daily_limit` | 24 小时 |
|
|
17
|
+
面板分三个 tab,按「先看数、再接入、最后可选加桌面端上游」排序:
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
## 积分额度
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
将 Agnes 的 Token Plan 接入dsh,,用超了只能等窗口重置。这个 tab 把数字搬进 DSH,写代码时不用切网页就能盯住:
|
|
22
|
+
|
|
23
|
+
- **额度窗口**:模型请求(5 小时滚动)、每周请求、生图与视频(各 24 小时),**平台报出已用量**、独立滚动,(含百分比与重置时间)
|
|
19
24
|
- **账号累计用量**:控制台口径的累计请求 / 文本 Token / 生图 / 视频秒数 / 活跃天数,以及近 N 天的分桶柱图
|
|
20
|
-
-
|
|
21
|
-
- **模型清单**:当前 Key 实际能调哪些模型,其中哪些能看图(按平台 `input_modalities` 判定,不靠名字猜)
|
|
22
|
-
- **可选接入**:把 Agnes 模型接进 DSH 对话,思考强度可选;并可注册出图 / 视频工具
|
|
23
|
-
- **桌面端上游(默认关)**:面板「AgnesCode」tab 读取本机 AgnesCode 桌面端的登录态,独立 provider 与独立积分池
|
|
25
|
+
- **套餐对比**:平台**公开**的套餐目录(六档),无需登录即可读,用来回答"升级能买到什么"
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+

|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
首次使用在「连接 Agnes 控制台」填一次账号和密码(Agnes 不发 refresh token,续期就是自动重登一次)。登录失败时表单会直接显示 Agnes 返回的原因;密码错误属于**凭据型拒绝**,面板**绝不自动重试**(Agnes 有失败次数锁定)。想清除账号,用面板底部的按钮。
|
|
28
30
|
|
|
29
|
-
##
|
|
31
|
+
## 接入 API(可选)
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
把 Agnes 模型注册为 DSH provider,参与对话与出图。
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
- **模型清单**:在「API Key」卡粘贴 Key 保存`AGNES_TOKEN_PLAN_API_KEY`,Host 以 `agnes-token-plan` 之名注册 OpenAI 兼容 provider,模型列表随 `/v1/models` 自动刷新;
|
|
36
|
+
- **语言模型**:显示当前 Key 实际能调哪些模型,其中哪些能看图(按平台 `input_modalities` 判定,不靠名字猜)。
|
|
37
|
+
- **出图工具**:Host 给 agent 注册 `agnes_draw_image` ,出图模型按 catalog 的 `output_modalities` 结构化判定。
|
|
38
|
+
- **视频工具**:Host 给 agent 注册 `agnes_video_generate`,按选中模型分派 V2.0 / 2.5 两套互斥参数。
|
|
39
|
+
- 开关与勾选都在面板热生效,无需重启。但工具的实际挂载 / 缺席发生在**下一次 Host 启动**(agent tools 没有 unregister 语义)。细节见 [docs/SETUP.md](docs/SETUP.md) §3、[docs/PROVIDER-HOT-RELOAD.md](docs/PROVIDER-HOT-RELOAD.md) 与 [docs/AGNES-API.md](docs/AGNES-API.md) §7.5。
|
|
37
40
|
|
|
38
|
-
|
|
41
|
+

|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
注意:`sk-` 走 API 按量计费,`cpk-` 走订阅配额(本 tab 只读订阅配额),两类 Key 有独立限制池,需从官网了解实际限制。
|
|
41
44
|
|
|
42
|
-
##
|
|
45
|
+
## AgnesCode(可选,默认关)
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
2. 在「积分额度」tab 点「连接 Agnes 控制台」,填一次账号和密码,点登录。
|
|
46
|
-
3. 之后令牌失效会自动重登(Agnes 不发 refresh token,续期的唯一路径就是重登一次),无需再操作。
|
|
47
|
+
**读取 AgnesCode 桌面端** 留在本机的加密会话文件,获取登录态,再以 provider id `agnescode` 注册**独立** provider、独立积分池——两条上游凭据互不相通:
|
|
47
48
|
|
|
48
|
-
登录失败时表单会直接显示 Agnes 返回的原因;密码错误属于**凭据型拒绝**,面板**绝不自动重试**(Agnes 有失败次数锁定),只有你主动点「登录」才会再发一次。想清除账号,用面板底部的按钮。
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
1. **接口地址**:写在会话文件里、**按账号跟随**,钉死在 Agnes 域名族内,地址不对就拒绝使用;
|
|
51
|
+
2. **显示口径**:积分是**订阅池**(时效 + 永久);模型清单带「会员」标记而不隐藏——会员门槛是账号状态,不是模型不存在;
|
|
52
|
+
3. **约 28 天续期一次**:JWT 过期后没有自动路径,开一次桌面 App、再点「检测本机登录态」重新采集即可。
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
协议探针记录见 [docs/ROADMAP.md](docs/ROADMAP.md) §6.3。
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+

|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
注意:检测不到登录态时,面板会逐条列出探测过哪些文件、各自为什么没成(「没装 App」「解不开密」「会话里没有令牌」是三种不同的处理);
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
## 边界
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
- 面板**不代你操作账务**——不改套餐、不代扣额度、不碰 Key 明文;数据来自 Agnes 控制台自己的 API,与网页控制台口径一致。
|
|
63
|
+
- 注册 provider、挂出图工具、挂视频工具、接桌面端上游,全部 opt-in 且**默认关闭**;一个都不打开时,插件退化为纯信息展示。
|
|
61
64
|
|
|
62
|
-
|
|
65
|
+
## 安装
|
|
63
66
|
|
|
64
|
-
|
|
67
|
+
1. 在 DSH「插件」页搜索 `dsh-connect-agnes-token-plan` 点击安装,或运行:
|
|
68
|
+
|
|
69
|
+
```powershell
|
|
70
|
+
dsh plugin --profile web add dsh-connect-agnes-token-plan # Web 端
|
|
71
|
+
dsh plugin --profile desktop add dsh-connect-agnes-token-plan # 桌面端
|
|
72
|
+
```
|
|
65
73
|
|
|
66
|
-
|
|
74
|
+
2. **完全退出 DSH(含托盘)再启动**。
|
|
67
75
|
|
|
68
|
-
|
|
76
|
+
3. 打开 DSH 的 **Plugins 页**,找到 `dsh-connect-agnes-token-plan` 的插件卡(面板是页内的内联卡片,**不在侧边栏**)。
|
|
69
77
|
|
|
70
|
-
|
|
78
|
+
> 装到的是哪一版由源决定:安装器会询问 profile 配的 registry,**默认含 `registry.npmmirror.com`,刚发布的版本在镜像上可能延迟几分钟**,官方源立即可用;要确认拿到了哪一版,对照 `npm view dsh-connect-agnes-token-plan version --registry=https://registry.npmjs.org`。三种 target 形态(npm 包名 / git 地址 / 本地路径)见 [docs/SETUP.md](docs/SETUP.md)。
|
|
79
|
+
|
|
80
|
+
## 它是怎么工作的
|
|
71
81
|
|
|
72
|
-
|
|
82
|
+
登录原理:
|
|
83
|
+
- Host 在后台向 `{consoleBase}/api/user/login` 发**一次**账号密码 POST 换取 access token(Agnes 没有 OIDC 跳转、没有 refresh token),令牌过期或被拒时用同一路径**重登一次**;
|
|
84
|
+
- `/api/cn/user/subscription` 直接返回每个窗口的 `used` / `limit` / `reset_at` / `usage_pct`(控制台「当前用量」那一屏的数据源),面板逐字转写、不做减法。下方的「账号累计用量」统计同理,
|
|
85
|
+
- 面板打开时才轮询一个只读本地路由,关掉即停。协议细节(一跳登录、密码明文过 TLS 与「不落盘」纪律、防锁号节流)见 [docs/AUTH.md](docs/AUTH.md),接口契约见 [docs/AGNES-API.md](docs/AGNES-API.md)。
|
|
73
86
|
|
|
74
|
-
面板「AgnesCode」tab 接的是 **AgnesCode 桌面端**的登录态:微信扫码发生在桌面 App 里,本插件只**读取** App 留在本机的加密会话文件(Chromium os_crypt,密钥经系统 DPAPI 解封,全程内存使用、不落盘不显示;解出的凭据随后存入 DSH 凭据服务,与账号密码同一纪律),并以 provider id `agnescode`(显示名 AgnesCode)注册**独立** provider。它的接口地址写在会话文件里、**按账号跟随**(钉死在 Agnes 域名族内,地址不对就拒绝使用);显示的积分是**订阅池**口径(时效 + 永久),模型清单带「会员」标记(会员门槛是账号状态,不是模型不存在,所以标记而不隐藏)。检测不到登录态时,面板逐条列出**探测过哪些文件、各自为什么没成**——「没装 App」「解不开密」「会话里没有令牌」是三种不同的处理方式,不会笼统叫你重新登录。JWT 有效期约 28 天,过期后开一次桌面 App 再点「检测本机登录态」即可;协议探针记录见 [docs/ROADMAP.md](docs/ROADMAP.md) §6.3。
|
|
75
87
|
|
|
76
88
|
## 运维诊断:这台机器现在挂没挂 provider?
|
|
77
89
|
|
|
@@ -90,7 +102,7 @@ npm run doctor:json # 机器读:JSON(可进你的巡检 / 工单脚本
|
|
|
90
102
|
- [docs/API.md](docs/API.md) — 路由与控制台端点
|
|
91
103
|
- [docs/AGNES-API.md](docs/AGNES-API.md) — Agnes 接口全集(控制台额度侧 + 推理侧)
|
|
92
104
|
- [docs/TESTING.md](docs/TESTING.md) — 测试体系
|
|
93
|
-
- [docs/PITFALLS.md](docs/PITFALLS.md) — 真实踩坑(
|
|
105
|
+
- [docs/PITFALLS.md](docs/PITFALLS.md) — 真实踩坑(49 条)
|
|
94
106
|
- [CHANGELOG.md](CHANGELOG.md) — 版本变化
|
|
95
107
|
|
|
96
108
|
AI 协作会话请先读 [AGENTS.md](AGENTS.md)。
|
|
@@ -98,7 +110,6 @@ AI 协作会话请先读 [AGENTS.md](AGENTS.md)。
|
|
|
98
110
|
## 诚实声明
|
|
99
111
|
|
|
100
112
|
- 面板显示的是**控制台自己的口径**,与网页控制台一致;`GET /v1/models` 只区分权限,不计费也不占推理额度;
|
|
101
|
-
- 窗口卡片里的「已用」是控制台报出的「当前用量」,面板逐字转写、不做减法;下方「账号累计」覆盖的是另一段时间,不能与窗口上限相减;
|
|
102
113
|
- 令牌被拒时面板明确提示重新登录,而不是静默显示旧数据;
|
|
103
114
|
- 凭据(账号、access token)只经 DSH 凭据服务保存,**密码不落盘**;本插件不写任何明文凭据文件或调试日志。
|
|
104
115
|
|
|
Binary file
|
package/client.js
CHANGED
|
@@ -38,6 +38,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
38
38
|
"panel.refresh": "刷新",
|
|
39
39
|
"panel.updated": "更新于 {time}",
|
|
40
40
|
"panel.loading": "加载中…",
|
|
41
|
+
"panel.refreshing": "刷新中…",
|
|
41
42
|
"panel.error": "读取失败:{error}",
|
|
42
43
|
"panel.jwtMissing": "还没有配置控制台账号。",
|
|
43
44
|
"panel.jwtExpired": "控制台令牌已失效。Agnes 不发放 refresh 令牌,Host 会用已保存的账号重新登录一次;若仍失败,请手动重新登录。",
|
|
@@ -88,6 +89,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
88
89
|
"quota.cycle.yearly": "按年",
|
|
89
90
|
"quota.unit.requests": "次",
|
|
90
91
|
"quota.unit.images": "张",
|
|
92
|
+
"quota.unit.seconds": "秒",
|
|
91
93
|
"quota.used": "已用",
|
|
92
94
|
"quota.resetAt": "重置 {time}",
|
|
93
95
|
"quota.resetCountdown": "约 {minutes} 分钟后重置",
|
|
@@ -102,7 +104,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
102
104
|
"quota.total.requests": "模型请求",
|
|
103
105
|
"quota.total.tokens": "文本 Token",
|
|
104
106
|
"quota.total.images": "生图",
|
|
105
|
-
"quota.total.video": "
|
|
107
|
+
"quota.total.video": "视频",
|
|
106
108
|
"quota.total.activeDays": "活跃天数",
|
|
107
109
|
"quota.usageMissing": "{label}:暂未读到。",
|
|
108
110
|
"usage.none": "该区间内没有用量记录。",
|
|
@@ -225,6 +227,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
225
227
|
"agnescode.balancePermanentLabel": "永久",
|
|
226
228
|
"agnescode.models": "模型({count})",
|
|
227
229
|
"agnescode.memberOnly": "会员",
|
|
230
|
+
"agnescode.rateTitle": "平台公布的积分消耗倍率(0 为免费)",
|
|
228
231
|
"agnescode.registeredPill": "已注册",
|
|
229
232
|
"agnescode.rosterHint": "勾选决定哪些模型推送进 DSH 模型列表,改动即时生效。",
|
|
230
233
|
"agnescode.rosterSave": "保存",
|
|
@@ -256,6 +259,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
256
259
|
"panel.refresh": "Refresh",
|
|
257
260
|
"panel.updated": "Updated {time}",
|
|
258
261
|
"panel.loading": "Loading…",
|
|
262
|
+
"panel.refreshing": "Refreshing…",
|
|
259
263
|
"panel.error": "Could not read: {error}",
|
|
260
264
|
"panel.jwtMissing": "No Agnes console account is configured yet.",
|
|
261
265
|
"panel.jwtExpired": "The console token is no longer valid. Agnes issues no refresh token, so the Host signs in again with the saved account; if that also fails, sign in manually.",
|
|
@@ -306,6 +310,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
306
310
|
"quota.cycle.yearly": "yearly",
|
|
307
311
|
"quota.unit.requests": " times",
|
|
308
312
|
"quota.unit.images": " images",
|
|
313
|
+
"quota.unit.seconds": " s",
|
|
309
314
|
"quota.used": "Used",
|
|
310
315
|
"quota.resetAt": "resets {time}",
|
|
311
316
|
"quota.resetCountdown": "resets in ~{minutes} min",
|
|
@@ -320,7 +325,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
320
325
|
"quota.total.requests": "Model requests",
|
|
321
326
|
"quota.total.tokens": "Text tokens",
|
|
322
327
|
"quota.total.images": "Images",
|
|
323
|
-
"quota.total.video": "Video
|
|
328
|
+
"quota.total.video": "Video",
|
|
324
329
|
"quota.total.activeDays": "Active days",
|
|
325
330
|
"quota.usageMissing": "{label}: not read yet.",
|
|
326
331
|
"usage.none": "No usage recorded in this range.",
|
|
@@ -443,6 +448,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
443
448
|
"agnescode.balancePermanentLabel": "Permanent",
|
|
444
449
|
"agnescode.models": "Models ({count})",
|
|
445
450
|
"agnescode.memberOnly": "member",
|
|
451
|
+
"agnescode.rateTitle": "Credit multiplier as published by the platform (0 = free)",
|
|
446
452
|
"agnescode.registeredPill": "Registered",
|
|
447
453
|
"agnescode.rosterHint": "Ticking decides which models are pushed into DSH's model list; the change takes effect immediately.",
|
|
448
454
|
"agnescode.rosterSave": "Save",
|
|
@@ -544,11 +550,14 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
544
550
|
* decimal 128 000. A flat /1000 rounding once printed "1049k" for the 1M
|
|
545
551
|
* window and it read like a placeholder bug; so figures divisible by 1000 keep
|
|
546
552
|
* the decimal reading they were written with, binary-only figures (262144 →
|
|
547
|
-
* 256K, 65536 → 64K) get the binary one,
|
|
553
|
+
* 256K, 65536 → 64K) get the binary one, anything ≥ 1M goes to M and anything
|
|
554
|
+
* ≥ 1G goes to G — the account-lifetime token total (billions) must not print
|
|
555
|
+
* as a four-digit "5214M".
|
|
548
556
|
*/
|
|
549
557
|
function tokenSize(value) {
|
|
550
558
|
const number = typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : 0;
|
|
551
559
|
if (number <= 0) return "";
|
|
560
|
+
if (number >= 1e9) return `${Math.round(number / 1e8) / 10}G`;
|
|
552
561
|
if (number >= 1e6) return `${Math.round(number / 1e5) / 10}M`;
|
|
553
562
|
if (number % 1e3 === 0) return `${number / 1e3}K`;
|
|
554
563
|
if (number % 1024 === 0) return `${number / 1024}K`;
|
|
@@ -983,8 +992,8 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
983
992
|
color: "var(--dsw-alias-label-secondary)"
|
|
984
993
|
},
|
|
985
994
|
quotaRemaining: {
|
|
986
|
-
fontSize:
|
|
987
|
-
lineHeight: "
|
|
995
|
+
fontSize: 17,
|
|
996
|
+
lineHeight: "22px",
|
|
988
997
|
fontWeight: 650,
|
|
989
998
|
letterSpacing: "-0.02em",
|
|
990
999
|
fontVariantNumeric: "tabular-nums"
|
|
@@ -1306,6 +1315,14 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
1306
1315
|
background: "var(--dsw-alias-bg-layer-2)",
|
|
1307
1316
|
color: "var(--dsw-alias-label-secondary)"
|
|
1308
1317
|
},
|
|
1318
|
+
modelPromo: {
|
|
1319
|
+
flex: "none",
|
|
1320
|
+
fontSize: 11,
|
|
1321
|
+
padding: "1px 7px",
|
|
1322
|
+
borderRadius: 999,
|
|
1323
|
+
background: "#D1DDFC",
|
|
1324
|
+
color: "#003DD9"
|
|
1325
|
+
},
|
|
1309
1326
|
modelMeta: {
|
|
1310
1327
|
paddingLeft: 25,
|
|
1311
1328
|
fontSize: 11,
|
|
@@ -1323,6 +1340,12 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
1323
1340
|
borderRadius: 12,
|
|
1324
1341
|
background: "var(--dsw-alias-bg-layer-1)",
|
|
1325
1342
|
padding: "12px 14px"
|
|
1343
|
+
},
|
|
1344
|
+
diagRow: {
|
|
1345
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
1346
|
+
fontSize: 11,
|
|
1347
|
+
lineHeight: "16px",
|
|
1348
|
+
marginBottom: 2
|
|
1326
1349
|
}
|
|
1327
1350
|
};
|
|
1328
1351
|
}));
|
|
@@ -1904,6 +1927,64 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
1904
1927
|
...labelStyle ?? {}
|
|
1905
1928
|
} }, label));
|
|
1906
1929
|
}
|
|
1930
|
+
/**
|
|
1931
|
+
* The drawn radio dot, same discipline as the pill switch above: a NATIVE
|
|
1932
|
+
* radio input (transparent but focusable — keyboard focus ring and screen
|
|
1933
|
+
* reader semantics stay free) over a drawn circle whose selected state is a
|
|
1934
|
+
* brand-colored ring + inner dot. The bare native circle read as unstyled
|
|
1935
|
+
* next to the drawn switch and checkboxes; this puts the three controls in
|
|
1936
|
+
* one visual language without reimplementing the widget.
|
|
1937
|
+
*
|
|
1938
|
+
* The drawn span is `pointerEvents: "none"` so clicks reach the input; the
|
|
1939
|
+
* input is on top so the browser's own focus ring draws around the dot.
|
|
1940
|
+
* Hook-free like `Switch` — the caller owns `checked`/`onChange`, and the
|
|
1941
|
+
* surrounding `<label>` (the roster row) is what makes it clickable.
|
|
1942
|
+
*/
|
|
1943
|
+
function Radio({ checked, disabled, onChange, name }) {
|
|
1944
|
+
const size = 16;
|
|
1945
|
+
return h("span", { style: {
|
|
1946
|
+
position: "relative",
|
|
1947
|
+
flex: "none",
|
|
1948
|
+
width: size,
|
|
1949
|
+
height: size,
|
|
1950
|
+
display: "inline-block"
|
|
1951
|
+
} }, h("input", {
|
|
1952
|
+
type: "radio",
|
|
1953
|
+
name,
|
|
1954
|
+
checked,
|
|
1955
|
+
disabled,
|
|
1956
|
+
onChange,
|
|
1957
|
+
style: {
|
|
1958
|
+
appearance: "none",
|
|
1959
|
+
WebkitAppearance: "none",
|
|
1960
|
+
position: "absolute",
|
|
1961
|
+
inset: 0,
|
|
1962
|
+
width: size,
|
|
1963
|
+
height: size,
|
|
1964
|
+
margin: 0,
|
|
1965
|
+
background: "transparent",
|
|
1966
|
+
border: "none",
|
|
1967
|
+
cursor: disabled ? "default" : "pointer"
|
|
1968
|
+
}
|
|
1969
|
+
}), h("span", { style: {
|
|
1970
|
+
position: "absolute",
|
|
1971
|
+
inset: 0,
|
|
1972
|
+
borderRadius: "50%",
|
|
1973
|
+
boxSizing: "border-box",
|
|
1974
|
+
border: `1px solid ${checked ? "var(--agnes-brand, #1E40AF)" : "var(--dsw-alias-border-l3)"}`,
|
|
1975
|
+
background: "var(--dsw-alias-bg-layer-2)",
|
|
1976
|
+
pointerEvents: "none",
|
|
1977
|
+
transition: "border-color 120ms ease"
|
|
1978
|
+
} }, checked ? h("span", { style: {
|
|
1979
|
+
position: "absolute",
|
|
1980
|
+
left: 3,
|
|
1981
|
+
top: 3,
|
|
1982
|
+
width: 8,
|
|
1983
|
+
height: 8,
|
|
1984
|
+
borderRadius: "50%",
|
|
1985
|
+
background: "var(--agnes-brand, #1E40AF)"
|
|
1986
|
+
} }) : null));
|
|
1987
|
+
}
|
|
1907
1988
|
var LABEL_STYLE, TRACK_STYLE, THUMB_COLOR;
|
|
1908
1989
|
var init_switch = __esmMin((() => {
|
|
1909
1990
|
init_runtime();
|
|
@@ -2160,13 +2241,11 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
2160
2241
|
flex: "1 1 auto",
|
|
2161
2242
|
minWidth: 0,
|
|
2162
2243
|
cursor: busy ? "default" : "pointer"
|
|
2163
|
-
} }, h(
|
|
2164
|
-
type: "radio",
|
|
2244
|
+
} }, h(Radio, {
|
|
2165
2245
|
name: radioName,
|
|
2166
2246
|
checked: preferred === null && enabled,
|
|
2167
2247
|
disabled: busy || !enabled,
|
|
2168
|
-
onChange: () => void saveModel(null)
|
|
2169
|
-
style: S.modelCheck
|
|
2248
|
+
onChange: () => void saveModel(null)
|
|
2170
2249
|
}), h("span", { style: S.modelName }, k("autoOption"))), h("span", { style: S.modelBadge }, effective !== "" ? `${k("badge")} · ${effective}` : `${k("badge")} · ${k("badgeNone")}`))), ...candidates.map((id) => h("li", {
|
|
2171
2250
|
style: enabled ? S.modelRow : {
|
|
2172
2251
|
...S.modelRow,
|
|
@@ -2180,13 +2259,11 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
2180
2259
|
flex: "1 1 auto",
|
|
2181
2260
|
minWidth: 0,
|
|
2182
2261
|
cursor: busy ? "default" : "pointer"
|
|
2183
|
-
} }, h(
|
|
2184
|
-
type: "radio",
|
|
2262
|
+
} }, h(Radio, {
|
|
2185
2263
|
name: radioName,
|
|
2186
2264
|
checked: preferred === id && enabled,
|
|
2187
2265
|
disabled: busy || !enabled,
|
|
2188
|
-
onChange: () => void saveModel(id)
|
|
2189
|
-
style: S.modelCheck
|
|
2266
|
+
onChange: () => void saveModel(id)
|
|
2190
2267
|
}), h("span", {
|
|
2191
2268
|
style: S.modelName,
|
|
2192
2269
|
title: id
|
|
@@ -2648,27 +2725,27 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
2648
2725
|
{
|
|
2649
2726
|
key: "requests",
|
|
2650
2727
|
label: tt("quota.total.requests"),
|
|
2651
|
-
value: source.totalRequests
|
|
2728
|
+
value: count(source.totalRequests)
|
|
2652
2729
|
},
|
|
2653
2730
|
{
|
|
2654
2731
|
key: "tokens",
|
|
2655
2732
|
label: tt("quota.total.tokens"),
|
|
2656
|
-
value: source.totalTokens
|
|
2733
|
+
value: tokenSize(source.totalTokens) || count(source.totalTokens)
|
|
2657
2734
|
},
|
|
2658
2735
|
{
|
|
2659
2736
|
key: "images",
|
|
2660
2737
|
label: tt("quota.total.images"),
|
|
2661
|
-
value: source.totalImages
|
|
2738
|
+
value: count(source.totalImages)
|
|
2662
2739
|
},
|
|
2663
2740
|
{
|
|
2664
2741
|
key: "video",
|
|
2665
2742
|
label: tt("quota.total.video"),
|
|
2666
|
-
value: source.totalVideoSeconds
|
|
2743
|
+
value: `${count(source.totalVideoSeconds)} ${tt("quota.unit.seconds")}`
|
|
2667
2744
|
},
|
|
2668
2745
|
...typeof source.activeDays === "number" ? [{
|
|
2669
2746
|
key: "days",
|
|
2670
2747
|
label: tt("quota.total.activeDays"),
|
|
2671
|
-
value: source.activeDays
|
|
2748
|
+
value: count(source.activeDays)
|
|
2672
2749
|
}] : []
|
|
2673
2750
|
];
|
|
2674
2751
|
return h("div", null, h("div", { style: {
|
|
@@ -2678,7 +2755,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
2678
2755
|
} }, label), h("div", { style: S.metricGrid }, cells.map((cell) => h("div", {
|
|
2679
2756
|
key: cell.key,
|
|
2680
2757
|
style: S.metric
|
|
2681
|
-
}, h("span", { style: S.metricLabel }, cell.label), h("span", { style: S.metricValue },
|
|
2758
|
+
}, h("span", { style: S.metricLabel }, cell.label), h("span", { style: S.metricValue }, cell.value)))));
|
|
2682
2759
|
}
|
|
2683
2760
|
/**
|
|
2684
2761
|
* Per-bucket consumption as a mini bar chart.
|
|
@@ -2871,15 +2948,36 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
2871
2948
|
}, []);
|
|
2872
2949
|
useEffect(() => {
|
|
2873
2950
|
alive.current = true;
|
|
2874
|
-
|
|
2875
|
-
const
|
|
2951
|
+
let timer = null;
|
|
2952
|
+
const run = () => {
|
|
2876
2953
|
if (alive.current) load();
|
|
2877
|
-
}
|
|
2954
|
+
};
|
|
2955
|
+
const start = () => {
|
|
2956
|
+
if (timer === null) timer = setInterval(run, AGNESCODE_POLL_MS);
|
|
2957
|
+
};
|
|
2958
|
+
const stop = () => {
|
|
2959
|
+
if (timer !== null) {
|
|
2960
|
+
clearInterval(timer);
|
|
2961
|
+
timer = null;
|
|
2962
|
+
}
|
|
2963
|
+
};
|
|
2964
|
+
load();
|
|
2965
|
+
start();
|
|
2966
|
+
const onVisibility = () => {
|
|
2967
|
+
if (!alive.current) return;
|
|
2968
|
+
if (document.visibilityState === "hidden") stop();
|
|
2969
|
+
else {
|
|
2970
|
+
run();
|
|
2971
|
+
start();
|
|
2972
|
+
}
|
|
2973
|
+
};
|
|
2974
|
+
if (typeof document !== "undefined" && typeof document.addEventListener === "function") document.addEventListener("visibilitychange", onVisibility);
|
|
2878
2975
|
return () => {
|
|
2879
2976
|
alive.current = false;
|
|
2880
2977
|
generation.current += 1;
|
|
2881
2978
|
inFlight.current?.abort?.();
|
|
2882
|
-
|
|
2979
|
+
stop();
|
|
2980
|
+
if (typeof document !== "undefined" && typeof document.removeEventListener === "function") document.removeEventListener("visibilitychange", onVisibility);
|
|
2883
2981
|
};
|
|
2884
2982
|
}, [load]);
|
|
2885
2983
|
useEffect(() => {
|
|
@@ -3023,8 +3121,8 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
3023
3121
|
}, attempts.map((attempt, index) => h("div", {
|
|
3024
3122
|
key: `${String(attempt?.file ?? index)}-${index}`,
|
|
3025
3123
|
role: "listitem",
|
|
3026
|
-
style:
|
|
3027
|
-
}, h("span", { style: { color: attempt?.tier === "ok" ? "inherit" : "var(--dsw-alias-
|
|
3124
|
+
style: S.diagRow
|
|
3125
|
+
}, h("span", { style: { color: attempt?.tier === "ok" ? "inherit" : "var(--dsw-alias-state-warn-primary)" } }, `[${tt(`agnescode.tier.${attempt?.tier}`)}] ${String(attempt?.file ?? "")}${attempt?.detail ? ` — ${attempt.detail}` : ""}`)))) : null, note !== null ? h("div", {
|
|
3028
3126
|
style: {
|
|
3029
3127
|
...S.formNote,
|
|
3030
3128
|
fontSize: 12,
|
|
@@ -3092,11 +3190,13 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
3092
3190
|
* the unlinked frame — a roster inlined there is unassertable. The row is the
|
|
3093
3191
|
* SAME two-line shape as the sibling rosters (head line over an indented
|
|
3094
3192
|
* parameter line), sharing `S.modelRow`'s contract — and, since the panel can
|
|
3095
|
-
* now curate this provider, the SAME checkbox.
|
|
3096
|
-
*
|
|
3097
|
-
*
|
|
3098
|
-
*
|
|
3099
|
-
*
|
|
3193
|
+
* now curate this provider, the SAME checkbox.
|
|
3194
|
+
*
|
|
3195
|
+
* The head line's tail carries three platform-declared facts, in this order:
|
|
3196
|
+
* a PROMOTION tag (`displayLabel`, tinted like the desktop App's own chip), the
|
|
3197
|
+
* credit rate (`multiplier`, as `×N`), and the gating badge (`memberOnly`).
|
|
3198
|
+
* All three come from the live `/v2/models` catalogue — none is inferred, and
|
|
3199
|
+
* an absent field draws nothing rather than a placeholder.
|
|
3100
3200
|
*
|
|
3101
3201
|
* The checkbox is hook-free like the sibling rows: `onToggle` is handed in, so
|
|
3102
3202
|
* without it the box is display-only and the roster cannot be edited at all.
|
|
@@ -3139,6 +3239,8 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
3139
3239
|
const label = String(row?.name ?? id);
|
|
3140
3240
|
const on = modelIsOn(enabledIds, id);
|
|
3141
3241
|
const meta = [typeof row?.contextWindow === "number" && row.contextWindow > 0 ? format(tt("llm.contextBadge"), { ctx: tokenSize(row.contextWindow) }) : null, typeof row?.maxOutputLength === "number" && row.maxOutputLength > 0 ? format(tt("llm.metaOutput"), { out: tokenSize(row.maxOutputLength) }) : null].filter(Boolean).join(" · ");
|
|
3242
|
+
const rate = typeof row?.multiplier === "number" ? row.multiplier : null;
|
|
3243
|
+
const promo = typeof row?.displayLabel === "string" && row.displayLabel !== "" ? row.displayLabel : null;
|
|
3142
3244
|
return h("li", {
|
|
3143
3245
|
key: id,
|
|
3144
3246
|
style: {
|
|
@@ -3162,7 +3264,10 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
3162
3264
|
}), h("span", {
|
|
3163
3265
|
style: S.modelName,
|
|
3164
3266
|
title: id
|
|
3165
|
-
}, label)), h("span", { style: S.spacer }),
|
|
3267
|
+
}, label)), h("span", { style: S.spacer }), promo === null ? null : h("span", { style: S.modelPromo }, promo), rate === null ? null : h("span", {
|
|
3268
|
+
style: S.modelRate,
|
|
3269
|
+
title: tt("agnescode.rateTitle")
|
|
3270
|
+
}, `×${rate}`), row.memberOnly === true ? h("span", { style: S.modelBadge }, tt("agnescode.memberOnly")) : null), meta === "" ? null : h("div", { style: S.modelMeta }, meta));
|
|
3166
3271
|
})));
|
|
3167
3272
|
}
|
|
3168
3273
|
/**
|
|
@@ -3330,6 +3435,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
3330
3435
|
const [data, setData] = useState(null);
|
|
3331
3436
|
const [error, setError] = useState(null);
|
|
3332
3437
|
const [loadedOnce, setLoadedOnce] = useState(false);
|
|
3438
|
+
const [refreshing, setRefreshing] = useState(false);
|
|
3333
3439
|
const [updatedAt, setUpdatedAt] = useState(0);
|
|
3334
3440
|
const [, setLocaleRevision] = useState(0);
|
|
3335
3441
|
const [openSections, setOpenSections] = useState({
|
|
@@ -3356,6 +3462,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
3356
3462
|
generation.current += 1;
|
|
3357
3463
|
const mine = generation.current;
|
|
3358
3464
|
const isCurrent = () => generation.current === mine;
|
|
3465
|
+
setRefreshing(true);
|
|
3359
3466
|
inFlight.current?.abort?.();
|
|
3360
3467
|
const controller = typeof AbortController === "function" ? new AbortController() : null;
|
|
3361
3468
|
inFlight.current = controller;
|
|
@@ -3396,6 +3503,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
3396
3503
|
setError(reason instanceof Error ? reason.message : String(reason));
|
|
3397
3504
|
} finally {
|
|
3398
3505
|
if (isCurrent()) setLoadedOnce(true);
|
|
3506
|
+
if (isCurrent()) setRefreshing(false);
|
|
3399
3507
|
if (inFlight.current === controller) inFlight.current = null;
|
|
3400
3508
|
}
|
|
3401
3509
|
}, []);
|
|
@@ -3636,7 +3744,7 @@ var dsh_connect_agnes_token_plan_client = (function() {
|
|
|
3636
3744
|
} : S.button,
|
|
3637
3745
|
disabled: refresh === null,
|
|
3638
3746
|
onClick: () => refresh?.()
|
|
3639
|
-
}, tt("panel.refresh")), onClose ? h("button", {
|
|
3747
|
+
}, refreshing && plan.refresh === "snapshot" ? tt("panel.refreshing") : tt("panel.refresh")), onClose ? h("button", {
|
|
3640
3748
|
type: "button",
|
|
3641
3749
|
style: S.button,
|
|
3642
3750
|
onClick: () => onClose()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as DEFAULT_REASONING_EFFORT, w as name } from "./llm-models-
|
|
2
|
-
import { i as buildAgnescodeDescriptors, n as AGNESCODE_PROVIDER_ID, r as agnescodeRoster, t as AGNESCODE_DISPLAY_NAME } from "./agnescode-models-
|
|
1
|
+
import { t as DEFAULT_REASONING_EFFORT, w as name } from "./llm-models-Bep2p7Tp.js";
|
|
2
|
+
import { i as buildAgnescodeDescriptors, n as AGNESCODE_PROVIDER_ID, r as agnescodeRoster, t as AGNESCODE_DISPLAY_NAME } from "./agnescode-models-BMNUJaIy.js";
|
|
3
3
|
import { i as buildRetryPolicyConfig, n as STREAM_IDLE_TIMEOUT_MS, r as createWrappedPiAiAdapter, t as REQUEST_IMAGE_BUDGETS } from "./pi-ai-adapter-core-BKmN5s11.js";
|
|
4
4
|
import { createProvider } from "@earendil-works/pi-ai";
|
|
5
5
|
import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as num,
|
|
1
|
+
import { A as obj, D as num, F as str, i as PROBED_VISION, k as numZeroOk, w as name } from "./llm-models-Bep2p7Tp.js";
|
|
2
2
|
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
@@ -896,6 +896,17 @@ const AGNESCODE_HARVEST_TIER = Object.freeze({
|
|
|
896
896
|
OK: "ok"
|
|
897
897
|
});
|
|
898
898
|
/**
|
|
899
|
+
* Catalogue rows that are NOT models and must never reach the roster.
|
|
900
|
+
*
|
|
901
|
+
* `/v2/models` adds an `auto` row that `/v1/models` does not have. It is a
|
|
902
|
+
* routing alias (no vendor, no `points_cost_multiplier`, and the only row the
|
|
903
|
+
* platform omits the price on), so offering it as a selectable model would put
|
|
904
|
+
* a non-model in the picker. Keyed by id on purpose: a rule tied to "has no
|
|
905
|
+
* multiplier" would silently start leaking `auto` back in the day the platform
|
|
906
|
+
* prices it.
|
|
907
|
+
*/
|
|
908
|
+
const AGNESCODE_CATALOGUE_EXCLUDED_IDS = Object.freeze(["auto"]);
|
|
909
|
+
/**
|
|
899
910
|
* Whether a BFF base may carry the account's Authorization header. Pinned to
|
|
900
911
|
* the Agnes origin family over https — see the module header. Anything else
|
|
901
912
|
* reads as `UNTRUSTED_BASE` and the harvest keeps walking.
|
|
@@ -965,9 +976,12 @@ function decodeAgnescodeJwtExpMs(token) {
|
|
|
965
976
|
}
|
|
966
977
|
}
|
|
967
978
|
/**
|
|
968
|
-
* The header set one AgnesCode BFF request carries. The catalogue headers
|
|
969
|
-
*
|
|
970
|
-
* header mirrors the desktop client.
|
|
979
|
+
* The header set one AgnesCode BFF request carries. The catalogue headers
|
|
980
|
+
* (`X-App-Id` / `X-Platform`) were probed REQUIRED on the catalogue endpoint
|
|
981
|
+
* and are harmless elsewhere; the language header mirrors the desktop client.
|
|
982
|
+
* The catalogue moved from `/v1/models` to `{origin}/v2/models` on 2026-10-04
|
|
983
|
+
* and the same header set answers 200 there (re-probed live, so this map did
|
|
984
|
+
* not need to change with the endpoint).
|
|
971
985
|
* @param {object} credential - `{ accessToken }`.
|
|
972
986
|
* @returns {object} the header map.
|
|
973
987
|
*/
|
|
@@ -1248,13 +1262,29 @@ async function harvestAgnescodeLocalSession(options = {}) {
|
|
|
1248
1262
|
* adapter falls back to the static roster on `null` (the `console-client`
|
|
1249
1263
|
* silent-fallback discipline).
|
|
1250
1264
|
*
|
|
1251
|
-
*
|
|
1252
|
-
*
|
|
1253
|
-
*
|
|
1254
|
-
*
|
|
1265
|
+
* **Endpoint: `/v2/models`, not `/v1/models`** (switched 2026-10-04). The two
|
|
1266
|
+
* are different directories on the same host, not the same data: v1 carries 8
|
|
1267
|
+
* rows and NO credit multiplier, v2 carries 9 rows and the platform's own
|
|
1268
|
+
* `points_cost_multiplier` on 8 of them (measured live, same token/headers;
|
|
1269
|
+
* see ROADMAP §6.3.1 「倍率字段正记」). The desktop App reads v2 — that is why
|
|
1270
|
+
* its picker shows `1.20x` / `1.85x` while this plugin showed nothing.
|
|
1271
|
+
*
|
|
1272
|
+
* The member fact MOVES FIELDS between the two: v1 declares
|
|
1273
|
+
* `is_member_only: bool`, v2 declares `allowed_subscription: string[]`. The
|
|
1274
|
+
* mapping `memberOnly = allowed_subscription.length > 0` was verified against
|
|
1275
|
+
* v1 across all 8 shared rows with zero mismatches — so this is a re-encoding,
|
|
1276
|
+
* not a reinterpretation.
|
|
1277
|
+
*
|
|
1278
|
+
* `auto` is DROPPED: it exists only in v2, is a routing alias rather than a
|
|
1279
|
+
* real model, and carries no multiplier. Dropping by explicit id (not by
|
|
1280
|
+
* "no multiplier") keeps the filter honest if the platform later prices it.
|
|
1281
|
+
*
|
|
1282
|
+
* The rows carry a per-model credit multiplier — a fact about billing, not
|
|
1283
|
+
* gating, so it is KEPT and travels to the panel and the descriptor's display
|
|
1284
|
+
* name (see `agnescodeToDescriptor`).
|
|
1255
1285
|
* @param {object} credential - `{ accessToken, bffBase }`.
|
|
1256
1286
|
* @param {typeof fetch} [fetcher] - injected fetch.
|
|
1257
|
-
* @returns {Promise<object[]|null>} `[{id, name, vision, memberOnly, contextWindow, maxOutputLength}]`, or `null`.
|
|
1287
|
+
* @returns {Promise<object[]|null>} `[{id, name, vision, memberOnly, multiplier, contextWindow, maxOutputLength}]`, or `null`.
|
|
1258
1288
|
*/
|
|
1259
1289
|
async function fetchAgnescodeCatalog(credential, fetcher) {
|
|
1260
1290
|
const effective = fetcher ?? globalThis.fetch;
|
|
@@ -1262,7 +1292,7 @@ async function fetchAgnescodeCatalog(credential, fetcher) {
|
|
|
1262
1292
|
const bffBase = trustAgnescodeBffBase(source.bffBase);
|
|
1263
1293
|
if (bffBase === null) return null;
|
|
1264
1294
|
try {
|
|
1265
|
-
const response = await effective(`${bffBase}/models`, {
|
|
1295
|
+
const response = await effective(`${agnescodeApiRoot(bffBase)}/v2/models`, {
|
|
1266
1296
|
headers: agnescodeHeaders(source),
|
|
1267
1297
|
signal: AbortSignal.timeout(3e4)
|
|
1268
1298
|
});
|
|
@@ -1275,13 +1305,19 @@ async function fetchAgnescodeCatalog(credential, fetcher) {
|
|
|
1275
1305
|
const model = obj(raw);
|
|
1276
1306
|
const id = str(model.id, "");
|
|
1277
1307
|
if (id === "" || seen.has(id)) continue;
|
|
1308
|
+
if (id === AGNESCODE_CATALOGUE_EXCLUDED_IDS[0]) continue;
|
|
1278
1309
|
if (str(model.model_type, "text") !== "text") continue;
|
|
1279
1310
|
seen.add(id);
|
|
1311
|
+
const allowed = Array.isArray(model.allowed_subscription) ? model.allowed_subscription : [];
|
|
1312
|
+
const multiplier = numZeroOk(model.points_cost_multiplier);
|
|
1313
|
+
const displayLabel = str(model.display_label, "");
|
|
1280
1314
|
out.push({
|
|
1281
1315
|
id,
|
|
1282
1316
|
name: str(model.name, id),
|
|
1283
1317
|
vision: false,
|
|
1284
|
-
memberOnly:
|
|
1318
|
+
memberOnly: allowed.length > 0,
|
|
1319
|
+
...multiplier === void 0 ? {} : { multiplier },
|
|
1320
|
+
...displayLabel === "" ? {} : { displayLabel },
|
|
1285
1321
|
contextWindow: num(model.max_input_tokens),
|
|
1286
1322
|
maxOutputLength: num(model.max_output_tokens)
|
|
1287
1323
|
});
|
|
@@ -1346,6 +1382,7 @@ const AGNESCODE_FALLBACK_MODELS = Object.freeze([
|
|
|
1346
1382
|
name: "Agnes 3.0 Flash",
|
|
1347
1383
|
memberOnly: false,
|
|
1348
1384
|
vision: false,
|
|
1385
|
+
multiplier: 0,
|
|
1349
1386
|
contextWindow: 512e3,
|
|
1350
1387
|
maxOutputLength: 65536
|
|
1351
1388
|
},
|
|
@@ -1354,6 +1391,7 @@ const AGNESCODE_FALLBACK_MODELS = Object.freeze([
|
|
|
1354
1391
|
name: "Agnes 2.5 Flash",
|
|
1355
1392
|
memberOnly: false,
|
|
1356
1393
|
vision: false,
|
|
1394
|
+
multiplier: 0,
|
|
1357
1395
|
contextWindow: 512e3,
|
|
1358
1396
|
maxOutputLength: 65536
|
|
1359
1397
|
},
|
|
@@ -1362,6 +1400,7 @@ const AGNESCODE_FALLBACK_MODELS = Object.freeze([
|
|
|
1362
1400
|
name: "Agnes 2.5 Pro",
|
|
1363
1401
|
memberOnly: false,
|
|
1364
1402
|
vision: false,
|
|
1403
|
+
multiplier: 1,
|
|
1365
1404
|
contextWindow: 512e3,
|
|
1366
1405
|
maxOutputLength: 65536
|
|
1367
1406
|
},
|
|
@@ -1370,6 +1409,7 @@ const AGNESCODE_FALLBACK_MODELS = Object.freeze([
|
|
|
1370
1409
|
name: "DeepSeek V4 Flash",
|
|
1371
1410
|
memberOnly: true,
|
|
1372
1411
|
vision: false,
|
|
1412
|
+
multiplier: 1.2,
|
|
1373
1413
|
contextWindow: 1e6,
|
|
1374
1414
|
maxOutputLength: 393216
|
|
1375
1415
|
},
|
|
@@ -1378,6 +1418,7 @@ const AGNESCODE_FALLBACK_MODELS = Object.freeze([
|
|
|
1378
1418
|
name: "Agnes 2.0 Flash",
|
|
1379
1419
|
memberOnly: false,
|
|
1380
1420
|
vision: false,
|
|
1421
|
+
multiplier: 0,
|
|
1381
1422
|
contextWindow: 512e3,
|
|
1382
1423
|
maxOutputLength: 65536
|
|
1383
1424
|
},
|
|
@@ -1386,6 +1427,8 @@ const AGNESCODE_FALLBACK_MODELS = Object.freeze([
|
|
|
1386
1427
|
name: "GLM-5.2",
|
|
1387
1428
|
memberOnly: true,
|
|
1388
1429
|
vision: false,
|
|
1430
|
+
multiplier: 1.85,
|
|
1431
|
+
displayLabel: "限时七折",
|
|
1389
1432
|
contextWindow: 1e6,
|
|
1390
1433
|
maxOutputLength: 131072
|
|
1391
1434
|
},
|
|
@@ -1394,6 +1437,7 @@ const AGNESCODE_FALLBACK_MODELS = Object.freeze([
|
|
|
1394
1437
|
name: "Kimi K3",
|
|
1395
1438
|
memberOnly: true,
|
|
1396
1439
|
vision: false,
|
|
1440
|
+
multiplier: 5.3,
|
|
1397
1441
|
contextWindow: 1048576,
|
|
1398
1442
|
maxOutputLength: 131072
|
|
1399
1443
|
},
|
|
@@ -1402,6 +1446,7 @@ const AGNESCODE_FALLBACK_MODELS = Object.freeze([
|
|
|
1402
1446
|
name: "DeepSeek V4 Pro",
|
|
1403
1447
|
memberOnly: true,
|
|
1404
1448
|
vision: false,
|
|
1449
|
+
multiplier: 1.5,
|
|
1405
1450
|
contextWindow: 1e6,
|
|
1406
1451
|
maxOutputLength: 393216
|
|
1407
1452
|
}
|
|
@@ -1513,12 +1558,13 @@ function agnescodeRoster(catalog) {
|
|
|
1513
1558
|
for (const row of rows) {
|
|
1514
1559
|
const id = str(row?.id, "");
|
|
1515
1560
|
if (id === "") continue;
|
|
1561
|
+
const multiplier = numZeroOk(row?.multiplier);
|
|
1516
1562
|
out.push({
|
|
1517
1563
|
id,
|
|
1518
1564
|
name: str(row?.name, id),
|
|
1519
1565
|
vision: agnescodeVisionOf(row),
|
|
1520
1566
|
memberOnly: row?.memberOnly === true,
|
|
1521
|
-
multiplier
|
|
1567
|
+
...multiplier === void 0 ? {} : { multiplier },
|
|
1522
1568
|
contextWindow: num(row?.contextWindow),
|
|
1523
1569
|
maxOutputLength: num(row?.maxOutputLength)
|
|
1524
1570
|
});
|
|
@@ -1582,9 +1628,11 @@ function agnescodeToDescriptor(row, options = {}) {
|
|
|
1582
1628
|
const bffBase = str(options.bffBase, "");
|
|
1583
1629
|
if (bffBase === "") throw new Error("agnescodeToDescriptor: a pinned bffBase is required");
|
|
1584
1630
|
const vision = agnescodeVisionOf(row);
|
|
1631
|
+
const multiplier = numZeroOk(row?.multiplier);
|
|
1632
|
+
const name = str(row?.name, id);
|
|
1585
1633
|
return {
|
|
1586
1634
|
id,
|
|
1587
|
-
name:
|
|
1635
|
+
name: multiplier === void 0 ? name : `${name} · x${multiplier.toFixed(2)}`,
|
|
1588
1636
|
api: "openai-completions",
|
|
1589
1637
|
provider: AGNESCODE_PROVIDER_ID,
|
|
1590
1638
|
baseUrl: bffBase,
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import { S as writeStateFile, _ as profileSegment, a as filterAgnescodeRows, b as stateDir, c as fetchAgnescodeBalance, d as trustAgnescodeBffBase, f as createFileCatalogStore, g as ensureStateDir, h as createStateReadCache, l as fetchAgnescodeCatalog, m as STATE_READ_TTL_MS, n as AGNESCODE_PROVIDER_ID, o as AGNESCODE_FALLBACK_MODELS, p as normalizeEnabledIds, s as decodeAgnescodeJwtExpMs, t as AGNESCODE_DISPLAY_NAME, u as harvestAgnescodeLocalSession, v as profileStateDir, x as temporaryOf, y as readStateJson } from "./agnescode-models-
|
|
1
|
+
import { A as obj, C as isAdmitted, D as num, E as resolveSettings, F as str, I as verbatim, M as redactError, N as redactSecrets, O as numOrNull, P as retryBounded, S as inject, T as resolveAuthOverrides, _ as parseUsageSeries, b as CONFIG_DEFAULTS, c as summarizeCatalog, d as isVideoGenModel, f as checkShape, g as parseUsageOverview, h as parseSubscriptionUsage, j as pluginError, k as numZeroOk, l as visionOf, m as parsePlans, n as LLM_DISPLAY_NAME, o as filterByEnabled, p as matchCurrentPlan, r as LLM_PROVIDER_ID, s as rosterWithAvailability, t as DEFAULT_REASONING_EFFORT, u as isImageGenModel, v as quotaWindows, w as name, x as hostName, y as readSubscriptionExpiry } from "./llm-models-Bep2p7Tp.js";
|
|
2
|
+
import { S as writeStateFile, _ as profileSegment, a as filterAgnescodeRows, b as stateDir, c as fetchAgnescodeBalance, d as trustAgnescodeBffBase, f as createFileCatalogStore, g as ensureStateDir, h as createStateReadCache, l as fetchAgnescodeCatalog, m as STATE_READ_TTL_MS, n as AGNESCODE_PROVIDER_ID, o as AGNESCODE_FALLBACK_MODELS, p as normalizeEnabledIds, s as decodeAgnescodeJwtExpMs, t as AGNESCODE_DISPLAY_NAME, u as harvestAgnescodeLocalSession, v as profileStateDir, x as temporaryOf, y as readStateJson } from "./agnescode-models-BMNUJaIy.js";
|
|
3
3
|
import { rm } from "node:fs/promises";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { homedir } from "node:os";
|
|
@@ -2848,7 +2848,7 @@ function createAgnescodePublisher(deps = {}) {
|
|
|
2848
2848
|
const { panelSwitch, resolveToken, getLlm, loadAdapterModule, emit, logger } = deps;
|
|
2849
2849
|
const effectivePanelSwitch = panelSwitch ?? (async () => null);
|
|
2850
2850
|
const effectiveResolveToken = resolveToken ?? (async () => "");
|
|
2851
|
-
const effectiveLoadAdapterModule = loadAdapterModule ?? (() => import("./agnescode-llm-adapter-
|
|
2851
|
+
const effectiveLoadAdapterModule = loadAdapterModule ?? (() => import("./agnescode-llm-adapter-j7S1OMDU.js"));
|
|
2852
2852
|
const effectiveGetLlm = getLlm ?? (() => null);
|
|
2853
2853
|
const effectiveEmit = emit ?? (() => {});
|
|
2854
2854
|
const effectiveLogger = logger ?? { warn: () => {} };
|
|
@@ -3092,7 +3092,7 @@ function wireAgnescodePublisher({ store, panelSwitch, enabledIds, getLlm, loadAd
|
|
|
3092
3092
|
panelSwitch: panelSwitch ?? (async () => null),
|
|
3093
3093
|
resolveToken,
|
|
3094
3094
|
getLlm,
|
|
3095
|
-
loadAdapterModule: loadAdapterModule ?? (() => import("./agnescode-llm-adapter-
|
|
3095
|
+
loadAdapterModule: loadAdapterModule ?? (() => import("./agnescode-llm-adapter-j7S1OMDU.js")),
|
|
3096
3096
|
emit: emit ?? (() => {}),
|
|
3097
3097
|
logger
|
|
3098
3098
|
});
|
|
@@ -3208,7 +3208,7 @@ function createProviderPublisher(deps = {}) {
|
|
|
3208
3208
|
const { settings, panelSwitch, loadAdapterModule, getLlm, resolveApiKey, emit, logger } = deps;
|
|
3209
3209
|
const effectiveSettings = settings ?? {};
|
|
3210
3210
|
const effectivePanelSwitch = panelSwitch ?? (async () => null);
|
|
3211
|
-
const effectiveLoadAdapterModule = loadAdapterModule ?? (() => import("./llm-adapter-
|
|
3211
|
+
const effectiveLoadAdapterModule = loadAdapterModule ?? (() => import("./llm-adapter-iKICEhY6.js"));
|
|
3212
3212
|
const effectiveGetLlm = getLlm ?? (() => null);
|
|
3213
3213
|
const effectiveResolveApiKey = resolveApiKey ?? (async () => "");
|
|
3214
3214
|
const effectiveEmit = emit ?? (() => {});
|
|
@@ -3394,12 +3394,32 @@ function seedPublisherFromCatalog(publisher, listCatalog, listEnabled, signature
|
|
|
3394
3394
|
* use (an id whose modality flipped must rebuild even though the id list did
|
|
3395
3395
|
* not change), plus the curated allow-list. Anything else changing in a
|
|
3396
3396
|
* catalog entry does not affect the registered offer.
|
|
3397
|
+
*
|
|
3398
|
+
* **The multiplier IS part of the offer** (since 2026-10-04): it rides in the
|
|
3399
|
+
* descriptor's display name (`Name · xNN.NN` — see `agnescodeToDescriptor`),
|
|
3400
|
+
* because pi-ai's descriptor has no billing channel for it. So a repriced model
|
|
3401
|
+
* must rebuild the registration, or the picker keeps showing a stale factor:
|
|
3402
|
+
* measured on this signature, `glm-5.2` moving 1.85 → 9.99 produced an
|
|
3403
|
+
* IDENTICAL `id:vision` string, so the old shape would have kept advertising
|
|
3404
|
+
* 1.85 forever. This matters because the platform reprices on promotion
|
|
3405
|
+
* boundaries (`glm-5.2` carries `display_label: "限时七折"`).
|
|
3406
|
+
*
|
|
3407
|
+
* Reading the multiplier from `entries` (the raw catalogue) deliberately does
|
|
3408
|
+
* NOT catch the Token Plan side's operator-configured pseudo multiplier: that
|
|
3409
|
+
* one is attached later, by `matchMultiplier`, to the rows the snapshot hands
|
|
3410
|
+
* the panel — never to `catalog`. Turning that knob still does not rebuild the
|
|
3411
|
+
* registration, which is the documented intent (IMPROVEMENTS.md §7).
|
|
3397
3412
|
* @param {object[]} entries - the normalized catalog entries.
|
|
3398
3413
|
* @param {string[]} enabledIds - the allow-list (empty = all).
|
|
3399
3414
|
* @returns {string}
|
|
3400
3415
|
*/
|
|
3401
3416
|
function catalogSignature(entries, enabledIds) {
|
|
3402
|
-
return `${(Array.isArray(entries) ? entries : []).map((entry) =>
|
|
3417
|
+
return `${(Array.isArray(entries) ? entries : []).map((entry) => {
|
|
3418
|
+
const id = str(entry?.id, "");
|
|
3419
|
+
const vision = visionOf(entry).vision === true ? 1 : 0;
|
|
3420
|
+
const multiplier = numZeroOk(entry?.multiplier);
|
|
3421
|
+
return `${id}:${vision}:${multiplier === void 0 ? "-" : multiplier}`;
|
|
3422
|
+
}).join(",")}|${(Array.isArray(enabledIds) ? enabledIds : []).join(",")}`;
|
|
3403
3423
|
}
|
|
3404
3424
|
|
|
3405
3425
|
//#endregion
|
|
@@ -7090,7 +7110,7 @@ function apply(ctx, config = {}, deps = {}) {
|
|
|
7090
7110
|
}
|
|
7091
7111
|
};
|
|
7092
7112
|
const emitAdaptersUpdate = () => emitAdaptersUpdated((event) => ctx.emit?.(event));
|
|
7093
|
-
const loadAdapterModule = deps.loadAdapterModule ?? (() => import("./llm-adapter-
|
|
7113
|
+
const loadAdapterModule = deps.loadAdapterModule ?? (() => import("./llm-adapter-iKICEhY6.js"));
|
|
7094
7114
|
const publisher = createProviderPublisher({
|
|
7095
7115
|
settings,
|
|
7096
7116
|
panelSwitch: () => providerStore.enabled().catch(() => null),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as buildDescriptors, n as LLM_DISPLAY_NAME, r as LLM_PROVIDER_ID, t as DEFAULT_REASONING_EFFORT, w as name } from "./llm-models-
|
|
1
|
+
import { a as buildDescriptors, n as LLM_DISPLAY_NAME, r as LLM_PROVIDER_ID, t as DEFAULT_REASONING_EFFORT, w as name } from "./llm-models-Bep2p7Tp.js";
|
|
2
2
|
import { i as buildRetryPolicyConfig, n as STREAM_IDLE_TIMEOUT_MS, r as createWrappedPiAiAdapter, t as REQUEST_IMAGE_BUDGETS } from "./pi-ai-adapter-core-BKmN5s11.js";
|
|
3
3
|
import { createProvider } from "@earendil-works/pi-ai";
|
|
4
4
|
import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
|
|
@@ -89,6 +89,27 @@ function numOrNull$1(value) {
|
|
|
89
89
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
92
|
+
* Read a finite number that may legitimately be ZERO, else `undefined`.
|
|
93
|
+
*
|
|
94
|
+
* `num()` and `numOrNull()` both reject `0` because for their callers a zero is
|
|
95
|
+
* a missing reading (a limit, a window, a count — none of which is honestly
|
|
96
|
+
* zero when the platform simply did not say). This reader exists for the
|
|
97
|
+
* opposite case, and the distinction is load-bearing at the call site: the
|
|
98
|
+
* platform's `points_cost_multiplier` uses `0` to mean "this model is free",
|
|
99
|
+
* which is a published PRICE, not a missing value. Routing it through `num()`
|
|
100
|
+
* would collapse "free" into "not stated" and the panel would then render
|
|
101
|
+
* nothing where it should render the free badge (the sibling SenseNova plugin
|
|
102
|
+
* renders this exact figure as `· x0.00`).
|
|
103
|
+
*
|
|
104
|
+
* So: absent / non-numeric / non-finite / negative → `undefined` (no claim);
|
|
105
|
+
* `0` → `0` (a claim of free).
|
|
106
|
+
* @param {unknown} value - the raw field.
|
|
107
|
+
* @returns {number|undefined} the finite non-negative number, or `undefined`.
|
|
108
|
+
*/
|
|
109
|
+
function numZeroOk(value) {
|
|
110
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
92
113
|
* Run one attempt loop inside a bounded window.
|
|
93
114
|
*
|
|
94
115
|
* The shared backoff shape for every "a service or a seed may be late" case
|
|
@@ -1781,4 +1802,4 @@ function summarizeCatalog(entries) {
|
|
|
1781
1802
|
}
|
|
1782
1803
|
|
|
1783
1804
|
//#endregion
|
|
1784
|
-
export {
|
|
1805
|
+
export { obj as A, isAdmitted as C, num as D, resolveSettings as E, str as F, verbatim as I, redactError as M, redactSecrets as N, numOrNull$1 as O, retryBounded as P, inject as S, resolveAuthOverrides as T, parseUsageSeries as _, buildDescriptors as a, CONFIG_DEFAULTS as b, summarizeCatalog as c, isVideoGenModel as d, checkShape as f, parseUsageOverview as g, parseSubscriptionUsage as h, PROBED_VISION as i, pluginError as j, numZeroOk as k, visionOf as l, parsePlans as m, LLM_DISPLAY_NAME as n, filterByEnabled as o, matchCurrentPlan as p, LLM_PROVIDER_ID as r, rosterWithAvailability as s, DEFAULT_REASONING_EFFORT as t, isImageGenModel as u, quotaWindows as v, name as w, hostName as x, readSubscriptionExpiry as y };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-connect-agnes-token-plan",
|
|
3
3
|
"displayName": "DSH Connect Agnes Token Plan",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.10.0",
|
|
5
5
|
"description": "Agnes connect bundle for the Harness Web UI: Token Plan quota panel (account-wide quota windows, cumulative usage, console sign-in) plus optional provider registration that brings Agnes models into DSH conversation, with host-side rate-limit self-healing.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"dsh-plugin",
|
package/screenshots.json
CHANGED