diff --git a/cloud/README.md b/cloud/README.md index cfe629b..00b4c26 100644 --- a/cloud/README.md +++ b/cloud/README.md @@ -512,6 +512,49 @@ goal 模式的继续:server 把任务转成新 goal 语义(goal=新消息、 合并任务 worktree 已删、请分支(merged 409);冲突与新建一致 (plan + approval=full、plan + goal 各 400)。 +## 任务间互发消息(peer messages,Muse 式通用互发) + +任意两个同项目任务可以互发消息、对方做完可以回消息,不 +用经过用户中转。两个发送方: + +- API:`POST /tasks/<目标>/messages`,body + `{from_task_id, body, mode}`(mode 缺省 queued);调用方 + 须对目标项目有 create_task、对发送任务项目有 read(防冒 + 名)。`GET /tasks/<任务>/messages` 列出该任务发出的消息 + (收到的在 `/followups` 里,带 sender_task_id)。 +- Agent:任务里跑的 agent 在回合输出里写标记块,worker 在 + 回合结束后解析并投递——agent 不用联网、不用凭证,本地 + 与 Docker 执行器都通。块格式见 + `examples/peer-message-prompt.txt`;每轮最多 5 块。 + +投递语义(核心约束:互发消息不中断任务): + +- 目标排队中 / 运行中:消息排成一条后续消息(带 + sender_task_id),worker 排空循环在轮次边界执行——direct + 优先、队内 FIFO,与用户后续消息同款,当前轮绝不被打断。 + 接收方 agent 看到的 prompt 带发送方前缀 + `[来自任务 的消息]`,凭此知道回给哪个任务。 +- 目标已终态(completed / failed / interrupted):消息复活 + 它——把带前缀的正文写进 resume_message 并把状态置回 + queued,下次认领按续跑跑这一轮。没有复活,B 回给已结束 + 的 A 的消息会直接丢失,A→B→A 的往返没法成立。 +- 一律拒绝(409 或投递层跳过,只记审计):发给自己、跨 + 项目、目标是 goal 任务、目标已合并、目标已有待续跑消息 + (复活位被占)、目标不存在。 +- 只有 completed 轮次的标记块被投递(失败 / 超时 / 取消 / + 配额中断的轮次不投递);goal 任务的回合不解析标记块,且 + 目标是 goal 时直接拒绝——所以 goal 任务既不收也不发。 +- 投递不查发送方配额(发送本身不花钱),但目标任务执行时 + 的配额门照常生效:排空前查配额,超限时该条回 pending、 + 任务走配额中断;复活任务认领时认领门同样生效。互发消息 + 不构成配额绕过。 +- 边界:标记块正文不能含围栏(非贪婪匹配会把块截断成非法 + JSON 而被跳过);worker 投递的 direct 消息只有排空优先 + 权,没有 API 直接发送那种“立即进链路”的标记(worker 侧 + 链路目录不一定在本机);复活投递的消息没有 followup 行, + 发出列表里查不到,查审计 peer_message_sent 与目标的续跑 + 轮次;控制台“给其他任务发消息”框走 /tasks 下的 + /messages,不用新增 nginx location。 ## 测试 diff --git a/cloud/console.html b/cloud/console.html index a5f34c8..c84942d 100644 --- a/cloud/console.html +++ b/cloud/console.html @@ -263,6 +263,17 @@
+

给其他任务发消息

+
+ + +
+ + + +
+
+