Files
HomeAgent/internal/agent/api/device.go
JianFeeeee 55fa2685ae feat(security,device): security 成为独立内核模块(闸门+策略+限式),device 接管内置工具路由
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 包全绿
2026-10-26 20:55:25 +08:00

74 lines
3.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package api
// Device 数据面的**公共契约**(低层包,避免 import 环)。
//
// ## 为什么这些类型必须住在这里
//
// 依赖图上有两个方向的需求:
//
// internal/kernelmod/device → kernelboot → internal/agent/core
// internal/agent/core → 需要满足 device 的 ToolHost 接口
//
// 如果接口定义在 kernelmod/device,agent/core 就得 import 它 ⇒ **循环**。
// 所以契约下沉到 agent/api(core 早已依赖它,而它不依赖任何内核模块)。
// ToolDefinition 是工具定义的数据面投影(与具体 schema 表示解耦)。
type ToolDefinition struct {
Name string
Description string
// ParallelSafe 声明该工具可与同批其他工具并发执行。
ParallelSafe bool
// Timeout 是声明的超时(空 = 用内核默认)。
Timeout string
}
// ToolHost 是 device 需要 agent 提供的那部分能力。
//
// ★ 用接口而不是具体类型:第 2 步把工具实现迁进 device 时,agent 只需
// 继续满足这个接口,双方都不必互相 import。
type ToolHost interface {
// ToolDefinitions 返回当前 agent 可见的工具定义(含运行期门控)。
ToolDefinitions() []ToolDefinition
// ExecuteTool 执行一个工具调用(已含参数校验、授权闸、超时、脱敏)。
ExecuteTool(name string, args map[string]interface{}) (string, error)
}
// DeviceSurface 是 device 数据面暴露给内核的最小面(KernelState.Device 的类型)。
//
// 只放"别的模块真的要读"的东西:诊断与状态面用工具清单与数量;
// 执行只经 Agent(安全闸门在那边),**不**从这里暴露任意执行入口。
type DeviceSurface interface {
Tools() []ToolDefinition
ToolCount() int
}
// BuiltinToolHandlers 是**内置工具的族处理器**(每个族一个方法)。
//
// ## 为什么用族的粒度而不是逐工具
//
// 族内工具共享同一批依赖(memory 族要 graph、knowledge 族要 store、
// coldcontext 族要 docStore…)。按族传接口,device 的分发层就能
// 在不认识 Agent 内部字段的前提下完整接管**路由**:
//
// device.Dispatch(tc) → 选族 → handler.ExecuteMemoryTool(tc)
//
// 第二阶段再把族实现搬进 device(那时依赖改为显式 Deps 结构体),
// 路由这一段不用再改。
type BuiltinToolHandlers interface {
ExecutePersonaTool(tc ToolCall) string
ExecuteMemoryTool(tc ToolCall, turnScenes []string) string
ExecuteSocialTool(tc ToolCall) string
ExecuteKnowledgeTool(tc ToolCall) string
ExecuteColdContextTool(tc ToolCall) string
ExecuteSecretTool(tc ToolCall) string
ExecuteOutputSendHelp(tc ToolCall) string
ExecuteOutputSend(tc ToolCall) string
ExecuteOutputListChannels() string
ExecuteInputChannels(tc ToolCall) string
ExecuteResidentAgents(tc ToolCall) string
ExecuteNotifyParent(tc ToolCall) string
ExecuteInputchNote(tc ToolCall) string
ExecutePluginReload() string
ExecuteGetPluginTools(pluginName string) string
}