opencode: 修正权限档位接线——session.create 不支持 permission,改用提示词 advisory

根因:opencode 1.18.29 的 session.create API 只接受 {parentID, title} + query.directory,
permission 字段被静默丢弃(SDK types.gen.d.ts 证实 SessionCreateData 无此字段)。
之前传入的规则不报错也不生效,plan 档下 bash 仍执行。

修复:
- 移除 session.create({permission: ...}) 调用(已被 API 忽略)
- 在 deliverMail 的 prompt 构造里注入 permBriefing(modeBriefing advisory 路径)
- permBriefing 与 homeagent 同理:如实说「这个平台无法强制这一档」
- 修正 catch (e: any) 语法错误(.js 文件不支持 TS 类型注解)
- 补充 import modeBriefing

L5 实测:opencode plan 档回信「由于当前权限档位为 plan(只读),我无法直接执行 bash 命令」
模型自愿遵守 advisory 约束(行为正确,但非平台强制)
This commit is contained in:
2026-09-06 20:38:33 +08:00
parent b76d0d6c96
commit fc958f8809
2 changed files with 29 additions and 5 deletions

View File

@ -682,11 +682,15 @@ async function resolveSessionForMail(client, directory, data, kind) {
// 故意不传 titleopencode 只在标题缺省时才让模型按首轮对话生成摘要标题,
// 传了占位标题就等于掐掉平台自己的命名机制。标题稍后由 session.updated 事件回写。
const permMode = normalizeMode(data.permission_mode);
const created = await client.session.create({
query: wantDir ? { directory: wantDir } : undefined,
permission: opencodePermissions(permMode),
});
let created;
try {
created = await client.session.create({
query: wantDir ? { directory: wantDir } : undefined,
});
} catch (e) {
console.error(`[mail-bridge] session.create 失败: ${e?.message || e}`);
throw e;
}
const session = created?.data ?? created;
const sessionID = session?.id;
if (!sessionID) throw new Error("session.create 未返回 id");
@ -901,6 +905,9 @@ async function deliverMail(client, directory, data, kind) {
}
const fromHuman = data.from_human === true;
// opencode 1.18+ 不支持 session.create permission 参数,
// 只能在提示词里告知模型档位约束advisory 路径)。
const permBriefing = modeBriefing({ mode: normalizeMode(data.permission_mode), enforcement: 'advisory', workspace: directory || '' });
const text = kind === "permission"
? `你之前发起的权限请求已有结论:${data.decision}(决策人:${data.decided_by || "用户"})。请据此继续后续工作。`
: [
@ -921,6 +928,8 @@ async function deliverMail(client, directory, data, kind) {
`请先调用 read_inbox 读取完整正文(附带附件清单,如有附件可用 download_attachment 取回),然后处理其中的请求。`,
``,
...replyInstruction({ fromHuman, replyAddress: data.reply_address }),
``,
permBriefing,
].join("\n");
// 按管理员划定的范围逐个尝试,全部失败才回一封说明失败原因的邮件。