mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-01 14:57:38 +00:00
security(新模块 internal/kernelmod/security)
- 凭据闸门:出向拦截成 @{别名}、入向清洗、执行前回填(internal/security/{gate,runtime}.go)
- 工具黑白名单 + 沙箱(读写根、网络、.. 逃逸):internal/security/policy.go
- 敏感词过滤 + 提示词注入预警(Finding 不带原文):internal/security/content.go
- 按主体授权(hard-private 对非内部主体永久拒绝):internal/security/principal.go
- 插件命名限式(可选档位,插件声明/内核执行,只能收窄):internal/security/profile.go
- 启动装配从 cmd/homed 迁入模块;启动顺序判据改盯真实装配点
device(新模块)
- 正式内核模块,Provides FacDevice,KernelState.Device
- 内置工具路由表下沉到 internal/toolroute(避免 core↔kernelboot 环),
device 保留对外入口;agent 未挂载时退化本地 switch
- Agent 侧只留 api.ToolHost/DeviceSurface 适配层
SDK
- InjectOptions.SecurityProfile:插件按 inputch 声明本轮安全档位(可选)
- InjectOptions.TurnHint:插件注入**本轮事实**,内核以独立 system 消息注入,
不混进用户正文(人设负责怎么说话,TurnHint 只放这一轮成立的事实)
- FacilitySecurity / FacilityDevice
提示词
- 内核自带 prompt/skill/工具返回全面英文化(中文提示会让模型行为漂移)
- 机制解释下沉到 4 个内置 skill(memory/output/tool-order/plugins),
skill 描述压到 80 runes 内(原来 94–108 全被索引截断)
- 默认人格模板英文化;[Voice] 段删除,规则并入 persona 块(单一段落)
- 历史记忆工具改名 coldcontext_query/commit,图记忆语义改称 stable memory
修复
- tracker: exec mount → unix.Mount(降权运行 + AmbientCapabilities 下才能挂)、
区分 EPERM 与不支持;启动日志说明后果与恢复方式
- healthcheck_kernel 输出瘦身:status.Tools 只给摘要(原 98,989 tokens/151% 预算)
- plugin_list 描述讲清 auto_start(按需)与 alive(此刻是否在跑),
明确不能由 alive=false 推断能力不存在
- pluginmgr/webui 去掉写死的 /home/newqqagent 回退路径(env → pluginDir 反推 → 报错)
- lua: 盘上适配器与内置版本不一致且无基线时响亮告警(deepseek 流式丢失
tool_calls 导致'模型不调工具'的真因)
测试:go build ./... 通过;go test ./... 60 包全绿
160 lines
5.3 KiB
Go
160 lines
5.3 KiB
Go
package core
|
||
|
||
// Agent 侧的 **device 数据面适配层**。
|
||
//
|
||
// ## 为什么适配层在 core 而不是让 device 直接操作 Agent
|
||
//
|
||
// 工具执行必须**始终**经过 Agent 的完整执行链:
|
||
//
|
||
// 参数 schema 校验 → 工具授权闸 / 设备授权闸 → 超时与取消
|
||
// → panic 恢复 → 明文脱敏(出向 + 入向)→ ToolResult 成败判定
|
||
//
|
||
// 这些是**执行安全**,与敏感信息安全(security 模块)是两件事,
|
||
// 都不能被对方顶替(见 plan.md §五)。所以 device 只拿到窄接口
|
||
// (api.ToolHost),拿不到 Agent 内部字段,也就绕过不了这条链。
|
||
|
||
import (
|
||
"sort"
|
||
|
||
"github.com/JianFeeeee/HologramAgent/internal/agent/api"
|
||
)
|
||
|
||
// ToolDefinitions 实现 api.ToolHost:返回当前可见的工具定义。
|
||
//
|
||
// ★ 复用 buildToolDefs 的同一批生成逻辑 —— 两处各写一份必然漂移
|
||
// (历史上就出现过"模型看得到但插件查不到"的两套语义)。
|
||
func (a *Agent) ToolDefinitions() []api.ToolDefinition {
|
||
if a == nil {
|
||
return nil
|
||
}
|
||
raw := a.buildToolDefs()
|
||
out := make([]api.ToolDefinition, 0, len(raw))
|
||
for _, item := range raw {
|
||
m, ok := item.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
fn, ok := m["function"].(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
name, _ := fn["name"].(string)
|
||
if name == "" {
|
||
continue
|
||
}
|
||
desc, _ := fn["description"].(string)
|
||
out = append(out, api.ToolDefinition{
|
||
Name: name,
|
||
Description: desc,
|
||
// 并发资格与超时**不在这里重算**:它们由 argvalidate.go 的
|
||
// batchRunnable / resolveToolTimeout 统一判定(单一事实来源)。
|
||
ParallelSafe: a.toolParallelSafe(name),
|
||
Timeout: "",
|
||
})
|
||
}
|
||
sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name })
|
||
return out
|
||
}
|
||
|
||
// ExecuteTool 实现 api.ToolHost:走完整执行链执行一次工具调用。
|
||
//
|
||
// 通道用内置标记:工具执行本身不产出"用户可见输出",
|
||
// 而记忆写入等场景需要一个稳定的来源标识(见 defaultChannelForBuiltin)。
|
||
func (a *Agent) ExecuteTool(name string, args map[string]interface{}) (string, error) {
|
||
if a == nil {
|
||
return "", errNoAgentForDevice
|
||
}
|
||
return a.executeToolCall(api.ToolCall{
|
||
ID: "device_" + name,
|
||
Name: name,
|
||
Arguments: args,
|
||
}, a.defaultChannelForBuiltin()), nil
|
||
}
|
||
|
||
// MountDevice 挂载 device 数据面。
|
||
//
|
||
// 单向依赖:core 只认识低层接口(api.DeviceSurface),不认识
|
||
// kernelmod/device 的具体类型 —— 否则 core ↔ kernelboot ↔ device 会成环。
|
||
//
|
||
// 幂等:重复挂载只覆盖(装配期可能因重建 Agent 而重挂)。
|
||
func (a *Agent) MountDevice(d api.DeviceSurface) {
|
||
if a == nil {
|
||
return
|
||
}
|
||
// 挂载同时接上路由适配器:device 由此拿到"选族后调谁"。
|
||
a.builtinHandlers = builtinHandlers{a: a}
|
||
a.deviceMu.Lock()
|
||
a.device = d
|
||
a.deviceMu.Unlock()
|
||
}
|
||
|
||
// Device 返回已挂载的数据面(未挂载时为 nil)。
|
||
func (a *Agent) Device() api.DeviceSurface {
|
||
if a == nil {
|
||
return nil
|
||
}
|
||
a.deviceMu.RLock()
|
||
defer a.deviceMu.RUnlock()
|
||
return a.device
|
||
}
|
||
|
||
// errNoAgentForDevice 表示 device 调用时 Agent 未装配(装配顺序错误)。
|
||
var errNoAgentForDevice = &deviceHostErr{"device: agent 未装配"}
|
||
|
||
type deviceHostErr struct{ msg string }
|
||
|
||
func (e *deviceHostErr) Error() string { return e.msg }
|
||
|
||
// builtinHandlers 把 Agent 的族处理器暴露成 api.BuiltinToolHandlers。
|
||
//
|
||
// 为什么用适配器而不是把 Agent 的方法全部导出:
|
||
// - 导出只会让"谁都能调内置工具",绕过 executeToolCall 的授权闸
|
||
// - 适配器只在 core 内部构造,然后交给 device 的路由层
|
||
type builtinHandlers struct{ a *Agent }
|
||
|
||
func (h builtinHandlers) ExecutePersonaTool(tc api.ToolCall) string {
|
||
return h.a.executePersonaTool(tc)
|
||
}
|
||
func (h builtinHandlers) ExecuteMemoryTool(tc api.ToolCall, scenes []string) string {
|
||
return h.a.executeMemoryTool(tc, scenes)
|
||
}
|
||
func (h builtinHandlers) ExecuteSocialTool(tc api.ToolCall) string {
|
||
return h.a.executeSocialTool(tc)
|
||
}
|
||
func (h builtinHandlers) ExecuteKnowledgeTool(tc api.ToolCall) string {
|
||
return h.a.executeKnowledgeTool(tc)
|
||
}
|
||
func (h builtinHandlers) ExecuteColdContextTool(tc api.ToolCall) string {
|
||
return h.a.executeDocTool(tc)
|
||
}
|
||
func (h builtinHandlers) ExecuteSecretTool(tc api.ToolCall) string {
|
||
return h.a.executeSecretTool(tc)
|
||
}
|
||
func (h builtinHandlers) ExecuteOutputSendHelp(tc api.ToolCall) string {
|
||
return h.a.executeOutputSendHelp(tc)
|
||
}
|
||
func (h builtinHandlers) ExecuteOutputSend(tc api.ToolCall) string {
|
||
return h.a.executeOutputSendTool(tc)
|
||
}
|
||
func (h builtinHandlers) ExecuteOutputListChannels() string {
|
||
return h.a.executeOutputListChannels()
|
||
}
|
||
func (h builtinHandlers) ExecuteInputChannels(tc api.ToolCall) string {
|
||
return h.a.executeInputChannels(tc)
|
||
}
|
||
func (h builtinHandlers) ExecuteResidentAgents(tc api.ToolCall) string {
|
||
return h.a.executeResidentAgents(tc)
|
||
}
|
||
func (h builtinHandlers) ExecuteNotifyParent(tc api.ToolCall) string {
|
||
return h.a.executeNotifyParent(tc)
|
||
}
|
||
func (h builtinHandlers) ExecuteInputchNote(tc api.ToolCall) string {
|
||
return h.a.executeInputchNote(tc)
|
||
}
|
||
func (h builtinHandlers) ExecutePluginReload() string {
|
||
return h.a.executePluginReload()
|
||
}
|
||
func (h builtinHandlers) ExecuteGetPluginTools(pluginName string) string {
|
||
return h.a.executeGetPluginTools(pluginName)
|
||
}
|