承接 453f451(pi 桥)。用户批准后把同款缺口在其余四家逐一核对:
**zcode 本来就有**(`说明:${decision.note}`),homeagent / dsh / opencode 三家缺。
## homeagent(Go,能完整修)
SSE 事件结构里**根本没有 Note 字段**(json 里只有 decision/decided_by)⇒ 备注在
解码那一步就没了。补上字段,并把提示词抽成纯函数 `permissionDecisionPrompt(evt)`,
加了判据(说明必须出现 + 反向对照:无说明/空白说明不得凭空造出说明段)。
构建(`go build -buildmode=plugin`)后 install 到
`/home/newqqagent/plugins/homeagent-mail-bridge/plugin.bin` 并重启,已核验部署件
含新符号(`grep -a`,中文用 strings 查是查不到的)。
## dsh / opencode(平台回执放不下理由 → 分两步)
两家的审批回执都是**三态字符串**:DSH `ApprovalOutcome` 只有
allowed-once / rejected / cancelled / unavailable,openCode 只有 once / always / reject
—— **没有地方放人类的说明**。所以:
1. 提示词("你之前发起的权限请求已有结论:…")统一走 `permissionPrompt(data)`,
带上 `用户的说明:…`。dsh 原有**三处**内联文案(续谈/新会话/通知投递),
措辞分叉正是这类信息漏掉的地方 —— 判据直接钉"只有一处拼这句话"。
2. 带说明的决策**另投一趟通知**,让模型在会话里看到理由。代价是多一轮;比悄悄
丢掉人的指令轻(原缺陷就是丢了指令,模型把同一条命令换写法又问一遍,连问 9 次)。
3. 决策回执不再被当成"新任务"(内容已随 permission_decision 交付),并记下
`decision_mail_id` 防重复 —— 与 pi 桥同源。
判据:dsh / opencode 各 5 条(含"拿缺陷时的源码形态喂进来必须判红"的自检)。
## 部署与代价
- dsh → 快照 20260914-081456、opencode → 20260914-081516、homeagent → 新 plugin.bin,
三家的服务 active 且心跳/连接已核。
- 重启 dsh 时它正在"续谈"一封邮件(08:10:45 日志)——事后核对:那一轮**已回完**
(faad0037 的 parent = 4919aa88),没有丢活。
- 套件:dsh 372、opencode 323、homeagent go test ok、zcode 382 全绿。
31 lines
1.2 KiB
Go
31 lines
1.2 KiB
Go
package main
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
// 人类的说明必须出现在注入给模型的提示词里。
|
||
//
|
||
// 缺陷现场(2026-09-13):人类在权限决策里写「我说了让你拉取仓库到program下你听不懂吗」,
|
||
// 而注入的提示词只有"结论 + 决策人" —— 模型不知道要改什么,把同一条命令又问了一遍。
|
||
func TestPermissionDecisionPromptCarriesNote(t *testing.T) {
|
||
const note = "我说了让你拉取仓库到program下你听不懂吗"
|
||
got := permissionDecisionPrompt(mailEvent{
|
||
Subject: "拒绝", FromName: "jianf", Note: note,
|
||
})
|
||
if !strings.Contains(got, note) {
|
||
t.Fatalf("提示词必须原样带上人类的说明,实际:%q", got)
|
||
}
|
||
|
||
// 反向对照:没写说明时不得凭空造出"用户的说明"
|
||
plain := permissionDecisionPrompt(mailEvent{Subject: "同意", FromName: "jianf"})
|
||
if strings.Contains(plain, "用户的说明") {
|
||
t.Fatalf("无说明却出现了说明段:%q", plain)
|
||
}
|
||
// 空白说明同样算没有(ss TrimSpace 过的)
|
||
if s := permissionDecisionPrompt(mailEvent{Subject: "拒绝", FromName: "jianf", Note: " "}); strings.Contains(s, "用户的说明") {
|
||
t.Fatalf("空白说明不该算说明:%q", s)
|
||
}
|
||
}
|