|
|
6d38a164eb
|
chore(module): Go module 路径随托管地迁移 gitcode → github
## 背景
仓库早已迁移到 GitHub(`github.com/JianFeeeee/HomeAgent`,CI/CD 都在那边跑),
gitcode 保留为**国内只读镜像**(`ci.yml` 的 sync-gitcode-main 快进推送)。
但 go.mod 的 module 路径一直是 `gitcode.com/JianFeeeee/...` —— 既与权威源
不符,`meta.SourceURL`(AGPL §13 的源码提供入口)也指向镜像而非实际运行的代码。
## 关键区分(这是本次改动安全的前提)
两个 module 是**不同**的,影响面差一个数量级:
| module | 谁依赖 | 改它的后果 |
|---|---|---|
| `.../HomeAgent`(主仓) | **只有主仓自己** | 内部重构,零外部影响 |
| `.../homeagent-sdk`(SDK 仓) | 主仓 49 文件 + 所有外部插件 | 需重编插件 |
★ 实测确认:**插件不 import 主仓 module**(`strings qq/plugin.bin | grep HomeAgent` = 0),
只依赖 SDK 仓。而插件与内核的边界是 **RPC 方法名字符串**
(`plugin.init` / `tool.invoke`…,见 proc/protocol.go),**与 Go module 名无关**。
⇒ module 改名**不改变任何 wire 协议**,现网已装的插件照常运行。
SDK 的 GitHub 仓名是 `homeagentsdk`(无连字符),module 路径必须与之精确匹配,
否则 `go get` 会因路径不符失败,故取 `github.com/JianFeeeee/homeagentsdk`。
## 改动
- `go.mod` / `go.sum`:两个 module 路径 + require/replace
- 277 个 Go 文件 + Makefile + 打包脚本的 import 与 ldflags 路径
- SDK 仓 `meta.CoreModule`、`tools/hmapdev` 的 module 声明与工程模板
- 对外文档/链接的仓库地址(README、PLUGIN_DEV、OVERVIEW 等)
## 明确**保留** gitcode 的地方(镜像机制,不能动)
- `GITCODE_TOKEN`、`GC_URL="…@gitcode.com"`(CI 同步 job)
- `gitcode.com/api/v5/...`(release 附件上传)
- git remote `gitcode`(镜像拉取/推送)
- `docs/zh/ci-cd-runbook.md`(整篇讲镜像运维)
## 验证
- `go build ./...` / `go vet ./...` 绿
- `go test ./... -count=1` → 48 包 ok / 0 FAIL
- hmapdev 工具链编译通过(`third_party/homeagent-sdk/tools/hmapdev`)
- 全仓残留检查:module 形态的 `gitcode.com/JianFeeeee` = 0
- 镜像机制抽验:GC_URL / @gitcode / api/v5 / remote 均完好
## 顺带修正
`hmapdev/templates.go` 的注释此前写「gitcode 的模块不在 proxy.golang.org 上」——
module 已迁 GitHub,该论断不再成立。改为如实说明**为何仍默认 replace 到本机 SDK**:
离线可构建、避免版本漂移、内网可用。理由与托管地无关,故 replace 保留。
|
2026-10-08 10:40:17 +08:00 |
|
|
|
849acf4c81
|
fix(plugins): 修三处端口/监听缺陷 + 让测试用临时端口(消除既有 flaky)
排查内核 SIGSEGV 时用 A/B 对照(我的树 20 轮 vs 干净树 20 轮)确认了
两条**既有** flaky,与 C 化改动无关。本提交把它们修掉。
## 缺陷 ①(真 bug,不只是测试卫生):pluginmgr 监听地址是包级可变全局
`var HTTPAddr = "127.0.0.1:9876"` 是包级可变全局,`Start()` 还把 settings 读到的值
**反写**回它,`startHTTPServer` 再读它。后果:
- 多实例互相污染:后启动的实例把地址写进全局,先启动那个读到的是**别人的**地址
(实测与生产 homed 抢 9876)
- 全局读写无同步,属数据竞态
修法:改为实例字段 `p.httpAddr`(默认走 `const defaultHTTPAddr`),
不再有可被任意代码改写的包级状态;并新增 `HTTPURL()` 访问器。
## 缺陷 ②:remotedevice 用 ListenAndServe,监听失败静默且 :0 无法回报端口
`p.server = &http.Server{Addr: p.addr}` + `ListenAndServe()` 在后台 goroutine 里报错,
端口被占时只打一行日志、`Start()` 仍返回 nil —— 插件表面「已加载」而网关根本没跑。
且 `:0` 下拿不到真实端口。
修法:改为 `net.Listen` + `Serve`(与 webui/pluginmgr 同形):
- 监听失败**同步**返回,交给加载器
- 用**实际绑定**地址回写 p.addr,日志与诊断面显示真实端口
## 测试侧:全部改用 :0,不再抢固定端口
新增 `ConfigRegistry.SetPluginConfig(name, key, value)`:插件表原本只在
`RegisterDef`(插件 Start 时)创建,导致「想在插件加载前预置配置」无从下手
(直接 Set 会因表不存在而失败,错误常被忽略)。新方法先建表再写,填补该时序缺口。
`setupIntegration` 在 `Load()` 前预置:
- pluginmgr.http_addr / remotedevice.listen_addr → `127.0.0.1:0`
- webui 走已有的 `SetListenOverride("127.0.0.1:0")`(它有独立旁路)
实测三个插件现在各自绑到 OS 分配的空闲端口(41895 / 35855 / 34021)。
## 缺陷 ③:deepsearch 测试把「上游限流」当成功能回归
`TestRealPlugin_DeepSearchInvoke` 的断言会在上游限流时失败,但插件此时返回的是
**正常结果**(err==nil,content 含 "未返回结果" 与无响应引擎列表)——那是外部条件。
实测失败信息:`brave(Suspended: too many requests), duckduckgo(CAPTCHA), google cse(...)`。
更糟的是它**不可控地随机红**:干净树连跑 20 轮复现 2 次,与代码改动无关。
这种判据会让真正的回归淹没在噪声里。
修法:区分「上游不可用(限流/CAPTCHA)⇒ t.Skip 并说明理由」与
「其他异常 ⇒ fail」。不用静默 return,避免环境退化时判据无声失效。
## 由此发现并修掉的真缺陷:监听地址被硬编码在三处
`127.0.0.1:9876` 曾硬编码在 pluginmgr / cli / webui 各一份。cli 与 webui 后来改为
运行时读 `pluginmgr.http_addr` 设置(本次核实),pluginmgr 自己却仍是全局 —— 三处
口径现在统一为「读设置 + 实例字段」。
## 验证
- 新增 `TestTwoInstances_ListenIndependently`(pluginmgr):两个实例同时监听、
各自 HTTPURL 指向自己端口、两个地址都真的可连。
★ 经**忠实变异**验证有牙:复原「包级全局 + Start 反写 + 读全局」后该测试判红
(我第一版测试只断言字段不共享,变异证明它没牙,已重写为端到端判据)。
- `internal/plugins` 连跑 **30 轮:30/30 全过**(修复前干净树 18/20)。
- 全量连跑 3 轮:38 ok / 0 FAIL / 0 bind 冲突。
- go build ./... / go vet ./... 干净。
|
2026-09-25 17:57:15 +08:00 |
|
|
|
562704a6be
|
test(plugins): deepsearch E2E 不再带走共享搜索后端(附回归判据)
背景:E2E 临时目录里拉起的插件实例在 teardown 时执行了 `docker compose stop -t 2`,
把线上正在用的 SearXNG 关掉,表现为「搜索后端起不来」。
- integration_test.go:把 ConfigRegistry 暴露给测试环境(其余不变)
- deepsearch_e2e_test.go:
- forbidStoppingSharedBackend:测试实例一律 stop_searxng_on_exit=false
(配置表按内核约定先 RegisterDef 再 Set)
- 新增 TestRealPlugin_DeepSearchKeepsSharedBackendOnStop:停掉插件实例后,
6 秒内 healthz 必须始终 200 —— 判据落在网络层,直接钉住「跑测试不能断线上搜索」
验证:三条 E2E 全过,且跑完 healthz 仍 200、容器 StartedAt 未变(未重启)。
|
2026-09-13 09:55:33 +08:00 |
|
|
|
f967ebf6e9
|
chore: 撤回误提交的未跟踪文件 internal/plugins/deepsearch_e2e_test.go
该文件是工作区里**别人 in-flight** 的未跟踪文件(我上一步用 git add -A internal/ 时被顺带收进来)。
它不是我这次改动的一部分,因此从索引里撤出,文件本体保留在工作区(仍为未跟踪状态),
由它的作者决定何时提交。
|
2026-09-13 09:07:02 +08:00 |
|
|
|
2353b8b15d
|
feat(channel): N1a —— inputch 一等化(归属插件/归属 agent/容量/共享登记表)+ 单工具多视图总览
设计:docs/zh/resident-subagent-design.md §4.6(里程碑 N1a)。
## 用户要求
「父 agent 可以看到所有已注册的 inputch 以及 inputch 的划分情况,用**单工具多视图**方式构筑」
## 登记层(internal/agent/io/inputch.go)
inputch 是**最基本的输入路由单位**(由插件注册,一个插件可注册多个),
所以登记表以 inputch 为键,每条记录:
名字 / 归属插件 / 归属 agent(被划给谁) / 容量 / 默认回程 outputch / 记忆策略(ChannelDef)
- 新增 `ChannelRegistry`,设计成**可共享对象**(`*ChannelRegistry`):
根 agent 与驻留子共用同一份,"划入/授权"才有意义;`SetChannelRegistry` 注入。
- **插件重载不得抹掉划分**:重复登记只更新「归属插件 + 策略」,
保留已有 Owner/Capacity/Output(否则一次 reload 就把父做的划分清空)。
- `Assign` 语义按设计 R6 默认:**读写授权,不转移所有权**(Plugin 与 Owner 分别记录)。
- 原 `inputChannels map[string]ChannelDef` 被登记表取代;`GetInputChannelDef` 保持兼容。
- `plugin.Registry` 注册时带上**归属插件名**(此前完全无归属信息)。
## 总览工具(internal/agent/core/inputch.go)
单工具 **`input_channels`** + `view` 参数(不是一堆小工具):
all(默认)= 全部已注册(带归属插件)
mine = 划给本 agent 的
unassigned = 尚未划出的
by_agent = 划分情况总览(按归属分组)
detail = 单个 inputch 全字段(需 name)
未知 view **报错并列出可用值**(拼错不得被静默当成默认视图);登记表为空时明确说明。
## 验收
- `internal/agent/io/inputch_test.go`:归属记录、重载保划分、Assign/视图数据面、
**跨 manager 共享登记表**、策略查询向后兼容 —— 5 项
- `internal/agent/core/inputch_test.go`:单工具多视图逐视图断言(含未知 view 与空表)—— 2 项
- 全仓 `go test ./...` 37 包 ok / 0 FAIL;`-race ./internal/agent/... ./internal/plugin/...` 干净
|
2026-09-13 09:06:50 +08:00 |
|