Files
HomeAgent/internal/sdk/memory.go
JianFeeeee 3f834794c5 refactor: SDK module 路径统一改为 hologramagentsdk(59 文件 + go.mod)
## 为什么必须做

SDK 仓(独立仓库)已把 module 从 `github.com/JianFeeeee/homeagentsdk`
改名为 `hologramagentsdk`。主仓通过 `replace` 直接引用它的**物理目录**:

    replace github.com/JianFeeeee/homeagentsdk => ./third_party/homeagent-sdk

一旦 SDK 侧改成新 module 名,主仓立刻炸:

    go: ./third_party/homeagent-sdk@ used for two different module paths
        (github.com/JianFeeeee/hologramagentsdk and github.com/JianFeeeee/homeagentsdk)

Go **不允许**同一目录被两个 module 路径 replace。所以不能"新旧并存",
只能把主仓 59 个文件的 import 全部改到新名,并删掉旧 replace。

## 一个被证伪的前提

我最初按"third_party/homeagent-sdk 是独立仓库,不能在此仓修改其源码"
来处理,并因此判断两个仓的改动可以隔离。实际上主仓是靠 `replace` 指向
该目录的物理副本 —— **两个仓的改动不可能真正隔离**:SDK 侧改 module 名,
主仓必然跟着改 import。

这个前提应该在做任何改动之前用 `go list -m` 验证,而不是假设。

## 连带修掉两处

| 缺陷 | 性质 |
|---|---|
| `TestLuaSDKMockSingleSource` 失败 | SDK 的 `sdk/lua/sdk.lua` 变了,主仓内嵌副本未同步(跑 `scripts/sync-lua-sdk.sh` 修复) |
| `sdkModuleNames` 分散两处 | 已在 SDK 仓合并为单一数据源(见 SDK 仓 725732b) |

第一条是**副本一致性判据抓到的**,不是我自己发现的 —— 这类判据的价值在此:
两个仓必然有副本,靠人记住"改了 A 要同步 B"是做不到的。

## 验证

- `go build ./...` / `go vet ./...` 干净
- `go test ./... -count=1`:**58 包 0 失败**
- `internal/plugin`(Lua SDK 副本一致性)+ `internal/sdk` 全绿
- 主仓 `third_party/homeagent-sdk/` 与 SDK 仓 `main` 无差异
2026-10-23 15:51:02 +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 sdk
import (
"time"
pubsdk "github.com/JianFeeeee/hologramagentsdk/sdk"
)
// MemoryBlockView 是块的最小只读视图(供星图轮询端点)。
//
// ★ 不直接用 memory.MemoryBlock:那是内核内部类型,而本包是**插件边界**。
//
// SDK 接口只暴露端点真正要用的字段(原来是先 GraphData 全量再转成
// graphBlockView 做同样的事,只是绕了一圈)。
type MemoryBlockView struct {
ID string `json:"id"`
Modality string `json:"modality"`
Text string `json:"text,omitempty"`
HasData bool `json:"has_data"` // 媒体负载在块内(CAS 淘汰后),只报有无不回显内容
MIME string `json:"mime,omitempty"`
Source string `json:"source,omitempty"`
Tool string `json:"tool,omitempty"`
Scene string `json:"scene,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// MemoryAPI 是内置插件使用的全量图记忆接口。
type MemoryAPI interface {
pubsdk.MemoryAPI
// GraphData 返回整个知识图谱的完整快照。
GraphData() (map[string]interface{}, error)
// BlocksChangedSince 返回自 since 之后创建或更新过的块(供星图轻量轮询)。
//
// ★ 为何单开一个方法而不复用 GraphData:后者是全量快照(生产实测
// 3190 块 + 2692 边,JSON 约 3.3MB、135ms),而轮询端点只想知「有新东西」。
// 原先 pulse 端点是先取全量再过滤 —— 实测与全量端点同价(145ms),
// 「轻量端点」名不副实。库侧 SQL 过滤后响应体差两个数量级。
//
// 属内置接口(非 pubsdk),与 GraphData 同理,不影响外部插件。
BlocksChangedSince(since time.Time, limit int) ([]MemoryBlockView, error)
// MediaBytes 按**块引用**取回媒体块的字节与 MIME。
//
// ★ 这是 CAS 淘汰后插件取媒体的唯一入口:块 ID 就是媒体的身份
// (内容派生 blk_media_<hash>),不再有独立的 digest 寻址层。
// ref 可以是完整块 ID,也可以是唯一前缀(模型/跨进程只带短引用)。
//
// 取不到(无唯一对应块、或块无负载)时返回 (nil, "", false, nil) ——
// 「这个引用没有媒体」是调用方能自己处理的常态,不是错误。
MediaBytes(ref string) (data []byte, mime string, ok bool, err error)
}
type Entity = pubsdk.Entity
type Relation = pubsdk.Relation
type Triple = pubsdk.Triple
// TextMemoryAPI 是内置插件使用的全量文本记忆接口。
type TextMemoryAPI interface {
pubsdk.TextMemoryAPI
// RecentEvents 返回最近 n 条记忆事件。
RecentEvents(n int) ([]TextEvent, error)
// Stats 返回文本记忆的运行统计。
Stats() map[string]interface{}
}
type TextEvent = pubsdk.TextEvent
// MediaAttachment 是记忆附件(媒体)在插件边界上的表示。
// 与公共 SDK 同一类型,内置插件与外部插件用同一套字段。
type MediaAttachment = pubsdk.MediaAttachment
type DocMemoryAPI = pubsdk.DocMemoryAPI
type Doc = pubsdk.Doc