@zxh126/pi-qqbot 2.3.0 → 2.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/CHANGELOG.md +370 -314
- package/README.md +518 -439
- package/approver.ts +174 -174
- package/attachment.ts +502 -502
- package/billing.ts +579 -0
- package/config.ts +281 -280
- package/constants.ts +51 -51
- package/docs/README.zh-CN.md +477 -410
- package/index.ts +1856 -1571
- package/package.json +60 -60
- package/qq/api.ts +107 -107
- package/qq/gateway.ts +265 -265
- package/qq/upload.ts +288 -288
- package/remote.ts +81 -81
- package/selfupdate.ts +212 -0
- package/slash.ts +862 -826
package/CHANGELOG.md
CHANGED
|
@@ -1,314 +1,370 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
本文件记录 pi-qqbot 的版本变更。格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
|
|
4
|
-
版本号遵循 [SemVer](https://semver.org/lang/zh-CN/)。
|
|
5
|
-
|
|
6
|
-
## [2.
|
|
7
|
-
|
|
8
|
-
### Added
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
`
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
###
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
- `
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
`
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
|
|
69
|
-
`
|
|
70
|
-
|
|
71
|
-
-
|
|
72
|
-
|
|
73
|
-
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
`
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
### Tests
|
|
88
|
-
|
|
89
|
-
- 新增 `test/
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
- `
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
- `
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
-
|
|
140
|
-
|
|
141
|
-
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
-
|
|
164
|
-
|
|
165
|
-
- `
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
-
|
|
171
|
-
`
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
- `/
|
|
269
|
-
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
-
|
|
286
|
-
|
|
287
|
-
## [
|
|
288
|
-
|
|
289
|
-
###
|
|
290
|
-
|
|
291
|
-
- `/
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
本文件记录 pi-qqbot 的版本变更。格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
|
|
4
|
+
版本号遵循 [SemVer](https://semver.org/lang/zh-CN/)。
|
|
5
|
+
|
|
6
|
+
## [2.4.0] - 2026-11-01
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- **模型欠费 / key 失效时不再沉默**:provider 报错时 pi 只在 assistant 消息上留下 `stopReason: "error"`
|
|
11
|
+
+ `errorMessage`,**不产生任何正文**,所以 QQ 侧以前只能看到「没反应」。现在 `message_end` 会把错误
|
|
12
|
+
归类(`billing` / `auth` / `permission` / `rate` / `other`)并在 `agent_settled` 回执:点名**当前模型**
|
|
13
|
+
(`provider/model`)、附服务端原文、给三条恢复路。401/402/`1311 套餐未开放` 都走「可恢复」分支;
|
|
14
|
+
有正文的报错、用户取消的 run、以及 500 类错误行为不变。
|
|
15
|
+
- **远程换 key**:欠费后直接发一串 key(`sk-…` / `ark-…` / `AIza…` / 十六进制 / base64 / 本地服务占位串
|
|
16
|
+
`ollama`,带引号或反引号也认)→ 写进 `~/.pi/agent/auth.json` 的对应 provider,再用 `GET <baseUrl>/models`
|
|
17
|
+
真探测一次,回执给打码片段与探测结果。**不假设 `sk-` 前缀**:判据只有「非空 + 可打印 ASCII + 无空白」;
|
|
18
|
+
裸串(整条消息就是 key)额外要求长度 ≥12 且带数字/大写/分隔符,避免把 `configuration.ts` 这类正文吞掉。
|
|
19
|
+
- **QQ 里接入新 endpoint**:发 `https://host/v1 <key>` 或 `endpoint <url> <key> models a,b` → 探测 `/models`
|
|
20
|
+
(不带版本号时回退 `/v1`;401/403 立刻判 key 无效)→ 过滤 `embedding`/`rerank`/语音/生图等非对话 id →
|
|
21
|
+
写 `models.json` + `pi.registerProvider()`(当前进程立即可用)→ 发**带上下文大小的编号列表**,
|
|
22
|
+
回编号即 `pi.setModel()` 切过去(复用现有 picker,10 分钟有效)。provider id 自动取 `qq-<host>`,撞名加序号。
|
|
23
|
+
- **模型参数向内置目录看齐**:`/models` 通常只给 id,所以 `borrowModelMeta()` 按模型 id 从
|
|
24
|
+
`modelRegistry.getAll()`(内置 catalog + 已配置 provider)借 `contextWindow` / `maxTokens` / `reasoning` /
|
|
25
|
+
`input` / `thinkingLevelMap` / `cost` / `compat` / `inputLimits`;排序为「同 host > 同厂商域名族 >
|
|
26
|
+
`openai-completions`」。借不到才用保守默认(128k / 16k),回执会明说有几个是补全的、几个是默认值。
|
|
27
|
+
- **从 QQ 更新自己**:`/update`(或「更新自己」「升级一下插件」「自更新」)→ `npm view` 查最新版 →
|
|
28
|
+
**`pi update npm:@zxh126/pi-qqbot`** → **版本校验闸门**(磁盘 `package.json` 必须等于 registry 版本,否则只回执不重载)
|
|
29
|
+
→ `/qq reload`(`ctx.reload()`)。自然语言口令刻意收窄,单说「更新」不认。
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- **配置 `commands.allowUpdate`**(默认 `false`,与 `allowReload` / `allowQuit` 同风格):`/update` 与
|
|
34
|
+
「更新自己」的门禁;顶层默认值 + 每个 bot 逐键覆盖。
|
|
35
|
+
- **`PickerKind` 新增 `model`**:编号选择支持「新接入服务的模型」,选完直接 `pi.setModel()`;模型已不在目录时
|
|
36
|
+
不静默,提示重新 `/model`。
|
|
37
|
+
- **错误提示与日志**:`errorMessage` 统一过 `redactSecrets()` + 压空白 + 截 600 字;错误分类与当前模型写进
|
|
38
|
+
`pi-qqbot.log`(`[reply] 本轮模型接口报错: <类别> <provider/model> <原文>`),事后可排查。
|
|
39
|
+
|
|
40
|
+
### Compatibility
|
|
41
|
+
|
|
42
|
+
- 纯增量:不配 `commands.allowUpdate` 时没有任何行为变化;不处于欠费/鉴权失败状态时,裸 key 不会被当成凭据
|
|
43
|
+
(显式 `key …` 除外)。
|
|
44
|
+
- 需 pi 提供 `message_end` 的 `stopReason` / `errorMessage`、`pi.registerProvider()`、`pi.setModel()`(现版 pi 1.4.x 均具备)。
|
|
45
|
+
- 写盘只碰 pi 自己的 `auth.json` / `models.json`,用 pi 同款 `proper-lockfile` + 原子 rename;`models.json`
|
|
46
|
+
只增改自己的 provider,不动别人。
|
|
47
|
+
- 安装目录共享:`/update` 只更新磁盘,其它仍在跑旧代码的 pi 进程需各自 reload / 重启。
|
|
48
|
+
|
|
49
|
+
### Tests
|
|
50
|
+
|
|
51
|
+
- 共 **14 套 / 191 条**全绿(`npm test`)。
|
|
52
|
+
- 新增 `test/billing.test.mjs`(26):错误分类、中文文案、`parseCredentialMessage` 各类写法、
|
|
53
|
+
`looksLikeSecret`(含非 `sk-` 前缀 6 种形态、显式/裸串两档松紧)、`stripWrapping`、`normalizeBaseUrl` /
|
|
54
|
+
`extractModelIds`、`probeEndpoint`(成功 / `/v1` 回退 / 401 立即返回 / 网络异常)、`providerIdForEndpoint`、
|
|
55
|
+
`borrowModelMeta`、`filterChatModelIds`、`modelLabel`、`updateProviderKey` / `upsertEndpointProvider` 落盘。
|
|
56
|
+
- 新增 `test/credential-intake.test.mjs`(11):走真实 `handleMessage`——欠费发裸 key、没欠费不吞、显式前缀、
|
|
57
|
+
endpoint 注册 + 编号列表、元数据借用、探测 401、带 `models` 重发、编号选择 `setModel`、非 `sk` 前缀 key、带引号 key。
|
|
58
|
+
- 新增 `test/selfupdate.test.mjs`(13):版本比较(含 prerelease)、npm 输出解析、五种流程结局
|
|
59
|
+
(最新 / 已更新 / 检查失败 / 更新失败 / 版本不一致)、`isUpdateSelfIntent`、`/update` 门禁。
|
|
60
|
+
- 新增 `test/error-notice.test.mjs`(8):402 / 401 / 500 / 有正文 / 取消 / 跑通后作废 / 凭据闸门 / 脱敏。
|
|
61
|
+
|
|
62
|
+
## [2.3.0] - 2026-10-31
|
|
63
|
+
|
|
64
|
+
### Added
|
|
65
|
+
|
|
66
|
+
- **远程上下文提醒**:`before_agent_start` 里先判断「这一轮是不是本扩展刚派发的 QQ 消息」,是才把一段说明写进
|
|
67
|
+
系统提示的 `qq-remote-context` section(排在用户消息之前,QQ 侧与 TUI 都看不到):说明对话来自远程 QQ 用户、
|
|
68
|
+
对方看不到本机屏幕与弹窗;默认**禁用桌面截屏 / 屏幕 OCR / UI 自动化 / 键鼠模拟 / 带界面的浏览器**
|
|
69
|
+
(点名 `mcp__screenshot`、`mcp__winui`),需要图就离屏渲染生成 PNG 再用 `qq_send_file` 发回,
|
|
70
|
+
只有确认是否锁屏时才允许截一次桌面。**仅仅载入扩展、或本机 TUI 直接对话时都不注入**,必须等第一条 QQ 消息真的开跑。
|
|
71
|
+
- **系统提示规则**:每次**来自 QQ 的** run 追加三条短规则(远程用户 / 锁屏→离屏渲染 /
|
|
72
|
+
需要人工就直说),避免长会话被压缩摘要后丢失;同一轮重复触发不叠加,本机 TUI 自己的 run 不加。
|
|
73
|
+
- **压缩后重注入**:`session_compact` 之后清掉「已提醒」标记,下一条消息重新注入。
|
|
74
|
+
- **配置 `remote`**:`notice`(默认 `true`,每会话一次)、`guidelines`(默认 `true`)、`extra`(追加到提醒末尾,
|
|
75
|
+
默认空);顶层默认值 + 每个 bot 逐键覆盖。
|
|
76
|
+
- **本机接管更正**:同一个会话里「上一轮来自 QQ、下一轮本机 TUI 直接打字」时,本机那一轮注入一次
|
|
77
|
+
`qq-local-handoff` section(「远程 QQ 用户」前提作废:可正常截屏、不需要 `qq_send_file`),连续本机对话不重复;
|
|
78
|
+
用 `input` 事件的 `source=interactive` 识别(本扩展的 `sendUserMessage` 是 `extension`,不会误判);
|
|
79
|
+
QQ run 跑到一半时插话不算接管(没有新的 run)。`/status` 新增「来源: QQ(远程)/ 本机(TUI)」。
|
|
80
|
+
|
|
81
|
+
### Fixed
|
|
82
|
+
|
|
83
|
+
- **等审批期间不再推自动进度**:有工具审批在等用户回复时,自动进度推送暂缓(否则每 15s 一条进度会把审批提示
|
|
84
|
+
顶出屏幕),审批处理完(或超时)后下一拍自动恢复;主动问 `/progress` 不受影响;`/status` 会显示
|
|
85
|
+
「等审批期间暂缓」。本会话内手动暂停(`/progress off`)与配额静默的语义不变。
|
|
86
|
+
|
|
87
|
+
### Tests
|
|
88
|
+
|
|
89
|
+
- 新增 `test/remote-notice.test.mjs`(默认值 / 文案要素 / `extra` 追加 / 系统规则长度)。
|
|
90
|
+
- `test/config.test.mjs` 新增 `remote` 全局默认 + 账号逐键覆盖用例。
|
|
91
|
+
- `test/accounts.test.mjs` 新增 3 个用例:**本机直接对话不注入**、第一条 QQ 消息的 run 才注入且每会话一次、
|
|
92
|
+
压缩后重注入;`remote.notice=false` 只关说明、`remote.extra` 追加;`remote.guidelines=false` 只关规则,
|
|
93
|
+
且同一轮重复触发不叠加。
|
|
94
|
+
- `test/progress.test.mjs` 新增用例:等审批期间不推送、`/status` 显示暂缓、手动问进度仍回一次、审批处理完自动恢复。
|
|
95
|
+
- `test/accounts.test.mjs` 再加 2 个用例:本机接管只更正一次(`/status` 显示来源);交接待定会被新的 QQ 轮覆盖,
|
|
96
|
+
`source=extension` 的 input 不算接管。
|
|
97
|
+
- `test/remote-notice.test.mjs` 加 `qq-local-handoff` 的 tag 与文案断言。
|
|
98
|
+
|
|
99
|
+
## [Unreleased]
|
|
100
|
+
|
|
101
|
+
## [2.2.1] - 2026-02-11
|
|
102
|
+
|
|
103
|
+
### Fixed
|
|
104
|
+
|
|
105
|
+
- **把「文案」当成了「指令」**:用户把审批提示整段引回来(或以「你这句话里说『取消自动同意』」这种句子讨论),
|
|
106
|
+
旧代码用**未锚定**的正则,句子里出现「取消自动同意」「以后都同意」就会被当成真的审批动作(日志里能看到
|
|
107
|
+
回了一句「当前没有开启自动同意」)。现在 `parseReply` 先去掉空白与标点做**整句匹配**,并卡长度上限(≤ 12 字),
|
|
108
|
+
引用提示、长句、感叹句一律不解析,当普通聊天交给 pi。
|
|
109
|
+
- **审批提示太啰嗦**:从 3 行(含「停止」「以后都同意」「取消自动同意」三句)压到 2 行:
|
|
110
|
+
`[审批 #N] <摘要>` + `回「同意 N」或「拒绝 N」;想全部放行回「以后都同意」。`;
|
|
111
|
+
发文件这类每次都要确认的工具改用 strict 文案(不提「以后都同意」)。
|
|
112
|
+
|
|
113
|
+
### Tests
|
|
114
|
+
|
|
115
|
+
- 新增 `test/approver.test.mjs`(6 个用例:批/拒的各种写法、停止/以后都同意/取消自动同意、
|
|
116
|
+
引用提示不解析、句中关键词不解析、「停止汇报」不算指令、超长句不解析、提示文案≤两行)。
|
|
117
|
+
- `test/queue.test.mjs` 同步 strict 文案断言(19 个用例)。
|
|
118
|
+
|
|
119
|
+
## [2.2.0] - 2026-02-11
|
|
120
|
+
|
|
121
|
+
### Added
|
|
122
|
+
|
|
123
|
+
- **把本机文件发到 QQ**:新增工具 `qq_send_file(path, name?)` 与命令 `/sendfile <路径>`。按官方富媒体接口走
|
|
124
|
+
分片上传(`upload_prepare` → 分片 `PUT` → `upload_part_finish` → 合并拿 `file_info`),再用
|
|
125
|
+
`msg_type=7` + `media.file_info` 以**被动回复**发出(`srv_send_msg:false`,不烧主动额度)。
|
|
126
|
+
本地文件没有公网 URL,而二进制直传只有 5MB 上限,所以统一走分片,不依赖中转。
|
|
127
|
+
- **`file_type` 判定**:png/jpg/jpeg → 图片(1)、mp4 → 视频(2)、silk → 语音(3)、其余 → 文件(4);
|
|
128
|
+
否则 QQ 报 `850019`。图片/视频/语音直接展示,其他格式对方收到可下载的文件卡片。
|
|
129
|
+
- **外发文件强制审批(每次都要问)**:`qq_send_file` 被加入 `FORCE_APPROVAL_TOOLS`,无论 `approve.tools` 怎么配都
|
|
130
|
+
必须先回 QQ 审批;并且**跳过会话级「以后都同意」与记住的决策**,每个文件单独确认,也不会写入 remember。
|
|
131
|
+
审批文案会显示文件路径与显示名,并注明「需单独确认」。
|
|
132
|
+
- **配置 `files`**:`enabled`(默认 true)、`maxBytes`(默认 30MB;QQ 硬限 200MB),可按 bot 逐键覆盖。
|
|
133
|
+
- **错误码翻译**:`850031` 超大、`850019` 格式不支持、`40093002` 今日容量上限、`850027` 超时、
|
|
134
|
+
`850018` 禁言/限频、`40093001` 转存失败,都转成中文回执。
|
|
135
|
+
|
|
136
|
+
### Changed
|
|
137
|
+
|
|
138
|
+
- `qq/api.ts`:新增 `sendC2CMedia(openid, fileInfo, { msgId })`,复用已有的发送队列与 `msg_seq` 计数。
|
|
139
|
+
- `slash.ts`:新增可接管命令 `sendfile`(不受 `commands.allowSession` 限制,由 `files.enabled` + 审批把关)。
|
|
140
|
+
- `index.ts`:`State` 记录 `restBase`;`/help` 增加 `/sendfile` 说明。
|
|
141
|
+
- `package.json`:新增 peer 依赖 `typebox`(工具参数 schema,pi 运行时已内置别名)。
|
|
142
|
+
|
|
143
|
+
### Tests
|
|
144
|
+
|
|
145
|
+
- 新增 `test/upload.test.mjs`(9 个用例:file_type 映射、md5/sha1/md5_10m、分片全链路与字节回拼、
|
|
146
|
+
图片类型、分片失败重试、本地校验(不存在/目录/空文件/超限)、合并缺 `file_info`、错误码翻译、
|
|
147
|
+
`sendC2CMedia` 的 `msg_type=7` 请求体)。
|
|
148
|
+
- `npm test` 新增该文件;全套 130 → 140 个用例全绿(queue 18 → 19,新增「发送文件每次都审批」)。
|
|
149
|
+
|
|
150
|
+
## [2.1.0] - 2026-02-11
|
|
151
|
+
|
|
152
|
+
### Added
|
|
153
|
+
|
|
154
|
+
- **接收 QQ 附件(图片 / 语音 / 视频 / 文档 / 压缩包 / 普通文件)**:收到的附件马上下载到临时文件,
|
|
155
|
+
再把路径以标记行交给 pi——图片是 `图片路径 <path>`,其余按类型是 `语音路径` / `视频路径` /
|
|
156
|
+
`文档路径` / `压缩包路径` / `文件路径`。原有文字保持在第一行,与路径同属一轮对话;pi 的 `read` 工具
|
|
157
|
+
可以直接打开图片,`bash` 可以处理文件。(v2.1.0 之前只保留图片且完全没落盘,纯图片消息会给 pi 送空串。)
|
|
158
|
+
- **QQ 回执**:落盘后先回一条「已收到 N 个附件(图片 ×1、文档 ×1),已存为临时文件并交给 pi:」+ 各条路径;
|
|
159
|
+
下载失败会列出原因,文字部分照常执行。
|
|
160
|
+
- **临时文件自动清理**:落盘目录按日期分子目录(`<系统临时目录>/pi-qqbot/<bot>/<YYYY-MM-DD>/`),
|
|
161
|
+
每次会话启动时按 `attachments.retentionHours`(默认 24 小时)与 `attachments.maxFiles`(默认 200)
|
|
162
|
+
清理;目录里不是本插件建的 `<日期>` 子目录一律不动。
|
|
163
|
+
- **配置 `attachments`**:`enabled` / `dir` / `maxBytes` / `maxPerMessage` / `retentionHours` / `maxFiles`,
|
|
164
|
+
支持像 `queue` / `progress` 一样在 `qqbots[]` 里逐 bot 覆盖。`enabled: false` 时回一句忽略提示、只处理文字。
|
|
165
|
+
- **新的 `attachment.ts`**:六类判定、文件名规整(只保留 `[0-9a-zA-Z._-]`)、并发下载(默认 3)、
|
|
166
|
+
单个 25 MB 上限、下载超时 30 秒、401/403 带凭据重试一次、失败不影响其它附件。
|
|
167
|
+
|
|
168
|
+
### Changed
|
|
169
|
+
|
|
170
|
+
- `qq/gateway.ts`:`QQMessage.attachments` 改为 `{ url, contentType, filename?, size? }[]`,
|
|
171
|
+
**不再丢弃非图片附件**;语音消息的消息体只有 `voice_wav_url` 时也取它当下载地址。
|
|
172
|
+
- 网关日志不再打整包 JSON(里面带 `rkey` 临时凭据),改为 openid / content 摘要 / 附件数量 / 来源主机。
|
|
173
|
+
- `handleMessage()`:带附件的消息**绕过**斜杠命令、审批解析、编号选择与内置指令,一律当普通内容(忙碌时照旧入队)。
|
|
174
|
+
|
|
175
|
+
### Tests
|
|
176
|
+
|
|
177
|
+
- 新增 `test/attachment.test.mjs`(12 个用例:六类判定、扩展名、落盘内容、超限、401 重试、部分失败、
|
|
178
|
+
单条上限、回执文案、目录清理)。
|
|
179
|
+
- `test/queue.test.mjs` 12 → 18 个用例(纯图片派发、文字+文档拼行、忙碌入队、`enabled=false` 忽略提示、
|
|
180
|
+
绕过 `/status`、下载失败照发正文)。
|
|
181
|
+
|
|
182
|
+
## [2.0.1] - 2026-10-25
|
|
183
|
+
|
|
184
|
+
### Fixed
|
|
185
|
+
|
|
186
|
+
- **口令语序:「暂停汇报进度」之前不被识别**,会漏成普通对话丢给模型。现在「暂停**进度汇报**」与
|
|
187
|
+
「暂停**汇报进度**」两种语序都认;「别汇报了**吧**」这类双尾字也不再漏。
|
|
188
|
+
|
|
189
|
+
### Changed
|
|
190
|
+
|
|
191
|
+
- **口语静音词扩充**:「别汇报了」「别说了」「别讲了」「别推了」「别发了」「别报了」「闭嘴」「安静」
|
|
192
|
+
「打住」「甭」等,与 `/progress off` 等价(恢复用「恢复汇报」「接着说」)。
|
|
193
|
+
- **「停」改为中断任务**(按用户反馈):`停`/`停下`/`停一下`/`停停`/`停掉`/`别跑了` 归入 `RE_CANCEL`,
|
|
194
|
+
与 `/cancel` 完全等价;只有带名词的「停止汇报」或纯闭嘴词才是静音。
|
|
195
|
+
- **主动问进度归为指令**:「汇报一下当前进度」「看一下进度」「说说进度」「进度如何」「进度怎么样」
|
|
196
|
+
不再当聊天转给 pi,忙时回一次摘要且不入队,空闲时直接回「当前没有正在运行的任务」。
|
|
197
|
+
- `/help` 区分两种语义:只关推送用 `/progress off`/「别汇报了」/「闭嘴」;「停」是中断任务。
|
|
198
|
+
- 两份 README 新增「口语说法」对照表(意图 → 可说的话)。
|
|
199
|
+
|
|
200
|
+
### Tests
|
|
201
|
+
|
|
202
|
+
- `test/progress.test.mjs` 16 → 22 个用例(新增 / 改写:语序两边、口语静音词、
|
|
203
|
+
「停/停下/停一下/停止/取消」均为中断、「停止汇报」仍为静音、主动问进度三姿态、口令不误伤)。
|
|
204
|
+
|
|
205
|
+
## [2.0.0] - 2026-10-25
|
|
206
|
+
|
|
207
|
+
### Added
|
|
208
|
+
|
|
209
|
+
- **多 QQ bot(一份配置、一台机器、多个 pi 进程)**:配置里用 `qqbots: [...]` 写多组
|
|
210
|
+
`appId` / `appSecret`,支持 `name`、以及逐账号覆盖 `sandbox` / `allowlist` / `queue` /
|
|
211
|
+
`progress` / `approve` / `commands`(未写的继承全局默认值,逐键合并)。
|
|
212
|
+
- **自动抢占**:每个 pi 进程启动时(`session_start`)按配置顺序找第一个**未上线**的 bot 接入;
|
|
213
|
+
抢不到的进程不接入 QQ、但每 5 秒重扫,别人退出后接管。一进程一把锁,绝不并发多接。
|
|
214
|
+
- **「不抢别人 reload 中临时释放的 bot」**:会话重建(`/reload`、`/new`、`/fork`、`/resume`)时,
|
|
215
|
+
释放锁**之前**写 20 秒预约窗口,其他进程跳过该 bot;抢锁后还会二次读预约记录,
|
|
216
|
+
撞上就让出(关掉竞态窗口)。新 runtime 用同一 pid 认回自己的 bot,静默不打扰。
|
|
217
|
+
- **身份可见**:接入日志带 bot 名称 / appId / cwd / pid;QQ 首条回执前加「(已接入 qqbot「work」)」;
|
|
218
|
+
`/status` 首行显示 `bot: work (…0143) · cwd: …`。
|
|
219
|
+
- **换进程接管提示**:`~/.pi/agent/pi-qqbot-<appId>.owner.json` 记录上一位持有者的 pid 与工作目录,
|
|
220
|
+
换进程时日志写新旧 pid/cwd,QQ 首条回执带「(qqbot「work」已由新实例接管 · 当前工作目录 …)」。
|
|
221
|
+
- `PI_QQBOT_ACCOUNT=<name|appId>` 钉选账号(调试/固定目录用),名字不存在则不接入并写日志。
|
|
222
|
+
- **抢占后先验凭据**:抢到锁立即换一次 `access_token`,失败就**放锁**并跳过该 bot(继续试下一个),
|
|
223
|
+
避免「凭据写错的 bot 占着锁位但永远连不上」;全部不可用时不空转重扫。
|
|
224
|
+
- **修复** `AuthManager`:QQ 平台对无效凭据返回 HTTP 200 + `code 100016`,以前只拿空 token 去连网关,
|
|
225
|
+
现在直接抛错(带 code/message),并在抢占阶段被发现。
|
|
226
|
+
- 新增文档 [docs/accounts.md](docs/accounts.md);新增测试 `test/config.test.mjs`(9)、
|
|
227
|
+
`test/lock.test.mjs`(8,真子进程 + 真 lockfile,含「同一工作目录也能各接一个」)、
|
|
228
|
+
`test/accounts.test.mjs`(9,端到端抢占/提示/凭据无效降级)、`test/auth.test.mjs`(3)。
|
|
229
|
+
|
|
230
|
+
### Changed
|
|
231
|
+
|
|
232
|
+
- 日志按账号分文件:`~/.pi/agent/pi-qqbot-<name>.log`(同机多进程不再交错);
|
|
233
|
+
单 bot 旧格式仍写 `pi-qqbot.log`。
|
|
234
|
+
- `/status` 增加 bot 身份与工作目录行;`/help` 增加多 bot 说明。
|
|
235
|
+
- 配置加载改为 `loadAccounts()`(返回按顺序排好的账号列表),`loadConfig()` 保留为兼容包装。
|
|
236
|
+
|
|
237
|
+
### Compatibility
|
|
238
|
+
|
|
239
|
+
- **旧的单 bot 配置零改动可用**(等价于名为 `default` 的账号,行为与 1.5.0 一致);
|
|
240
|
+
`QQ_BOT_APPID` / `QQ_BOT_APPSECRET` 仍只用于单 bot 场景。
|
|
241
|
+
- 同时写顶层 `appId` 与 `qqbots` → 报错不接入(歧义不猜);单个账号凭据缺失/`appId` 重复/`name`
|
|
242
|
+
重复 → 跳过该条并写日志,其余照常。
|
|
243
|
+
- **bot 与工作目录无绑定**:分配只看配置顺序与在线状态,与 cwd 无关——同一目录开多个 pi
|
|
244
|
+
也照样一人接一个 bot。cwd 仅用于日志、接管提示与 `/status` 展示。
|
|
245
|
+
- 升级后建议重启(或 `/reload`)一次:新版本启动时才会按账号分文件写日志。
|
|
246
|
+
|
|
247
|
+
## [1.5.0] - 2026-10-25
|
|
248
|
+
|
|
249
|
+
### Added
|
|
250
|
+
|
|
251
|
+
- **暂停 / 恢复自动进度汇报(会话内有效)**:`/progress off`(别名 `/p pause`、`暂停`、`stop`、
|
|
252
|
+
「暂停汇报」「关闭自动汇报」)停掉定时推送,`/progress on`(别名 `resume`、`start`、`恢复`、
|
|
253
|
+
「恢复汇报」「继续汇报」)重新打开。
|
|
254
|
+
- 手动暂停跨 run 保留(`agent_start` 不再顺手复位),只在 `session_start`(`/new`、`/reload`、重启)复位为默认开启。
|
|
255
|
+
- 手动暂停期间,`/progress`、「进度」、「当前进度」、「现在进度」、「进展」**只回一次当前摘要**,
|
|
256
|
+
不会偷偷把 15 s 定时器打开,回复末尾附「(自动汇报已暂停,发 /progress on 恢复)」提示。
|
|
257
|
+
- 与原有的「配额静默」严格区分:配额静默是发送失败后的自动暂停,问一次进度即恢复;
|
|
258
|
+
手动暂停只有 `on`/「恢复汇报」能解除。
|
|
259
|
+
- `/progress <看不懂的参数>` 回用法提示,不再静默忽略。
|
|
260
|
+
- `/status` 新增 `自动汇报:` 一行,区分四种模式:`开启(每 Ns)` / `已暂停(本会话…)` /
|
|
261
|
+
`推送失败已静默` / `未启用(配置 progress.enabled=false)`。
|
|
262
|
+
- 裸文本口令「当前进度」「现在进度」「目前进展」(可带子命令,如「进度 暂停」)也走进度查询。
|
|
263
|
+
- 测试:`test/progress.test.mjs` 新增 7 个用例(暂停/恢复即时生效、跨 run 保留、暂停后手动查看不解除、
|
|
264
|
+
中文口令且不误伤任务句、空闲时问「当前进度」、`/status` 文案、未知子命令)。
|
|
265
|
+
|
|
266
|
+
### Changed
|
|
267
|
+
|
|
268
|
+
- `/progress`(无参数)在**手动暂停**状态下不再解除暂停(此前任何一次问询都会清掉暂停标志)。
|
|
269
|
+
- 「推送失败已静默」与「用户手动暂停」拆成两个独立状态(`progressPaused` / `progressMuted`),
|
|
270
|
+
互不覆盖。
|
|
271
|
+
- README(英文)与 `docs/README.zh-CN.md` 的指令表、进度小节、`progress.enabled` 说明同步更新。
|
|
272
|
+
|
|
273
|
+
## [1.4.0] - 2026-10-24
|
|
274
|
+
|
|
275
|
+
### Added
|
|
276
|
+
|
|
277
|
+
- 任务运行期间按 `progress.intervalMs`(默认 15 s)推送进度摘要:轮次、工具调用次数与前三名、
|
|
278
|
+
失败次数、最近完成的工具(含耗时)、正在跑的工具、token 用量。全部由本地事件拼装,
|
|
279
|
+
不调用模型、不消耗 token。
|
|
280
|
+
- 全链路敏感信息脱敏(`redact.ts`):进度摘要、审批提示、队列预览、日志落盘统一过一遍,
|
|
281
|
+
覆盖 `Authorization` / QQ bot token / `sk-…` / `ghp_…` / `npm_…` / `AKIA…` / JWT / PEM /
|
|
282
|
+
`token=` / `password=` / `--api-key` / URL `user:pass@` / 高熵串。
|
|
283
|
+
- `/progress`(别名 `/p`、「进度」)与忙碌时的「到哪了」「怎么样了」问询。
|
|
284
|
+
- 最终答案因配额发不出去时缓存,下条消息以「(上一条回复发送失败,补发如下)」补发。
|
|
285
|
+
- 配置 `progress.enabled` / `progress.intervalMs`(环境变量 `PI_QQBOT_PROGRESS_MS` 可覆盖)。
|
|
286
|
+
|
|
287
|
+
## [1.3.3] - 2026-10-24
|
|
288
|
+
|
|
289
|
+
### Fixed
|
|
290
|
+
|
|
291
|
+
- `/usage` 报告读回改为轮询等待:`appendEntry` 晚于命令 `await` 返回,导致偶发读不到刚写入的报告。
|
|
292
|
+
|
|
293
|
+
## [1.3.2] - 2026-10-24
|
|
294
|
+
|
|
295
|
+
### Fixed
|
|
296
|
+
|
|
297
|
+
- `/usage` 读回兜底:`getEntries` 尚未刷新时直接读会话文件尾部;`generatedAt` 兼容毫秒时间戳。
|
|
298
|
+
|
|
299
|
+
## [1.3.1] - 2026-10-24
|
|
300
|
+
|
|
301
|
+
### Fixed
|
|
302
|
+
|
|
303
|
+
- `/usage rate` 真正执行并读回配置文件确认,不再「口头成功」。
|
|
304
|
+
|
|
305
|
+
## [1.3.0] - 2026-10-24
|
|
306
|
+
|
|
307
|
+
### Added
|
|
308
|
+
|
|
309
|
+
- `/usage`、`/cost`(只往 `ctx.ui.*` 输出的扩展命令)桥接回 QQ,不再沉默。
|
|
310
|
+
- `/mcp`、`/llama` 这类需要主机 TUI 选择框/登录的命令改为明确回执说明。
|
|
311
|
+
|
|
312
|
+
## [1.2.1] - 2026-10-24
|
|
313
|
+
|
|
314
|
+
### Changed
|
|
315
|
+
|
|
316
|
+
- 日志时间戳改为本地时间并带 UTC 偏移(如 `[2026-10-24T07:39:09.762+08:00]`),与文件 mtime、
|
|
317
|
+
进程启动时间直接对齐,不再需要心算时区。
|
|
318
|
+
|
|
319
|
+
## [1.2.0] - 2026-10-24
|
|
320
|
+
|
|
321
|
+
### Added
|
|
322
|
+
|
|
323
|
+
- 忙碌时收到的消息进入队列,当前任务 settle 后自动续跑;`/cancel` 永远不入队、立即生效。
|
|
324
|
+
- `/queue`(别名 `/q`)查看队列,`/queue clear`、`/queue drop <编号>` 管理队列。
|
|
325
|
+
- 配置 `queue.max`(0 = 关闭排队)、`queue.ack`。
|
|
326
|
+
|
|
327
|
+
## [1.1.0] - 2026-10-24
|
|
328
|
+
|
|
329
|
+
### Added
|
|
330
|
+
|
|
331
|
+
- `/tree`、`/fork`、`/resume` 的编号选择器接管:回一个最多 10 项的列表,只对发出者有效、10 分钟过期;
|
|
332
|
+
- `/clone` 支持。
|
|
333
|
+
|
|
334
|
+
## [1.0.0] - 2026-10-24
|
|
335
|
+
|
|
336
|
+
### Added
|
|
337
|
+
|
|
338
|
+
- 接管 pi 的斜杠命令(白名单 `commands.passthrough` / `allowReload` / `allowQuit` / `allowSession`):
|
|
339
|
+
`/reload`、`/new`、`/compact`、`/session`、`/name`、`/model`、`/thinking`、`/quit`,
|
|
340
|
+
以及扩展命令、prompt 模板、`/skill:name` 的透传。
|
|
341
|
+
- 有任务在跑时,`/reload`、`/new`、`/compact`、`/quit`、`/tree`、`/fork`、`/clone`、`/resume` 拒绝执行。
|
|
342
|
+
|
|
343
|
+
## [0.3.0] - 2026-10-24
|
|
344
|
+
|
|
345
|
+
### Added
|
|
346
|
+
|
|
347
|
+
- `/cancel`(别名 `/stop`、`/abort`、「取消」「停止」「中止」「终止」「算了」)中断正在运行的任务:
|
|
348
|
+
先终止待审批、清空队列,再 `ctx.abort()`,丢弃半截回复;8 秒看门狗兜底释放忙碌标记。
|
|
349
|
+
|
|
350
|
+
## [0.2.1] - 2026-10-24
|
|
351
|
+
|
|
352
|
+
### Changed
|
|
353
|
+
|
|
354
|
+
- 中文 README 移入 `docs/README.zh-CN.md`,修复 npm 页面默认 readme 被中文版顶掉。
|
|
355
|
+
|
|
356
|
+
## [0.2.0] - 2026-10-24
|
|
357
|
+
|
|
358
|
+
### Added
|
|
359
|
+
|
|
360
|
+
- 会话级「以后都同意」自动放行(`approve.remember`),含已在等待的那一条;
|
|
361
|
+
「取消自动同意」「恢复审批」等**长得像取消**的说法仍走审批分支。
|
|
362
|
+
- 中英文双语 README。
|
|
363
|
+
|
|
364
|
+
## [0.1.0] - 2026-10-16
|
|
365
|
+
|
|
366
|
+
### Added
|
|
367
|
+
|
|
368
|
+
- 初始版本:把 Pi coding agent 接入 QQ 单聊(C2C),单会话 + `proper-lockfile` 单实例锁(宿主接管)、
|
|
369
|
+
危险工具(`bash` / `powershell` / `write` / `edit` 及 `destructiveHint` 工具)执行前远程审批、
|
|
370
|
+
长回复自动分段。
|