Files
homeagent-sdk/docs/api/memory.md
JianFeeeee 0a6e2b7dc4 docs: 插件 SDK 文档站(API 参考从源码生成 + 自建检索)
为插件作者建一个文档站,重点是**能按描述搜到 API**,以及**明确能力边界**。

## 为什么 API 参考要生成而不是手写

公开 API 面有 115 个符号、11 个接口。手抄必然与代码漂移——这是文档站最常见的
死法(本仓 README 里已经有过几处「文档说一套、代码是另一套」)。

所以 `tools/apidoc` 直接从 `sdk/*.go` 提取签名、文档注释与代码块示例,渲染成
`docs/api/*.md`。发现文档不对时改的是**源码注释**,不是生成物。生成页首行带
「勿手改」标记,防止有人改了下次构建白改。

- `extract.go`:go/ast + go/doc 提取(只用标准库,离线可跑,不引入依赖)
- `gensite/`:渲染 Markdown + 检索索引
- `gensite/usages.go`:从 `example/` 21 个示例插件里反查**真实调用点**,
  贴在每个 API 下(源码注释里几乎没有可运行示例,但示例插件都是能编译跑的真代码)

## 能力边界:写这个站时查出的三处文档错误

这是本次最有价值的部分。原以为「公开 SDK 里有的 API 外部插件都能用」,
实测对照桥接模板后发现三处不符,站内已更正:

1. **`PluginMgr()` 被写成「仅内置可用」——错的。** 桥接模板第 692 行显式
   `base.SetPluginMgrAPI(procPluginMgr{})`,公开 `PluginMgrAPI` 注释也写「外部插件可调用」。
   真正的区别是**方法数**:公开面 3 个(ReloadOne/ListLoadedPlugins/IsPluginDisabled),
   内部面 9 个。容易混淆是因为两个包里有同名但不同的接口。
2. **`Events()` 外部插件恒为 nil。** `SetEventSubscriber` 全仓只有定义、无调用点,
   故 subscriber 从未被注入。外部插件的事件订阅实际由生成的运行时走
   `events.subscribe` RPC 完成——旧文档把它当成可用入口,会让人写出必然失效的代码。
3. **`UnregisterOutputChannel` 是静默无效,不是报错。** 桥接只注入 registrar、
   不注入 unregistrar,于是 `regOutputUnreg == nil`,函数命中 else 分支**直接返回 nil**
   (sdk/plugin.go:539-549)——不报错、通道也没注销。

每条裁定的依据写进 `tools/apidoc/tiers.json`(文件:行号 或 grep 结论),
站上以告警框呈现,读者可自行核对。判断依据三源:桥接模板的 `base.Set*` 注入点、
`internal/sdk` 完整面、`internal/plugin/proc/protocol.go` 的 RPC 表。

## 检索(用户的核心诉求)

两套互补:

- **MkDocs 内置搜索**:全文,中文走 jieba 分词。
- **自建 API 检索**(`docs/javascripts/api-search.js` + `assets/api-index.json`):
  支持四类查询——按名称、**按功能描述**(「注册工具」→ RegisterTool、
  「崩溃」→ SetAutoRestart)、按 `限定符.方法`(`memory.recall` → MemoryAPI.Recall)、
  按签名片段(`(string) error`)。并标出「仅内置」,避免外部插件作者踩空。

自建的理由:Material 内置搜索按整页文本索引,搜 `InjectText` 会列出所有提到它的
页面,但分不清哪条是它的定义;而且它要等 mkdocs build 才更新。

## 文档结构

- `docs/guide/`:快速开始、Go/Lua 首个插件、能力边界、打包发布、多平台、受限 SDK 与安全
- `docs/api/`:10 个按「你想做什么」划分的章节(工具/阶段/记忆/通道/配置/生命周期/
  事件/LLM/常量/桥接)+ 仅内置汇总页
- `docs/versions.md`:SDK 版本语义(跟随内核中版本、patch 恒为 .0)、
  1.0.0 是唯一破坏性变更、RPC 协议版本

## 验证

- `mkdocs build --strict` 零告警
- 23 个页面的全部站内链接与锚点可达(自动校验)
- 1440 / 768 / 390px 三视口:无横向溢出、无控制台错误
- 四种检索模式实测有结果且跳转锚点正确
- 构建产物 `site_build/` 已 gitignore

用法:`tools/apidoc/build.sh`(生成+构建)、`tools/apidoc/build.sh serve`(预览)。
2026-09-24 12:08:37 +08:00

10 KiB
Raw Blame History

记忆(Memory)

三层记忆的读写接口:图记忆(三元组关系)、文档记忆(带元数据的文档)、文本记忆(事件流水)。以及知识库。

DocMemoryAPI

DocMemoryAPI provides access to the document vector store.

方法 说明
Insert
InsertWithMedia InsertWithMedia 写入文档并关联媒体。attachments 里带 Data 的会落进
Query
Remove
Stats

DocMemoryAPI.Insert

Insert(doc *Doc) error

memory.go:76

DocMemoryAPI.InsertWithMedia

InsertWithMedia(doc *Doc, attachments []MediaAttachment) error

InsertWithMedia 写入文档并关联媒体。attachments 里带 Data 的会落进 内容寻址存储(相同字节只存一份),只带 Digest 的直接引用已有内容。 媒体成为文档直接持有的一等记忆块:文档向量会融合它们的原生向量, 因此图片按自己的向量被召回,不依赖任何生成的描述文本。

memory.go:81

DocMemoryAPI.Query

Query(text string, topK int) []*Doc

memory.go:75

DocMemoryAPI.Remove

Remove(id string)

memory.go:82

DocMemoryAPI.Stats

Stats() map[string]interface{}

memory.go:83

KnowledgeAPI

KnowledgeAPI provides access to the knowledge store.

方法 说明
Add
List
Search

KnowledgeAPI.Add

Add(name, content string) error

knowledge.go:6

KnowledgeAPI.List

List() ([]string, error)

knowledge.go:7

KnowledgeAPI.Search

Search(query string, topK int) ([]*Knowledge, error)

knowledge.go:5

MemoryAPI

MemoryAPI provides access to the graph memory (entity-relation store).

方法 说明
Commit
Introspect
MergeEntities
Purge
Recall

MemoryAPI.Commit

Commit(triples []Triple) error

memory.go:6

MemoryAPI.Introspect

Introspect() (map[string]interface{}, error)

memory.go:7

MemoryAPI.MergeEntities

MergeEntities(source, target string) (int, error)

memory.go:8

MemoryAPI.Purge

Purge(criteria map[string]string, mode string) (int, error)

memory.go:9

MemoryAPI.Recall

Recall(query []string, depth int) ([]Entity, []Relation, error)

memory.go:5

SocialAPI

SocialAPI provides read-only access to the social graph (person profiles and relationships). External plugins can query person traits and social networks but cannot modify them.

方法 说明
GetNetwork
GetPerson
GetRelations
GetTrait
ListPersons

SocialAPI.GetNetwork

GetNetwork(name string, depth int) ([]*PersonProfile, error)

memory.go:104

SocialAPI.GetPerson

GetPerson(name string) (*PersonProfile, error)

memory.go:101

SocialAPI.GetRelations

GetRelations(name string) ([]SocialRelation, error)

memory.go:103

SocialAPI.GetTrait

GetTrait(name, trait string) (string, bool)

memory.go:102

SocialAPI.ListPersons

ListPersons() ([]string, error)

memory.go:105

TextMemoryAPI

TextMemoryAPI provides access to chronological text event storage.

方法 说明
Append

TextMemoryAPI.Append

Append(evt TextEvent) error

memory.go:44

Doc

type Doc struct { ID string `json:"id"` Title string `json:"title"` Content string `json:"content"` Score …

Doc represents a document in the document store.

MediaDigests / Attachments 在 Query 返回时由内核填充(仅元数据,不带字节)。

memory.go:89

PluginSDK.DocMemory

func (s *PluginSDK) DocMemory() DocMemoryAPI

DocMemory returns the document memory API (may be nil if not available).

plugin.go:418

DocMemoryAPI

type DocMemoryAPI interface { Query(text string, topK int) []*Doc Insert(doc *Doc) error // InsertWithMedia 写入文档并关联媒体。attachments 里带 Data 的会落进 …

DocMemoryAPI provides access to the document vector store.

memory.go:74

Entity

type Entity struct { Name string `json:"name"` Type string `json:"type"` MentionCount int `json:"mention_count"` }

Entity represents a named entity in the knowledge graph.

memory.go:13

PluginSDK.Knowledge

func (s *PluginSDK) Knowledge() KnowledgeAPI

Knowledge returns the knowledge store API (may be nil if not available).

示例插件里的真实用法

插件 位置 代码
recoverydiag example/recoverydiag/plugin.go:978 if p.sdk != nil && p.sdk.Knowledge() != nil {

plugin.go:425

Knowledge

type Knowledge struct { Name string `json:"name"` Content string `json:"content"` }

Knowledge represents a knowledge entry.

示例插件里的真实用法

插件 位置 代码
recoverydiag example/recoverydiag/plugin.go:978 if p.sdk != nil && p.sdk.Knowledge() != nil {

knowledge.go:11

KnowledgeAPI

type KnowledgeAPI interface { Search(query string, topK int) ([]*Knowledge, error) Add(name, content string) error List() ([]string, error) }

KnowledgeAPI provides access to the knowledge store.

knowledge.go:4

MediaAttachment

type MediaAttachment struct { Digest string `json:"digest,omitempty"` MIME string `json:"mime,omitempty"` Data []byte `json:"data,omitempty"` Name string `json:"name,omite …

TextEvent represents a single text memory event. MediaAttachment 描述一份与记忆关联的媒体。

两个方向共用一个类型:

  • 写入(InsertWithMedia):给 Data + MIME 就是新内容;只给 Digest 则是引用已有内容。
  • 读出(Query):内核只填 Digest/MIME,不回 Data—— 一次检索可能命中几十张图,把字节全塞回插件会把 ABI 消息撑爆。 需要字节时拿 Digest 单独取。

刻意没有 Description 字段:媒体不作为文本被索引,也不带任何生成的描述。 它只按自己的原生向量被检索与召回;附加文字请写在文档 / 三元组的文本里。

memory.go:58

PluginSDK.Memory

func (s *PluginSDK) Memory() MemoryAPI

Memory returns the graph memory API (may be nil if not available).

plugin.go:404

MemoryAPI

type MemoryAPI interface { Recall(query []string, depth int) ([]Entity, []Relation, error) Commit(triples []Triple) error Introspect() (map[string]interface{}, error) Merg …

MemoryAPI provides access to the graph memory (entity-relation store).

memory.go:4

PersonProfile

type PersonProfile struct { Name string `json:"name"` Traits map[string]string `json:"traits,omitempty"` Relations []SocialRelation `json:"relations,omitemp …

PersonProfile represents a person's complete profile (traits + social relations).

memory.go:109

Relation

type Relation struct { SourceName string `json:"source_name"` TargetName string `json:"target_name"` RelationType string `json:"relation_type"` Confidence float6 …

Relation represents a relationship between two entities.

memory.go:20

PluginSDK.Social

func (s *PluginSDK) Social() SocialAPI

Social returns the social graph API (may be nil if not available).

plugin.go:439

SocialAPI

type SocialAPI interface { GetPerson(name string) (*PersonProfile, error) GetTrait(name, trait string) (string, bool) GetRelations(name string) ([]SocialRelation, error) G …

SocialAPI provides read-only access to the social graph (person profiles and relationships). External plugins can query person traits and social networks but cannot modify them.

memory.go:100

SocialRelation

type SocialRelation struct { Person string `json:"person"` Relation string `json:"relation"` }

SocialRelation represents a social relationship between two persons.

memory.go:116

TextEvent

type TextEvent struct { Role string `json:"role"` Content string `json:"content"` Timestamp int64 `json:"timestamp"` Channel …

memory.go:65

PluginSDK.TextMemory

func (s *PluginSDK) TextMemory() TextMemoryAPI

TextMemory returns the text memory API (may be nil if not available).

plugin.go:411

TextMemoryAPI

type TextMemoryAPI interface { Append(evt TextEvent) error }

TextMemoryAPI provides access to chronological text event storage.

memory.go:43

Triple

type Triple struct { Subject string `json:"subject"` Relation string `json:"relation"` Object string `json:"object"` Confidence float64 `json:"c …

Triple represents a subject-relation-object triple for the knowledge graph.

SentenceText 是这条三元组的原句,会写进 sentences 表;媒体引用挂在句子上, 所以 MediaDigests 非空时内核会保证句子存在(不给就自动合成一句)。

memory.go:31