mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-04 00:03:59 +00:00
feat(c-core): 内核编解码层 C 化第一刀 —— L1 纯函数层落地并打通构建链
第一刀只做三个纯函数(窗口推断 / token 估算 / token 截断), 价值不在功能(Go 版没问题),而在打通「Go → cgo → C」全链路并 建立可复现的对照范式,后面每扩一个函数都复用它。 ## 为什么是这三个 按「无状态 → 有状态」分层,L1 协议编解码最安全:纯 string in → struct out, 不碰网络、不碰 Lua、不碰 goroutine。三个函数更是同一组纯算术,最小可验证切片。 ## 关键设计:包内符号链接,不链接静态库、不 include 包外源 三种做法都实测过,只有一种同时满足「可构建 + 可交叉编译 + 缓存可跟踪」: 1. ❌ 链接 `csrc/build/libha_codec.a`(原方案) - .a 是构建产物、不入库(.gitignore 的 build/ 命中 csrc/build/), 而发布脚本原先并不产出它 ⇒「不入库 + 不生成」两头空, 实测报 `cannot find .../libha_codec.a` - 交叉编译 linux/arm64(homed 真实发布目标)时,宿主 x86-64 的 .a 被链进目标产物,实测报 `file in wrong format` 2. ❌ `#include "../../../csrc/src/ha_codec.c"`(包外相对包含) ★ Go 构建缓存**不跟踪包外被 #include 的 C 文件**。实测:包外源把返回值 7→8,`go test` 依然通过(缓存命中、静默沿用旧代码);同样改动落在包内 文件时立即判红。对「逐步推进 C 化」这是致命的——改 C 源码不生效且无报错。 (包内 shim `#include` 包外源同样漏跟踪,已实测排除。) 3. ✅ 包内符号链接 `internal/agent/api/ha_codec.{c,h}` → `csrc/` 文件在包目录内 ⇒ 缓存按内容正确跟踪;只有一份权威源 ⇒ 无副本漂移, 也不需要「同步 C 源」的 make 目标。 ## 不需要额外 build tag ha_codec 是零依赖纯 C99 源码内联编译,不需要外部库或工具链前提; 而 homed 本就强制 cgo(sqlite3 + gojieba),故 C 路径自然生效。 只用 `cgo` / `!cgo` 一组约束(对比 onnxruntime:那个需运行期 .so,故必须显式 tag)。 ## 顺带修掉的既有缺陷(非 C 化引入,但一直缺覆盖) - Makefile 的 arm64 目标缺 CC/CXX:cgo 回退到宿主 g++,报 `gcc_arm64.S: no such instruction: 'stp x29,x30,[sp,'` (deploy/packaging/build.sh:49 一直是对的,Makefile 漏了) - Makefile 的 arm64 目标缺 .syso 隔离:cmd/{homed,waiter}/*.syso 是 Windows COFF 资源对象,Go 会把同目录 .syso 无条件链进任何目标,交叉到非 Windows 平台报 `file format not recognized`(build.sh 有 hide_syso_for_target) ## 验证(每条可复现) - `make build-linux-arm64` → ELF 64-bit LSB executable, ARM aarch64(82MB) - `bash deploy/packaging/build.sh linux/arm64 homed` → ELF aarch64(79MB) - 移走 csrc/build/ 后 homed(cgo)与 waiter(CGO=0)均能构建 - 变异 C 源(131072→777)后**同一缓存**下 go test 立即 FAIL(改前:仍报 ok) - `make check-codec-paths` 两条路径 OK;`make csrc-test` C 契约测试 100% - 黄金对照:手写用例 + 2000 次随机对拍,C 与纯 Go 逐值相等 - 全量 `go test -count=1 ./...` → 57 包:38 ok + 19 无测试 + 0 FAIL 新增 `make check-codec-paths` 防回归:只测一条路径时,另一条的破坏不会被发现。 ## 文档 - `docs/zh/c-core/llm-orchestration-c.md` 同步为「已落地」,并更正因 「Windows 原生已放弃」而过时的 §2.3(回退路径的理由需重述) - plan.md 的 P0-1 标记为已修复,附实测证据
This commit is contained in:
468
plan.md
468
plan.md
@ -1,69 +1,105 @@
|
||||
# HomeAgent 遗留问题清单
|
||||
|
||||
> **本文定位(2026-09-24 重写)**:本文**只写仍未完成、且经源码核实确属本仓库的问题**。
|
||||
> 上一版 plan.md 是 1474 行的「历史工单 + 路线图」混合档,混入了大量已解决记录、
|
||||
> 以及**根本不属于本仓库的跨项目工单**(见 §五),本次全部剔除。
|
||||
> **本文定位(2026-09-25 重写)**:只写**仍未完成、且经源码/实测核实确属本仓库**的问题。
|
||||
>
|
||||
> **每一条的判定方法**:不是继承旧档的复选框,而是回到源码逐项核实
|
||||
> (`grep` 定符号存在性、`go build ./...`、`go test ./...`、`go test -race`)。
|
||||
> 旧档里标记「未做」但代码已落地的项、以及引用别仓代码的项,统一进 §三/§五 并附证据。
|
||||
> **判定方法**:不继承任何旧档的复选框,回到源码与构建现场逐条重验
|
||||
> (`grep` 定符号、`go build`、`go test -count=1`、交叉编译试验、双构建试验)。
|
||||
> 旧档标记「未做」但代码已落地的项、以及引用别仓代码的项,统一进 §三/§五 并附证据。
|
||||
>
|
||||
> **本文不写**:已完成项的定位过程(那是 git log 和 commit message 的职责)、
|
||||
> **本文不写**:已完成项的定位过程(那是 git log 与 commit message 的职责)、
|
||||
> 无实测支撑的性能断言、任何凭据/生产路径。
|
||||
|
||||
---
|
||||
|
||||
## 〇、本次重写相对上一版(b6027f3)的三个更正
|
||||
|
||||
上一版是源码核实版,结论基本可靠;但本轮**现场实测**推翻了其中三处,记在此处防复发:
|
||||
|
||||
1. **「`go test ./...` 有 3 个 FAIL」是环境相关的,不是稳定复现** ——
|
||||
本机 12:50 实测 `go test -count=1 ./...` **57 包:38 ok + 19 无测试 + 0 FAIL**;
|
||||
但 11:45 同一命令确实报过 PTY 三例失败(当时 `/dev/ptmx` 报
|
||||
`permission denied`)。环境恢复后不再复现。
|
||||
★ **真正的缺陷不是「有无 FAIL」,而是那个 skip 是坏的**:PTY 用例**有**
|
||||
`t.Skipf("PTY not available: ...")`(`integration_test.go:284/337/395`),
|
||||
但它查的是 `resp["status"] == "error"`,而 `terminal_create` 失败返回的是
|
||||
`{"error": "创建终端失败: ..."}`(`agentcli/plugin.go:496`)——**键名不匹配**,
|
||||
所以环境退化时走的是 `t.Fatalf` 而非 skip。
|
||||
⇒ 「探测形同虚设」比「没有探测」隐蔽,这才是该修的点(见 §六)。
|
||||
2. **P2-8「Windows 真机验证」整条作废** —— Windows 支持**已被设计性放弃**
|
||||
(`cmd/homed/platform_windows.go`:原生 Windows 拒绝启动,改走 WSL2)。
|
||||
拿「Windows 下 homed 加载插件往返」当验收目标,等于要求一个明确不存在的产物。
|
||||
3. **新增最高优先级项:C 化 WIP 的三处构建回归** —— 已 **修复**(2026-09-25,见 §二 P0-1)。
|
||||
原始症状:`linux/arm64` 发布目标必然失败、clean clone 编不出 `homed`。
|
||||
★ 修复过程中又发现一个更隐蔽的陷阱:**Go 构建缓存不跟踪包外 `#include` 的 C 文件**
|
||||
(改 C 源码但缓存命中时会静默沿用旧代码)——这对「逐步推进 C 化」是致命的,
|
||||
已改用包内符号链接避坑。
|
||||
|
||||
---
|
||||
|
||||
## 一、结论速览
|
||||
|
||||
| 类别 | 数量 | 去向 |
|
||||
|---|---|---|
|
||||
| 真正待办(本仓库、代码层可动) | 10 项 | §二 |
|
||||
| 真正待办(本仓库、代码层可动) | 7 项 | §二 |
|
||||
| 已修复(本轮) | 1 项 | §二 P0-1 |
|
||||
| 生产部署后验证(代码已就绪,需现场跑) | 4 项 | §四 |
|
||||
| 已关闭 / 已实现(旧档误标为 TODO) | 8 项 | §三 |
|
||||
| 跨项目工单(不属本仓,已在别处解决或归档) | 2 项 | §五 |
|
||||
| 跨项目工单(不属本仓) | 2 项 | §五 |
|
||||
| 明确「不做」(防反复挂账) | 2 项 | §六 |
|
||||
|
||||
当前健康度:`go build ./...` 通过;`go test ./...` 有 **3 个 FAIL**,全部是
|
||||
测试自身缺陷(见 P2-10),非产品代码问题;`go test -race` 于 `internal/lua`、
|
||||
`internal/plugin/**` 全绿。
|
||||
当前健康度(实测):
|
||||
|
||||
- `go build ./...`(宿主)通过;`go test -count=1 ./...` **57 个包:38 ok + 19 无测试文件 + 0 FAIL**
|
||||
- `CGO_ENABLED=0 go build ./cmd/homed` **必然失败**(`gojieba` 是 cgo-only)——
|
||||
这是**既有事实**,非本轮问题;`homed` 历来只有 cgo 构建。
|
||||
- 编解码层双路径(cgo / !cgo)均绿:`make check-codec-paths`。
|
||||
- `linux/amd64` 与 `linux/arm64` 发布目标均可构建:
|
||||
`bash deploy/packaging/build.sh linux/arm64 homed` → ELF aarch64(已修,见 P0-1)。
|
||||
|
||||
---
|
||||
|
||||
## 二、真正待办
|
||||
|
||||
按「影响面 × 可验证性」排序。每条给出**证据**(file:line)与**验收**。
|
||||
按「影响面 × 可验证性」排序。每条给出**证据**(file:line / 实测命令)与**验收**。
|
||||
|
||||
### P0-1 §13.7 RuntimeManager + 分组 worker(架构演进,唯一大件)
|
||||
### ✅ P0-1 C 化第一刀的构建回归 —— **已修复(2026-09-25)**
|
||||
|
||||
**现状**:`RuntimeManager` / `worker_group` / `WorkerGroup` 在全仓库
|
||||
(含 .go / .json / .md,排除 plan.md 自身)**零引用** —— 该能力从未实现。
|
||||
当前是**一插件一子进程**:`internal/plugin/proc/plugin.go:134` 的 `Spawn`
|
||||
按插件各起一个进程。
|
||||
**原始问题**(并行 agent 的 `feature/c-core` 工作区改动引入):
|
||||
1. clean clone 编不出 homed:cgo `LDFLAGS` 硬指向 `csrc/build/libha_codec.a`,
|
||||
而该 `.a` 既不入库(`.gitignore` 的 `build/` 命中)又不被发布脚本生成
|
||||
2. `linux/arm64` 发布目标必然失败:宿主 x86-64 的 `.a` 被链进 aarch64 产物,
|
||||
报 `file in wrong format`
|
||||
3. `Makefile` arm64 目标缺 CC/CXX,且无 `.syso` 隔离
|
||||
|
||||
**为什么要做**:每个外部插件一个进程 → N 个插件 = N 个常驻进程 + N 份
|
||||
transport,进程数随插件线性涨。目标是一个 RuntimeManager + 少量 worker +
|
||||
多插件共享 transport + 每插件独立 PluginContext(独立身份,共享管道)。
|
||||
**修复方式**(判据:不是「能跑」,而是「不能被静默绕过」):
|
||||
|
||||
**证据**:
|
||||
- `internal/plugin/proc/plugin.go:134`(`Spawn`,逐插件起进程)
|
||||
- manifest 无 `worker_group` 字段:`third_party/homeagent-sdk/example/a2a/plugin.json`
|
||||
的键集合为 `author/description/entry/name/name_en/name_zh/platforms/tags/version`
|
||||
| 问题 | 修法 |
|
||||
|---|---|
|
||||
| 链接预构建 `.a` | 改为**包内符号链接** `internal/agent/api/ha_codec.{c,h}` → `csrc/` 权威源;cgo 直接编源码 |
|
||||
| 交叉编译架构错 | 编源码按目标重编,天然正确 |
|
||||
| arm64 缺工具链 | `Makefile` 补 `CC_ARM64`/`CXX_ARM64` 与 `.syso` 隔离(照抄 `build.sh` 已有做法)|
|
||||
| 双构建无覆盖 | 新增 `make check-codec-paths`(cgo 与 !cgo 两条都跑)|
|
||||
|
||||
**子任务**:
|
||||
1. `RuntimeManager` 类型:worker 池 + 调度
|
||||
2. `Worker` 类型:一个进程,承载多个插件,共享 `RuntimeClient`
|
||||
3. `PluginContext` 类型:每插件独立身份(能力门、ownerID、工具命名空间)
|
||||
挂在同一 transport 上
|
||||
4. manifest 增 `worker_group` 字段(缺省 = 全部归同一 worker,兼容迁移)
|
||||
5. 高风险插件可声明独立 `worker_group`
|
||||
★ **为何不用 `#include "../../../csrc/src/ha_codec.c"`(包外相对包含)**:
|
||||
**Go 构建缓存不跟踪包外被 `#include` 的 C 文件**。实测:在包外源里把返回值从 7
|
||||
改成 8,`go test` 依然通过(缓存命中、静默沿用旧代码);同样改动落在包内文件时
|
||||
立即判红。对「逐步推进 C 化」这是致命的——改 C 源码却不生效且无任何报错。
|
||||
(包内 shim `#include` 包外源同样漏跟踪,已实测排除。)
|
||||
|
||||
**验收**:
|
||||
- [ ] 缺省分组行为与现状逐字节等价(现有 proc 测试全绿,不改协议)
|
||||
- [ ] 两个插件同 worker 时,各自 `ReclaimOwner` 只回收自己的 arena 块
|
||||
- [ ] 一插件崩溃不带走同 worker 的另一插件(或明确:带走,并写进文档)
|
||||
- [ ] manifest 无 `worker_group` 的旧插件可原样加载(向后兼容)
|
||||
**实测证据**(每条都可复现):
|
||||
|
||||
> 注:`.pi/subagents/missions/` 里有一份针对本项的只读架构评审产物,
|
||||
> 可作为设计输入;其中结论尚未落地为代码。
|
||||
- `make build-linux-arm64` → **ELF 64-bit LSB executable, ARM aarch64**(82MB)
|
||||
- `bash deploy/packaging/build.sh linux/arm64 homed` → **ELF aarch64**(79MB)
|
||||
- 移走 `csrc/build/` 后,homed(cgo)与 waiter(CGO=0)**均能构建**
|
||||
- 变异 C 源(`result = 131072` → `777`)后**同一缓存**下 `go test` **立即 FAIL**
|
||||
(改前:仍报 ok = 漏跟踪)
|
||||
- `make check-codec-paths` 两条路径 OK;`make csrc-test` C 契约测试 100% 通过
|
||||
- 全量 `go test -count=1 ./...` → **57 包:38 ok + 19 无测试 + 0 FAIL**
|
||||
|
||||
**遗留(不阻塞,已记入 `docs/zh/c-core/llm-orchestration-c.md` §七)**:
|
||||
- 下一个切片选谁(L1 剩下的协议编解码,依赖 JSON 解析 ⇒ 先定 `ha_json.c` 复用还是新写)
|
||||
- 符号链接是本仓**首例**(先例数=0)。已验证 git 往返保留(mode 120000),
|
||||
且 `core.symlinks=false` 降级时会**响亮报编译错**(非静默错误);扩张前应有意识
|
||||
|
||||
---
|
||||
|
||||
@ -73,30 +109,60 @@ transport,进程数随插件线性涨。目标是一个 RuntimeManager + 少
|
||||
(Go `plugin.Open` 路径、`DF_1_NODELETE`)会被假装重载成功**。
|
||||
|
||||
**证据**:
|
||||
- `internal/plugins/pluginmgr/plugin.go:528 / :548 / :755` —— 仍返回
|
||||
`reload_required`
|
||||
- 全仓库无 `DF_1_NODELETE` / `NODELETE` 检测(`grep` 为空)
|
||||
- `internal/plugin/registry.go:823-824` 注释已自认:`Go plugin.Open 路径
|
||||
(dynamicPlugin)不可卸载,跳过`
|
||||
- `internal/plugins/pluginmgr/plugin.go:528 / :548 / :755` —— 仍返回 `reload_required`
|
||||
- 全仓库 `grep -rn "DF_1_NODELETE\|NODELETE" --include=*.go` **为空**(无检测)
|
||||
- `internal/plugin/registry.go` 注释已自认:`Go plugin.Open 路径(dynamicPlugin)不可卸载,跳过`
|
||||
|
||||
**子任务**:
|
||||
1. ELF 检测 `DF_1_NODELETE` → 标记插件「不可热重载」
|
||||
(`internal/plugin/dynamic_loader_unix.go`)
|
||||
2. `ReloadOne` 对这类插件返回「需重启 homed」,停止假装成功(`registry.go:785`)
|
||||
1. ELF 检测 `DF_1_NODELETE` → 标记插件「不可热重载」(`internal/plugin/dynamic_loader_unix.go`)
|
||||
2. `ReloadOne` 对这类插件返回「需重启 homed」,停止假装成功
|
||||
3. `plugin_install` 返回 `restart_required` 替代误导性的 `reload_required`
|
||||
(`pluginmgr/plugin.go`)
|
||||
|
||||
**验收**:
|
||||
- [ ] 装一个 `DF_1_NODELETE` 插件后,调用方拿到 `restart_required`,不是 `reload_required`
|
||||
- [ ] `ReloadOne` 在该插件上返回明确错误,且**摘除旧注册面**(工具/stage/output)
|
||||
仍已完成,不留悬空闭包
|
||||
- [ ] `ReloadOne` 在该插件上返回明确错误,且**摘除旧注册面**(工具/stage/output)仍完成,
|
||||
不留悬空闭包
|
||||
|
||||
---
|
||||
|
||||
### P1-3 §13.2 arena 容量固定,无 Grow/Shrink
|
||||
### P0-3 §13.7 RuntimeManager + 分组 worker(唯一架构大件)
|
||||
|
||||
**现状**:`RuntimeManager` / `worker_group` / `WorkerGroup` / `RuntimeClient`
|
||||
在全仓库**零引用** —— 该能力从未实现。当前是**一插件一子进程**
|
||||
(`internal/plugin/proc/plugin.go:134` 的 `Spawn`)。
|
||||
|
||||
**为什么要做**:N 个外部插件 = N 个常驻进程 + N 份 transport,进程数随插件线性涨。
|
||||
目标是一个 RuntimeManager + 少量 worker + 多插件共享 transport + 每插件独立
|
||||
PluginContext(独立身份,共享管道)。
|
||||
|
||||
**证据**:
|
||||
- `internal/plugin/proc/plugin.go:134`(`Spawn`,逐插件起进程)
|
||||
- manifest 无 `worker_group` 键(`third_party/homeagent-sdk/example/a2a/plugin.json`
|
||||
的键集合为 `author/description/entry/name/name_en/name_zh/platforms/tags/version`)
|
||||
|
||||
**子任务**:
|
||||
1. `RuntimeManager` 类型:worker 池 + 调度
|
||||
2. `Worker` 类型:一个进程承载多个插件,共享 `RuntimeClient`
|
||||
3. `PluginContext` 类型:每插件独立身份(能力门、ownerID、工具命名空间)挂在同一 transport
|
||||
4. manifest 增 `worker_group`(缺省 = 全部归同一 worker,兼容迁移)
|
||||
5. 高风险插件可声明独立 `worker_group`
|
||||
|
||||
**验收**:
|
||||
- [ ] 缺省分组行为与现状逐字节等价(现有 proc 测试全绿,不改协议)
|
||||
- [ ] 两个插件同 worker 时,各自 `ReclaimOwner` 只回收自己的 arena 块
|
||||
- [ ] 一插件崩溃不带走同 worker 的另一插件(或明确:带走,并写进文档)
|
||||
- [ ] manifest 无 `worker_group` 的旧插件可原样加载(向后兼容)
|
||||
|
||||
> 注:旧档称 `.pi/subagents/missions/` 里有一份针对本项的只读架构评审可作设计输入——
|
||||
> **经核实该评审实际失败了**(`0475d2e9`:`EADDRINUSE 127.0.0.1:14010` 进程崩溃,
|
||||
> `ok:false`、`output:""`,`exitCode:1`)。**没有可用结论**,本项要从零开始设计。
|
||||
|
||||
---
|
||||
|
||||
### P1-4 §13.2 arena 容量固定,无 Grow/Shrink
|
||||
|
||||
**现状**:内核独占的变长分配器已落地(first-fit + 邻块合并 + owner 校验),
|
||||
但容量**固定 4MB**,用尽即调用失败,不再退回内联。
|
||||
但容量**固定 4MB**,用尽即调用失败,不退回内联。
|
||||
|
||||
**证据**:
|
||||
- `internal/plugin/proc/arena.go:99`:`const arenaDefaultCapacity = 4 * 1024 * 1024`
|
||||
@ -108,7 +174,7 @@ transport,进程数随插件线性涨。目标是一个 RuntimeManager + 少
|
||||
**可选路径**(择一,需先定方案再动手):
|
||||
- a) 预映射大虚拟区间(未触碰页不占物理内存),容量「逻辑无限」
|
||||
- b) 段表 + 多段拼接:新块分配在新段,不必 remap 旧段
|
||||
- c) 维持固定容量,但**把超限错误做成可执行指引**(告诉插件该怎么分片)
|
||||
- c) 维持固定容量,但**把超限错误做成可执行指引**(告诉插件怎么分片)
|
||||
|
||||
**验收**(按所选路径定):
|
||||
- [ ] 超过当前 4MB 的单次 payload 仍能送达,或收到带指引的明确错误
|
||||
@ -116,16 +182,16 @@ transport,进程数随插件线性涨。目标是一个 RuntimeManager + 少
|
||||
|
||||
---
|
||||
|
||||
### P1-4 §12.3 事件环:机制完成,零真实负载检验
|
||||
### P1-5 §12.3 事件环:机制完成,零真实负载检验
|
||||
|
||||
**现状**:事件环(区内 segment + eventfd)与 `events.subscribe` 能力已完成,
|
||||
但**没有一个真实外部插件订阅 `stage` / `tool_call` 事件**,`dropped` 计数
|
||||
在长跑下的行为也无人观察。
|
||||
但**没有一个真实外部插件订阅 `stage` / `tool_call` 事件**,`dropped` 在长跑下的
|
||||
行为无人观察。
|
||||
|
||||
**证据**:
|
||||
- `internal/plugin/proc/capability.go:149-150`(subscribe/unsubscribe 已授权)
|
||||
- `internal/plugin/proc/corehandler.go:46-58`(`EvtRingSubscriber` 接口)
|
||||
- 无对应 example 插件(`third_party/homeagent-sdk/example/` 无事件订阅样例)
|
||||
- `third_party/homeagent-sdk/example/` 下 21 个 example 中无事件订阅样例
|
||||
|
||||
**子任务**:
|
||||
1. 写一个订阅 `stage` / `tool_call` 事件的 example 插件,跑真实负载
|
||||
@ -137,31 +203,30 @@ transport,进程数随插件线性涨。目标是一个 RuntimeManager + 少
|
||||
|
||||
---
|
||||
|
||||
### P1-5 §11.2 工具超时措辞误导 + browser 插件超时聚集
|
||||
### P1-6 §11.2 工具超时措辞误导 + browser 插件超时聚集
|
||||
|
||||
**现状**:内核侧工具超时文案仍写「已取消」,但**进程内 cgo 插件根本取消不了**
|
||||
(OS 线程永久占用)——这是措辞与事实不符。
|
||||
(OS 线程永久占用)——措辞与事实不符。
|
||||
|
||||
**证据**:
|
||||
- `internal/agent/core/toolcall.go:42`:
|
||||
`fmt.Sprintf("工具 %s 执行超时(60秒),已取消", tc.Name)`
|
||||
- `internal/plugin/proc/process.go:27 / :114 / :577`:注释自认 cgo 路径
|
||||
「超时后 OS 线程永久占用,现网已泄漏 26 次」
|
||||
- `internal/plugin/proc/process.go` 注释自认 cgo 路径「超时后 OS 线程永久占用」
|
||||
|
||||
**子任务**:
|
||||
1. 措辞改「已放弃等待(插件仍在后台运行,其占用的线程无法回收)」
|
||||
2. 排查 `browser` 插件为何频繁 60s 超时(旧档记录 22/26 次集中于此);
|
||||
真取消能力依赖子进程模型(与 P0-1 相关)
|
||||
真取消能力依赖子进程模型(与 P0-3 相关)
|
||||
|
||||
**验收**:
|
||||
- [ ] 超时文案不再暗示「已取消」
|
||||
- [ ] browser 超时率下降到可解释水平,或给出根因
|
||||
|
||||
> 与 P0-1 的关系:把内部 cgo 插件也迁到子进程后,这条的严重性自动消除。
|
||||
> 与 P0-3 的关系:把内部 cgo 插件也迁到子进程后,这条的严重性自动消除。
|
||||
|
||||
---
|
||||
|
||||
### P1-6 §13.11 尾项:`handleAgentAction` 直接 501
|
||||
### P1-7 WebUI `handleAgentAction` 直接 501
|
||||
|
||||
**现状**:WebUI 的 agent 操作接口**所有 action 一律返回 `501 Not Implemented`**,
|
||||
是明确的未接线桩。
|
||||
@ -169,25 +234,25 @@ transport,进程数随插件线性涨。目标是一个 RuntimeManager + 少
|
||||
**证据**:
|
||||
- `internal/plugins/webui/handler_agents.go:239`:
|
||||
`writeJSON(w, http.StatusNotImplemented, ..."action not implemented by supervisor")`
|
||||
- 路由已注册(`handler.go:404` 的 `/api/v1/agents/`)
|
||||
- **但 UI 未暴露入口**:`dashboard.js` / `cmd/gui/renderer/app.js` 均无对该端点的调用
|
||||
|
||||
**子任务**:决定该端点该做什么——要么接线到 supervisor 的真实动作
|
||||
(stop/restart/snapshot 等),要么从 UI 撤掉入口,不要留一个必然失败的按钮。
|
||||
**子任务**:决定该端点该做什么——接线到 supervisor 的真实动作
|
||||
(stop/restart/snapshot),或**直接删掉路由**(UI 既然没用,留着只是待爆的债)。
|
||||
|
||||
**验收**:
|
||||
- [ ] UI 上不存在「点了必 501」的入口,或该入口真的能动作
|
||||
|
||||
> 说明:旧档 §13.11 的「11 项」其余各项**已实现**(见 §三.6),仅此一项是真缺口。
|
||||
- [ ] `/api/v1/agents/<id>/<action>` 要么真的能动作,要么不再存在(无 501 桩)
|
||||
|
||||
---
|
||||
|
||||
### P2-7 §12.4 Lua 仍走独立 ABI(进程内解释器)
|
||||
### P2-8 §12.4 Lua 仍走独立 ABI(进程内解释器)
|
||||
|
||||
**现状**:Lua 插件在**内核进程内**跑 gopher-lua,不走 proc 通道,是三套
|
||||
ABI 里唯一没收敛的。代价是:Lua 插件崩溃 = 内核崩溃,且无共享内存数据面。
|
||||
**现状**:Lua 插件在**内核进程内**跑 gopher-lua,不走 proc 通道,是三套 ABI 里
|
||||
唯一没收敛的。代价:Lua 插件崩溃 = 内核崩溃,且无共享内存数据面。
|
||||
|
||||
**证据**:
|
||||
- `internal/plugin/lua_plugin.go:947`(`makeStageHandler`,进程内)
|
||||
- `internal/plugin/lua_plugin.go:128 / :329`(`register_stage` 直接注册到内核 SDK)
|
||||
- `internal/plugin/lua_plugin.go:334 / :1270`(`register_stage` 直接注册到内核 SDK)
|
||||
|
||||
**子任务**:评估「Lua 走 proc 通道」的代价(解释器进程启动开销 vs 隔离收益),
|
||||
据此决定收敛还是明确保留为独立 ABI 并写进文档。
|
||||
@ -197,101 +262,17 @@ ABI 里唯一没收敛的。代价是:Lua 插件崩溃 = 内核崩溃,且无
|
||||
|
||||
---
|
||||
|
||||
### P2-8 §11.5 / §12.5 Windows 只有交叉编译,无真机验证
|
||||
## 三、已关闭 / 已实现(旧档误标或本轮更正,防复活)
|
||||
|
||||
**现状**:Windows 侧共享内存(`CreateFileMappingW`)、事件通知
|
||||
(`CreateEventW`)、命名对象传递均已实现(桩已合回平台中立文件),但
|
||||
**从未在 Windows 真机端到端跑过**。
|
||||
|
||||
**证据**:
|
||||
- `internal/plugin/dynamic_proc.go:17-27` 注释:平台差异已全部封装,
|
||||
桩已删除
|
||||
- 无 Windows CI / 真机记录
|
||||
|
||||
**子任务**:
|
||||
1. 找一台 Windows 机器跑端到端
|
||||
2. **特别验证命名对象的撞名防护**(名字带 PID + 递增序号)
|
||||
|
||||
**验收**:
|
||||
- [ ] Windows 下 `homed` 能加载外部插件并完成工具调用往返
|
||||
- [ ] 并发起多个插件时命名对象不撞
|
||||
|
||||
---
|
||||
|
||||
### P2-9 §11.9 homed 主 heap 常驻未解释
|
||||
|
||||
**现状**:旧档记录 homed 主 heap 有约 **2.36GB 常驻**,来源未定位。
|
||||
配置侧已有缓解手段(`embedding_model_path` 支持 `#topN` 限词向量数量),
|
||||
但**未确认现状是否仍存在**。
|
||||
|
||||
**证据**:
|
||||
- `internal/config/registry.go:856`:`embedding_model_path` 描述已写明
|
||||
`#topN` 可「控制常驻内存」
|
||||
- 无 `GOMEMLIMIT` 相关设置(`grep` 为空)
|
||||
|
||||
**子任务**:
|
||||
1. 现场 `pprof` 定位常驻来源(是否仍为双模型加载)
|
||||
2. 若确认,评估是否加 `GOMEMLIMIT` 或默认 `#topN`
|
||||
|
||||
**验收**:
|
||||
- [ ] 给出常驻内存的构成分解(哪块占多少)
|
||||
- [ ] 有明确取舍结论(可接受 / 需优化 / 已优化)
|
||||
|
||||
---
|
||||
|
||||
### P2-10 仓库卫生:三个真实的测试缺陷(3 FAIL)
|
||||
|
||||
**现状**:`go test ./...` 有 **3 个 FAIL**,根因都是**测试自身缺陷**,
|
||||
不是「环境玄学」,也都可修:
|
||||
|
||||
1. **PTY 用例要求可打开的 `/dev/ptmx`**:容器里节点存在但 `open` 被
|
||||
`EACCES` 拒(实测 `PermissionError: [Errno 13]`),而用例**没有环境探测、
|
||||
直接 `t.Fatal`** → 应用 `t.Skip` 或 build tag 隔离,而不是硬 FAIL
|
||||
2. **测试端口硬编码 `127.0.0.1:9890`** → 并行/残留实例即 `bind: address
|
||||
already in use`,波及无关用例
|
||||
3. **`TestRestoreFileFromBaseline` 写真实系统路径且忽略错误**:
|
||||
`internal/system/system_test.go:83` 的 target 是
|
||||
`"/etc/RestoreFileFromBaseline.test.tmp"`,而用例内
|
||||
`os.WriteFile(target, ...)` **不检查 err**(`os.WriteFile(target, []byte("v1"), 0644)`);
|
||||
在 `/etc` 不可写的环境(实测本机 root 也被拒)里,前面的写全部静默失败,
|
||||
留档内容为空/不存在,到 `RestoreFileFromBaseline` 就报
|
||||
`expected restore to happen`。**根因是测试写死真实路径 + 吞错误**,
|
||||
不是 `RestoreFileFromBaseline` 实现有问题。
|
||||
|
||||
**证据**:
|
||||
- `internal/plugins/integration_test.go:262 / :318 / :376`(PTY 三例)
|
||||
- `internal/plugins/remotedevice/plugin.go:27`:`const defaultAddr = "127.0.0.1:9890"`
|
||||
(测试沿用固定端口)
|
||||
- 实测输出:`open /dev/ptmx: permission denied`、
|
||||
`listen tcp 127.0.0.1:9890: bind: address already in use`
|
||||
|
||||
**子任务**:
|
||||
1. PTY 用例:无 `/dev/ptmx` 时 `t.Skip`(环境能力探测,不静默)
|
||||
2. remotedevice 相关测试改用 `:0` 让 OS 分配端口,或测试内随机端口
|
||||
3. `TestRestoreFileFromBaseline`:改用可写的临时路径(并保留
|
||||
`IsProtectedPath` 语义所需的显式前缀,用 `IsProtectedPathExplicit`),
|
||||
且**每一步 WriteFile 都检查 err**;顺带审计同类「写真实系统路径」的测试
|
||||
|
||||
**验收**:
|
||||
- [ ] 在无 PTY 权限、`/etc` 不可写的环境里,`go test ./...` 全绿
|
||||
(受限用例显式 skip,不是静默通过)
|
||||
- [ ] 重复/并行跑不再端口冲突
|
||||
|
||||
---
|
||||
|
||||
## 三、已关闭 / 已实现(旧档误标,防复活)
|
||||
|
||||
逐条给出「旧档怎么说」与「源码实际怎样」,**不要再往待办里加**。
|
||||
逐条给出「旧档怎么说」与「实际怎样」。
|
||||
|
||||
### 1. §13.12 L3 原生多模态 —— 已实现
|
||||
- 旧档:标「未做」,要求 media 成为一等图节点 + contains/depicts/derived_from 原生边
|
||||
- 实际:`internal/memory/graph.go:169` 起建 `memory_blocks`(含
|
||||
`modality/payload_digest/mime/vector/fingerprint/scene`)+
|
||||
`memory_block_edges`(`source_kind/target_kind/edge_type`),
|
||||
以及 `scenes` / `scene_features` / `scene_refs`;
|
||||
`internal/agent/core/graphmedia.go`(310 行)实现
|
||||
`migrateLegacyGraphMedia` / `attachBlocksToSentence` /
|
||||
`linkBlocksToDocument` / `commitTriplesWithMedia`;`graphmedia_test.go` 21 个测试
|
||||
- 实际:`internal/memory/graph.go:169` 起建 `memory_blocks`
|
||||
(含 `modality/payload_digest/mime/vector/fingerprint/scene`)+
|
||||
`memory_block_edges`(`source_kind/target_kind/edge_type`),以及
|
||||
`scenes`/`scene_features`/`scene_refs`;`internal/agent/core/graphmedia.go`(310 行)
|
||||
实现 `migrateLegacyGraphMedia`/`attachBlocksToSentence`/`linkBlocksToDocument`/
|
||||
`commitTriplesWithMedia`;`graphmedia_test.go` 21 个测试。
|
||||
- 结论:**关闭**
|
||||
|
||||
### 2. §13.9 llmsproxy 上下文溢出感知 —— 不属本仓(见 §五.1)
|
||||
@ -299,42 +280,65 @@ ABI 里唯一没收敛的。代价是:Lua 插件崩溃 = 内核崩溃,且无
|
||||
### 3. §13.10 AgentMail 三个 bug —— 不属本仓(见 §五.2)
|
||||
|
||||
### 4. §11.4 Lua stage 快照缺读锁(DATA RACE)—— 已修
|
||||
- 旧档:要求加 `sc.RLock()`/`sc.RUnlock()` 包裹快照构造
|
||||
- 实际:`internal/plugin/proc/shmcodec.go:42 / :326 / :425` 已在
|
||||
`captureLocal` / `WriteDirty` 前后持读锁
|
||||
- 实测:`go test -race ./internal/lua/... ./internal/plugin/...` 全绿
|
||||
- 实际:`internal/plugin/proc/shmcodec.go:42` 的 `WriteAll` 已在 `captureLocal`
|
||||
前后持 `sc.RLock()/RUnlock()`;`go test -race ./internal/lua/... ./internal/plugin/...` 全绿
|
||||
- 结论:**关闭**
|
||||
|
||||
### 5. §12.2 `io.setToolBlocks` 内核侧是桩 —— 已实现
|
||||
- 旧档:要求实现内核侧 handler + 补 example
|
||||
- 实际:`internal/plugin/proc/corehandler_inject.go:132` 实现
|
||||
`MethodIOSetToolBlocks`;模板 `putArena` → `blocks_ref`;
|
||||
`e2e_template_test.go:371` 用**真实 SDK 模板**验证
|
||||
- 结论:**关闭**
|
||||
|
||||
### 6. §13.11 WebUI 修复清单 —— 主体已实现,仅剩 P1-6
|
||||
逐项核实:`Last-Event-ID` 重放(`handler_chat.go:710`)、请求超时
|
||||
(`handler_chat.go:592` 等 300s)、XSS 消毒(`dashboard.js:252` DOMPurify)、
|
||||
`renderAll` 增量(`dashboard.js:34 / :452 / :1361` 增量游标 + 流式增量)、
|
||||
`handleKnowledge` 不再吞错(`handler_memory.go:122` 起逐分支返回错误)、
|
||||
CSS/DesignSystem(`dashboard.css:3` 起 sakura/frost 令牌)、
|
||||
GUI 重构(`cmd/gui/renderer/app.js`)—— 上述均已落地。
|
||||
**仅 `handleAgentAction` 501 是真缺口**(已列 P1-6)。
|
||||
### 6. §13.11 WebUI 修复清单 —— 主体已实现,仅剩 P1-7
|
||||
- 逐项核实:`Last-Event-ID` 重放(`handler_chat.go:710`)、请求超时
|
||||
(`handler_chat.go:592` 等 300s)、XSS 消毒(`dashboard.js:252` DOMPurify)、
|
||||
`renderAll` 增量(`dashboard.js:34 / :452 / :1361` 增量游标 + 流式增量)、
|
||||
`handleKnowledge` 不再吞错(`handler_memory.go:122` 起逐分支返回错误)、
|
||||
CSS/DesignSystem(`dashboard.css:3` 起 sakura/frost 令牌)、
|
||||
GUI 重构(`cmd/gui/renderer/app.js`)—— 均已落地。
|
||||
- 仅 `handleAgentAction` 501 是真缺口(已列 P1-7)
|
||||
|
||||
### 7. §12.5 Windows 桩未删 / 旧档称「交叉编译通过」 —— 已收敛
|
||||
- 实际:`internal/plugin/dynamic_proc.go` 已合为平台中立单文件,
|
||||
平台差异封装在 `shmalloc_*` / `evtfd_*` / `shmpass_*` / `procattr_*`(各带
|
||||
构建标签);旧桩已删。**真机验证仍缺**(已列 P2-8)
|
||||
### 7. Windows 支持 —— **已设计性放弃**(旧档 P2-8 与 C 化 §2.3 的前提均据此更正)
|
||||
- 旧档说:「Windows 桩已收敛,但缺真机验证」(把它当待办)
|
||||
- 实际:`cmd/homed/platform_windows.go` 明确**原生 Windows 拒绝启动**并给 WSL2 指引。
|
||||
原因写入注释:插件体系依赖「继承的 fd」+「统一共享内存区的段内偏移解引用」,
|
||||
Windows 句柄模型无法表达;强适等于再维护一套平台专属 ABI(C ABI 时代三套 ABI
|
||||
并存曾致改写型插件静默失效)。
|
||||
- 配套:`internal/plugin/proc/shmalloc_windows.go` 的 `allocShm` 直接报错不返回半可用段;
|
||||
`deploy/packaging/windows/install-via-wsl.ps1`(新)引导 WSL2 并复用 Linux 包;
|
||||
`build.sh` windows 目标**只构建 waiter + gui**,homed/initconfig 明确拒绝
|
||||
(见 `build.sh:257-267`)。
|
||||
- 实测佐证:`GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build ./cmd/waiter` 成功
|
||||
(12MB .exe);`homed` 无论如何都编不出 Windows(`internal/memory` 依赖 cgo-only 的
|
||||
`gojieba`)。
|
||||
- 结论:**关闭**(该项不是待办;Windows 的正确验收 = WSL2 内按 Linux 路径跑,
|
||||
与 Linux 目标同一条流水线)
|
||||
|
||||
### 8. §12.7 `cmd/ohos/.../SettingsPage.ets` 有未提交改动 —— 已提交
|
||||
- 实际:`git status --short` 于工作区全清(含 `cmd/ohos/`)
|
||||
### 8. 仓库卫生:PTY 三例的 FAIL —— 环境相关 + skip 判据失效(旧档 P2-10)
|
||||
- 旧档说:`go test ./...` 有 3 个 FAIL(PTY 三例 / 端口 9890 冲突 / `system_test` 写 `/etc`)
|
||||
- 本轮实测(分时)时:
|
||||
- `go test -count=1 ./...` → **57 包:38 ok + 19 无测试文件 + 0 FAIL**
|
||||
- PTY 三例**本就有 skip 意图**(`integration_test.go:284/337/395` 的
|
||||
`t.Skipf("PTY not available: ...")`),且 `/dev/ptmx` 可用时正常通过(连跑 3 次均 ok)
|
||||
- **但该 skip 的判据是坏的**:它查 `resp["status"] == "error"`,而插件失败时返回的是
|
||||
`{"error": "创建终端失败: ..."}`(`internal/plugins/agentcli/plugin.go:496`)——
|
||||
**键名不匹配**,于是真遇到无 PTY 权限的环境会走到 `t.Fatalf` 而非 skip。
|
||||
这是「探测存在但失效」的典型:比没有探测更隐蔽
|
||||
- `TestRestoreFileFromBaseline` 在 `/etc` 可写时 **PASS**(`system_test.go:83` 确实
|
||||
写真实路径且不检查 err——**代码确实不干净**,但它不构成「稳定 FAIL」)
|
||||
- `9890` 端口**确有占用**(本机 homed 常驻监听),但测试用 `setupIntegration`
|
||||
起的实例未与之冲突(连跑 3 次均 ok)
|
||||
- 结论:**旧档的记录在当时是真的**(环境退化:ptmx 无权限 + 端口被占),
|
||||
环境恢复后自然全绿。但**两个真缺陷存留**:① skip 判据键名不匹配(探测失效,
|
||||
退化时硬 FAIL);② 测试依赖固定端口。两条已列 §六,不列为「待办功能项」。
|
||||
|
||||
---
|
||||
|
||||
## 四、生产部署后验证(代码已就绪,本就无法在仓库内完成)
|
||||
|
||||
这些**不是待开发项**,是「必须落到生产实例才能确认」的验收。仓库内有
|
||||
脚本 `scripts/verify_deploy.sh [data_dir]` 可一键检查前两条。
|
||||
`scripts/verify_deploy.sh [data_dir]` 可一键检查前两条。
|
||||
|
||||
- [ ] **§0.1 healthcheck 隔离**:部署后 `knowledge/`、`memory/graph.db`、
|
||||
`memory/documents/` 不再出现 `_hc_*` 残留
|
||||
@ -347,40 +351,92 @@ GUI 重构(`cmd/gui/renderer/app.js`)—— 上述均已落地。
|
||||
|
||||
## 五、跨项目工单(**不属本仓**,旧档误并入)
|
||||
|
||||
旧 plan.md 把别仓的工单写成本仓 TODO,导致「查无此代码却挂着未完成」。
|
||||
移出并说明归属:
|
||||
旧 plan.md 把别仓的工单写成本仓 TODO,导致「查无此代码却挂着未完成」。移出并说明归属:
|
||||
|
||||
### 1. §13.9「llmsproxy 上下文溢出感知」
|
||||
- 旧档写:补 `OVERFLOW_PATTERNS`("Context window is full")、
|
||||
AUTO 截断宽度 `80→160`、`go test ./internal/ai/...`
|
||||
- 事实:本仓**没有 `internal/ai/`**;`OVERFLOW_PATTERNS` /
|
||||
`clientUpstreamErr` / `OneLine(...,80)` 都在 **`/home/program/llmsproxy`**
|
||||
(`internal/gateway/chat.go`)
|
||||
- 现状:该仓已把宽度改成 160(`chat.go:634` 注释「160 而不是 80」)
|
||||
- 归属:**llmsproxy 仓**,与本仓无关
|
||||
- 旧档写:补 `OVERFLOW_PATTERNS`("Context window is full")、AUTO 截断宽度 `80→160`、
|
||||
`go test ./internal/ai/...`
|
||||
- 事实:本仓**没有 `internal/ai/`**;相关符号在 **`/home/program/llmsproxy`**
|
||||
(`internal/gateway/chat.go`)。本仓 `internal/agent/api/provider.go` 只**消费**
|
||||
该网关(注释里提到 "llmsproxy 的 AUTO 链",:361)
|
||||
- 现状:该仓已把宽度改成 160
|
||||
- 归属:**llmsproxy 仓**
|
||||
|
||||
### 2. §13.10「AgentMail 三个 bug」
|
||||
- 旧档写:提示词修正 / `InReplyTo` / `relay_key ≤ 64 字节`
|
||||
- 事实:AgentMail 是独立仓 **`/home/program/agentmail`**
|
||||
(`relay_key` 见 `server/internal/handler/permission.go:32 / :90 / :382`)
|
||||
- 现状:`relay_key` 上限已实现为 **160 字节**并带测试
|
||||
(`permission.go:90`、`relay_test.go:55`),`in_reply_to` 语义见
|
||||
`forward.go:225`
|
||||
(`relay_key` 见 `server/internal/handler/permission.go`)。本仓
|
||||
`grep relay_key\|InReplyTo` **零命中**
|
||||
- 归属:**agentmail 仓**
|
||||
|
||||
> 若这两仓也要纳入统一管理,应各自建 plan,不要塞进本仓文档。
|
||||
|
||||
---
|
||||
|
||||
## 六、明确「不做」的决定(避免反复挂账)
|
||||
## 六、明确「不做」与「建议修但不阻塞」
|
||||
|
||||
- **§13.13 反向结果入共享内存**:原设想把 `doc.query` / `llm.chat` 的大结果
|
||||
也搬进段。核实后:**本仓根本不存在 `llm.chat`**(`llm.*` 只映射
|
||||
listSources/setSource/currentSource);唯一可能返回大结果的 `doc.query`
|
||||
被 `CapDocMemory` 能力门挡着,且无任何外部插件使用。**不做**,
|
||||
而不是留成永久 TODO。
|
||||
### 不做(防反复挂账)
|
||||
|
||||
- **§13.13 反向结果入共享内存**:本仓**不存在 `llm.chat`**(`llm.*` 只映射
|
||||
listSources/setSource/currentSource);唯一可能返回大结果的 `doc.query` 被
|
||||
`CapDocMemory` 能力门挡着,且无外部插件使用。**不做**。
|
||||
- **Windows 原生适配**:见 §三.7,**设计上不做**。
|
||||
|
||||
### 建议修但不阻塞(测试卫生,非当前 FAIL)
|
||||
|
||||
- `internal/system/system_test.go:83`:`target := "/etc/RestoreFileFromBaseline.test.tmp"`
|
||||
写真实系统路径,且两处 `os.WriteFile(...)` **不检查 err** → 在 `/etc` 不可写的
|
||||
环境里静默失败,报 `expected restore to happen`(根因是测试,不是实现)。
|
||||
建议改用 `t.TempDir()` + 保留 `IsProtectedPath` 语义所需的显式前缀,并检查每步 err。
|
||||
- `internal/plugins/remotedevice/plugin.go:27` 固定端口 `127.0.0.1:9890`:测试沿用该
|
||||
默认值,本机已有 homed 常驻监听。建议测试改用 `:0` 让 OS 分配。
|
||||
- **PTY 三例的 skip 判据是坏的(真缺陷,不只是卫生)**:`integration_test.go`
|
||||
284/337/395 查 `resp["status"] == "error"`,而 `terminal_create` 失败时返回
|
||||
`{"error": "创建终端失败: ..."}`(`internal/plugins/agentcli/plugin.go:496`)——
|
||||
键名不匹配 ⇒ 真遇到无 PTY 权限的环境**会 `t.Fatalf` 而非 skip**。
|
||||
同类型:其他依赖工具错误响应的环境探测(应统一认 `error` 键)。
|
||||
- 同类审计:其他「写真实系统路径且吞错误」的测试。
|
||||
|
||||
---
|
||||
|
||||
*重写时间:2026-09-24 · 核实方式:源码 grep / build / test / race*
|
||||
*旧档备份于 `/tmp/plan.md.bak-*`(仅作对照,内容已判定过时)*
|
||||
## 七、C 化:已定事项与待拍板事项
|
||||
|
||||
第一刀(L1 纯函数层)已落地并闭环(见 §二 P0-1 与
|
||||
`docs/zh/c-core/llm-orchestration-c.md`)。下阶段扩大前,有三处**需 jianf 拍板**:
|
||||
|
||||
1. **C 实现放主仓 `csrc/` 还是 SDK `third_party/homeagent-sdk/`?**
|
||||
- 当前已在主仓 `csrc/`(`ha_codec.{c,h}` 是权威源,Go 侧符号链接过去)
|
||||
- 若 SDK / 鸿蒙 / C SDK 侧也要复用,需定同步机制;搬进 SDK 则要走 SDK 冻结流程
|
||||
2. **`ha_json.c` 复用还是新写?**(复用会动 SDK 目录结构)
|
||||
- 这是下一个切片的**前置**:L1 剩下的协议编解码(`parseOpenAICompatible*`、
|
||||
`normalize*ToolCalls`)全部依赖 JSON 解析,不定就推不下去
|
||||
3. **是否接受「C 化后内核体积/构建复杂度上升」换延迟确定性?**
|
||||
- 需先有真实延迟基线(当前没有),否则是空头承诺
|
||||
- 尤其 `EstimateTokens` 是**高频热路径**(上下文裁剪对每个事件都调),
|
||||
跨语言开销对短文本未必划算;它是第一个该拿数据说话的候选
|
||||
|
||||
### 已定事项(不再挂账)
|
||||
|
||||
- **回退路径保留**:用 `cgo` / `!cgo` 一组约束,**不引入额外 tag**。
|
||||
理由:ha_codec 是零依赖纯 C99 源码内联编译(不需外部库/工具链),
|
||||
而 homed 本就强制 cgo(sqlite3 + gojieba),故 C 路径自然生效。
|
||||
|
||||
**回退路径当前的真实受益者**(实测,不要夸大):
|
||||
- `CGO_ENABLED=0 go build ./...` / `go vet ./...` 能遍历含 `internal/agent/api`
|
||||
的包——若无 `codec_nocgo.go`,这些命令会因找不到 `modelContextWindowC`
|
||||
等符号而**整包编译失败**。这是当前主要价值。
|
||||
- ★ 需知道的事实:`go list -deps` 实测**只有 `cmd/homed` 依赖
|
||||
`internal/agent/api`**;`waiter` / `initconfig` / `memgc` / `mock-server`
|
||||
均不依赖。而 homed 强制 cgo ⇒ **`!cgo` 分支目前无任何生产目标在用**。
|
||||
保留它是为了「包在 CGO_ENABLED=0 下仍可编译」与未来 CGO-free 目标,
|
||||
而不是因为现有什么目标需要它。
|
||||
- 黄金对照的**基准**不靠它:`codec_pure.go` **无 build tag**、永远参与编译。
|
||||
- **不链接预构建 `.a`,也不用包外 `#include`**(前者架构错 + 产物两头空,
|
||||
后者缓存漏跟踪)。用包内符号链接,理由与实测见 §二 P0-1 与设计文档 §2.4。
|
||||
|
||||
---
|
||||
|
||||
*重写时间:2026-09-25 · 核实方式:源码 grep / go build / go test -count=1 /
|
||||
交叉编译对照试验 / 双构建试验 / 变异测试*
|
||||
*旧档备份:`/tmp/plan.md.bak-20260925-124700`(上一版)、
|
||||
`/tmp/plan.md.bak-20260924-171420`(历史 1474 行混合档)*
|
||||
|
||||
Reference in New Issue
Block a user