diff --git a/plugins/homeagent-mail-bridge/permission_mode.go b/plugins/homeagent-mail-bridge/permission_mode.go new file mode 100644 index 0000000..2ee56fd --- /dev/null +++ b/plugins/homeagent-mail-bridge/permission_mode.go @@ -0,0 +1,53 @@ +package main + +// permission_mode.go — 权限档位的本地翻译(advisory:仅提示词告知模型) +// +// homeagent 没有任何工具调用拦截点(没有 tool_call hook、没有沙箱), +// 档位在这里是 advisory —— 只能在提示词里告诉模型「请遵守」。 +// 假装是强制的更危险:模型会以为越界会被拦,于是不必自己小心, +// 那比做不到本身更危险。 + +const ( + ModePlan = "plan" + ModeWorkspace = "workspace" + ModeFull = "full" +) + +var validModes = map[string]bool{ + ModePlan: true, ModeWorkspace: true, ModeFull: true, +} + +// NormalizeMode 把外部输入收敛成合法档位。 +// 非法值回落到默认档(workspace),不是 full。 +func NormalizeMode(m string) string { + if validModes[m] { + return m + } + return ModeWorkspace +} + +// ModeBriefing 生成给模型看的档位说明,放进提示词。 +// +// homeagent 永远是 advisory(无法强制),所以措辞必须如实说 +// 「这个平台无法强制这一档」—— 假装强制会让模型以为越界会被拦, +// 于是不必自己小心,那比做不到本身更危险。 +func ModeBriefing(mode, enforcement string) string { + m := NormalizeMode(mode) + + if m == ModeFull { + return "本任务权限档位:full(全权)。工具调用不需要额外授权。" + } + + if m == ModePlan { + return "本任务权限档位:plan(只读)。" + + "**这个平台无法强制这一档**,所以约束靠你自己遵守:" + + "请不要写文件、改文件或执行命令。" + + "请把结论、方案、需要人工执行的步骤写在回信里。" + + "需要动手请让发件人把档位改成 workspace。" + } + + // workspace + return "本任务权限档位:workspace。请把改动限制在本任务的工作目录内。" + + "**这个平台无法强制这一档**,所以边界靠你自己遵守:" + + "需要改该目录之外的东西时,不要直接动手,先在回信里说明。" +} diff --git a/plugins/homeagent-mail-bridge/plugin.go b/plugins/homeagent-mail-bridge/plugin.go index 9998287..4c1dca2 100644 --- a/plugins/homeagent-mail-bridge/plugin.go +++ b/plugins/homeagent-mail-bridge/plugin.go @@ -501,6 +501,7 @@ func (p *Plugin) register() error { func (p *Plugin) heartbeat() error { payload := map[string]interface{}{} + payload["mode_enforcement"] = "advisory" // homeagent 无沙箱,档位只在提示词里告知 // B-2.3:带上模型目录 if len(p.modelCatalog) > 0 { @@ -698,6 +699,9 @@ type mailEvent struct { FromHuman bool `json:"from_human"` // InReplyTo 非空 = 这封是对本方某封信的回复,不是新派的活。 InReplyTo string `json:"in_reply_to"` + // PermissionMode 是会话的权限档位(plan / workspace / full)。 + // homeagent 无法强制执行任何档位(advisory),只能在提示词里告知模型。 + PermissionMode string `json:"permission_mode"` // Decision / DecidedBy 只在 permission_decision 事件上有值。 Decision string `json:"decision"` DecidedBy string `json:"decided_by"` @@ -970,10 +974,11 @@ func (p *Plugin) handleNewMail(evt mailEvent, resumed bool) { "%s\n\n"+ "发件人:%s\n主题:%s\n邮件 ID:%s\n%s身份:你是 %s\n%s\n"+ "请先调用 read_inbox 读取完整正文,然后处理其中的请求。\n\n"+ - "%s", + "%s\n%s", inboundHeadline(evt.InReplyTo, evt.FromHuman, false), evt.FromName, evt.Subject, evt.MailID, replyLine, p.agentName, addrLine, replyInstruction(evt.FromHuman, evt.ReplyAddr), + ModeBriefing(evt.PermissionMode, "advisory"), ) // InjectInputSync 阻塞等待 agent 处理完毕,返回最终回复文本。