Commit Graph

17 Commits

Author SHA1 Message Date
6e6035141a fix(resident/plugin): 二进制级压测暴露的三个真问题(DataDir 漏接线 / inputch 未登记 / create 不开工)+ 通道双向登记贯穿全部内建插件
在真实内核二进制(私有 netns + mock LLM + CLI unix socket)上做压力测试时,
下面三个问题**只有跑真二进制才暴露** —— 单元测试里都显式传了参数、没走插件加载,
所以全绿也照样漏。

## ① 根 agent 的 DataDir 没接线 ⇒ 驻留子永远建不出来

现象:模型调用 `resident_agents` 成功,但结果是
`创建驻留子需要 data_dir 或显式 temp_path`。
根因:`cmd/homed/main.go` 构造 AgentConfig 时没有 `DataDir`,
而驻留子的 temp 图库需要 `<data>/residents/<id>/graph.db` 这个锚点。
(单测里 `AgentConfig{DataDir: dir}` 显式给了,所以测不出来。)

修:main.go 接线 `DataDir: cfg.Daemon.DataDir`;并在工具层加**兜底 + 告警** ——
data_dir 为空时从主图库路径反推(`<data>/memory/graph.db` ⇒ `<data>`),
失败才报错。静默失败会让线上表现成"工具能调但永远建不出来"。

## ② 插件通道没登记为 inputch ⇒ "划入 inputch"必然失败

现象:`划入 inputch cli: inputch 未注册`。
根因:`cli` 插件只调 `RegisterOutputChannel("cli", ...)`,却用同一个名字
`InjectTextSync("cli", ...)` 注入输入 —— 内核 inputch 登记表里根本没有它。
(实测审计:内建 6 个插件里只有 0 个登记过入站通道;SDK 示例里只有 qq/weather 是对的。)

修两处:
- **全部内建插件显式登记入站通道**:`cli`/`agentcli`/`timer`/`webui`(+`http`, NoMemory)/
  `clawhubadapter`(每个 OC 通道声明处)/`remotedevice`(`device/<id>` 懒登记,幂等)。
- `registry.go` 把隐式兜底改成**留痕的兼容网**:只有当该名字还没登记为 inputch 时
  才兜底登记,并打日志说明"建议显式 RegisterInputChannel"。
  实测:改完内建插件后,启动日志里兜底告警 **0 次**。

## ③ create 之后子不开工 ⇒ rounds 恒为 0

现象:`[agent] r1 started, waiting for IO interrupts` 之后什么都没有,登记表里 rounds=0。
根因:`TaskPrompt` 只进了子的**系统提示词**,从没作为输入投给子。
修:create 即开工 —— 把任务提示词作为**第一条排队输入**投给子(排队而非中断:
创建是"安排工作",不是"打断它正在做的事")。

## 测试

- `TestResident_InputchTableAutoAndProactive` / `TestLightKernel_TraditionalContextNoTrimming`
  随行为更新:create 会多跑一轮(任务提示词那轮也会写处理表),
  断言改为"以创建时的表长为基线 + 等待新的一轮"。
- 全量 `go test ./...` = 37 包 ok / 0 FAIL;`-race`(agent/plugin/plugins)干净。

## 真实二进制压力测试结果(修复后)

私有 netns 里跑 mock LLM + 内核,用 CLI socket 驱动多并发连接:
- 密集:16 连接×12 输入 + 4 线程×20 次 L4 中断 → **274 任务 executed=274 / rejected=0 / errors=0**,
  峰值排队 15、峰值待处理中断 76;
- 稀疏(中断每 3s 一次,压在排队任务的流式段上)→ **suspended=27 / resumed=27 / preempted=27**;
- 驻留子全链路:父建子(inputchs=["cli"])→ 子开工 → 子 `notify_parent` → 父侧收到
  `interrupt from r1/child/r1`(L3,且父被抢占 suspended/resumed=1);
- 优雅退出:SIGTERM 后驻留子 temp 目录被清除、无残留进程。
2026-09-13 11:38:03 +08:00
f0cdbdb030 feat(sdk): SettingsAPI.DataDir() 插件专属数据目录 + ai_image 本地交付
【SDK DataDir API】
- SettingsAPI 新增 DataDir() string:返回插件专属数据目录
  <data>/plugin_data/<name>(内核保证存在),解决此前插件只能
  靠 GetCore("daemon.data_dir") 手工解析的缺陷
- settingsImpl 新增 dataDir 字段 + SetDataDir;Registry buildSDK
  注入(<data>/plugin_data/<name> 并 MkdirAll);main.go 接线
- cabi 新增 CORE_SETTINGS_DATA_DIR (id 51);plugindev dispatchSettings
  模板补 DataDir() 实现

【ai_image 交付本地路径】
- 生成后下载临时 S3 URL 到插件数据目录,返回本地文件路径(永久不
  过期),而非 1 小时过期的 S3 URL。带 UA 规避图床对无 UA 客户端拦截
  (此前 agent 裸 curl 验证被拒导致误报失败)
- 返回 local_paths 字段 + 提示用 output_send(type=image) 展示

端到端:ai_image_generate → plugin_data/ai_image/*.png 有效 PNG(1024²),
经 llmsproxy→siliconflow 生成。
2026-08-26 21:40:29 +08:00
5f126d4d10 feat(skillmgr): 原生技能管理器插件 + OpenClaw 兼容层职责分离
新增 internal/plugins/skillmgr(native skill 全生命周期 owner):
- skill_list/info/load/unload/enable/disable/create/export/install
- skill_create 两步式:先生成骨架模板,LLM 补全后传 content 覆盖写入
  (plugin.ValidateSKILLContent 校验)并自动加载生效
- .skm 分发包(tar.gz):packSkill/unpackSkill 含 TarSlip 防护
  (拒绝绝对路径/../逃逸、强制单根目录、校验包内 SKILL.md)
- skills 目录扫描:纯 SKILL.md/skill.json 条目归本插件;
  sidecar(main.js/main.py)/OC plugin(openclaw.plugin.json) 留给兼容层

clawhubadapter 职责分离(OpenClaw 兼容层不再持有 native skill):
- 删除 p.skills 字段与 default 分支 LoadSKILL 逻辑
- 发现纯 SKILL 条目改为发布 events.EventSkillDetected 移交事件,
  由 skillmgr 订阅注册;启动时序 c<s 下全扫兜底,事件用于热新增
- claw_list/plugin_info 不再输出 SKILL 段,统一走 skill_list

方案B prompt 注入:
- agentCore 新增 SkillIndexProvider 接口 + SetSkillIndexProvider
- buildSystemPrompt 注入【可用技能】轻量索引(名称+版本+描述),
  LLM 匹配场景时主动 skill_info 拉全文按文档执行
- main.go 在插件加载后将 skillmgr 实例接线到 agent

内核小修:
- extractDescription 跳过 YAML frontmatter 块(此前所有带 frontmatter
  的 SKILL.md 描述都被误判为 '---')
- extractField 剥离 YAML 成对引号(version: "1.0" 不再带尾引号)
- plugin.ValidateSKILLContent 导出供生成侧校验
2026-08-25 20:25:57 +08:00
2338f3f4f3 fix: 插件增量重载 + clawhubadapter ipcGoroutine 优雅退出
- Registry.Reload 改为增量: 对比插件入口文件(plugin.so/main.lua) SHA256, 仅重载有变更的插件, 未变更保持运行, 消除 plgreload 触发全量 StopAll+Load 导致的重复加载与内置插件状态错乱
- Registry 新增 pluginHashes 记录 + pluginEntryHash 辅助
- clawhubadapter.ipcGoroutine 无退出条件导致重载后旧 goroutine 永久残留(线程累积): 增加 stopCh/stopOnce, Stop() 关闭, ipcGoroutine 用 select 监听退出
- 新增 TestRegistryIncrementalReload 验证无变更跳过/变更重载
2026-08-17 08:53:39 +08:00
8dcce5a3a9 webui 删除彻底化:清理残留 config/defs/provider 悬空
审计发现 webui 多处删除只清一处、留下鬼影:
- RemovePlugin: 仅 DROP config_<name> 与 defs,config 表 plugin.<name>.* 键永不删 →
  补 DELETE config LIKE 'plugin.<name>.%'
- ConfigRegistry.Delete: 删 core.llm.sources.<name>.* 后遗留 ConfigDef、且删 core.llm.*
  不更新 guard 快照(重启/failback 会把已删源复活)→ 同步清 source defs + 写 llm 快照
- llm_impl.ReloadFromConfig: 删除默认源后 core.llm.provider 悬空,SetDefault 指向不存在源
  → 仅当源仍注册时才 SetDefault
- clawhubadapter 测试 mockSettings 补 RemoveCore/RemovePlugin
- mcp 服务器删除仍为进程内需 reload 生效(符合既有 removeServerHandler 语义)

验证: go test ./... 26 包 0 失败;本机部署 sources=3、27 插件加载、对话正常
2026-08-10 09:51:30 +08:00
33e97f2a99 clawhubadapter: sidecar_test mockSettings 补 Remove 接口方法 2026-08-05 10:00:05 +08:00
a965a74d27 clawhubadapter: agent 全量管理 OpenClaw 插件与通道(管理接口补齐)
新工具(agent 可直接调用):
- plugin_info:插件详情(OC/sidecar/SKILL 类型、工具列表、关联通道及状态)
- plugin_reload:重新加载插件(reloadPlugin)
- channel_list:全部注册通道 + 实时运行状态
- channel_send:向通道注入消息(SendToChannel → channel/send → pollQueues)
- channel_start / channel_stop:通道账号启停

manager 新 RPC:
- plugins/channels:registeredChannels 摘要(type/status/accounts)
- channel/start:fire-and-forget startChannels 恢复账号(startAccount 永久挂起语义)
- channel/stop:stopAccount 停止心跳/轮询,支持按 channel 全停或按 accountId 单停

Go 侧 channelSummary 合并 manager 注册信息与 channel_status 实时缓存(缓存优先)。
验证:微信端到端(本地 mock LLM 源)channel_list 返回 wechat running=true connected=true、
channel_send 投递成功;standalone manager 验证 channel/start 心跳恢复与 channel/stop。
2026-08-02 13:32:51 +08:00
3cc8d84def clawhubadapter: 补充 chatPolls/getPolls 轮询消息源(通用通道插件输入闭环)
- manager:chatPolls/getPolls 改读 per-account pollQueue(poll 取走即消费);
  新增 channel/send RPC(Go 端注入外部输入)
- plugin.go:SendToChannel(channel, payload) + ChannelSender() 单例
- 验证:mock-poll(纯 chatPolls 轮询型通道插件)channel/send → poll got msg →
  dispatchReply → channel_input 完整入站;微信通道回归正常
2026-08-02 13:07:31 +08:00
76ef49e9a6 clawhubadapter: OpenClaw 通道插件兼容修复(gateway 生命周期桥 + channelRuntime + deliver 事件式输出)
- manager/main.js:makeChannelRuntime(dispatchReplyWithBufferedBlockDispatcher 入站 + deliver 出站
  绑定 + typingCallbacks)、startChannels/stopChannels(gateway.startAccount fire-and-forget 生命周期
  桥、listAccountIds/resolveAccount 规范签名 cfg 传参)、tools/call 通道分支无 outbound 走 deliver
  事件式发送、SIGTERM 优雅停靠、console 输出重定向 stderr 防 JSON-RPC 流污染
- plugin.go:channel_input 改 InjectInputSync 同步注入取回复并经 CallTool 回发通道(修复
  InjectInterruptText 无 ResponseCh 致回复静默丢弃);channel_status/channel_output 通知接入
- registry.go:channelStatus 状态缓存
- SDK:公共 IOInjector 增加 InjectInputSync(source, channel, text) string + ioAdapter 实现
- 生产验证:微信发消息 → pollLoop → dispatchReply → mock LLM 回文本 → deliver →
  ilink/bot/sendmessage status=200 送达
2026-08-02 13:03:49 +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
a899d777c3 sdk: embed non-toolchain SDK in third_party, add NoMemory/Cleaner support
- Embed sdk/, example/, meta/, go.mod from homeagent-sdk (no .git)
- Core .gitignore excludes SDK toolchain: bin/, tools/, package/
- RegisterInputChannel + ChannelDef(NoMemory, Cleaner) in SDK
- IOManager input channel registry with GetInputChannelDef
- eventloop: apply channel Cleaner/NoMemory to interrupt text
- context engine: channelDefLookup applied in textForVector
- document store: ChannelCleaner param for archive functions
- All callers/adapters updated with ChannelDef{} default
2026-07-29 14:48:23 +08:00
f91b20ee16 v0.7.3: 重构 Provider 层 + 计算层隔离 + Cleaner/NoMemory 架构
- 删除 OpenAIProvider/OllamaProvider 死代码,LuaAdaptedProvider 独存
- DisableThinking 从 ExtraBody 移到 CompletionRequest 顶层字段
- ContextWindow 从 Provider 签名移到 BaseConfig/ModelContextWindow() 统管
- 确认 CleanText 仅做基本空白 trim,QQ 模板剥离归插件 Cleaner
- Cleaner/NoMemory 仅作用于向量计算和 jieba 分词层,原文不变
- context.ContextEvent/Doc.Content 始终保存原文
- 删除 nlp/download.go 死代码
- media.go: context.Background() -> a.ctx 级联
- clawhubadapter: HTTP 超时
- cut.go: 跨平台 mod cache 路径 (GOMODCACHE->GOPATH->HomeDir)
- bridge_e2e_test: 移除未用 runtime import
- lua 适配器: disable_thinking 传参
2026-07-28 11:42:29 +08:00
d4cb9cb8cc refactor(clawhubadapter): merge manager/simulator, fix provider dispatch, add OC plugin load delegation
- Manager now handles OC plugin loading via plugins/load JSON-RPC
  instead of launching a separate simulator process
- Added 8 missing provider registration methods to manager
- Added explicit registeredChannels declaration in manager
- Provider dispatch now strips _provider suffix correctly (lookupType)
- Skip .simulator directory in skills scanning
- detect OC via package.json openclaw field (hasOCPackage)
- All registration notifications include plugin name for correct tool prefix
- Fix ToolRegistry/ProviderRegistry/ChannelRegistry to use plugin name
  from notification data instead of hardcoded 'manager'
- test: add mockSettings, fix TestLoadOCPluginViaPluginStart panic
2026-07-23 16:34:26 +08:00
4b6caae605 feat(clawhubadapter): bridge OC channels to HomeAgent output/input channels
- registry.go: replace channelDevice+RegisterChannel with RegisterOutputChannel
  handler routes output via sp.CallTool to JS manager outbound handlers
  register {plugin}_read_{ch}_input tool for agent to poll buffered input
- plugin.go: handle channel_input notifications in translateAndRegister
  buffer payload in channelInputBuf + InjectInterruptText to notify agent
- manager/main.js: registerChannel supports {plugin: ChannelPlugin} format
  tools/call routes channel names to outbound.sendText/sendMedia
  submitInput sends channel_input notification to Go side
2026-07-23 14:45:10 +08:00
3a5f548326 fix(clawhubadapter): manager CLI improvements, pysimulator updates, sidecar fixes 2026-07-23 13:54:04 +08:00
9b4d0cb50d feat(clawhubadapter): rename plugin tools, universal uninstall; feat(mcp): add dynamic server management; feat(prompt): long-task guidance 2026-07-22 17:32:45 +08:00
76a4619ed5 refactor: rename openclaw -> clawhubadapter, add ClawHub search/install, fix agent interrupt
- Rename internal/plugins/openclaw/ -> internal/plugins/clawhubadapter/
- Add RegistryDispatcher with 5 sub-registries (Tool, Provider, Channel, Stage, Cap)
- Add clawhubadapter_search tool for ClawHub marketplace search
- Add clawhub: prefix support for installing from ClawHub (ZIP/tgz auto-detect)
- Add CallProvider RPC and provider/call routing
- Fix QQ interrupt: check interceptCh before/after each tool execution
2026-07-21 22:47:14 +08:00