716ee46471
docs(scheduler): M3 拆为 M3a(所有权重构)/M3b(抢占语义)
...
真正的中途挂起要求帧跨越 prepare→step…→finish 全生命周期;若只让
process() 可挂起,processInput 会在挂起返回后继续 context.Append 与
emitResponse,造成重复提交。故 M3 分为两步:M3a 行为等价的所有权重构
(含移除 process() 整轮持有的 a.mu),M3b 再引入优先级与抢占。
2026-09-12 23:51:13 +08:00
06edff1af2
docs(scheduler): 输入调度器设计稿(四级优先级/可抢占/现场保存 + 测试点与里程碑)
...
背景:现状排队与中断两条语义建立在串行 eventLoop 上,存在队头阻塞、
中断三条隐式降级路径、回执无任务归属、断链点静默、背压策略分裂、
假取消、不可观测七个已确认问题。
设计:四级内核预定义优先级(严格大于才抢占)、显式临界区、
单调度线程 + 单中断线程、step 化任务帧与安全点、suspendPool/pendingInterrupts/
readyQueue 三集合统一选择函数、任务级 responseCh。
含 11 组测试点(优先级/恢复/回执/队列/深度饥饿并发/端到端),
测试方式与预期结果逐条写明;M0–M7 里程碑逐步实现。
公开 SDK 在 v1 保持冻结(diff 必须为 0)。
2026-09-12 23:39:10 +08:00
ea21803acb
docs(branching): 明确开发者文档的发布归属——以 rel 分支的形态为准,再合入 main
...
用户裁定:开发者文档应当在每个 rel 分支被修正为对应 rel 的形式,随后合入 main。
新增 §二.7,写清:
- 规则与做法(release 上按本版口径改 → cherry-pick 到 main,遵守 §三 只 pick 不 merge)
- 为什么不能直接改 main:main 语义是「下一个未发布版本」;assets/docs 会随发行包
分发并在 WebUI 被阅读,服务的是「这一版」;版本号/工具名/机制有无都随版变动
- main 上描述「下一版才有」的行为必须显式标注(如「(下一版)」)
- 反例表(本仓真实踩过):人格卡写死 v0.9.0 + 已删除的 C ABI、架构文档把已移除的
描述式索引/引用计数写成现行、README 停在旧版本
- 配套硬约束:任何会被当作事实的文本不得写死版本号,须插值或读运行时快照并加测试
2026-09-12 13:05:24 +08:00
b15d0bd114
refactor(plugin)!: 重编提示与模板路径改用 hmapdev;文档全面对齐 1.2.0
...
工具链在 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(模板路径切换后仍通过)。
2026-09-12 12:42:43 +08:00
85223fc1c9
docs(matrix): 记录 v1.2.x 的接口扩展,以及本次审计抓出的两处漂移
...
§九 原本只写到 v1.1.x。补上 1.2.0 的接口增量(注入侧的 InjectOptions 与六个
*Opts 变体、ContextPolicy 取值、ChannelDef.ContextPolicy 与它的 JSON tag),
并明确一件容易被误读的事:**「接口纯追加」不等于「无需重编」**——同版把插件运行
协议升到了 2(fd3 布局改变),协议不匹配会在握手时被明确拒绝,这两件事必须分开说。
同时把这次扩展自己抓出来的两处漂移入档(都属于本节第 3 条要防的类型):
1. 模板接线守卫 `TestProcTemplate_CoversAllCoreMethods` 红了:模板不再发
io.injectTextNoMem(改走 io.injectText + NoMemory),而内核保留该 id 是刻意的
向后兼容面。修的是判据(显式 deprecated 表 + 反向保护)。
2. mocksdk 与公共 SDK 机械求差,差集为旧的三参数 InjectInputSync(通道类插件闭环
要调的方法);git log -S 证实从来就缺,已补齐。
验证表按**本机实跑结果**填写:示例 vet 17/17、plugindev 测试全绿、
sdk -race -count=5 通过、mocksdk 差集为空。
2026-09-12 09:41:39 +08:00
727768e083
docs(git): 修正上一提交的错字(但声两仓 → 但两仓)
2026-09-12 09:01:59 +08:00
0247206dfe
docs(git): 写清「两仓 main 同步推进」的前提,修正 SDK 路牌
...
§七.4 原来只说「在 1.1.x 线发布期间,两仓 main 上的值都是 1.2.0」,容易被读成
「两仓 main 永远同值」,我正是据此把 SDK main 也推到了 1.3.0(已回退为 1.2.0)。
补写前提:推进以**该中版本已正式发布**为条件。
- 核心切出 release/v1.2.x 后 1.2.0 归发布线所有 → main 立即到 1.3.0(beta 也算占号)
- SDK 因 §七.2(beta 不发 SDK)要等核心正式 tag 才定版 → 在那之前 main 停在 1.2.0
并明确:**此阶段核心 main(1.3.0) 与 SDK main(1.2.0) 故意不对称**,
不是遗漏同步。§三 的 SDK 表行同步修正。
2026-09-12 09:01:34 +08:00
f778c613f1
docs(git): 1.2.x tag 历史补上 v1.2.0-beta.1
...
release/v1.2.x 已按 §2.4 走出 beta 通道:tag v1.2.0-beta.1(提交 215804c),
注释里写明通道、不兼容点与验收证据;beta 阶段不发 SDK(§七.2)。
正式 tag 待试运行无回退问题后再打,届时同步 SDK 仓。
同时把 tag 名资产整理记录在案:历史大写 tag V0.8.0 / V0.7.1 已按用户确认删除
(提交本身未受影响),现在主仓 tag 全部符合 SemVer 小写 v 约定。
2026-09-12 08:54:09 +08:00
a070cb563d
docs(git): 分支对齐更新到 2026-09-12(1.2.x 线开启)
...
- main 路牌调到 1.3.0;release/v1.2.x 承载 1.2.0(vendored SDK 定版 1.2.0)
- release/v1.1.x 按 §2.6 退役(保留供追溯);两个历史 feature 分支
(memory-media / plugin-proc-migration)已从远端删除,旧表待删项清掉
- 新增「1.2.x 发布线 tag 历史」表(当前尚无 tag),并写明它与存量插件
**不兼容**(RPC 协议 2、fd3 布局改变、不支持滚动升级)以及
**不满足 §2.4 跳级条件**的理由(改动面大,非单点修复)
- SDK 仓的 release/v1.2.x 尚未创建:按 §七.3 随核心**正式** tag 一起做
2026-09-12 08:39:05 +08:00
d4c5e808c7
feat(packaging): 模型与 ONNX Runtime 随 server/full 包发布
...
模型与运行库是发行版能力的一部分,不做成「装完再自己下载」:
- package-linux.sh:新增 stage_multimodal_assets(),打 server/full 前校验产物
SHA256SUMS、逐文件非空、运行库架构与目标一致,缺一即失败;client 包不含。
顺带修掉三个让打包在最后一步才炸的既有缺陷:
· 版本串直接取 git describe(v1.0.0-68-gxxx-dirty)不是合法包版本——deb 要求
数字开头、rpm 不允许 '-'。以前只有显式 VERSION=1.0.3 才打得出来;默认路径
从来没通过过。现在归一化,非数字开头时显式报错。
· 三处 mktemp -d 落在 /tmp(本机 9.8GB tmpfs),而 staging 要复制 719MB 模型,
中途 ENOSPC;报错文本指向某个 .onnx 文件,看着像资产坏了。改为落在与构建产物
同盘的 build/.stage-tmp。
· 开工前删掉旧的 SHA256SUMS:失败时脚本直接退出、不重算,留着像在为残缺产物背书。
- setup.sh:把包内 /usr/lib/homeagent/models/chinese-clip-vit-b16-onnx 软链到
<dataDir>/models/…(不复制 754MB、保持 dataDir 可迁移、已有自定义目录不覆盖)
- homeagent.service:ExecStart 改 /usr/bin/homed(deb 装在那里,此前写 /usr/local/bin,
装了也不会被 unit 用上)、加 ONNXRUNTIME_DIR 与 StateDirectory、MemoryMax 2G→8G
(实测常驻约 4.5GB,2G 会在首次全量建索引时被 cgroup OOM)
- control-{full,server}:补 libstdc++6 / libgcc-s1(libonnxruntime.so 需要)
- providers/{chineseclip,qwen3vl}:findOnnxLib 支持 ONNXRUNTIME_DIR / ONNX_ML_DIR
与包内 /usr/lib/homeagent/onnxruntime,随包的运行库才真的会被用上
- postinst:修掉两个让「装完即用」失效的点——它检查 /lib/systemd/system/ 下的 unit
而 deb 装到 /etc/systemd/system/,于是 daemon-reload/enable **从未执行**;以及
setup.sh 的失败被 `|| true` 吞掉(正是 initconfig 静默缺陷被藏住的原因)。现在
三个候选路径都查、失败可见并给出补救命令、首装 start / 升级 restart。
- docs/zh/multimodal-space.md:新增「随包分发」一节,并修正播种判据的说明
验收(从真实 deb 走一遍,不是读脚本):
- 包内 initconfig 已是动态链接,凭据真的写进 config.db
- 解包 → 按 postinst 顺序跑 setup.sh → 包内 homed 冷启动:
multimodal space active: provider=chineseclip dim=512 fp=cd2a495cf990
modalities=[text image]
- 全新安装的默认值确实被播种(core.plugin.dir / provider / model_dir 都在)
- 真实对话拿到回复(3.4s,回复中含唯一标记)
- 包内模型 SHA256SUMS 5/5 通过;包内 ORT 与源同 sha256;server 包 722MB
(旧版 17MB,差额即模型与运行库);full 包同样含全部资产;client 包不含
2026-09-12 08:10:44 +08:00
ba0b5a1fe0
feat(release): 发行版默认启用本地向量空间(onnxruntime 标签 + chineseclip 默认)
...
用户要求:后续发行版默认带 ONNX 模型能力。这条要求落到两处,并顺带修掉一个
被它**暴露出来**的真缺陷。
## 1. 构建默认带 onnxruntime(deploy/packaging/build.sh)
`HOMED_TAGS` 默认 `onnxruntime`,需要极简构建时显式 `HOMED_TAGS=` 关闭。
不带标签时 provider 仍注册、但打开即报「requires build tag」并优雅降级——
不静默假装成功。运行期还需要 `libonnxruntime.so`(provider 按
/opt/onnxruntime、/usr/local/lib、/usr/lib 顺序查找),缺失时同样是
「日志里明确错误 + 降级」。
## 2. 新装默认选 chineseclip(internal/config/registry.go)
`SeedDefaults` 写入:
core.memory.multimodal_space.provider = chineseclip
core.memory.multimodal_space.options.model_dir = <dataDir>/models/chinese-clip-vit-b16-onnx
选它而不是 qwen3vl:后者实测常驻 9.4GB,多数机器装不下;chineseclip 是
1.99GB(实测,见下)。同时更新两个 ConfigDef 的默认值与描述(WebUI 显示用)。
**老安装不会自动拿到这两个默认值**,这是有意的:`seedDBValues` 对非空配置库
直接返回,`GetString` 缺键时回落到调用方默认值(main.go 传的是空串)。
升级就静默加载 ~1.8GB 模型不是无副作用的事,应由部署显式开启。已写进文档。
## 3. 修掉 ORT 环境被重复初始化 + 误销毁(internal/nlp/onnx.go)
这是「默认带标签」才暴露的缺陷:此前不带标签时进程内不会有多个 ORT 消费者。
- `NewONNXParser` 无条件 `InitializeEnvironment()` → 若多模态 provider 先初始化,
这里报「The onnxruntime has already been initialized」并**降级**(实测日志:
`ONNX parser init: init onnx env: ... using fallback`)。
- 更严重的是失败路径与 `Close()` 里的 `DestroyEnvironment()`:它会把别人
(多模态 provider)正在用的进程级环境一起拆掉,让对方的会话失效。
改为:初始化前先 `IsInitialized()`;**任何消费者都不销毁环境**(随进程存活),
只销毁自己的会话。providers/chineseclip 与 providers/qwen3vl 本来就是这个约定,
现在三处一致。
## 验证(实测)
- 全新数据目录启动:配置库出现上述两个默认值。
- 模型未安装:`multimodal space active` 不出现,代之以明确错误
(点名缺失的 embed_config.json 路径 + 已注册 provider 列表)+ 降级,不静默。
- 模型就位:`multimodal space active: provider=chineseclip dim=512 fp=cd2a495cf990
modalities=[text image]`。
- 内存:同一份 homed,启用时 RSS **1.99GB**(峰值 2.09GB),不启用 **0.17GB**。
- NLP 修复:日志由 `ONNX parser init: ... using fallback` 变为 `dep parser initialized`。
- 构建矩阵:`go build/vet ./...` 与 `-tags onnxruntime` 两种都过;
`bash -n deploy/packaging/build.sh` 通过。
## 未做(明确记录)
- `libonnxruntime.so`(24MB)与 Chinese-CLIP 产物(754MB)目前都需自行安装/导出,
发行版尚未打包它们。若要让「默认启用」在干净机器上真正开箱可用,需要决定
是随包分发、安装时下载、还是保持文档指引。
2026-09-12 00:10:32 +08:00
bfdb395731
feat(memory): 新增 chineseclip provider —— text+image 的小体积可商用向量空间
...
## 为什么
用户决定「本轮不覆盖 video,先支持 text+image」。这一刀正好解锁了此前
「小 + 可商用 + 覆盖视频」三者不可兼得的僵局:不要求视频后,唯一同时满足
**小、可商用、中文原生** 的选项是 Chinese-CLIP ViT-B/16。
实测对比(同机、真实跑出来的数字):
| | Chinese-CLIP | jina-v5-omni-nano | Qwen3-VL-Emb-2B |
|---|---|---|---|
| 参数量 | 188M | 1.04B | 2B |
| 产物 / 常驻内存 | 754MB / **1.15GB** | ~2GB / 2.23GB | 8GB / 9.4GB |
| 维度 | 512 | 768 | 2048 |
| 许可 | **Apache-2.0** | CC BY-NC(不可商用) | Apache-2.0 |
| 视频 | 无 | 有 | 有 |
本机可用内存只有 5.3GB,Qwen 的 9.4GB 无法进程内使用;而 ORT format + mmap
那条路被证实当前不通(转换器对三段图段错误;走通还需同时升 ORT 运行时与
Go 绑定,v1.36 要求 API 29 而本机只有 28)。1.15GB 则可以直接进程内跑。
**代价已写进包注释与文档**:CLIP 是双塔对比学习,text↔image 是强项,但纯文本
语义明显弱于 MLLM 型嵌入器;文本检索仍由既有词向量/TF-IDF 路径兜底。
需要更强文本语义或视频时切回 qwen3vl。
## 内容
- `providers/chineseclip/`:按公共 SPI 实现的 provider(注册名 `chineseclip`),
含 BERT WordPiece 分词器、图像预处理、ONNX 双塔推理、无标签 stub。
- `scripts/export_chineseclip_onnx.py`:从官方权重导出规范产物 + 冻结参考,
自带逐用例 PyTorch 对比与覆盖度断言(计划集合≠执行集合即非零退出)。
- `cmd/homed/main.go`:空白导入两个 provider,由配置选其一。
- `go.mod`:`golang.org/x/text` 由间接依赖转为直接依赖(删音标需要 NFD)。
## 实现要点
- **分词器逐 token 对齐官方**。第一版探针自己拼 BertTokenizer(只给 vocab.txt、
没删音标、中文没逐字切),中文被整体切成 [UNK],三个不同句子产出几乎相同的
向量(余弦 0.98)——差点把「模型坏了」当成结论。官方配置是 do_lower_case=true
+ 删音标生效 + 中文逐字切分;`TestTokenizerMatchesOfficialReference` 钉住
逐 token 一致。
- **图像缩放自写 bicubic**(复刻 PIL 的 precompute_coeffs + a=-0.5 核),不引
golang.org/x/image:它未进本机模块缓存,且最新版要求把整个工具链升到 Go 1.26,
为一个缩放函数动工具链不划算。
- **归一化在 provider 侧**(两个塔的图里都没归一化),检索按余弦。
- **指纹覆盖全部影响语义的产物**:两个 ONNX 图 + vocab.txt + embed_config.json,
读不到就写 MISSING(跳过等于对缺件不敏感)。
- 会话 Run 用 runMu 串行化(ORT 会话不保证并发安全),创建/销毁用 mu。
## 模态范围
只声明 `text` 与 `image`;`audio`/`video` 明确返回 `ErrUnsupportedModality`,
绝不用别的模型向量冒充(这是「音频明确 unsupported」纪律的落地)。
## 验证(实测)
导出侧:10 个用例(5 文本 + 5 图像)ONNX vs 官方 PyTorch 全部
`cos = 1.000000000`,覆盖度断言 10/10 通过。
Go 侧(`CHINESECLIP_MODEL_DIR=... go test -tags onnxruntime ./providers/chineseclip/ -v`):
11/11 通过,其中
- 文本 5 用例 `cos = 1.000000000000`(逐位一致)
- 图像 4 纯色用例 `cos = 1.000000`(与官方预处理在 6 位小数内一致)
- 跨模态判别:红图对「红色」文本高于「蓝色」文本
- 模态拒绝 / 空输入 / 指纹稳定 / 产物缺失报错
顺带修掉测试自身的一个假通过:参考向量是**未归一化**的原始输出(模长 10~36),
原先「点积当余弦 + 单侧下界」会让 13.6 也判过,已改为真余弦 + 双侧容差。
构建矩阵:`go build/vet ./...` 与 `-tags onnxruntime` 两种都过;
`providers/... pkg/... internal/config/... internal/memory/vector/...` 回归通过
(qwen3vl 的 TestVideoModelInputMRope 需要 QWEN_ONNX_MODEL_DIR 指向含视频档的
v3 目录,缺该环境变量时用的是只有文本+图像的目录,与本改动无关)。
## 未做(明确记录)
- 发行版默认 provider 与构建标签变更:留下一提交(涉及打包与模型分发策略)。
- 模型产物(754MB)不进仓库,由导出脚本生成。
2026-09-11 23:58:53 +08:00
a37bc7333e
refactor(memory): 核心不再适配具体模型——公共 embedding provider SPI + 注册表
...
问题:cmd/homed 里 `case "onnx": qwen.New(modelDir)` 把模型适配写进了核心,
`type=onnx` 名义上是格式、实际写死了一个模型家族;2117 行 Qwen 专属代码
(BPE、chat template、M-RoPE、Vision_gN 命名)住在内核树里,还带着一对
`//go:build onnxruntime` 的 stub。加任何新模型都要改内核。
现在核心只认一个模型无关的公共契约(pkg/embedding):
- 输入是不透明的 Data+MIME,解码/预处理/时序分组全归 provider
- 能力是数据(Info.Modalities),不是接口方法——新增模态无需改核心接口
- 不支持的模态返回 embedding.ErrUnsupportedModality(可 errors.Is 识别)
- 按名字注册,重复注册 panic;Options 是 provider 私有命名空间,核心不解释
改动:
- 新增 pkg/embedding:Modality/Purpose/Input/Info/Provider/Config + 注册表
(Open 校验 Info,ValidateVector 在入库前拦下维度错与非有限值)
- providers/qwen3vl:Qwen 实现整体移出内核(git mv),实现公共 SPI 并自注册
- internal/memory/vector:新增 ProviderAdapter(公共 SPI → 内部小接口);
ErrModalityUnsupported 改为公共哨兵别名;删除 VideoEmbedder 可选接口
(那正是「核心为每个新模态长方法」的坏味道)
- http embedder 也变成普通 provider(注册名 http)
- cmd/homed:删除 qwen import 与 onnx/http 分支,改为按 provider 名打开 +
透传 options.*;provider 打开失败只警告并禁用多模态检索,不影响启动
- config:multimodal_space.type/onnx./http.* → provider + options.*
- 删除 internal/memory/qwen(整体搬迁)
测试:
- pkg/embedding:注册表隔离/未知名字/非法 Info 自动关闭/ValidateVector
- vector:适配器原样透传字节与 MIME、维度错被拦、Close 幂等且停止使用、
两个哨兵 errors.Is 互通
- providers/qwen3vl:新增公共 SPI 全链路集成测试(Open→Info→Embed→
未知模态哨兵),并明确断言 Info 不声明 video
已知未完成(不得当作已验证):
- 视频冻结回归 TestEmbedderVideoMatchesONNXReference **显式跳过**:Go 侧
video 模板缺少 processor 按时间组插入的字面时间戳文本
(<0.0 seconds>/<1.0 seconds>),同一输入 Python seq=1190(1152+38)、
Go 只有 22 个文本 token。时间戳也占 M-RoPE 位置,故现有 M-RoPE 自洽断言
通过不能证明与官方实现一致。修复属 provider 内部工作。
- 视觉侧三档已导出并逐档校验通过(cos 1.000000119/1.000000119/1.000000000)
验证:go build ./... ;go vet -tags onnxruntime ./... ;
go test -short ./internal/memory/... ./internal/agent/core/... ./internal/sdk/... ./pkg/...
;onnxruntime 下 providers/qwen3vl 全绿(视频为显式 skip)
2026-09-11 18:26:19 +08:00
1a02971f88
feat(memory): 千问三段式 ONNX 嵌入补齐——可复现导出脚本 + Go 侧首次完整验证
...
此前三段式拆分后 ONNX 路径从未从 Go 侧跑通:embedder_onnx_test.go 仍引用
分段前的 API(e.renderInput、TextTower.onnx、旧目录),go vet -tags onnxruntime
直接编译失败。导出脚本只在 /tmp 且硬编码本机路径、从第三个目录拷贝固定形状的
Vision.onnx,完全不可复现。音频会被视觉塔编码,静默往统一空间灌入错误坐标。
本提交补齐这些缺口:
一、可复现导出脚本(scripts/export_qwen3vl_embedding_onnx.py)
- 自动拉取模型(HuggingFace 优先,失败回落 ModelScope,支持 HF_ENDPOINT 镜像);
- 导出 TokenEmbedding + Transformer + Vision 三段图,图文共用同一 token
embedding、28 层 Transformer、last-token 池化与 fingerprint;
- 双重自检(不可省):分段 PyTorch vs 完整模型 + 导出后的 ONNX vs 完整模型,
cos < 0.999999 即非零退出——「能加载」不等于「算得对」;
- 默认把 L2 归一化后的冻结参考向量写入产物目录(qwen_reference.json)——
Go 测试据此做逐维冻结回归,且「该目录是哪次导出的」从文件本身可追溯;
- --verify-only 校验既有产物不重新导出,可用来确认线上在用的图没坏。
关键实测结论(已写入 docs/zh/multimodal-space.md 与长期记忆):
原生多帧视频不可行——Qwen3-VL 视觉塔把 grid_thw 当 Python 值消费
(grid_thw.tolist()),legacy tracer 固化为常量,导出后图中根本没有 grid_thw
输入,换帧数调用直接 Invalid input name: grid_thw。故视觉塔固定 (1,48,48),
视频由上层抽帧后逐帧按图像编码(同模型/同维度/同 fingerprint),音频明确
unsupported。
二、模态边界(vector.ErrModalityUnsupported)
- 新增 vector.ErrModalityUnsupported:表示「该模态不在本统一空间的原生覆盖
范围内」,与普通错误语义不同——调用方应把它当「永远不会有向量」而非
「本次失败、下次重试」;
- qwen.EmbedImageDense 按 mime 拒绝 audio/* 与 video/*:此前它会拿视觉塔
去解音频字节,往统一空间灌入语义错误的坐标且静默;
- reembedStaleMedia 对 ErrModalityUnsupported 不计失败、不重试、不用别的
模型向量顶替(TestReembedStaleMedia_SkipsUnsupportedWithoutFaking 守住)。
三、Go ONNX 测试首次完整通过
- 重写 embedder_onnx_test.go:修复编译 + 文本冻结回归 + 图像冻结回归 +
两条阴性对照(不同输入必须不同、图像与文本必须不同)+ 不支持模态断言;
- 参考值从产物目录的 qwen_reference.json 读取(不在测试里硬编码浮点);
- 用线上部署产物实测全部通过(text cos=0.999999940, image cos=0.999999762)。
四、.gitignore 修复
- /scripts/ 此前被列在「运行时产物」下,但它是作者维护的工具目录
(模型导出、侧车、部署校验),deploy/systemd/embed-sidecar.service 直接
引用 scripts/embed_sidecar.py,忽略它会让那份 unit 在别人的机器上指向
不存在的文件。改为只忽略 __pycache__。
五、文档(docs/zh/multimodal-space.md)
- 获取/启用/产物契约/模态边界/验证/资源成本/与现有部署产物的等价性。
验证:go build ./...、go vet ./...、go vet -tags onnxruntime ./...、
go test -short 全部通过;ONNX 标签测试对线上部署产物全部通过。
2026-09-11 13:45:25 +08:00
6c2039f5c9
feat(vector): pluggable multimodal vector space
...
核心暴露 MultimodalEmbedder 接口,两条路径共享同一套 L0/L2/L3
向量缓存、media.Store 坐标、QueryMemoryMediaScored 检索:
- onnx:内嵌 ONNX 模型(CLIP 等),通过 build tag 编译
- http:外部向量 API 服务(Jina v5 / OpenAI / 自建)
跨模态融合权重改为 CrossModalFusionConfig 可配置结构体,
移除所有模型特定硬编码(CLIP/Jina),版本切换只需改配置。
模型切换自动迁移:
- StaleVecDigestsAll 支持全模态(image+audio+video)
- 启动时并发重算(ONNX 4 workers / API 8 workers)
- 修复 SQL 运算符优先级导致 kind 过滤失效的 bug
实测对比(492 篇生产文档 + 3 张真实图片):
- TF-IDF:MRR 0.457(精确匹配快,语义差)
- fastText:MRR 0.530(语义中等,延迟 8ms)
- Jina v5-omni:MRR 0.900(全面领先,延迟 40ms)
- 中文文本→图片:Jina MRR 0.833 vs CLIP 0.611
See docs/embedding-comparison.md for full benchmark.
2026-09-09 17:38:34 +08:00
b889934bba
docs: 同步仓库文档到 v1.1.1,补媒体记忆与接口扩展规则
...
五处文档此前停在 v1.0.0,而 v1.1.0/v1.1.1 都已发布并在现网运行。
本轮补齐三层记忆的媒体架构、模型工具的媒体参数、通信面 method 数,
以及冻结解除后的替代约束。
## 中英双语 OVERVIEW.md
三层记忆段只写了 Context/Document/Graph 三层,而 v1.1.0 起图片/音频是
三层里的一类节点。补上媒体记忆的架构概要:CAS + 引用计数 GC + 标记格式
(描述文本才是持久语义记忆,blob 是可淘汰的缓存)+ 插件边界贯通。
## 中英双语 ARCHITECTURE.md
- 「记忆工具」表补 `memory_commit`/`doc_commit` 的 `media_digests` 与
`sentence_text`(后者从未暴露给模型,而它是媒体绑定链的必经环节)
- 「三层记忆」段新增媒体记忆子节:CAS 设计表(寻址/完整性/写入原子性/引用/GC)、
标记格式、可选性(`enabled=false` 时整条链路静默退化)
- 「三个通信面」从 51 改为 55 个 method,新增四个 media method 的说明
- 「SDK 四通道」代码示例补媒体注入三方法 + 与 SetToolBlocks 的区别
## plugin-interface-matrix.md
- 状态从「完成 v2」改「完成 v3」,v3 记录 v1.1.1 的接口扩展
- §二 A3 DocMemoryAPI 补 InsertWithMedia
- §二 A4 补三个媒体注入方法 + 为何不能搭 SetToolBlocks 的车
- §二 A5 补 MediaAttachment 类型 + Triple/Doc/TextEvent 的扩展字段
- §六「新获得的能力」补 SetToolBlocks 已落地、媒体入记忆、插件主动发起
带媒体的对话
- §七 冻结检查点补第 5 条(冻结已解除,取代它的是 §九)
- 新增 §九「v1.1.x 的接口扩展规则」:冻结解除后的三条硬约束
(只增不减签名不改 / 新增方法方向 / 模板接线六处失败链)+ 验证方式
(存量插件 17/17、旧产物 4/4 建链、模板断言、压测 -race)
## 为何分立两笔 commit
前一笔(SDK 仓 README + 内核 README)改的是给**插件开发者**看的文本,
本笔改的是给**架构师与维护者**看的技术文档。受众与改动层次不同,
放在同一个 commit 会让追溯时看不出"文档在哪一层跟上了代码"。
2026-09-06 15:07:14 +08:00
8c6b593a54
docs(git): SDK 仓版本语义与发版联动,并明确 main 永不作发版分支
...
三条此前没写进规范、于是被我在实际操作中做错的规则:
## 一、SDK 版本号跟随核心的中版本,patch 位恒为 .0(新 §七.1)
整条核心 1.1.x 线共用 SDK 1.1.0;只有核心进入 1.2.0 这种中版本跃迁时 SDK 才升。
核心的 patch 位专用于 bugfix 与漏洞修复,这类改动不碰公开 SDK 接口,SDK 版本号
没有理由跟着动。
**为什么不逐位对齐**:SDK 版本号是插件开发者的依赖声明。若核心每发一个 bugfix
就给 SDK 推一个新号,开发者要么被迫跟版、要么怀疑自己版本过时,而接口其实一个
字都没变。让 SDK 号只在**接口可能变化的中版本边界**上跳,开发者只需关心「我在
为哪个中版本写插件」。
因此「两仓版本对齐」在本规范里指**中版本对齐**(核心 1.1.x ↔ SDK 1.1.0),
不是三位全等。核心 1.1.1 配 SDK 1.1.0 就是对齐状态。§四 的措辞同步修正。
## 二、beta 阶段不发 SDK(新 §七.2)
核心的 alpha/beta tag 不伴随 SDK 仓发版:SDK 仓在这一阶段不打 tag、不建 release。
**为什么**:beta 是核心自己的测试阶段,此时 SDK 接口尚未固定。若此刻给 SDK 发版,
插件开发者会照着一个还会变的接口写代码——那是无效开发。接口没定就没有可依赖的
契约,发出去的版本号是一个假承诺。
这条约束的对象是 **SDK 仓的发版动作**,不是核心二进制里有没有 SDK 代码。主仓用
`replace => ./third_party/homeagent-sdk`,任何核心构建都必然含 vendored SDK 源码,
那是构建机制决定的,不在约束范围内。
核心打**正式** tag 时 SDK 才随之发版(§七.3):SDK 仓也有自己的 `release/vX.Y.x`,
定版为 `X.Y.0`,打 tag、建 release、传 5 平台 plugindev 产物。同一中版本内的后续
核心 patch 不重复发 SDK。
## 三、main 永远不是发版分支(补进 §四)
版本号 bump、打 tag、构建产物、上传附件,全部只在 `release/vX.Y.x` 上做。
**即使某个改动刚合进 main、即使 main 此刻可部署,也不从 main 打 tag。**
main 的版本号是「下一个未发布中版本」的路牌,不是任何一次发布的版本号。
这条本该是 §2.1「main 的 meta.Version 始终是下一个未发布版本」的直接推论,但
只写了状态、没写禁令,于是留下了「main 可部署 ⇒ 可以从 main 发版」的误读空间。
§三 的分支表补上 main 现值 `1.2.0` 与 1.1.x 线的 tag 历史,让路牌语义有实例可对。
## 四、公开接口改动是 feature,不是发布准备(补进 §六)
它必须走 `feature/xxx` → 合回 main → cherry-pick 到发布分支,不允许当成「发布
分支上的 bug 修复」直接提交进 release——发布分支冻结功能(§2.3),而接口是最
典型的功能面。§五 补上这条路径的命令示例,以及 SDK 仓同步发版的命令。
2026-09-06 09:52:52 +08:00
e2d04a31a7
docs(git): 发布分支改为一个中版本一条,补三级发布通道规范
...
## 一个中版本一条发布分支
原规范写 release/vX.Y.Z(含 patch 位),实践中 1.0.0 与 1.0.1 各建了一条
分支,导致同一条 1.0.x 发布线被切成互不相连的碎片——追溯时无法用一条
分支看完整条线的演进。改为 release/vX.Y.x,patch 位用 x 占位,
承载该中版本全部 patch 直到下一条中版本分支切出。
## 三级发布通道(alpha / beta / 正式)
通道由 tag 区分而非分支:三者共用同一条 release/vX.Y.x。
alpha vX.Y.Z-alpha.N 功能齐了未充分验证 仅内部自测
beta vX.Y.Z-beta.N alpha 问题已修 小范围试用
正式 vX.Y.Z 通过验证可上现网 所有用户
这是 semver 标准预发布语义(1.1.0-alpha.1 < 1.1.0-beta.1 < 1.1.0),
版本比较逻辑天然认得,无需额外约定。允许跳级但要在发布说明写明理由;
alpha/beta 产物不上现网——预发布通道的存在就是为了不拿 24/7 服务冒险。
## 回流仍是 cherry-pick
明确不改 merge:merge 会把已发布的版本号带进 main,与「main 的
meta.Version 始终是下一个未发布版本」直接矛盾。
新补一条:修复落地当天要 pick 到所有活跃 feature 分支,否则它们合回
main 时可能带回旧代码(2026-09-04 的 stage 双重解锁修复即同时 pick 到
main 与 feature/memory-media)。
## 运维纪律沉淀
把今天走通的部署流程写进第四节,其中两条是踩过的坑:
- 备份配置库用 sqlite3 .backup 而非 cp(WAL 模式下 cp 可能拿到
不一致快照)
- install -m 0755 替换而非 cp(原子 rename,不写坏运行中的进程镜像)
健康检查列出六项,含「一次真实对话」与「fatal error 计数为 0」。
## 当前分支对齐
第三节更新为 2026-09-04 的实际状态,并记录 1.0.x 的 tag 历史表
(含 v1.0.2 未使用的原因、v1.0.3 直接跳正式 tag 的理由)。
按 patch 号命名的历史发布分支标注为应当删除的遗留形态。
2026-09-04 20:11:19 +08:00
2a03a83ce0
docs: Part 6.6 文档收尾 —— 迁移计划/接口矩阵/PLUGIN_DEV 全量更新
...
## plugin-migration-plan.md
Part 6 标记完成,并**记录实际执行与计划的偏离**而非假装一致:
原计划「逐插件迁移,随时回退」。用户决策改为彻底舍弃 .so、无回退通道,
本轮直接删 internal/plugin/cabi/。因此【V】的「.so ↔ .bin 混跑集群冒烟」
不再适用——新内核根本不认 .so。改为验证「新内核面对旧 .so 给可操作错误
且不崩溃」,已在真实二进制上确认。
最终验收清单加「结果」列,13 项逐项对账。**两项未完全达标,如实标注**:
- #9 SetToolBlocks:method 已定义并划入 CapCore,但内核侧仍返回未实现。
C ABI 时代它也是空实现(§1.4),故不是回归,但也没兑现 §3.8 的承诺。
- #13 内存:15 进程 RSS=88.0MB,远超「基线 +29MB」。根因是每插件静态链接
整个 Go runtime,15 个不同二进制无共同物理页(PSS/RSS 99.9% vs 基线 44%)。
实验 5 基线用的是 2.68MB 最小插件,绝对数字不可比;结构性指标
(均摊线程 5.5 vs 4.9)同量级。
新增两节实录:Part 6.5 生产切换(执行顺序为何不能反过来、hmap 正规通道
vs 手工拷贝的对照表、真实 QQ 消息的端到端证据链)与 Part 6.6 压测数据。
## plugin-interface-matrix.md
状态从「基线 v1」升为「完成 v2」。三个合同面逐一标注达成情况:
- 合同面 B:51 个整数 method id 已平移为 Method* 字符串常量。保留原表作
历史对照,但注明 case 25(CoreFreeString)无对应 method(内存管理是 C 层
特有问题),以及 io.setToolBlocks 已定义但内核侧未实现。
- 合同面 C:C1 标题从「今天」改为「迁移前」(迁移已完成,「今天」会误导);
C2 补上「全部插件共享同一块 memfd」这个关键决定及其理由——第一版设计
是每插件一段,那会退化成副本模型复现 lost update。
- 第六节「新获得的能力」加「实际结果」列。事件订阅标注机制已完成但
零用户使用,故未经真实负载检验——这比只写 ✅ 诚实。
「刻意不给」清单同步为带 API 后缀的新命名(SelftestAPI 等),与
capability.go 的 withheldCapabilities 对齐,并说明为何加后缀:
不加时子串匹配会把 tool.register / io.setToolBlocks 误判为泄漏 ToolAPI。
## PLUGIN_DEV.md(中英双份)
C ABI 时代的描述全部改掉:
- 「动态 .so/.dll 插件」→「子进程插件」
- 「生成 C ABI bridge(z_bridge_gen.go + z_entry.c)」→ 子进程运行时三文件
- 「go build -buildmode=c-shared」→「go build(CGO_ENABLED=0)」
- 平台二进制表:三平台统一 plugin.bin(bundle 包内按 goos.goarch 区分)
- 「不能跨 C ABI 边界序列化」→「不能跨进程序列化」
- 「ABI v2 写回」→「Stage 写回」
新增 v1.0.0 破坏性变更提示框,五条要点:.so 不再加载、业务代码不需改、
entry 字段对 Go 插件已无意义、不再需要 cgo、Windows 从 3 字段升到全字段。
保留 .so 字样的只有变更说明本身(3 处),其余全部清理。
2026-09-03 08:12:30 +08:00
62bdfa2b54
meta: 内核版本升到 1.0.0;生产切换脚本改走 hmap 正规通道(Part 6.5)
...
## 版本号
1.0.0:外部插件从 C ABI 动态库迁到子进程 + 共享内存。首个不再加载
`.so`/`.dll` 的版本,与 0.9.x 不兼容(存量插件必须用新版 plugindev 重编)。
SDKCompatibleVersion 同步升 1.0.0。
同时删掉 ABIVersion / CABINum / 51 个 Core<Method> 整数 ID —— 随 Part 6.2
删 internal/plugin/cabi/ 就已无使用者(grep 确认只剩定义处)。留着会让人
以为 C 层协商还在生效,或以为加 method 要同步维护那张整数表。
⚠️ 注意 Makefile 的 `VERSION ?= $(shell git describe --tags --dirty)`:
实际注入值来自 git tag,meta.go 里的默认值只在不带 ldflags 时生效。
make build 当前注入 v0.9.1-56-g2572688-dirty。要让 1.0.0 真正生效需打
v1.0.0 tag 或显式传 VERSION=1.0.0。
## 生产切换脚本重写
第一版是手工拷 plugin.bin + 手改 plugin.json 的 entry —— 那等于**重新实现
了一遍 hmap 解包逻辑,且实现得更差**。漏掉的东西:
platforms 字段 hmap 内的 plugin.json 本来就写对了
平台二进制选择 我硬编码 _linux_amd64,正规路径用 platformBinary()
overwrite 语义 StopAndUnload 停旧实例但**保留配置表**
失败回滚 os.Rename 备份旧目录,解包失败自动恢复
校验 validatePackage 查 manifest + 各平台二进制齐全
配置保留那条尤其关键:生产 17 个插件都有配置(qq 账号、weather 默认城市、
browser profile 路径)。我的脚本恰好没碰配置表所以侥幸不丢,但那是运气
不是设计。
改为 POST 到 pluginmgr 的 HTTP 端点(127.0.0.1:9876/plugins),
传 {path, overwrite:true} 走 installFromPath → installFromData。
保留的一个设计:**先全部校验再动手**。任一插件缺 hmap 就整批中止——
新 homed 不认 .so,「一半装了一半没装」的中间态最难排查。
## 生产切换已执行
顺序(先换二进制再装包,而非反过来):
1. systemctl stop homeagent
2. 换 /usr/local/bin/homed
3. 起服务 —— 15 个 .so 插件报可操作错误被跳过,homed 本体与 16 个内置正常
4. 逐个 POST 装 17 个 hmap(overwrite=true)
5. 待重启核对
第 3 步顺带在真实二进制上验证了 Part 6.2 的可操作错误:
[plugin] dynamic weather: 检测到旧 C ABI 产物(plugin.so/.dll/.dylib)。
外部插件已改为子进程模式,请用新版 plugindev 重编产出 plugin.bin
(业务代码无需修改)
不崩溃,只跳过。若反过来先装包,旧 homed 的 StopAndUnload 会停掉 qq
消息通道且无法重载 .bin,会卡在「插件全挂」的状态。
结果:17/17 成功,全部 config_kept=true;0 个残留 .so;17 个 plugin.bin
均有执行位;17 个 manifest 的 entry 均为 plugin.bin;无 .bak 残留。
bundle 包正确挑了当前平台(weather 目录只留 8.7MB 的 linux/amd64 那份)。
备份:/home/newqqagent-migration-backup-20260902-214812
(plugins 全目录 + homed.old + homeagent.service,162MB)
验证:go build ./... 通过;go test ./... 全仓无失败。
Ref: docs/zh/plugin-migration-plan.md Part 6.5
2026-09-02 22:40:47 +08:00
2572688c51
proc: 性能基准 + 流式压测(Part 6.6 验收项)
...
此前只做了功能冒烟与内存快照,延迟与压测都没测。这两项是计划里
明确列出的验收条件,补上。
## 基准结果(AMD Ryzen 7 7840HS)
| 项目 | 实测 | 基线 |
|---|---|---|
| 工具调用 RPC 往返 | 24.1 µs | 实验 11: 19.6 µs(同量级) |
| 锁仲裁(内核侧) | 0.76 µs | 见下注 |
| 事件环写入 | 95 ns | — |
| 事件环并发写入 | 83 ns | 无锁竞争恶化 |
| 完整 stage 往返 | 132 µs | 含 3 次进程间往返 |
| 共享段编解码 | 3.7 µs | 占 stage 的 2.8% |
**锁仲裁 0.76µs 不可与实验 3 的 19.40µs 对照**——测的不是同一个东西:
实验 3 测插件经 RPC 请求锁的完整跨进程往返,本基准只测内核侧
lockRegistry.acquire/release。真实成本仍在 20µs 量级。
基准原名 BenchmarkStageLockRoundTrip 有误导性,已改为
BenchmarkStageLockArbitration,并在注释里写明不可对照的理由——
否则日后有人拿 0.76µs 去比 19.4µs 会得出「优化了 25 倍」的错误结论。
**stage 往返 132µs 的成本构成**:共享段编解码只占 3.7µs,其余是
一次 stage 要走 3 次进程间往返(stage.invoke + 插件侧反向的
stage.lock / stage.unlock)。相对 LLM 往返 2-8 秒可忽略;要优化的方向是
把 lock/unlock 合入 stage.invoke 的请求/应答,省掉两次往返。
## 流式压测:§4.3 标记「风险高」的那一项通过
原文担忧:「Bus.Publish 路径禁用任何锁/阻塞——流式输出逐 token 发布,
任何等待都会卡顿」。事件环是 Part 5 新加在这条路径上的,必须验。
```
5000 次 Publish + 每条睡 20µs 的慢消费者
实测 2.29ms,均摊 457 ns/token
同步语义理论下限 100ms
订阅者 1 个:1.547ms(515 ns/次)
订阅者 8 个:1.518ms(506 ns/次) ← 无线性恶化
环溢出(无消费者写 30000 次,cap=8192):均摊 35 ns/次 ← 仍 O(1)
```
2.29ms 与实验 4 的数字完全一致(那次也是 2.29ms / 0.46µs per token),
post-and-forget 在实现中成立。
第三项的意义:消费者完全停摆时写端覆盖最旧 slot,这条路径仍是 O(1),
故「消费者卡住」不会连带拖慢内核主循环。
Ref: docs/zh/plugin-migration-plan.md Part 6.6、docs/zh/架构迁移评估.md §4.3
2026-09-02 21:42:18 +08:00
1d7f011e5d
plugin: 17 插件全量重编 + 端到端冒烟验证(Part 6.3)
...
## 17 个插件源码零改动,全部重编为 plugin.bin
16 个 × 3 平台(linux/darwin/windows),qq 1 平台(plg.json 自己声明
bundle:false)。luademo 走 Lua 解释器不适用。
git status example/ 无输出 —— 这是「业务代码零改动」的硬证据。
批 3 那些预估高风险的插件(qq 2686 行双向通道、browser 12 工具 +
InjectInterruptText、a2a/acp 的 InjectInputSync 同步注入)一次全过,
因为它们只碰公开 SDK 合同面,而合同面在 Part 2 已 51 个 method 全量平移。
唯一一次失败与迁移无关:rss 的 github.com/mmcdole/gofeed 不在本地模块
缓存且 proxy.golang.org 不通,换 GOPROXY=https://goproxy.cn 后通过。
## 真实 homed 加载验证
15 个外部插件全部经 proc 通道建链(protocol=1 sdk=0.9.2,各自独立 PID),
31 个插件 loaded(15 外部 + 16 内置)。
ai_image / files 未走 proc 通道:同名内置插件优先(工厂编译期注册),
外部插件被遮蔽。这是既有行为,与迁移无关。
事件环与共享段均正常创建,且共享段是**一块** 256KB 服务全部 15 个插件。
## 冒烟测试 4 项(internal/plugins/real_plugin_smoke_test.go)
用真实 example 产物而非 testdata 假插件;manifest 刻意写 "entry":"plugin.so"
验证工具链与内核都已不看 entry 值。未重编时 skip 而非 fail。
- ToolInvokeRoundTrip:工具真实调用往返(此前只验证到"注册")。
weather_current 返回结构化参数校验错误——这恰是链路通的证据。
- StageRewriteTakesEffect:sanitizer 清洗 ANSI 序列,改写经共享段回到
内核 StageContext
- MultiPluginShareOneSegment:sanitizer + weather 并发,清洗结果不被覆盖
- CrashDoesNotKillKernel:SIGKILL 插件进程后 homed 存活、17 插件仍在
(对比 C ABI 下插件 panic 直接带崩 homed,§1.2 现网已发生)
## 开销实测与基线偏差
15 个插件进程 RSS=88.0MB PSS=87.9MB 线程=82,均摊 5.87MB / 5.5 线程。
RSS 88MB vs 实验 5 基线 29.1MB **不是回归,是基线不可比**:实验 5 用
2.68MB 最小插件,真实插件 3.1~14.8MB。可比的结构性指标:
- 均摊线程 5.5 vs 4.9 —— 同量级,无线程膨胀
- PSS/RSS 99.9% vs 44% —— **明显差于基线**
第二项是真实发现:基线里 PSS 远低于 RSS 说明 Go runtime 只读代码页在
进程间共享;实测几乎不共享,因为 15 个插件是 15 个不同的二进制,没有
共同物理页可映射。这是「每插件独立二进制」的固有代价,意味着实际内存
开销高于 §4.3 的乐观估计。压这一项的方向是共享 launcher 二进制。
## 工具脚本入 experiments/19-migration-verify
scripts/ 被 .gitignore 排除,故放到已跟踪的 experiments 目录下,
与 01~18 的可复跑实验并列。
measure-plugin-overhead.sh 第一版有统计口径 bug:RSS 读 status 的 VmRSS、
PSS 读 smaps_rollup 的 Pss,输出 PSS(87.9MB) > RSS(69.1MB) —— 物理上不可能。
两者对共享内存段计入方式不同(smaps 的 Rss 含 Pss_Shmem)。已统一从
smaps_rollup 读。另修 bc 不可用导致 MB 全显示 0.0(改用 awk)。
Ref: docs/zh/plugin-migration-plan.md Part 6.3、docs/zh/架构迁移评估.md §4.3
2026-09-02 20:20:25 +08:00
53a148cb54
docs: Part 5 标记核心已完成,进度快照更新事件环
...
Part 5 通知面内核侧 + 模板侧均已完成,端到端测试通过。
事件订阅从 C ABI 的空实现(case 23/24)变成真正可用。
测试数量更新:proc 38 项 + plugin 16 项(含 -race)。
下一步转 Part 6 逐插件迁移。
2026-09-02 17:07:43 +08:00
4f14d0947f
docs: 更新迁移计划进度(Part 2/3/4 完成标记)
...
Part 2(子进程通道)、Part 3(plugindev .bin 构建)、Part 4(RunStage 接线)
标记为已完成,下一步转 Part 5 通知面。
记录两处与原计划的偏差及原因:
- Part 3 模板落地方式从 templates.go 的 raw string 换成真实 .go 源文件 +
//go:embed —— 900+ 行代码塞在字符串里写错只能等生成插件时才炸。
- Part 2 最初每插件一块共享段,等于副本模型换壳,已改为全部插件共享同一 memfd。
另记 lifecycle.autoRestart 缺口:公开 SDK 的 SetAutoRestart 是纯 setter
无 hook,隔着进程边界内核读不到,需模板在 Start 返回后显式上报。
2026-09-02 13:12:08 +08:00
bfa95ba320
docs(plan): Part 1 完成 + Part 4 核心完成标记,0.3/0.4 标记跳过
...
- Part 0.3/0.4 标记 ⏭️ 跳过并记录理由(子进程模型下问题整体消失,不给待删代码打补丁)
- Part 1 加载分派骨架 ✅ 完成(修改/审查/验证三步逐条勾选)
- Part 4 共享内存数据面 ✅ 核心完成(段/编解码/锁仲裁,RunStage 接线待 Part 2)
- 目录加进度快照
2026-09-02 10:43:40 +08:00
fe2fdc9692
docs: 固化当前分支对齐记录(update→feature/plugin-proc-migration)
2026-08-31 12:37:43 +08:00
69a138c1af
docs: Git 分支管理规范(main 长命 + feature/release/hotfix cherry-pick 流程)
...
- main 唯一长命、永远可部署;现网永远部署 release tag 构建
- feature/xxx 从 main 开出合回;release/vX.Y.Z 切出打 tag 构建
- hotfix 提交 release 分支 + 版本号分离提交,只 cherry-pick 修复回 main
- 明确'不需合并 release 回 main'(hotfix 已逐个 pick 回,避免冲突)
- 两仓(TrueAgent + homeagent-sdk)同用本规范
2026-08-31 12:36:44 +08:00
2e2602f437
docs(plan): Part 0.1/0.2 勾选 + 迁移计划进度标记
...
- plan.md 11.1 (3 checkbox)、11.3 (3 checkbox) 全部勾选
- plugin-migration-plan.md: 0.1/0.2 标记 ✅ 完成(含踩坑记录与待部署项)
2026-08-31 12:33:24 +08:00
b74ee15321
fix(cabi): output_send 等待真实发送结果,消除假成功(plan 11.1 / Part 0.1)
...
根因:CORE_REGISTER_OUTPUT_CH handler 无条件返回 {status:queued}+err=nil,
模型永远收到「已发送」,实际失败(如 meta 缺 user_id)只写日志,模型无法感知不会重试。
现网近 7 天成功 44 次、失败 2 次全部谎报成功。
改动:
- loader.go: 新增 awaitOutputResult(+可注入版 awaitOutputResultWith)+ outputSendTimeout=10s
goroutine 执行 cgo 发送 + 带超时 channel 等结果 → sent / error / unconfirmed 三态
handler 由 executeOutputSendTool 从 Go 侧调起,非 cgo 栈,不构成 cgo 嵌套
- output.go: executeOutputSendTool 识别 unconfirmed|queued,回报「发送结果未确认」而非「已发送」
- output_test.go: Success/Failure/Timeout 三用例
验证: go build exit 0; go test ./internal/plugin/... ./internal/agent/... 全绿
接口冻结: git diff third_party/homeagent-sdk/sdk/ 为空
2026-08-31 12:16:39 +08:00
8a1a7df406
docs(plugin-arch): 外部插件多进程化适配计划(修改→审查→验证三步微循环)
...
7 个 Part,每 Part 一个微循环:
- Part 0 脆弱基线先行(11.1/11.3/11.6,现网止血,不依赖迁移)
- Part 1 加载分派骨架(entry 双通道共存,可回退前提)
- Part 2 子进程通道原型(spawn/JSON-RPC/procPlugin,参考 sidecar.go)
- Part 3 plugindev 工具链改造(.bin 产物,SDK 仓)
- Part 4 共享内存数据面(StageContext 并发改写,最高风险)
- Part 5 通知面(EvtRing + eventfd,post-and-forget)
- Part 6 迁移收尾(17 插件 + 删 cabi + 权限显式化)
每 Part 含修改对象/审查要点/验证标准 + 13 项最终验收 + 风险回退表
2026-08-31 12:01:11 +08:00
fa99f6b4eb
docs(plugin-arch): 外部插件接口不变矩阵(多进程化整改基线 v1)
...
钉死「暴露给外部插件的接口不变」约束的合同面:
- 合同面A: 公开SDK类型/接口(sdk/plugin.go等,纯Go无cgo)
- 合同面B: bridge 51个method id ↔ SDK方法映射表(RPC平移清单)
- 合同面C: StageContext 跨ABI 10字段 → 共享内存16字段(能力扩展)
- 外部插件实测触达面 ⊆ 公开SDK合同面(接口不变成立的依据)
- 迁移后新获得能力/刻意不给项/检查点
2026-08-31 11:52:31 +08:00
304cad0648
docs(plugin-arch): 归档插件架构迁移评估 + plan 第11节整改计划
...
- docs/zh/架构迁移评估.md: C ABI→子进程+共享内存完整迁移论证(1621行)
- docs/zh/experiments/: 18项可复跑可行性实验(架构评估的所有数字来源)
- plan.md §11: 11.1~11.9 插件架构缺陷修复清单(唯一权威编号)
- main 保持干净,本批次为 update 特性分支的整改起点
2026-08-31 11:45:52 +08:00
bc9ef15eb0
三层回退恢复机制(L0写前留档/L1恢复梯子/L2离线回滚)+ guard 父守护
...
- L0: files 插件写受保护系统路径(/etc 等)前自动留档,AbstractBeforeWrite 到 data/file_baseline
- L1: failback 受限 worker 执行恢复梯子 probe→还原DNS/proxy→还原LLM配置+ReloadFromConfig→probe,N轮有界
- L2: tracker changeset 持久化原文 blob,guard 离线 RollbackFromDisk 回滚 agentfs;SystemSnapshot 支撑
- guard 父守护: 心跳 IPC(PING/ACK unix socket, 文件心跳回退)、失败计数、退出码协议(42/43/44)、最后手段
- 发行版路径适配: system.protected_paths/network_paths 可注入,默认面向主流 Linux
- Windows 兼容: guard.go/failback.go 加 //go:build linux, guard_windows.go 提供 no-op 桩
- 修复: guard.yaml last_resort 键冲突、changeset Content 不落盘导致离线回滚丢原文
Build 全绿, vet 干净, system/recovery/ipc/tracker 单元测试全过
2026-08-05 16:00:08 +08:00
dbbd73b930
refactor: migrate built-in plugins to SDK-only interface
...
- Six-phase plan complete: webui/cli/healthcheck/pluginmgr/clawhubadapter
now interact with the kernel exclusively via internal/sdk interfaces;
all Configure() calls and package-level global injection removed
- buildSDK in internal/plugin/registry.go is the single assembly point
- Add internal/sdk/events.go exporting event types/constants
- Fix ProviderManager cooldown sharing: LuaAdaptedProvider.Name() now
returns the source name instead of lua_<adapter>, so multiple sources
sharing an adapter (single script load via shared VM AdapterCache) no
longer share failure-cooldown state
- Verified: build/vet/tests green, deployed to homeagent.service with
full plugin capability testing via local OpenAI-compatible mock
2026-08-01 12:17:17 +08:00
2c5f9ff262
v0.7.2: 根目录清理 + Agent 心跳重构 + 内嵌 ONNX 模型
...
- 根目录清理: branding/docs/knowledge -> assets/, package/tools/deploy -> deploy/
- meta.go: Version 0.7.2, SDKCompatibleVersion 语义改为最高兼容
- Makefile: 版本回退 0.7.2
- registry.go: 系统提示词改用 meta.Version 格式化
- Agent 心跳: reorgGraph 拆分为三个独立循环(archive/merge/review),各自可配间隔
- GraphDB: 新增 sentences 表 + 关系句子溯源 + ClearSentenceID + CleanupOrphanedSentences
- Knowledge: 支持词嵌入向量化器
- NLP 四阶段流水线: Parse -> Extract -> Verify -> Fuse + SentenceRef
- 移除远程 HTTP 解析器(remote_parser.go)
- 新增内嵌 ONNX 模型(vocab + dep_parser.onnx):
+build onnxruntime: 全量 ONNX Runtime 推理
!build onnxruntime: 内嵌词表规则式降级解析器
- config: core.agent.onnx_model_path 替代 dep_parser_url
2026-07-28 09:56:26 +08:00
1cb3e87dde
feat: 完整实现 NLP 三元组提取系统 + token budget 上下文分配
...
- 重写 extractor.go: 分句、17条 POS 模板、依存模板 + COO 链、ATT合并
- parser.go: 分句循环 + TransE 向量验证(h+r≈t)
- fallback.go: jieba POS 降级解析器
- bridge.go: nlp.Triple ↔ memory.Triple 转换
- pipeline.go: extractKeyTriples 改用 NLP 提取器, 删除5条旧前缀规则
- distill.go: docToTriples 改用 NLP 提取器
- reorgGraph: 语义相似度增强检测, 保持纯 LLM 决断
- Provider 接口加 MaxContextTokens() + 模型窗口映射表
- tokenbudget.go: 中文 token 估算器 + budget 分配(80%利用率)
- process.go/buildSystemPrompt: 按 token 预算截断 memory+timeline
2026-07-27 15:26:23 +08:00
31664a7853
feat: NoMemory/Cleaner memory system + doc update
...
- _sdk_local/ removed (moved to standalone sdk repo)
- internal/agent/core: NoMemory/Cleaner data-flow breakpoints
- internal/memory: clean_text, document store refactor
- internal/plugin/registry.go: plugin API alignment
- docs: PLUGIN_DEV.md, ARCHITECTURE.md NoMemory/Cleaner docs
- plan.md, review.md: status update
2026-07-25 11:17:31 +08:00
097c8e80b7
docs: revise architecture docs for academic rigor and source-code accuracy
...
- Rewrite 体系结构原则/Architectural Principles section with precise
implementation details from source code (3-way eventLoop select,
StageHost parallelism, provider ordered fallback, recency bias)
- Document shared StaticEmbedder vector space between Context and Document
- Remove marketing tone, OS analogy table, and mascot emoji separators
- Remove contrastive sentence patterns (而非/not...but/rather than)
- Align terminology with actual implementation across all 6 doc files
2026-07-24 12:12:37 +08:00
659545069a
docs: update file references after agent.go split (process.go, eventloop.go, distill.go)
2026-07-22 17:34:35 +08:00
85992902d9
refactor: split agent.go into 12 files + add mcp_restart_server tool
2026-07-22 15:40:27 +08:00
c1d14681bf
docs: sync PLUGIN_DEV.md with SDK toolchain updates
...
- Fix project structure: remove main.go, add auto-generated bridge files note
- Clarify plg.json (targets) vs plugin.json (entry/platforms) distinction
- Add --bundle multi-platform build section
- Add plugindev sdk version management subcommands
- Update entry point section: NewPlugin is in plugin.go, no separate main.go
- Sync zh and en versions
2026-07-19 12:32:56 +08:00
4da2ad5376
feat: multi-platform .hmap bundle + platform auto-selection
...
- PluginManifest: add platforms field declaring supported OS
- validatePackage: accept bundle .hmap with platform-aware binary check
- extractPackage: extract only current OS binary, skip others (macOS renames .dylib → .so)
- installFromPath/installFromURL: path install keeps source, URL install auto-cleanup
- cabi/loader.go + dynamic.go: add linux/darwin build constraints for Windows cross-compile
- dynamic_loader_unix/windows: split SO loading with proper build tags
- package/build.sh: enable windows/amd64 for homed, add CXX export for arm64
- tryLoadSO: fallback to plugin.dylib on macOS
- docs: update PLUGIN_DEV.md for bundle format and install methods
2026-07-19 12:01:35 +08:00
7601a2970f
docs: update output channel interface (payload/meta/type) in architecture docs
2026-07-19 10:35:25 +08:00
c70c95d6d9
docs: restore bili entry, update browser to web+webfetch merge only
2026-07-18 21:11:18 +08:00
bfa6d4854a
docs: replace web/webfetch/bili with merged browser plugin in example tables
2026-07-18 21:06:56 +08:00
719eb11078
docs: 恢复内置插件中断投递 API 文档
...
PLUGIN_DEV.md 第二节保留公开 API (InjectText/InjectInterruptText/InjectTextNoMemory),
第四节新增"输入投递(内置插件)"小节展示 InjectInput/InjectInterrupt/InjectInputSync 等
内置插件专属方法,附注说明区分外部与内置插件 API 边界。
2026-07-18 20:48:54 +08:00
c9e67d3d55
docs: 修正全部文档使其与源码实现一致
...
主仓库:
- 修复 4 份英文文档语言切换链接指向错误 (../zh/ → ../en/)
- ARCHITECTURE.md 标题 "三种加载方式" → "四种加载方式" (实际表格4行)
- PLUGIN_DEV.md 示例表: 添加 webfetch, 移除不存在的 luaplugintest/testlua
- PLUGIN_DEV.md 代码示例: InjectInput/InjectInterrupt → InjectText/InjectInterruptText
- PLUGIN_DEV.md 代码示例: Memory/Knowledge/LLM/Events 接口签名修正
- PLUGIN_DEV.md .hmap 内容统一, plugindev 编译去除 .exe 后缀
SDK 仓库:
- Plugin.Start(sdk *PluginSDK) 接口签名改为指针
- 方法表重写: 移除 CallLLM/QueryKnowledge/SetMemory 等不存在方法
- IOInjector 参数顺序修正为 (source, channel, text)
- 删除虚构 SDKConfig, 替换为实际 New() 构造函数签名
- .hmap 内容描述一致化
修正前一次会话中的 QQ/Bili 插件问题:
- qq napcat() 超时, fetchBotInfo 竞态, handleWebhook 同步阻塞
- bili CDN 直连失败, 添加 HTTP_PROXY 代理
2026-07-18 20:46:58 +08:00
f9ea80abbf
docs: update sequence diagram, memory flow, vectorization strategy for StaticEmbedder + CleanTemplateText + three-branch vector
2026-07-17 21:51:03 +08:00
3c441649c9
docs: mascot before each section heading in tutorial docs
2026-07-17 21:44:15 +08:00
10638f1308
feat: mascot integration - WebUI/GUI icons, chat avatar, system prompt, docs
2026-07-17 21:41:03 +08:00