@zxh126/pi-qqbot 1.0.0 → 1.2.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 +67 -13
- package/config.ts +14 -0
- package/constants.ts +4 -0
- package/docs/README.zh-CN.md +58 -10
- package/index.ts +352 -46
- package/package.json +4 -1
- package/queue.ts +118 -0
- package/slash.ts +261 -31
package/README.md
CHANGED
|
@@ -11,12 +11,13 @@ Bridge the **[Pi](https://pi.dev) coding agent** into QQ private (C2C) chats: se
|
|
|
11
11
|
| Feature | Description |
|
|
12
12
|
|---|---|
|
|
13
13
|
| **Chat-driven agent** | QQ private messages are fed into the current pi session; the assistant's answer is sent back to QQ (long replies are split automatically). |
|
|
14
|
+
| **Message queue** | While a task is running, further QQ messages are **queued** instead of rejected; each one starts automatically as soon as the current run settles. `/cancel` is the exception — it acts immediately and clears the queue. |
|
|
14
15
|
| **Remote approval** | Before pi runs `bash` / `powershell` / `write` / `edit` — or any tool annotated `destructiveHint` — the bot asks in QQ first. |
|
|
15
16
|
| **Session-scoped "always allow"** | Reply 「以后都同意」 and every approval request in the **current session** is auto-approved, including the one already waiting. |
|
|
16
17
|
| **Single-instance lock** | Only one pi process hosts the QQ gateway; the others stand by and take over automatically when the host exits. |
|
|
17
|
-
| **Cancel a running task** | Send `/cancel` (or 「取消」/「停止」) and the current run is aborted immediately — the QQ reply, the pending tool calls
|
|
18
|
+
| **Cancel a running task** | Send `/cancel` (or 「取消」/「停止」) and the current run is aborted immediately — the QQ reply, the pending tool calls, the half-written answer and the pending queue are all cleaned up. |
|
|
18
19
|
| **Slash-command routing** | QQ messages starting with `/` are routed: pi extension commands, prompt templates and `/skill:name` are dispatched to pi; a set of pi built-ins (`/reload`, `/new`, `/compact`, `/session`, `/name`, `/model`, `/thinking`, `/quit`) is taken over; host-only commands are answered instead of being fed to the model. |
|
|
19
|
-
| **Built-in commands** | `/status`, `/reset`, `/cancel`, `/help`. |
|
|
20
|
+
| **Built-in commands** | `/status`, `/queue`, `/reset`, `/cancel`, `/help`. |
|
|
20
21
|
|
|
21
22
|
## Install
|
|
22
23
|
|
|
@@ -42,6 +43,10 @@ Then create `~/.pi/agent/pi-qqbot.json`:
|
|
|
42
43
|
"approve": {
|
|
43
44
|
"tools": ["bash", "powershell", "write", "edit"],
|
|
44
45
|
"remember": true
|
|
46
|
+
},
|
|
47
|
+
"queue": {
|
|
48
|
+
"max": 20,
|
|
49
|
+
"ack": true
|
|
45
50
|
}
|
|
46
51
|
}
|
|
47
52
|
```
|
|
@@ -56,6 +61,8 @@ Then create `~/.pi/agent/pi-qqbot.json`:
|
|
|
56
61
|
| `approve.tools` | `["bash","powershell","write","edit"]` | Tools that require approval; tools annotated `destructiveHint` are always gated too |
|
|
57
62
|
| `approve.remember` | `true` | Remember the decision per tool inside the session (no more prompts for that tool) |
|
|
58
63
|
| `commands` | see below | Slash-command routing gates: `passthrough`, `allowReload`, `allowQuit`, `allowSession` |
|
|
64
|
+
| `queue.max` | `20` | How many messages may wait while a task runs; `0` disables queueing (busy messages are refused as before) |
|
|
65
|
+
| `queue.ack` | `true` | Reply to QQ when a queued [message](#queueing-while-busy) starts (the "queued" ack is always sent) |
|
|
59
66
|
|
|
60
67
|
Credentials can also come from the `QQ_BOT_APPID` / `QQ_BOT_APPSECRET` environment variables.
|
|
61
68
|
|
|
@@ -66,8 +73,9 @@ Start pi, then message the bot in QQ; pi handles it and replies.
|
|
|
66
73
|
| Command | Description |
|
|
67
74
|
|---|---|
|
|
68
75
|
| `/reset` | Clear the reply buffer, approval memory and session-wide auto-approve (**does not** switch sessions — send `/new` for that) |
|
|
69
|
-
| `/status` | Show busy/idle state, auto-approve state and pending approval count |
|
|
70
|
-
| `/
|
|
76
|
+
| `/status` | Show busy/idle state, queue length, auto-approve state and pending approval count |
|
|
77
|
+
| `/queue` | Show the queue (aliases: `/q`); `/queue clear` empties it, `/queue drop <id>` removes one entry |
|
|
78
|
+
| `/cancel` | **Interrupt the task that is running right now** and empty the queue (aliases: `/stop`, `/abort`, 「取消」, 「停止」, 「中止」, 「终止」, 「算了」) |
|
|
71
79
|
| `/help` | Show help |
|
|
72
80
|
|
|
73
81
|
### Slash commands from QQ
|
|
@@ -90,15 +98,26 @@ Any message that starts with `/` is routed before it can become a chat prompt:
|
|
|
90
98
|
| `/name [name]` | get or set the session name | `commands.allowSession` |
|
|
91
99
|
| `/model [provider/model]` | list available models or switch | `commands.allowSession` |
|
|
92
100
|
| `/thinking [level]` | get or set the thinking level | `commands.allowSession` |
|
|
101
|
+
| `/tree` | list branch points (numbered), answer with a number to jump there | `commands.allowSession` |
|
|
102
|
+
| `/fork` | list earlier user messages (numbered), answer with a number to fork from it | `commands.allowSession` |
|
|
103
|
+
| `/clone` | duplicate the current session at its current leaf | `commands.allowSession` |
|
|
104
|
+
| `/resume` | list the project's other sessions (numbered), answer with a number to switch | `commands.allowSession` |
|
|
93
105
|
| `/quit` | shuts the host pi down | `commands.allowQuit` (default **false**) |
|
|
94
106
|
|
|
95
107
|
Host-only (answered, never forwarded to the model): `/settings`, `/hotkeys`, `/changelog`,
|
|
96
|
-
`/trust`, `/login`, `/logout`, `/scoped-models`, `/llama`, `/
|
|
97
|
-
`/
|
|
108
|
+
`/trust`, `/login`, `/logout`, `/scoped-models`, `/llama`, `/import`, `/export`, `/share`, `/bug`,
|
|
109
|
+
`/copy`, `/privacy`.
|
|
98
110
|
|
|
99
111
|
Guards:
|
|
100
112
|
|
|
101
|
-
- `/reload`, `/new`, `/compact` and `/
|
|
113
|
+
- `/reload`, `/new`, `/compact`, `/quit`, `/tree`, `/fork`, `/clone` and `/resume` refuse to run while a task
|
|
114
|
+
is in progress — send `/cancel` first.
|
|
115
|
+
- Prompt templates and `/skill:name` start an agent run, so while a task is in progress they are
|
|
116
|
+
**queued** like ordinary messages (see [Queueing while busy](#queueing-while-busy)). Extension commands
|
|
117
|
+
that manage their own LLM interaction still run immediately.
|
|
118
|
+
- Selection commands (`/tree`, `/fork`, `/resume`) answer with a numbered list of at most 10 entries, scoped to
|
|
119
|
+
the user who asked and valid for 10 minutes. The next bare number from that user executes the choice; anything
|
|
120
|
+
else (or 「取消」) abandons it. A number without a pending list is ordinary chat.
|
|
102
121
|
- `/reload` is off by default: it restarts the bot, and if the new code fails to load the bot stays
|
|
103
122
|
down until someone fixes it on the host. Turn it on with `commands.allowReload: true`.
|
|
104
123
|
- Why the indirection: pi only dispatches **extension** commands from a message
|
|
@@ -107,6 +126,39 @@ Guards:
|
|
|
107
126
|
hard-coded here because pi does not export its built-in list; any unknown `/word` falls back to
|
|
108
127
|
plain text.
|
|
109
128
|
|
|
129
|
+
### Queueing while busy
|
|
130
|
+
|
|
131
|
+
pi's session runs one agent run at a time, so the bot serializes QQ input itself:
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
you: 帮我把测试跑一遍
|
|
135
|
+
bot: 收到,正在处理
|
|
136
|
+
you: 顺便看看 README 有没有错别字
|
|
137
|
+
bot: 已排队 #1,当前任务结束后自动执行。发 /queue 查看队列,/cancel 可中止当前任务并清空队列。
|
|
138
|
+
you: /queue
|
|
139
|
+
bot: 当前任务:处理中(发 /cancel 可中断)
|
|
140
|
+
队列:1 条(上限 20)
|
|
141
|
+
1. #1 · 12s 前 · 顺便看看 README 有没有错别字
|
|
142
|
+
发 /queue clear 清空,/queue drop <编号> 删除一条。
|
|
143
|
+
bot: (第一轮结束后)开始执行队列 #1
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Semantics:
|
|
147
|
+
|
|
148
|
+
- Every message that would start a run — plain chat, prompt templates, `/skill:name` — is queued while a
|
|
149
|
+
task is running, in arrival order (FIFO). Replies go to the QQ user who sent that message.
|
|
150
|
+
- The next entry starts when pi has **settled** (`agent_settled`, no automatic continuation left), so a
|
|
151
|
+
retry, a compaction retry or a follow-up turn is never cut in half.
|
|
152
|
+
- The queue holds at most `queue.max` entries; beyond that the message is refused with a notice. `queue.max: 0`
|
|
153
|
+
restores the old "上一条消息还在处理中" behaviour.
|
|
154
|
+
- If handing a message to pi fails (pi was still finishing the previous run), it is put back at the head of
|
|
155
|
+
the queue and retried — messages are not lost. A run that already started is never retried, so a failure
|
|
156
|
+
inside a run cannot execute the same message twice.
|
|
157
|
+
- Control commands are **not** queued: approvals, `/status`, `/queue`, `/reset`, `/help`, the pi built-ins
|
|
158
|
+
and `/cancel` all act immediately.
|
|
159
|
+
- `/cancel` empties the queue as well, because "cancel" means "stop doing all of this". Use `/queue drop <id>`
|
|
160
|
+
to remove a single entry instead.
|
|
161
|
+
|
|
110
162
|
### Cancelling a run
|
|
111
163
|
|
|
112
164
|
Long tasks started from QQ (installs, builds, a runaway agent loop) can be interrupted without going
|
|
@@ -114,14 +166,16 @@ back to the machine:
|
|
|
114
166
|
|
|
115
167
|
```
|
|
116
168
|
you: /cancel
|
|
117
|
-
bot: 已取消当前任务,并终止了 1
|
|
169
|
+
bot: 已取消当前任务,并终止了 1 个待审批请求,队列中的 2 条已清空。可以发送新消息继续。
|
|
118
170
|
```
|
|
119
171
|
|
|
120
|
-
What it does, in order: terminate every pending approval request, call `ctx.abort()` on
|
|
121
|
-
run (the same path as pressing Escape in the TUI), drop the partially streamed answer so it is
|
|
122
|
-
sent to QQ,
|
|
123
|
-
|
|
124
|
-
|
|
172
|
+
What it does, in order: terminate every pending approval request, empty the queue, call `ctx.abort()` on
|
|
173
|
+
the current run (the same path as pressing Escape in the TUI), drop the partially streamed answer so it is
|
|
174
|
+
not sent to QQ, keep the busy flag until pi reports `agent_settled` (so messages arriving during the abort
|
|
175
|
+
are queued instead of racing it), and reply with a confirmation. If `agent_settled` never arrives, an
|
|
176
|
+
8-second watchdog releases the busy flag and continues the queue. Replies that only *look* like cancelling
|
|
177
|
+
— 「取消自动同意」, 「恢复审批」 — still go to the approval handler, so the auto-approve switch keeps working
|
|
178
|
+
as before.
|
|
125
179
|
|
|
126
180
|
Anything else is forwarded to pi as a user message.
|
|
127
181
|
|
package/config.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import { CONFIG_PATH } from "./constants";
|
|
3
3
|
import { DEFAULT_COMMANDS, type CommandConfig } from "./slash";
|
|
4
|
+
import { DEFAULT_QUEUE_MAX } from "./queue";
|
|
5
|
+
|
|
6
|
+
export interface QueueConfig {
|
|
7
|
+
/** 忙碌时最多排队多少条消息;0 = 关闭排队(忙碌时直接拒绝) */
|
|
8
|
+
max: number;
|
|
9
|
+
/** 排队任务开始执行时是否给 QQ 回执(入队回执不受此开关控制) */
|
|
10
|
+
ack: boolean;
|
|
11
|
+
}
|
|
4
12
|
|
|
5
13
|
export interface ApproveConfig {
|
|
6
14
|
/** 需要 QQ 审批的工具名(如 bash/powershell/write/edit) */
|
|
@@ -20,6 +28,8 @@ export interface QQBotConfig {
|
|
|
20
28
|
approve: ApproveConfig;
|
|
21
29
|
/** QQ 侧斜杠命令的路由开关(/reload、/new… 以及扩展命令透传) */
|
|
22
30
|
commands: CommandConfig;
|
|
31
|
+
/** 忙碌时的消息队列 */
|
|
32
|
+
queue: QueueConfig;
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
export function loadConfig(): QQBotConfig | null {
|
|
@@ -50,5 +60,9 @@ export function loadConfig(): QQBotConfig | null {
|
|
|
50
60
|
allowQuit: file.commands?.allowQuit ?? DEFAULT_COMMANDS.allowQuit,
|
|
51
61
|
allowSession: file.commands?.allowSession ?? DEFAULT_COMMANDS.allowSession,
|
|
52
62
|
},
|
|
63
|
+
queue: {
|
|
64
|
+
max: file.queue?.max ?? DEFAULT_QUEUE_MAX,
|
|
65
|
+
ack: file.queue?.ack ?? true,
|
|
66
|
+
},
|
|
53
67
|
};
|
|
54
68
|
}
|
package/constants.ts
CHANGED
|
@@ -10,6 +10,10 @@ export const MAX_REPLIES_PER_MSG_ID = 4;
|
|
|
10
10
|
export const APPROVAL_TIMEOUT_MS = 10 * 60 * 1000;
|
|
11
11
|
export const STREAM_FLUSH_INTERVAL_MS = 1200;
|
|
12
12
|
export const GATEWAY_PATH = "/gateway";
|
|
13
|
+
/** 队列任务派发给 pi 失败(通常是上一轮还没收尾)时的重试间隔 */
|
|
14
|
+
export const DISPATCH_RETRY_MS = 3000;
|
|
15
|
+
/** /cancel 之后等 agent_settled 的宽限时间,超时就强制释放 busy */
|
|
16
|
+
export const CANCEL_SETTLE_GRACE_MS = 8000;
|
|
13
17
|
|
|
14
18
|
const PI_DIR = path.join(os.homedir(), ".pi", "agent");
|
|
15
19
|
export const CONFIG_PATH = () => path.join(PI_DIR, "pi-qqbot.json");
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -11,12 +11,13 @@
|
|
|
11
11
|
| 功能 | 说明 |
|
|
12
12
|
|---|---|
|
|
13
13
|
| **对话驱动 agent** | QQ 单聊消息送入当前 pi 会话,AI 的回复发回 QQ(长文本自动分片)。 |
|
|
14
|
+
| **消息队列** | 正在处理任务时,后续 QQ 消息会被**排队**而不是被拒;当前任务结束(settled)后按到达顺序自动逐条执行。`/cancel` 是例外——立即生效并清空队列。 |
|
|
14
15
|
| **远程审批** | pi 执行 `bash` / `powershell` / `write` / `edit`,或任何带 `destructiveHint` 注解的工具前,先在 QQ 里申请审批。 |
|
|
15
16
|
| **会话级「以后都同意」** | 回复「以后都同意」,**当前会话**内所有审批请求直接放行,连已经挂起的那条也一起放行。 |
|
|
16
17
|
| **单实例锁** | 只有一个 pi 进程作为宿主连接 QQ,其余待命,宿主退出后自动接管。 |
|
|
17
|
-
| **中断正在运行的任务** | 发 `/cancel`(或「取消」/「停止」),当前任务立刻中断 —— QQ
|
|
18
|
+
| **中断正在运行的任务** | 发 `/cancel`(或「取消」/「停止」),当前任务立刻中断 —— QQ 回复、待审批工具调用、写到一半的回答、排队中的消息一并清理。 |
|
|
18
19
|
| **斜杠命令路由** | 以 `/` 开头的 QQ 消息会先被路由:pi 的扩展命令、prompt 模板、`/skill:name` 交给 pi 派发;一部分 pi 内置命令(`/reload`、`/new`、`/compact`、`/session`、`/name`、`/model`、`/thinking`、`/quit`)由本扩展接管;只能在主机执行的内置命令直接回执,不会送给模型。 |
|
|
19
|
-
| **内置指令** | `/status`、`/reset`、`/cancel`、`/help`。 |
|
|
20
|
+
| **内置指令** | `/status`、`/queue`、`/reset`、`/cancel`、`/help`。 |
|
|
20
21
|
|
|
21
22
|
## 安装
|
|
22
23
|
|
|
@@ -42,6 +43,10 @@ pi install ./pi-qqbot
|
|
|
42
43
|
"approve": {
|
|
43
44
|
"tools": ["bash", "powershell", "write", "edit"],
|
|
44
45
|
"remember": true
|
|
46
|
+
},
|
|
47
|
+
"queue": {
|
|
48
|
+
"max": 20,
|
|
49
|
+
"ack": true
|
|
45
50
|
}
|
|
46
51
|
}
|
|
47
52
|
```
|
|
@@ -56,6 +61,8 @@ pi install ./pi-qqbot
|
|
|
56
61
|
| `approve.tools` | `["bash","powershell","write","edit"]` | 需要审批的工具名;带 `destructiveHint` 注解的工具同样会拦截 |
|
|
57
62
|
| `approve.remember` | `true` | 会话内按工具记住决策(同类工具不再重复询问) |
|
|
58
63
|
| `commands` | 见下 | 斜杠命令路由开关:`passthrough`、`allowReload`、`allowQuit`、`allowSession` |
|
|
64
|
+
| `queue.max` | `20` | 任务运行期间最多排队多少条;`0` = 关闭排队(忙碌时直接拒绍,回到旧行为) |
|
|
65
|
+
| `queue.ack` | `true` | 排队消息开始执行时是否回执 QQ(入队回执总是会发) |
|
|
59
66
|
|
|
60
67
|
也可用环境变量 `QQ_BOT_APPID` / `QQ_BOT_APPSECRET` 代替文件里的凭据。
|
|
61
68
|
|
|
@@ -66,8 +73,9 @@ pi install ./pi-qqbot
|
|
|
66
73
|
| 指令 | 说明 |
|
|
67
74
|
|---|---|
|
|
68
75
|
| `/reset` | 重置:清空回复缓冲、审批记忆与自动同意开关(**不换会话**,换会话发 `/new`) |
|
|
69
|
-
| `/status` |
|
|
70
|
-
| `/
|
|
76
|
+
| `/status` | 查看忙闲状态、队列长度、自动同意状态、待审批数量 |
|
|
77
|
+
| `/queue` | 查看队列(别名 `/q`);`/queue clear` 清空,`/queue drop <编号>` 删一条 |
|
|
78
|
+
| `/cancel` | **中断当前正在运行的任务**并清空队列(别名:`/stop`、`/abort`、「取消」、「停止」、「中止」、「终止」、「算了」) |
|
|
71
79
|
| `/help` | 帮助 |
|
|
72
80
|
|
|
73
81
|
### QQ 里的斜杠命令
|
|
@@ -90,15 +98,23 @@ pi install ./pi-qqbot
|
|
|
90
98
|
| `/name [名字]` | 查看或设置会话名 | `commands.allowSession` |
|
|
91
99
|
| `/model [provider/model]` | 列出可用模型或切换 | `commands.allowSession` |
|
|
92
100
|
| `/thinking [等级]` | 查看或设置思考等级 | `commands.allowSession` |
|
|
101
|
+
| `/tree` | 列出会话树上的分支点(编号),回编号即跳转 | `commands.allowSession` |
|
|
102
|
+
| `/fork` | 列出之前的用户消息(编号),回编号即从该处分叉 | `commands.allowSession` |
|
|
103
|
+
| `/clone` | 在当前叶子位置复制整个会话 | `commands.allowSession` |
|
|
104
|
+
| `/resume` | 列出本项目其他会话(编号),回编号即切换 | `commands.allowSession` |
|
|
93
105
|
| `/quit` | 关掉主机上的 pi | `commands.allowQuit`(默认 **false**) |
|
|
94
106
|
|
|
95
107
|
只能在主机执行(回执,不转发给模型):`/settings`、`/hotkeys`、`/changelog`、`/trust`、`/login`、
|
|
96
|
-
`/logout`、`/scoped-models`、`/llama`、`/
|
|
97
|
-
`/share`、`/bug`、`/copy`、`/privacy`、`/handoff`。
|
|
108
|
+
`/logout`、`/scoped-models`、`/llama`、`/import`、`/export`、`/share`、`/bug`、`/copy`、`/privacy`。
|
|
98
109
|
|
|
99
110
|
约束:
|
|
100
111
|
|
|
101
|
-
- 有任务在跑时,`/reload`、`/new`、`/compact`、`/quit` 会拒绝执行
|
|
112
|
+
- 有任务在跑时,`/reload`、`/new`、`/compact`、`/quit`、`/tree`、`/fork`、`/clone`、`/resume` 会拒绝执行
|
|
113
|
+
—— 先发 `/cancel`。
|
|
114
|
+
- prompt 模板与 `/skill:name` 会开启一轮 agent run,因此忙碌时会像普通消息一样**排队**
|
|
115
|
+
(见 [忙碌时的队列](#忙碌时的队列));自己管理 LLM 交互的扩展命令仍然立即执行。
|
|
116
|
+
- 选择型命令(`/tree`、`/fork`、`/resume`)会回一个最多 10 项的编号列表,只对该用户有效、10 分钟内有效;
|
|
117
|
+
该用户下一条「纯数字」消息即执行选择,其它内容(或「取消」)则放弃。没有待选列表时,数字就是普通对话。
|
|
102
118
|
- `/reload` 默认关闭:它会重启 bot,如果新代码加载失败,bot 会一直哑着,只能在主机上救。
|
|
103
119
|
置 `commands.allowReload: true` 才启用。
|
|
104
120
|
- 为什么要绕一层:pi 只对**扩展命令**执行派发(`prompt()` → `_tryExecuteExtensionCommand`),而
|
|
@@ -106,17 +122,49 @@ pi install ./pi-qqbot
|
|
|
106
122
|
改派成 `/qq reload`。内置命令名是硬编码的(pi 没有把内置清单导出给扩展);任何不认识的
|
|
107
123
|
`/xxx` 都会退回当普通文字。
|
|
108
124
|
|
|
125
|
+
### 忙碌时的队列
|
|
126
|
+
|
|
127
|
+
pi 的会话一次只跑一轮 agent run,所以串行调度由 bot 自己做:
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
你:帮我把测试跑一遍
|
|
131
|
+
机器人:收到,正在处理
|
|
132
|
+
你:顺便看看 README 有没有错别字
|
|
133
|
+
机器人:已排队 #1,当前任务结束后自动执行。发 /queue 查看队列,/cancel 可中止当前任务并清空队列。
|
|
134
|
+
你:/queue
|
|
135
|
+
机器人:当前任务:处理中(发 /cancel 可中断)
|
|
136
|
+
队列:1 条(上限 20)
|
|
137
|
+
1. #1 · 12s 前 · 顺便看看 README 有没有错别字
|
|
138
|
+
发 /queue clear 清空,/queue drop <编号> 删除一条。
|
|
139
|
+
机器人:(第一轮结束后)开始执行队列 #1
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
语义:
|
|
143
|
+
|
|
144
|
+
- 会开启一轮 run 的消息(普通对话、prompt 模板、`/skill:name`)在忙碌时按到达顺序(FIFO)排队;
|
|
145
|
+
回复发给该条消息的发送者。
|
|
146
|
+
- 下一条在 pi **settled**(不再有任何自动续跑)之后才启动,所以重试、压缩重试、follow-up 轮次
|
|
147
|
+
不会被从中间撗断。
|
|
148
|
+
- 队列上限为 `queue.max`,超出时拒绍入队并回执;`queue.max: 0` 回到旧的「上一条消息还在处理中」。
|
|
149
|
+
- 交给 pi 失败时(通常上一轮还没收尾)任务会放回队首重试,不丢消息;已经真的启动过 run 的报错
|
|
150
|
+
不会重试,避免同一条消息执行两次。
|
|
151
|
+
- 控制类指令**不排队**:审批回复、`/status`、`/queue`、`/reset`、`/help`、pi 内置命令与 `/cancel`
|
|
152
|
+
都立即生效。
|
|
153
|
+
- `/cancel` 会连队列一起清空(“取消”就是“都别做了”);只想删一条请用 `/queue drop <编号>`。
|
|
154
|
+
|
|
109
155
|
### 取消正在运行的任务
|
|
110
156
|
|
|
111
157
|
从 QQ 发起的耗时任务(装依赖、编译、agent 跑飞了)不必回到机器上处理:
|
|
112
158
|
|
|
113
159
|
```
|
|
114
160
|
你:/cancel
|
|
115
|
-
机器人:已取消当前任务,并终止了 1
|
|
161
|
+
机器人:已取消当前任务,并终止了 1 个待审批请求,队列中的 2 条已清空。可以发送新消息继续。
|
|
116
162
|
```
|
|
117
163
|
|
|
118
|
-
|
|
119
|
-
丢弃已经流式产生的半截回答(不会发到 QQ
|
|
164
|
+
执行顺序:先终止所有待审批请求、清空队列,再对当前 run 调用 `ctx.abort()`(和 TUI 里按 Escape 同一条路径),
|
|
165
|
+
丢弃已经流式产生的半截回答(不会发到 QQ),**忙碌标记保留到 pi 报 `agent_settled`**
|
|
166
|
+
(所以 abort 期间新来的消息会排队,而不是和收尾中的 run 撞车),最后回执确认。如果 `agent_settled`
|
|
167
|
+
一直不来,8 秒看门狗会强制释放忙碌标记并继续队列。
|
|
120
168
|
像「取消自动同意」「恢复审批」这类**只是长得像**取消的回复仍然走审批分支,自动同意开关行为不变。
|
|
121
169
|
|
|
122
170
|
其余文本都作为用户消息交给 pi。
|