Commit Graph

39 Commits

Author SHA1 Message Date
74a24f93d7 feat(memory): 媒体 GC 与描述生成两条后台循环
补齐媒体记忆的最后两块:容量上限真正生效,描述文本成为持久语义记忆。

## mediaGCLoop:让容量上限不再形同虚设

CAS 的 GC 只在被显式调用时执行,Put 路径不触发它。此前配置项
core.memory.media.max_mb 注册了却没有任何调用方——一次 see_video 抽 10 帧,
帧本身在工具结果被 Prune 后就没人引用了,若无人清理会一直堆在磁盘上。

现在按 gc_interval(默认 6h)周期调 GC(gc_min_age)。两个不变量:
  - 有引用的内容永不删除,即使超容量(宁可超限也不断引用)
  - gc_min_age(默认 1h)保护刚 Put 还没来得及 AddRef 的项——它们
    refcount 也是 0

## mediaDescribeLoop:描述才是能活过 GC 的那部分

blob 会被容量 GC 淘汰,而描述留在 media 表里,并经 mediaSummaryForEvent
写进 L0 事件、随归档进 L2 文档、经蒸馏进 L3 图库。于是「那张紫蓝红三色
带图」在原始字节早已被清掉之后仍然可被检索到。

复用既有的视觉回退链(resolveModalFallback + chatModalFallbackBatch),
不新造一套模型调用。

三个刻意的决定:

  - **走后台而非入库时同步**:视觉模型一次调用生产实测 9.6s。放在对话
    路径上会让每张图都给回复加十几秒,而描述的价值是几个月后还能检索到,
    不是这一轮——这一轮模型本来就直接看着图。
  - **逐条而非批量**:批量拿回来是一整段文字,无法可靠切分回各自的
    digest(模型未必按序号输出,也可能把两张图合并成一句)。宁可多几次
    往返也要保证「描述 ↔ digest」的对应关系确定。
  - **默认关闭**(describe_on_ingest=false):它消耗视觉模型配额。开启后
    每 30s 最多处理 4 条,不跟对话抢额度。

失败处理分三类:
  - 网络抖动/配额 → 不标记,下轮重试
  - 空回复 → 视作失败(上游剥离媒体时通常回空,与 modalfallback 同理)
  - 不可描述(kind=other、blob 已丢失)→ 标记 described_by=unsupported/
    content-missing,退出队列

## 顺带修掉 Pending 的一个真缺陷

测试写出来才发现:Pending 原先只看 `description = ''`,于是被标记为
described_by=unsupported 但 description 仍空的项**每轮都会被重新取出来
重试**,永久占着 LIMIT 的名额,真正需要描述的新项永远轮不到。
改为同时要求 described_by 也为空。

这是「先写断言再看它是否成立」抓到的——原本我以为标记一下就够了。

## 测试

medialoop_test.go 7 例:两条循环在禁用时立即返回(nil store / 零间隔 /
describe 关闭三种形态,不留空转 goroutine)、GC 清孤儿保留有引用项、
minAge 保护新项、无可用源时不误标记、不可描述大类被标记后退出队列。
media_test.go 补 1 例专测 Pending 的排除逻辑。

全仓 go build / go vet / go test 通过,SDK 冻结 diff = 0。
2026-09-04 22:00:03 +08:00
f855893d1c feat(memory): 媒体接入 L0/L2——digest 挂到对话事件,归档时引用随之转移
a822674 的 CAS 层之上把媒体真正接进记忆链路。此前 CAS 只是个孤立的
存储包,没有任何写入方。

## 媒体进入对话有两条路,两条都只把文字留给记忆

  1. 用户直接发图 → processMediaInput → mediaToBlocks
     ContextEvent.Input 只存 alt 文本("[从 qq 收到了 image]"),
     base64 随 message 数组发给模型后就丢了。
  2. 插件注入 → SetToolBlocks → process.go 的 mediaMsg
     ToolResultItem.Output 只存那句 "[已将图片注入后续对话] /tmp/x.png"。

于是下一轮起,模型能看到的只剩一句路径或一句 alt。那个文件被删、被覆盖,
或者本来就是 /tmp 下的临时产物,连线索都断了。

现在两条路在同一处收口(captureBlockMedia):从 ContentBlock 的 data URL
取出字节存进 CAS,digest 挂到当轮 ContextEvent。

## 改动

internal/agent/core/mediaref.go(新)
  - captureBlockMedia:ContentBlock → CAS。只处理 data URL——http(s) URL
    拿不到字节就无法内容寻址,而「下载它再存」会把一次对话变成一次网络
    请求(超时、鉴权、SSRF 全来了),不在本层解决。
  - stage/drainMediaDigests:媒体在 process() 期间被捕获,而承载它的
    ContextEvent 要等 process() 返回后才 Append——此刻还没有 owner_id,
    故先缓存。与既有 pendingMedia 同一手法,同受 a.mu 保护。
  - bindEventMedia:双向落地。evt.Media 让事件记得引了什么(随
    context.json 持久化),media_refs 让 CAS 知道谁在引用(GC 的判断依据)。
    只写一边的话,要么 GC 误删仍被引用的内容,要么孤儿永远清不掉。
  - mediaSummaryForEvent:把已有描述拼成一行写进 Input。这是方案 C 的
    落点——**描述文本才是持久语义记忆,blob 只是缓存**。blob 可能被容量
    GC 淘汰,但描述会一直留在 L0/L2/L3 的文本里,让「那张紫蓝红三色带图」
    几个月后仍可被检索。

ContextEvent 新增 ID 与 Media 两个字段,都是 omitempty:
  - ID 懒生成,只有真要挂媒体时才赋值。绝大多数对话没有媒体,全量生成
    会让每条事件都多一个字段进 context.json。
  - 存量 context.json 读回来两字段皆空,不影响任何既有行为(有测试)。

RelevanceContext.Prune 归档时转移引用(transferMediaRefs):
  **先挂到归档文档、再注销原事件引用**。顺序不能反——先销后挂会让引用
  计数瞬时归零,若此刻后台 GC 正在跑就会把仍被记忆引用的内容当孤儿清掉。
  为此把 Prune 内的局部类型 scored 提为包级 scoredEvent(局部类型无法
  出现在方法签名上)。

media 包新增 OwnerContext/OwnerDocument/OwnerGraphSentence 常量:
  owner_kind 进了主键,拼错一个字符就是一条永远对不上的孤立引用——
  AddRef 不报错,DropOwner 也永远匹配不到。

## 配置

core.memory.media.enabled(默认 true)、.dir、.max_mb(2048)、
.gc_interval(6h)、.gc_min_age(1h)。

关闭后全链路静默跳过,对话行为与本特性上线前完全一致(有测试)。
mediaStore 为 nil 时同理——它是记忆增强,不是对话必需品,开不起来
只记一条 warning 不阻止启动。

## 测试(11 例)

入库与 MIME 归类、http URL 跳过、nil store 全链路 no-op、音视频混合、
stage/drain 清空语义、懒生成 ID、描述作为持久记忆、**归档转移期间内容
始终可读且 refcount 不归零**、无媒体存储时归档照常、context.json
向后兼容往返。

全仓 go build / go vet / go test 通过,SDK 冻结 diff = 0。

## 尚未接入

L3 图库的 graph_sentence owner(常量已备好,无写入方)、
描述生成的后台任务(Pending() 已就绪,尚无消费者)、
媒体 GC 的定时触发(配置项已注册,尚未接 ticker)。
2026-09-04 20:53:32 +08:00
09071dc235 fix(multimodal): 修多模态假成功 + 落地视觉回退链 + see_video 帧数语义
## 起因

生产盲测:模型调 multimodal_see_picture 后声称看到了图,实际一个字
都没收到。工具却返回「[已将图片注入后续对话]」。

链路:core.llm.model=AUTO → llmsproxy 按优先级选 big-pickle(prio=100)
→ 转 opencode zen。llmsproxy 的 opencode.lua 明写着:

    -- zen 上游 schema 只接受 text content part(无视觉/音频能力)
    if part.type ~= nil and part.type ~= "text" then  -- 丢弃

判据:256x256 纯红 PNG,带图与不带图的 prompt_tokens 都是 256。
图片贡献零 token,即根本没进上游。

内核序列化与注入链本身是对的(Message.MarshalJSON 正确产出 content
数组,SetToolBlocks → IOManager → ConsumeToolBlocks → toolMsg.Blocks
全通)。缺的是「主模型能否消费这些块」这一判断——内核此前完全没有
多模态能力的概念(grep supportsVision|multimodal 在 agent/ 零命中)。

这与 v1.0.0 修的 output_send 假成功同类:告诉调用方成功而实际未送达。

## 1. 能力声明

新增 core.llm.sources.<name>.vision / .audio(走既有 sourceFieldDefs,
WebUI 配置页自动出现),types.LLMSource 与 api.BaseConfig 同步加字段。

新增 agentAPI.ModalProvider 接口 + ProviderSupportsVision/Audio 判定:
未实现该接口的 provider 一律按不支持处理。保守侧是刻意的——宁可多走
一次文字回退,也不能把图默默扔给会剥掉它的上游。

为何是声明而非探测:探测需额外真实调用且结果不稳定(取决于 AUTO 当次
路由到哪);而 200 响应 + 相同 token 数从响应侧无法区分「看到了但没
内容」和「被剥掉了」。

## 2. 回退链(modalfallback.go)

实现了 config/registry.go 里注册但从未被读取的 image/audio
fallback_provider + fallback_model(此前 0 处读取点)。

prepareToolBlocks 在 process.go 注入前判定:能直视就原样透传;不能就
调声明了该能力的源转写成文字,带 [由 X 转写,非当前模型直接感知] 标注。

几处刻意的设计:
- 逐模态判定,不一刀切。很多视觉模型能看图但听不到音频,全部降级会
  白白把可直视的图变成二手描述
- 混合场景下转写文字作为 text 块并入 native,两部分同时到达模型
- 配置指向未声明能力的源时拒绝并继续找——照用只会重演静默剥离
- 未配 fallback_provider 但某源声明了 vision 时自动扫出来用;静默失败
  比多找一个能用的源更糟
- 空回复算失败。上游剥掉媒体后模型往往回「我没看到图片」或空串,两种
  都说明回退链也没真看到
- 多媒体块按模态合包为一次请求(见下)

## 3. 批量合包(生产实测驱动的返工)

首版逐块调用,生产 see_video 6 帧实测:4 帧里 3 帧超时,整轮 363 秒。
改为按模态合包一次请求后同一用例 131 秒、6/6 成功。

顺带把 modalFallbackTimeout 从 90s 提到 180s:生产经网关转
claude-opus-5 看一张 400x400 图要 ~81s,90s 贴着上限。
多张时 detail 默认 low 控体积,单张用 high 看细节;插件显式给了
detail 则尊重它。

## 4. see_video 帧数语义

fps=1/N 是频率(每 N 秒一帧)不是数量。20s 视频实测:
frames=4 → 5 帧、frames=10 → 2 帧、frames=1 → 20 帧,要得越多拿得越少;
长视频下 frames=4 会产出 时长/4 帧,靠 i>=9 的 break 兜着才没炸上下文,
而那个 break 用的是 ReadDir 索引,跳过条目后与实际帧数错位。

改为 ffprobe 取时长 → fps=N/时长 + -frames:v N 硬封顶。
0.4s/3s/20s/120s × frames=1/2/4/7/10 全部精确。

极短视频的坑:fps=1 在 0.4s 素材上产出 0 帧(不足一秒抽不出),所以
时长探测失败时不能退化成 fps=1,改为不传 -vf 只靠 -frames:v。

## 验证

- modalfallback_test.go 14 例:直视透传 / 回退转写 / 无源如实报告 /
  未实现接口按不支持 / 混合模态拆分 / 空回复算失败 / 块数上限 /
  多图合一次调用 / detail 策略 / 拒绝未声明能力的源 / 未配置时自动扫源
- go test ./... 全绿,go vet 无警告
- 生产盲测(答案预先封存、生成时不读):随机三色带 → 模型答
  「紫、蓝、红」,与封存答案完全一致
- 负向验证:拿掉回退源后模型如实回答「没看到图片内容」并引用工具返回
  的配置提示,且主动纠正了上一轮的答案
- 生产 see_video 6 帧:单次转写,模型正确描述测试图卡的计数器递增与
  彩虹带滚动
2026-09-04 06:25:51 +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
6009ce801f feat(agent): spawn_child 支持 max_turns + 并行策略引导
1. spawn_child 新增 max_turns 参数(1-30,默认 5)
   子 Agent 工具轮数此前硬编码 5,复杂任务跑不完即截断。现可按任务
   复杂度调整;返回消息带轮数上限提示。

2. 工具描述与 system prompt 增加并行策略引导
   明确'多个互不依赖的子任务应并行 spawn 多个子 Agent,不要串行
   逐个执行;长耗时任务交给子 Agent 避免阻塞对话'——针对生产实例
   观察到的 agent 倾向自己串行处理所有子任务的问题。

小宅自定义 prompt 同步补充并行策略段。
2026-08-26 13:38:27 +08:00
cb76828e43 fix(cmd/files/webui): shell 语义修复 + 根沙箱误判 + 上传注入走 interrupt + UI 区分附件来源
1. cmd_run 改经 /bin/bash -c 执行完整 shell 语法
   旧实现 shellUnquote 拆词后直接 exec:'pwd; ls /' 变成执行名为
   'pwd;' 的程序(exit -1)、heredoc 被截断、管道/命令替换全部失效——
   agent 多次反馈命令解析奇怪即此。危险命令拦截(kill homed 等)保留。

2. files 沙箱根目录判断修复
   pathWithinSandbox 在 base='/' 时 prefix 变 '//',所有绝对路径误判
   逃逸(生产实锤:files.dir=/ 下 files_read/write/ls 全部报 outside
   sandbox)。根沙箱直接放行。

3. webui 文件上传注入改走 interrupt(system 角色)
   文件元信息不再混入用户消息气泡;用户附言作为正常消息先行注入,
   文件说明紧随其后以 no_memory interrupt 补充——对齐 terminal_watch/
   timer 工具提醒模式,聊天流保持干净。

4. 前端附件卡片按 role 区分来源
   user=右侧+『你发送的』标签+accent 底色;assistant=左侧+『小宅发送的』。
   📌 emoji 按钮换为 SVG 图标,前端 emoji 清零。
2026-08-26 10:24:47 +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
f960fde785 agent: 更智能的 LLM provider 调度(byModel 精确路由 + AUTO 优先级链)
吸收 llmsproxy 的调度思想适配 HomeAgent“一源一模型”结构:
- RoutableProvider{Model,Priority} 次级接口(不破坏既有 Provider 实现)
- ProviderManager.OrderedProviders 改为按 (优先级 desc, 可用, 默认优先) 稳定排序,
  AUTO/空模型走该优先级链
- 新增 ProviderManager.ResolveForModel:精确模型名路由到归属源,找不到回落 AUTO 链
- LuaAdaptedProvider 不再无条件覆写 req.Model;显式模型名原样转发
- LLMSource.Priority + core.llm.sources.<name>.priority 配置项
- process.go: 显式模型走 ResolveForModel,AUTO 走 OrderedProviders
- 新增路由单测(优先级排序 + byModel 解析)

验证: go test ./... 27 包 0 失败;Windows 交叉编译通过;部署后服务健康
2026-08-10 11:54:45 +08:00
f0dacef281 lua: 吸收 llmsproxy 适配器高级特性(worker 池/静态预提取/动态签名钩子)
- 适配器 worker 池化:单 LState+全局锁(串行瓶颈)→ 每 adapter 一个 gopher-lua
  LState 池,按使用该 adapter 的源并发上限求和配置池大小,并发 transform 互不阻塞
- staticInfo 预提取:name/version/endpoint/headers 加载期编译缓存,Endpoint/Headers
  读缓存不占 worker;加载即预编译首个 worker
- build_headers 动态钩子 + hmac/sha256/base64/tohex 全局:签名型上游(kimicode 等)可接入
- provider applyAdapterHeaders 接入动态头(url/method/body/api_key/timestamp/source 元数据),
  未定义时回落静态 headers,缺省补 Authorization
- LLMSource.MaxConcurrent + core.llm.sources.<name>.max_concurrent,注册时汇总
  VM.ConfigureConcurrency
- 新增 Lua VM 测试(load/transform/build_headers/并发)

验证: go test ./... 27 包 0 失败;Windows 交叉编译通过;部署后 9 adapter 全部预加载
2026-08-10 11:29:57 +08:00
171e6f233b llm: 统一源接入层修复(对照 llmsproxy)
- provider: 新增 OpenAI-compatible 响应/流兜底解析,Lua adapter 异常时也能解析
  choices/message/tool_calls/usage(含 function.arguments 缺失、对象/字符串参数)
- 过滤无效 LLM 源(<nil>/空/缺 http(s) scheme),main 与 ReloadFromConfig 均跳过,
  避免 mocktest 等坏源污染 fallback 与 healthcheck
- adapter(openai/deepseek/groq/mistral/github/kimicode): 修 tool_calls 对
  nil function 的崩溃,兼容扁平/嵌套结构;openai 流透传 reasoning/tool_calls
- config: ToConfig 探活端点过滤无效 base_url,修复 supervisor 误报 LLM unreachable
2026-08-09 20:39:54 +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
19410b0e26 蒸馏嵌入接线:Distiller/Agent 注入共享 embedder,修复配置缺失时蒸馏零产出 2026-08-05 09:59:33 +08:00
c7ee45d6e1 refactor: remove core skill direct loading, skills owned by clawhubadapter only
- Drop skill.NewManager from homed bootstrap; skills dir no longer core-managed
- Remove GetInjectedPrompt system-prompt injection (skills are not first-class)
- Delete internal/skill package, SkillAPI, webui /api/v1/skills, status skills block
- ConfigRegistry: plugin config tables now created only via RegisterDef; arbitrary
  scope Set/Get no longer implicitly creates config_<name> tables (fixes stray
  config_today_task table from SKILL directory name being used as a scope)
2026-08-02 11:40:13 +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
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
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
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
3fc2151588 refactor: pluginize text cleaning and tool NoMemory control
- SDK: ToolDef.NoMemory field, PluginSDK.RegisterTextCleaner/TextCleaners
- Registry: aggregate text cleaners from plugins, expose CleanText()
- Memory: replace hardcoded QQ regex CleanTemplateText with dynamic CleanText/SetTextCleaner
- StageHost: add ToolDef(name) lookup
- eventloop: check ToolDef.NoMemory before emitMemoryCandidate
- context/Prune: replace hardcoded agentcli/terminal source filter with ToolsUsed NoMemory check
- agentcli/cmd: mark tools with NoMemory: true
- main.go: wire memory.SetTextCleaner(pluginReg.CleanText)
2026-07-24 14:49:08 +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
69ceedf0ab feat: register embedding_model_path in ConfigRegistry instead of JSON config
- Add core.agent.embedding_model_path to seedDBValues and seedCoreDefs
- Wire cfgReg.GetString in main.go to AgentConfig.EmbeddingModelPath
- Follow existing core.agent.* ConfigRegistry pattern
2026-07-17 21:07:54 +08:00
c7e22fbe30 refactor: move webui.listen_addr from core.daemon to webui category 2026-07-14 11:22:46 +08:00
950090959f feat: restructure plugin system, add Lua plugin support, update docs 2026-07-13 21:48:13 +08:00
1f1233b823 refactor: P0-P3 fixes, C1 cleanup, architecture diagrams, go.work upgrade
- P0-1: ProviderError type + ReportStatus for precise 401/403 detection
- P0-2: Remove -config flag from deploy/homeagent.service
- P2-1: 5s debounce on context.go Save()
- P2-2→C1: Delete output_set_channel entirely
- P2-3: Extract mediaDataURL/mediaChat helpers
- P2-4: Dedup defaultSources var
- P3: Delete dead packages (embed/tokenizer/container/snapshot)
- P3: Delete dead functions (messagesToMap, RunStageAll)
- CL: Update .gitignore, docs, Makefile, gojieba removal
- Config: Delete config/config.yaml, update docs
- Arch: Remove EmitOutputTo from emitResponse
- CL-1: go.work 1.19→1.21
- Docs: Add Mermaid architecture diagrams to README
- Docs: Add kernel-rebuild requires plugin-rebuild note to PLUGIN_DEV.md
2026-07-12 11:42:56 +08:00
eb55a8fb98 feat: expand local operator controls across CLI and WebUI
- Add structured CLI commands for status/kernel/settings/plugins/memory/knowledge/agents
- Inject core dependencies directly into CLI plugin for non-HTTP operator workflows
- Add plugin management panel and API proxy endpoints to WebUI
- Let cmd_run inherit default workdir from core.agent.workdir
- Use fixed loopback address for pluginmgr API
- Remove stale MaxToolTurns config usage from homed wiring
2026-07-06 20:32:04 +08:00
8cec92d947 feat: 路径配置化 + 裸二进制启动 + pluginmgr 内置插件
- types.go: 新增 PluginDirConfig 结构体嵌入 Config
- config/registry.go: 新增7个路径配置项 (core.plugin.dir 等) + ConfigDef 元数据
- cmd/homed/main.go: -data 默认自动检测二进制同级目录,使用 cfg.Plugin.Dir
- internal/plugins/pluginmgr/: 内置插件实现 (4工具 + HTTP API + 包校验)
- all.go: 注册 pluginmgr
- manifest.go: 扩展 PluginManifest 字段
- sdk/settings.go: RegisterDef / Defs 接口
- webui: 设置页自动发现 ConfigDef 元数据
- config/config.go, config/config.yaml: 清理 YAML 死代码
- sdk/plugin.go: IO 通道泛型化支持非文本类型
- waiter: CLI 支持 socket 发现和交互模式
2026-07-04 16:56:32 +08:00
c3816dc699 IO 抽象层增强:非文本输入支持 + waiter CLI 重写
PluginSDK:
- 添加 InjectInput / InjectInputSync / InjectInterrupt 泛型接口
- 插件现在可注入 image/audio/file 等任意类型输入

Provider:
- 添加 ContentBlock / ImageURL / AudioURL 类型
- Message 增加 Blocks 字段,Content 在非空 Blocks 时序列化为数组(多模态格式)

Agent:
- handleInput 新增 image/audio 类型分发 → processMediaInput
- processMediaInput 将媒体数据附着到对话上下文,LLM 自主决策处理策略
- 新增内置工具:describe_image / transcribe_audio / ocr_image(pendingMedia 驱动)
- 工具仅当有未处理媒体数据时注册,通过 Provider 直接调用多模态模型

Config:
- 新增 InputProcessingConfig(image/audio 处理配置)
- 含 fallback_provider / describe_prompt / ocr_enabled 等选项

Waiter CLI 重写:
- 配置文件 ~/.config/homeagent/cli.yaml(自动发现 socket)
- 原始终端行编辑 + 命令历史持久化 + 彩色输出
- 内置命令:/help /reconnect /connect /remote /local /prompt
- 断线自动重连
2026-07-04 15:01:35 +08:00
fab58e709a feat: complete P0/P1/P2 — WebUI SPA, OpenClaw sidecar+simulator, healthcheck auto-sched+perf
P0: WebUI重构
- 完整 SPA 仪表盘 (7标签页), //go:embed dashboard.html
P1: OpenClaw兼容 (三通道: SKILL.md / sidecar / simulator)
- Node.js 模拟进程统一加载任意 OpenClaw 插件
- JSON-RPC 2.0 over stdio 协议, go:embed 内嵌
P2: Healthcheck 优化
- 定时自动执行 (startAutoCheck, 30min)
- healthcheck_perf 性能监控工具

其他: agentcli/cmd 插件, integration_test, status.go,
      test_deepseek 清理, 多项 bug 修复
2026-07-04 12:51:32 +08:00
77e12f7329 fix: 网络检测增强 + Tracker changeset 清理
网络检测 (monitor.go):
- TCP 拨测 (8.8.8.8:53 / 1.1.1.1:53 / 208.67.222.222:53)
- 延迟阈值检测 (>5s 标记降级)
- DNS 多目标检测 (google/baidu/cloudflare)
- NetworkCheckResult 新增 TCPReachable + LatencyDegraded

Tracker:
- 新增 WithKeepChangesets / WithMaxChangesetAge 选项
- Init 时自动清理过期 changeset (默认保留100份/30天)
- 先按年龄裁剪,再按数量裁剪
2026-07-03 21:31:00 +08:00
068af0569c test: 补齐4个模块测试 + LLM 图质量评估 + 文件日志
补齐测试:
- pipeline_test.go: 29 个测试 (蒸馏/刷盘/加载/三连提取/工具函数)
- social_test.go: 11 个测试 (特质CRUD/社交关系/网络/安全 nil 守卫)
- text/memory_test.go: 20 个测试 (追加/回放/并发/旋转/清理/持久化)
- indexer_test.go: 15 个测试 (同步/上下文/召回过滤/关键词/工具定义)

图质量评估:
- reorgGraph 新增 evaluateGraphQuality 步骤
- 自动识别蒸馏噪音 (用户-提及/AI-回应) 和低 confidence 关系
- 通过 enqueueConsolidationTask 交由 LLM 逐条判断保留/删除

文件日志:
- 启动时创建 data/log/ 目录
- io.MultiWriter 同时输出到 stderr 和 homed_<时间>.log
2026-07-03 21:26:55 +08:00
6d1b6b15d6 fix: 三层记忆/知识库数据泄漏修复 + 系统提示词动态化
问题修复:
- distiller: Append 添加 memDB==nil 守卫,避免数据泄漏
- indexer: 启动时立即 Sync(),消除前30分钟空窗期
- 系统提示词: 移除硬编码的13项工具列表,改为动态分类说明
- doc_query: 消去 Query+Consume 重复搜索,改为 Consume 一次完成
- extractKeyTriples: 从原文 dump 改为规则提取(姓名/居住地/喜好/年龄/职业)
2026-07-03 20:55:51 +08:00
239a22899b fix: 模型思考模式配置 + Unicode 截断 + 审计修复 (13 files)
模型模式:
- 新增 LLMConfig/Source.ThinkingEnabled 配置,通过 ExtraBody
  控制 DeepSeek thinking mode,默认关闭
- SeedDefaults/ToConfig 读写 core.llm.thinking_enabled
- deepseek.lua 移除硬编码 temperature=0

Unicode 截断:
- truncateStr 改按 rune 计数,修复中文截断乱码

审计修复 (Critical):
- graph.go: defer rows.Close 在 for 循环 → 显式 Close (连接池泄漏)
- cli/openclaw/plugin.go: bare type assertion → comma-ok (panic)
- channel.go: payload["type"].(string) → comma-ok (panic)
- webui/handler.go: .(string) → fmt.Sprint (panic)
- agent.go: 添加 nil provider 错误返回

审计修复 (High):
- events/bus.go: copy handler slice under RLock (data race)
- webui/handler.go: SSE 通过 channel 串行化写入 (data race)
- timer/plugin.go: time.Sleep → select with stopCh (Stop 阻塞)
- provider.go: stream ch <- 添加 select ctx.Done (goroutine 泄漏)
- main.go: outputCh goroutine 添加 ctx.Done 退出路径
2026-07-03 20:46:04 +08:00
2d314b3e9c 重构: 插件自注册 + .so 动态加载 + 中断打断机制
- 所有内置插件 init() 自注册 (plugin.RegisterFactory), 移除 main.go 硬编码
- 新增 .so 动态加载器 (internal/plugin/dynamic.go), 插件可编译为 plugin.so
- 新增 plugin.json 元数据 (internal/plugin/manifest.go)
- 新增 interceptLoop 独立 goroutine:
  (a) cancelLLM() 取消进行中的 HTTP 请求
  (b) interceptCh → drainInterrupt() 注入 [打断消息] 到 LLM 上下文
  (c) InjectInput 空闲时触发新处理循环
- 新增 internal/plugins/all.go 空白导入触发所有内置插件 init()
- internal/sdk/ 作为 PluginSDK 正式 Go API
- internal/api/ → internal/plugins/webui/ 迁移
- 删除旧 cmd/cli/, 使用 cmd/waiter/ 替代
- 更新 PLAN.md / ARCHITECTURE.md / README.md 文档
2026-07-03 16:53:34 +08:00
4442c9cea4 适配多个 LLM 源 (anthropic/gemini/mistral/groq/github) + SQLite 配置收敛 + 测试插件 2026-07-03 14:03:51 +08:00
672b098c4e feat: WebUI settings page with sidebar + ConfigRegistry integration
- /api/v1/settings endpoint: GET (list by prefix) + PUT (set key/value)
- Config tab redesigned: left sidebar (core + per-plugin) + right editor
- Sidebar groups: core.* and plugin.<name>.* from plugin registry
- Each setting rendered as editable input with save button
- WebUI now receives cfgReg and pluginReg from main
- handler_test.go updated with new NewHandler signature
2026-07-03 08:39:30 +08:00
9c33b3b149 feat: ConfigRegistry + SettingsAPI for plugin config access
Core exposes a unified settings interface through Plugin SDK:
- internal/config/registry.go: thread-safe namespaced KV store
  - Register/Get/Set/List/Delete with JSON persistence
  - Flush() for explicit save to disk
- SettingsAPI in SDK: plugins call plugin.Settings().Get/Set/List
  - Full access: read/write any key (core.*, plugin.<name>.*)
- plugin.Registry.SetConfigRegistry() wires it into SDK plugins
- main.go registers core.* keys at startup, flushes on shutdown
- 7 tests for ConfigRegistry
2026-07-03 08:32:41 +08:00
3e3c6a24d2 v4 architecture: pipeline stages, SDK, event bus, LLM-driven memory consolidation
- SDK PluginAPI (internal/plugin/sdk/): RegisterTool/RegisterStage/Subscribe/Publish
- EventBus (internal/events/): system-level pub/sub with wildcard support
- StageHost (internal/agent/core/stages.go): 7-stage message pipeline
- Agent core: on_input/pre_action/post_action/before_toolcall/after_toolcall/before_output/after_output
- Plugin Registry: SDK plugin registration and tool routing
- GraphDB.MergeEntities: entity consolidation with relation redirection
- memory_merge tool: allows LLM to merge similar entities
- Consolidation task: heartbeat detects conflicts, enqueues via IO for LLM decision
- _consolidation_ internal channel for system-level memory maintenance
- Comprehensive documentation: ARCHITECTURE.md, PLAN.md, DESIGN.md, README.md
- 54 tests across all packages, all passing
2026-07-03 08:04:39 +08:00
304c3ae294 refactor: remove IO route mapping, add HTTP API tests, system prompt update 2026-07-02 15:47:16 +08:00
3d7d24ebb8 feat: add plgreload tool for atomic plugin reload
- Agent can now call plgreload to reload plugins/ directory
- Atomic swap: new devices Start → routes swapped → old devices Stop
- Output channel capability validation on output_send
- output_list_channels tool for channel discovery
- OneBot V11 protocol implementation (Reverse WebSocket)
- Plugin = container with embedded IO channel (composition)
- Unified ToolDef type (agentIO.ToolDef = plugin.ToolDef)
2026-07-02 12:26:41 +08:00
bc26850b50 feat: complete HomeAgent architecture v2
- IO abstraction layer with OutputChannel routing and capability validation
- Three-layer memory (Context-Document-Graph) with TF-IDF relevance pruning
- OneBot V11 QQ protocol plugin with Reverse WebSocket client
- Plugin system with hot-reload (SKILL.md + native factories)
- Knowledge system with TF-IDF vector indexing
- Personality system (personal.md)
- Text memory (JSONL with rotation)
- Change tracker (overlayfs) with rollback
- Lua adapter VM
- Design document (DESIGN.md)

Module: gitcode.com/JianFeeeee/HomeAgent
2026-07-02 12:04:36 +08:00