mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 17:38:10 +00:00
工具链在 SDK 1.2.0 更名为 hmapdev(原 plugindev)。核心侧三处功能耦合同步:
1. 用户可见报错:旧 C ABI 产物 / 协议版本不匹配 / 共享段版本不匹配
三处「请用配套 plugindev 重编」→ hmapdev(对应两条测试断言同步)
2. e2e_template_test 的模板路径改为 tools/hmapdev/templates,
并保留旧路径回退(旧 SDK 检出仍能跑测试)
3. 注释与文档同步
文档更新(用户可见面):
- assets/docs/{zh,en}/PLUGIN_DEV.md:工具链章节整体改为 hmapdev,
补改名说明与 SDK 存储目录迁移;命令示例全部更新
- assets/docs/{zh,en}/ARCHITECTURE.md:**流程图与章节对齐 v1.2.0** ——
· 向量化章节改为三层降级:统一多模态空间(主)→ 词嵌入 → TF-IDF(回退),
写明「同指纹且同维度才参与融合」
· 媒体记忆章节重写:媒体是一等记忆块(无独立 GC / 无引用计数 / 无描述式索引 /
正文不再写 media marker),并写明 reembedStaleMedia 的跨空间迁移与写回
- README{,_EN}.md、docs/zh/plugin-interface-matrix.md:工具名与模板路径同步
(历史条目标注「当时名为 plugindev」)
验证:go test ./internal/plugin/ ./internal/plugin/proc/ ok,
含 4 条真实模板 E2E(模板路径切换后仍通过)。
113 lines
3.1 KiB
Go
113 lines
3.1 KiB
Go
package plugin
|
||
|
||
import (
|
||
"encoding/json"
|
||
"os"
|
||
"path/filepath"
|
||
)
|
||
|
||
const (
|
||
binEntry = "plugin.bin" // 子进程插件(纯 Go 二进制,stdio JSON-RPC + 共享内存)
|
||
luaEntry = "main.lua"
|
||
skillEntry = "SKILL.md"
|
||
metaEntry = "plugin.json"
|
||
)
|
||
|
||
// legacyCABIEntries 是已退场的 C ABI 产物名。
|
||
//
|
||
// 保留这张表只为**给出明确错误**:插件目录里躺着 plugin.so 而内核不再认它时,
|
||
// 静默跳过会让「目录在但插件没加载」看起来像配置问题,而实际原因是需要用
|
||
// 新版 hmapdev 重编。
|
||
var legacyCABIEntries = []string{"plugin.so", "plugin.dll", "plugin.dylib"}
|
||
|
||
// entryKind 描述插件入口归属的加载通道。
|
||
//
|
||
// C ABI 通道(.so/.dll/.dylib)已整体退场:外部插件统一走子进程 + stdio RPC,
|
||
// 三套独立 ABI 实现收敛为单一 RPC 实现(§9.2)。
|
||
type entryKind int
|
||
|
||
const (
|
||
entryUnknown entryKind = iota
|
||
entryProc // plugin.bin —— 子进程 + stdio JSON-RPC + 共享内存
|
||
entryLua // main.lua
|
||
entrySkill // SKILL.md
|
||
)
|
||
|
||
func (k entryKind) String() string {
|
||
switch k {
|
||
case entryProc:
|
||
return "proc"
|
||
case entryLua:
|
||
return "lua"
|
||
case entrySkill:
|
||
return "skill"
|
||
}
|
||
return "unknown"
|
||
}
|
||
|
||
// classifyEntry 把 manifest 的 entry 字段映射到加载通道。
|
||
//
|
||
// entry 为空或声明已退场的 C ABI 产物时返回 entryUnknown,
|
||
// 由调用方回退到目录探测(兼容无 manifest 的旧插件),
|
||
// 并在探测到 C ABI 残留时给出明确的重编提示。
|
||
func classifyEntry(entry string) entryKind {
|
||
switch entry {
|
||
case binEntry:
|
||
return entryProc
|
||
case luaEntry:
|
||
return entryLua
|
||
case skillEntry:
|
||
return entrySkill
|
||
}
|
||
return entryUnknown
|
||
}
|
||
|
||
// detectEntryKind 先读 manifest 的 entry,读不到则按目录内存在的入口文件推断。
|
||
//
|
||
// 注意:存量插件的 plugin.json 可能仍写着 "plugin.so"(工具链已不再据此分派,
|
||
// 但历史产物里有),此时 classifyEntry 返回 unknown,靠目录探测找到 plugin.bin。
|
||
func detectEntryKind(plgDir string) entryKind {
|
||
if mft := readManifest(plgDir); mft != nil {
|
||
if k := classifyEntry(mft.Entry); k != entryUnknown {
|
||
return k
|
||
}
|
||
}
|
||
for _, probe := range []struct {
|
||
file string
|
||
kind entryKind
|
||
}{
|
||
{binEntry, entryProc},
|
||
{luaEntry, entryLua},
|
||
{skillEntry, entrySkill},
|
||
} {
|
||
if st, err := os.Stat(filepath.Join(plgDir, probe.file)); err == nil && !st.IsDir() {
|
||
return probe.kind
|
||
}
|
||
}
|
||
return entryUnknown
|
||
}
|
||
|
||
// hasLegacyCABIEntry 判断插件目录里是否只剩已退场的 C ABI 产物。
|
||
//
|
||
// 用于给出「需要重编」而非「插件不存在」的错误。
|
||
func hasLegacyCABIEntry(plgDir string) bool {
|
||
for _, name := range legacyCABIEntries {
|
||
if st, err := os.Stat(filepath.Join(plgDir, name)); err == nil && !st.IsDir() {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
func readManifest(dir string) *PluginManifest {
|
||
data, err := os.ReadFile(filepath.Join(dir, metaEntry))
|
||
if err != nil {
|
||
return nil
|
||
}
|
||
var m PluginManifest
|
||
if err := json.Unmarshal(data, &m); err != nil {
|
||
return nil
|
||
}
|
||
return &m
|
||
}
|