mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-14 11:32:57 +00:00
feat(shm): 文档/知识正文入共享内存 + 协议版本 bump 到 2(§13.13)
## 数据面补齐 - doc.insert / doc.insertWithMedia:新增 doc_ref / attachments_ref, 模板序列化后 putValueInArena - knowledge.add:新增 content_ref(内容是 JSON 字符串,读出后再解一层) - 抽出通用 resolveJSONRef(resolveBlocks 也改用它),三处共用一套 “共享优先、内联回退”逻辑 ## 协议版本 bump:让错配显式失败,而不是静默坏 这是本轮更重要的部分。§13.6/§13.13 改了内核→插件 payload 的承载方式, 两种错配都不会报错、只会静默失效: - v1 插件只读内联 args(tool/cleaner/output)→ 遇到 v2 内核拿到空参数 - v2 插件发 blocks_ref → v1 内核反序列化时静默忽略(旧内核 io.setToolBlocks 还是桩实现) 现场表现为“输出变空 / 图注入没反应”,极难定位。所以把 ProtocolVersion 与模板 procProtocolVersion 一起 bump 到 2:双方都是等值校验,v1 插件遇上 v2 内核会在建链时明确报“协议版本不匹配…请用配套 plugindev 重编”。 测试里把“错误必须带出重编指令”也断言上了——生产上碰到它的现场就是 “只更新了内核没重编插件”,光报“不匹配”定位不到行动。 testdata 8 个插件的 protocol 同步更新(badprotoplugin 仍用 999 验证拒绝)。 工具链已重建并安装(协议 2,内嵌 blocks_ref/doc_ref/content_ref), 回滚副本 plugindev.bak-20260910-232544。 验证:-race 全绿。新增 KnowledgeAddViaArena(12000B 正文)、 KnowledgeAddInline、DocInsertViaArena、SetToolBlocks 三例 + 真实模板 e2e + 协议不匹配断言强化。 §13.13 第 5 条(反向大结果)范围更大——需把内核→插件的应答路径整体改成 “大结果写段 + 返回 ref”,涉及 callCore 的返回处理与 doc.query/llm.chat 等 所有读大结果的 method。已在 plan.md 标注未做,不冒充完成。
This commit is contained in:
@ -340,11 +340,16 @@ func (h *coreHandler) Handle(method string, params json.RawMessage) (interface{}
|
||||
return nil, errUnavailable("doc memory")
|
||||
}
|
||||
var p struct {
|
||||
Doc *pubsdk.Doc `json:"doc"`
|
||||
Doc *pubsdk.Doc `json:"doc,omitempty"`
|
||||
DocRef SharedRef `json:"doc_ref,omitempty"`
|
||||
}
|
||||
if err := unmarshal(params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 文档全文可达几十 KB~数 MB,优先走共享内存。
|
||||
if err := h.resolveJSONRef(p.DocRef, &p.Doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.Doc == nil {
|
||||
return nil, fmt.Errorf("doc.insert: 缺少 doc 字段")
|
||||
}
|
||||
@ -356,12 +361,21 @@ func (h *coreHandler) Handle(method string, params json.RawMessage) (interface{}
|
||||
return nil, errUnavailable("doc memory")
|
||||
}
|
||||
var p struct {
|
||||
Doc *pubsdk.Doc `json:"doc"`
|
||||
Attachments []pubsdk.MediaAttachment `json:"attachments"`
|
||||
Doc *pubsdk.Doc `json:"doc,omitempty"`
|
||||
Attachments []pubsdk.MediaAttachment `json:"attachments,omitempty"`
|
||||
DocRef SharedRef `json:"doc_ref,omitempty"`
|
||||
AttachRef SharedRef `json:"attachments_ref,omitempty"`
|
||||
}
|
||||
if err := unmarshal(params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 文档正文 + 附件(含媒体二进制/data URL)都优先走共享内存。
|
||||
if err := h.resolveJSONRef(p.DocRef, &p.Doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := h.resolveJSONRef(p.AttachRef, &p.Attachments); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.Doc == nil {
|
||||
return nil, fmt.Errorf("doc.insertWithMedia: 缺少 doc 字段")
|
||||
}
|
||||
@ -421,12 +435,18 @@ func (h *coreHandler) Handle(method string, params json.RawMessage) (interface{}
|
||||
return nil, errUnavailable("knowledge")
|
||||
}
|
||||
var p struct {
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content"`
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content,omitempty"`
|
||||
ContentRef SharedRef `json:"content_ref,omitempty"`
|
||||
}
|
||||
if err := unmarshal(params, &p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 知识正文可达数十 KB,优先走共享内存。内容是 JSON 字符串,
|
||||
// 所以从 ref 读出后需再解一层。
|
||||
if err := h.resolveJSONRef(p.ContentRef, &p.Content); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, kn.Add(p.Name, p.Content)
|
||||
|
||||
case MethodKnowledgeList:
|
||||
@ -651,18 +671,32 @@ type injectMediaParams struct {
|
||||
BlocksRef SharedRef `json:"blocks_ref,omitempty"`
|
||||
}
|
||||
|
||||
// resolveJSONRef 若 ref 非零则从共享内存读取并 JSON 反序列化到 out;
|
||||
// ref 为零时不动 out(调用方已填的内联值生效)。
|
||||
//
|
||||
// 供「大 payload 优先走共享内存、否则内联」的字段对共用。
|
||||
func (h *coreHandler) resolveJSONRef(ref SharedRef, out interface{}) error {
|
||||
if ref.IsZero() {
|
||||
return nil
|
||||
}
|
||||
data, err := h.host.Arena().Read(ref, h.host.Generation())
|
||||
if err != nil {
|
||||
return fmt.Errorf("读取共享内容失败: %w", err)
|
||||
}
|
||||
if err := json.Unmarshal(data, out); err != nil {
|
||||
return fmt.Errorf("解析共享内容失败: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// resolveBlocks 取出媒体块:优先共享内存,否则内联。
|
||||
func (h *coreHandler) resolveBlocks(p injectMediaParams) ([]pubsdk.ContentBlock, error) {
|
||||
if p.BlocksRef.IsZero() {
|
||||
return p.Blocks, nil
|
||||
}
|
||||
data, err := h.host.Arena().Read(p.BlocksRef, h.host.Generation())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取共享媒体块失败: %w", err)
|
||||
}
|
||||
var blocks []pubsdk.ContentBlock
|
||||
if err := json.Unmarshal(data, &blocks); err != nil {
|
||||
return nil, fmt.Errorf("解析共享媒体块失败: %w", err)
|
||||
if err := h.resolveJSONRef(p.BlocksRef, &blocks); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return blocks, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user