mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-06 17:27:31 +00:00
## 一、插件声明层(用户裁定)
> 「敏感词策略也应该是插件声明啊,每个插件声明自己轮次以及自己工具的
> 敏感词策略」
SecurityProfile 新增两个字段:
ToolSensitiveWords map[string][]string // key=工具名模式(尾 *),value=词表
DetectInjection bool // 开启内核内置注入迹象识别
语义是**追加不覆盖**:整轮 SensitiveWords 仍然生效。
取宽不取窄的理由:当前处置是 B 档(标记+警示,不阻断),
多标一条只是多一句警示,漏标则是安全缺口。
## 二、修掉我自己造的「莲藕式分层」
前一版把 *security.Round 从 runInputTask 一路搬到工具链
(prepareInputTask(evt, round) → TaskFrame.SecRound →
executeToolCallOutcomeWithRound),并在 rtchild 里另补一条。
那是把**分层策略实现成跨层传参**:每多一条工具执行路径就要求调用方
多传一次句柄。profileActivator 的设计注释早就写明了正路:
> 工具调用发生在 LLM 决定之后,此时插件已不在调用栈上。
> 唯一可靠的传递方式是**内核在输入进来时记住**,在该轮的工具判定里使用。
改为 security 自取:
Runtime.ScanContentForAgent(agentID, isChild, ins, text)
→ ForAgent(agentID, isChild) // per-agent 视图,天然不串档
→ EffectiveProfile() // session > longtime
→ 合并 全局词表 + 档位词表 + 工具词表 + DetectInjection
core 只递交**事实**(我是谁 / 哪个工具 / 什么文本),不认识 Round。
与 CheckToolForAgent 同一套身份推断,不引入第二个入口语义。
TaskFrame.SecRound / executeToolCallOutcomeWithRound 全部撤除。
## 三、目录名统一
third_party/homeagent-sdk → third_party/hologramagentsdk
module 与远端仓早已是 hologramagentsdk,只剩物理目录是遗留名。
同步改了 go.mod replace、构建/打包/部署脚本、5 处测试里的分段路径。
注意:这里改的是**主仓 vendored 的 SDK 源码路径**,example/ 由 SDK
独立仓自己跟踪,主仓不涉及。
## 判据
TestToolSensitiveWordsAppendOnlyForThatTool 词表只对目标工具生效 + 追加语义
TestToolSensitiveWordsUseAgentScope security 按 agent scope 自取生效
(变异验证:删掉 ForAgent 查询 → 红)
## 验证
go build ./... → 0
go vet ./... → 0
go test ./... -count=1 -race → 62 ok / 0 FAIL / 0 DATA RACE
gofmt -l internal/ → 干净
67 lines
3.0 KiB
Go
67 lines
3.0 KiB
Go
package sdk
|
||
|
||
// 受限事件总线(EventsAPI)。
|
||
//
|
||
// ## 为什么现在才敢暴露
|
||
//
|
||
// 事件总线是内核内部机制:它连接内核模块、状态面、WebUI 与插件。
|
||
// 早先不给插件的理由是**没有边界**——一给就是"任何插件能发任何事件、能订阅任何事件",
|
||
// 等于把内核内部的同步面变成公共 API,且没有任何审查。
|
||
//
|
||
// 2026-10 之后内核侧有了 security 模块(凭据闸门 + 内容审查 + 审计),
|
||
// 于是可以只开**受限的一条缝**:
|
||
//
|
||
// · 发布:只能用白名单事件类型,且只能在自己的命名空间下扩展
|
||
// · 载荷:出向经 security 审查(明文凭据会被换成 @{别名}),并限制大小
|
||
// · 订阅:只能订阅白名单里的只读事件
|
||
//
|
||
// ## 插件能做什么
|
||
//
|
||
// Publish("skill_detected", {...}) // 交接类事件(兼容层 → skillmgr)
|
||
// Publish("plugin.<自己名字>.<任意>", {...}) // 自己的命名空间,供插件间协作
|
||
// Subscribe("tools_ready", handler) // 等内核就绪再做事的入口
|
||
//
|
||
// 越界会**报错**而不是静默丢弃:静默丢弃会让插件以为发成功了。
|
||
|
||
// EventsAPI 是插件可见的事件总线。
|
||
//
|
||
// 它**不是** *events.Bus 的投影:这是一个有边界、有审查的接口。
|
||
type EventsAPI interface {
|
||
// Publish 发布一个事件。
|
||
//
|
||
// eventType 必须在白名单内(见 AllowedPublish),或形如
|
||
// "plugin.<本插件名>.<后缀>"。载荷大小与键数有上限。
|
||
Publish(eventType string, payload map[string]interface{}) error
|
||
|
||
// Subscribe 订阅一个白名单内的事件(只读面)。
|
||
//
|
||
// 返回的 cancel 在插件 Stop 时调用可解除订阅;宿主卸载插件时也会自动解除。
|
||
// handler 的 panic 会被总线隔离,不影响其他订阅者。
|
||
Subscribe(eventType string, handler func(payload map[string]interface{})) (cancel func(), err error)
|
||
|
||
// AllowedPublish 返回当前可发布的事件类型(白名单 + 自己的命名空间前缀)。
|
||
AllowedPublish() []string
|
||
|
||
// AllowedSubscribe 返回当前可订阅的事件类型。
|
||
AllowedSubscribe() []string
|
||
}
|
||
|
||
// 常用事件名(**只是名字,不是授权表**)。
|
||
//
|
||
// 授权表由内核 security 模块持有(`security.EventPolicy`)并可随配置调整;
|
||
// SDK 侧只声明"这些名字存在",避免插件作者拼错字符串。
|
||
//
|
||
// 是否允许你用某个名字,以运行时 `Events().Publish/Subscribe` 的返回为准:
|
||
// 越界会**报错**,不会静默丢弃。
|
||
const (
|
||
// EventNameSkillDetected:兼容层把发现的纯 SKILL 条目交给 skillmgr 接管。
|
||
// (职责链交接,不是执行指令)
|
||
EventNameSkillDetected = "skill_detected"
|
||
// EventNameToolsReady:全部插件加载完、工具注册齐(只读订阅)。
|
||
EventNameToolsReady = "tools_ready"
|
||
// EventNameSecurityReady:安全闸门装配完成(只读订阅)。
|
||
EventNameSecurityReady = "security_ready"
|
||
// EventNameDeviceReady:工具/设备数据面就绪(只读订阅)。
|
||
EventNameDeviceReady = "device_ready"
|
||
)
|