dsh-neartoken 0.0.0-stage → 0.4.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/README.md CHANGED
@@ -1,3 +1,123 @@
1
- # Temporary Holding Version
1
+ <p align="center">
2
+ <a href="https://dshfind.com/zh/plugins/huanlinoto/dsh-neartoken"><img src="https://dshfind.com/api/card/huanlinoto/dsh-neartoken?lang=zh" alt="dsh-neartoken card"></a>
3
+ </p>
4
+ # dsh-neartoken
2
5
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
6
+ 把 New API 站点(NearToken,`https://llm.pko.svcfusion.com`)变成 DSH 的模型供应商:**在设置页发起设备授权 → 用户在自己浏览器里登录站点并确认 → 插件自动接入 `neartoken` provider**。插件全程不接触密码。模型选择器再把这批模型按 New API 的渠道分组折成 **模型 → 分组 → 推理等级** 三级。
7
+
8
+ ## 架构
9
+
10
+ ```
11
+ ┌─ host 半边(src/index.ts + src/host/)────────────────────────────┐
12
+ │ NearTokenAccount(account.ts)+ DeviceAuthorizationClient │
13
+ │ · POST /api/dsh/device/authorize → 拿 device_code + user_code │
14
+ │ · 后台按 interval 轮询 POST /api/dsh/device/token │
15
+ │ authorization_pending / slow_down(+2s 退避) / access_denied / │
16
+ │ expired_token / granted │
17
+ │ · granted → 写 credentials 的 NEARTOKEN_API_KEY → 挂 provider │
18
+ │ routes.ts:webServer 同源路由(设置页调用) │
19
+ │ GET /neartoken/status POST /neartoken/authorize │
20
+ │ POST /neartoken/cancel POST /neartoken/logout │
21
+ │ GET /neartoken/models POST /neartoken/models(模型白名单) │
22
+ │ whitelist.ts:白名单读/写 │
23
+ │ · 存插件自身 Config 的 enabledModels(volatile),经 settings.update │
24
+ │ 写入 profile patch;volatile 使改动热提交、不重挂插件 │
25
+ │ · 空数组 = 没设白名单 = 全部显示 │
26
+ │ NearTokenProvider(provider-mount.ts) │
27
+ │ · 有 key → registerAdapter + registerConfigurableProviders │
28
+ │ · 没 key → 撤掉路由(列表里不会出现调不通的模型) │
29
+ │ NearTokenAdapter(adapter.ts) │
30
+ │ · listModels: GET /api/pricing → (group, model) 笛卡尔展开 │
31
+ │ catalog id = "<group>::<model>",name = "<model> @ <group>" │
32
+ │ 再按「模型过滤」与白名单(裸模型名)过滤;stream 用同批路由找分组│
33
+ │ · stream: POST /v1/chat/completions(OpenAI 协议) │
34
+ │ body.model = 裸模型名 │
35
+ │ header x-neartoken-group = 分组的 ref "#<id>"(不是分组名) │
36
+ └────────────────────────────────────────────────────────────────────┘
37
+ ┌─ client 半边(src/client/)────────────────────────────────────────┐
38
+ │ settings.section(order -5,账号与余额 ↔ 通用设置之间) │
39
+ │ NearTokenSection:连接按钮 / 确认码 + 打开浏览器 / 账号卡片 / 断开 │
40
+ │ + 模型白名单(搜索、全选、清空、全部显示、保存) │
41
+ │ · 行内:模型名 + 分组数 + 最低倍率胶囊;分组明细 hover 出浮层 │
42
+ │ · 分组名按站点规则渲染成彩色 tag 胶囊(低价=绿、反重力=青…) │
43
+ │ · 只列出可提供的模型(见下「模型过滤」) │
44
+ │ conversation.input.model(priority -1 覆盖内置模型座) │
45
+ │ · name 按 " @ " 拆回 (模型, 分组),同模型折叠成一行 │
46
+ │ · 触发器显示 "Claude Opus 5 C @ NearToken",不渲染分组 │
47
+ │ · 列表项按 displayModelName 美化(- → 空格,逐词首字母大写) │
48
+ │ · 分组只在「分组」那一级里出现("[低价][反重力] Claude" → tag 胶囊)│
49
+ │ · 倍率从 catalog description("分组倍率 0.4x")解析显示 │
50
+ │ · 数据仍走 ctx.modelDirectories(与 /model 弹窗同一份状态) │
51
+ └────────────────────────────────────────────────────────────────────┘
52
+ ```
53
+
54
+ ## 使用
55
+
56
+ 1. 装插件、重启 `dsh web`、硬刷新。
57
+ 2. 打开 **设置 → NearToken**,点「连接 NearToken」。
58
+ 3. 设置页显示一个确认码;点「打开浏览器确认」,在站点自己的页面里登录(密码、2FA、passkey 都走站点原生流程)并批准。
59
+ 4. 插件轮询到批准后自动完成:把站点为该插件铸造的 API key 写进 credentials 的 `NEARTOKEN_API_KEY`,并挂上 `neartoken` provider —— 模型选择器里立刻出现按分组折叠的模型。
60
+ 5. 「断开连接」删掉本地凭据、撤掉 provider,并调用站点的撤销端点。
61
+ 6. 卡片下方的「模型白名单」勾选即自动保存(无需点保存)——未勾选的不再出现在模型选择器里,且**当场生效、不用刷新页面**:保存后 Host 用 `AdapterRegistrationHandle.replace()` 重新声明同一条路由,它会同步发布 `llm/adapters-updated`,浏览器收到后重拉模型目录。没设置过白名单时默认全部显示;「全部显示」清空白名单。
62
+
63
+ 备用路径:直接让 credentials 服务存 `NEARTOKEN_API_KEY`(Web 端 Models 页写入),或启动环境导出同名变量——provider 会在启动时按凭据现状挂载。
64
+
65
+ > 这依赖 new-api 侧实现设备授权流端点,契约见 [HANDOFF-new-api.md](HANDOFF-new-api.md) 第一部分。站点尚未实现时,第 2 步会直接报「站点拒绝发起设备授权」。
66
+
67
+ 分组路由按同一文档第二部分:请求头 `x-neartoken-group` 的值是 `/api/pricing` 的 `group_refs` 给出的 **`#<id>`**(纯 ASCII),分组名只用于展示;某分组没有 ref 时不发该头,按令牌自身分组路由。
68
+
69
+ ## 配置
70
+
71
+ | 字段 | 默认 | 说明 |
72
+ |---|---|---|
73
+ | `baseURL` | `https://llm.pko.svcfusion.com` | 站点根地址,不带尾斜杠 |
74
+ | `apiKeyEnv` | `NEARTOKEN_API_KEY` | 授权写入、adapter 读取的凭据引用名 |
75
+ | `catalogTtlMs` | `300000` | `/api/pricing` 目录缓存时长 |
76
+ | `enabledModels` | `[]` | 模型白名单(裸模型名);空数组 = 全部显示。唯一 volatile 字段,设置页直接写它 |
77
+
78
+ ## 原型阶段的硬编码
79
+
80
+ | 位置 | 内容 |
81
+ |---|---|
82
+ | `src/client/groups.ts` `GROUPED_PROVIDERS` | 哪些 provider 的模型名带分组后缀(当前 `['neartoken']`) |
83
+ | `src/host/adapter.ts` `REASONING` | 所有路由统一通告 low/medium/high(演示值) |
84
+ | `src/client/groups.ts` `badgeOf` | badge 颜色规则:含「低价」→绿,「满血」→黄,其余→蓝 |
85
+ | `src/host/account.ts` `CLIENT_NAME` | 确认页上显示的客户端名 |
86
+
87
+ 改完 `pnpm run build` + 浏览器硬刷新即可(profile 是 `link:` 引用)。
88
+
89
+ ## 模型过滤与推理等级
90
+
91
+ 站点 `/api/pricing` 会列出它知道的所有模型,插件只提供能描述的那个子集(`src/host/model-caps.ts`):
92
+
93
+ | 隐藏条件 | 例子 |
94
+ |---|---|
95
+ | 名字以 `-c` 结尾 | `claude-opus-5-c`(站点总有一个同名无后缀的孪生) |
96
+ | 名字含 image / tts / transcribe / asr | `gpt-image-2.5-flare`、`gemini-3.8-flash-tts` |
97
+ | 不在模型能力表里 | `glm-5.0`、`grok-4.5量`、`qwen3-coder-plus` |
98
+
99
+ 推理档位来自 `@earendil-works/pi-ai` 的模型目录(DSH 的 `llm-pi-ai` 用的同一份数据)。插件不在运行时依赖它:`scripts/gen-model-caps.mjs` 把目录生成成 `src/host/model-caps.generated.ts`(1101 个 chat 模型 / 486 个带档位),升级依赖后跑 `pnpm run gen:model-caps` 重建。表里没有档位的模型照常提供,只是不显示「推理等级」这一级,请求也不带 `reasoning_effort`。
100
+
101
+ 同一模型 id 在不同 provider 下可能给出不同档位(网关常只列两档,厂商列六档),生成时取**最完整**的那份。
102
+
103
+ 按生产快照:104 个模型 → 保留 49 个,其中 40 个有真实档位。
104
+
105
+ ## 已知限制(原型)
106
+
107
+ - wire 层图片/文件以占位文本发送;`/model` 弹窗仍是内置平铺列表;箭头键盘导航未接。
108
+ - pricing 加载失败时沿用上一次成功的结果,从未成功过则目录为空(失败不写缓存,下次调用会重试)。
109
+ - 账号卡片不自动刷新:数字只来自授权那一刻 grant 里的 `user`(站点的 dashboard 接口认浏览器会话,不认本插件持有的 relay key),落盘到 profile 下的 `neartoken-account.json`,重启后从文件恢复。之后余额变化不会反映,需要重新连接一次。
110
+ - 供应商是授权态驱动的:断开连接后,正在使用 NearToken 模型的会话需要重新选模型。
111
+ - 设备授权流依赖 new-api 侧实现,未实现前插件只能走「外部导出 key」的备用路径。
112
+ - 白名单按裸模型名过滤:勾掉某模型会把它的所有分组一起隐藏。某个正在使用的模型被勾掉后,会话里已选中的 id 仍在,但选择器里不再列出它。
113
+ - 「-c 后缀」是站点自己的约定:带该后缀的模型工具调用不可靠,插件只在界面上标注(设置页与模型选择器),不拦截选择。
114
+ - 白名单写入走 DSH 的 Settings:profile 里该行只保留 volatile 字段,所以别把 `baseURL` 等非 volatile 字段写进**同一个 profile 行**(会在此后第一次保存白名单时被 Settings 的 strip 规则清掉)。
115
+
116
+ ## 开发
117
+
118
+ ```sh
119
+ pnpm install
120
+ pnpm run typecheck
121
+ pnpm run test # vitest:account(含设备授权轮询)/ pricing / adapter / groups / whitelist / routes / config
122
+ pnpm run build # lib/index.js (host) + lib/client.js (client) + lib/types
123
+ ```
@@ -0,0 +1,8 @@
1
+ # One browser plugin row for the NearToken provider. The row joins the dshClient
2
+ # roster so the modules node half serves lib/client.js into the boot graph; the
3
+ # browser half renders the NearToken settings page and shadows the built-in
4
+ # conversation.input.model seat at a lower slot priority to add the group
5
+ # dimension on top of it.
6
+ - insert:
7
+ - id: ui-neartoken-provider
8
+ name: 'dsh-neartoken'