Files
HomeAgent/internal/agent/core/builtin_toolapi.go
JianFeeeee b850feaef2 feat: 段页式记忆流转、coldcontext 重命名与安全治理
记忆层:
- MemoryBlock 承载 FrameTS/PageSeq/PageKind/BlockRole/CallID
- coldcontext 归档与回填按完整页传递,工具调用参数和配对键不丢失
- 召回先估算总 token,超预算时按全局页相似度标记 inactive
- inactive 仅是 context 渲染期状态,不落盘、不进入 coldcontext,Prune 后重置
- Peek/确认/Remove 两阶段召回,失败保留冷上下文副本
- stablemem 记录 last_recalled_at,删块连带清理边

命名:
- internal/memory/document → internal/memory/coldcontext
- Doc/DocEvent/DocHit → ColdDoc/ColdEvent/ColdHit
- ContextToColdContext/RecentColdContexts/FindColdContexts
- 保留既有 JSON 标签、doc_ 文件前缀与 doc_count 状态键,兼容存量数据

安全治理:
- 工具策略门禁、安全配置、事件总线发布者身份与入站脱敏
- 声明式 SecurityAPI 与 QQ owner/guest profile
- 日志保留策略与相关 e2e/回归判据

验证:go build ./...、go vet ./...、go test ./...(62 包);
生产副本 e2e:7013 块迁移后 ID/向量/指纹 0 变化、0 缺失。
2026-10-29 23:53:48 +08:00

131 lines
5.2 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 core
import (
agentAPI "github.com/JianFeeeee/HologramAgent/internal/agent/api"
sdk "github.com/JianFeeeee/HologramAgent/internal/sdk"
)
// 本文件实现内核侧对"内置工具注册面"(方案 B)的注入。
//
// 背景与方案 B 的完整理由见 internal/sdk/tool.go 末尾的注释。
// 一句话:`memory_*` / `knowledge_*` / `doc_*` / `person_*` 这 20+ 个是
// **内核内置**的,在 executeToolCallInner 里按前缀分派,从不进 ToolAPI,
// 于是插件(seq)既查不到也调不了 —— 真机实跑实证:seq_run 报
// 「工具 knowledge_list 不存在或未注册」,而同一轮模型直接调它是成功的。
//
// 注入必须**晚绑定**且**per-agent**:内置工具的可见性由运行期状态门控
// (`if a.memory != nil` / `if a.knowledge != nil` …),而驻留子是轻量内核、
// memory 为 nil。而 ToolAPI 是全局单例,拿不到 agent,只能由 agent 自己
// 提供一份 provider。
// builtinProvider 是 *Agent 上的适配器:把 agent 的内置工具面
// 转成 sdk.BuiltinProvider。
type builtinProvider struct{ a *Agent }
// Defs 返回当前 agent 可见的内置工具声明。
//
// ⚠️ **必须复用 buildToolDefs 的同一批生成逻辑**,否则会出现"两套语义":
// 一套决定模型看得到什么(buildToolDefs),另一套决定插件看得到什么。
// 这里直接从 buildToolDefs 里筛出**不在** StageHost/IOManager 中的那些,
// 从而保证门控条件(memory/knowledge 是否就绪)完全一致。
func (p builtinProvider) Defs() []sdk.BuiltinToolDef {
if p.a == nil {
return nil
}
// 先算出"插件/设备侧已有的名字",剩下的才是内核内置的。
external := map[string]bool{}
if p.a.io != nil {
for _, d := range p.a.io.GetAllTools() {
external[d.Name] = true
}
}
if p.a.stageHost != nil {
for _, d := range p.a.stageHost.GetToolDefs() {
external[d.Name] = true
}
}
var out []sdk.BuiltinToolDef
for _, raw := range p.a.buildToolDefs() {
m, ok := raw.(map[string]interface{})
if !ok {
continue
}
fn, ok := m["function"].(map[string]interface{})
if !ok {
continue
}
name, _ := fn["name"].(string)
if name == "" || external[name] {
continue
}
desc, _ := fn["description"].(string)
params, _ := fn["parameters"].(map[string]interface{})
out = append(out, sdk.BuiltinToolDef{
Name: name, Description: desc, Parameters: params,
})
}
return out
}
// Exec 执行一个内置工具。
//
// 直接复用 executeToolCall 的完整路径(内置分支 + 授权闸 + 异常处理),
// **不复用** executeToolCallInner:后者要求经前缀 switch,而 ToolAPI 的
// 存在性判定已在 ToolDefByName/ExecuteTool 做过一次。
//
// ⚠️ 传入的 toolCall 不带 RawArguments(插件侧没有原始 JSON),
// 因此 __arg_error 的信息面在插件路径上天然缺失 —— 插件调用的是
// **已解析**的参数,不存在被截断的中间态。
func (p builtinProvider) Exec(name string, args map[string]interface{}) (string, error) {
if p.a == nil {
return "", errBuiltinNoAgent
}
tc := agentAPI.ToolCall{
ID: "builtin_" + name,
Name: name,
Arguments: args,
}
return p.a.executeToolCall(tc, p.a.defaultChannelForBuiltin()), nil
}
// defaultChannelForBuiltin 给出内置工具执行时的输出通道。
//
// 内置工具本身不产出"用户可见输出"(结果回给调用方),但 executeToolCall
// 的签名需要 channel(如记忆写入会记场景)。用 agent 的调度当前通道不可靠
// (它逐任务变化),故用一个稳定的内部标记。
func (a *Agent) defaultChannelForBuiltin() string { return "builtin" }
// errBuiltinNoAgent 表示 provider 未绑定 agent(装配顺序错误)。
var errBuiltinNoAgent = &builtinErr{"内置工具执行器未绑定 agent"}
type builtinErr struct{ msg string }
func (e *builtinErr) Error() string { return e.msg }
// InstallBuiltinToolProvider 把本 agent 的内置工具面注入 ToolAPI。
//
// 供内核在**创建 agent 之后**调用(bootstrap / resident 创建处)。
// 幂等:重复调用只是覆盖为同一个 agent。
func (a *Agent) InstallBuiltinToolProvider() { a.installBuiltinProvider() }
// installBuiltinProvider 把本 agent 的内置工具面注入 ToolAPI。
//
// 由内核在**创建 agent 之后**调用(bootstrat / resident 创建处)。
// 注入是**全局**的:最后一次注入生效。⚠️ 因此多 agent 场景下,
// ToolAPI 看到的是"最近一个注入者"的内置工具面 —— 这是当前架构的
// 已知局限(ToolAPI 是单例却需要 per-agent 数据)。
// 记入设计文档 §10 待定项,不在本次解决。
func (a *Agent) installBuiltinProvider() {
sdk.SetBuiltinProvider(builtinProvider{a: a})
}
// ★ 已删除 isBuiltinToolName(2026-10-29)。
//
// 它自称"供提示词/文档用",实测**零生产调用方**,是 Dispatch 之外
// 又一份手抄前缀表。改名时改了 Dispatch(stablemem_)却漏了这里,
// 于是它成了"看起来是事实来源、实际只是过期副本"的第三种状态。
//
// 真需要判"是不是内置工具"时调 toolroute.Dispatch:它返回的 bool
// 就是权威答案(handled=false 表示应继续走插件/设备路径)。