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
4ef3371701
test(memory): 媒体存储的压力、冒烟与长稳测试
...
在 a822674 的 CAS 层之上补齐三类验证。
## 压力测试(stress_test.go,9 例)
核心不是吞吐数字,而是并发下的不变量。为此写了 checkRefIntegrity:
用 SQL 对比每个 digest 的 ref_count 与 media_refs 实际行数。这条对不上
就意味着 GC 的判断依据是错的——计数偏低会误删有引用的内容,虚高会让
孤儿永远清不掉。所有并发用例收尾都验它。
- 32 goroutine 并发 Put 同一内容 → digest 一致、磁盘只 1 份
- 400 个不同内容并发入库 → 无丢条目、逐条回读无内容串位
- 24 worker × 40 轮引用增删风暴(含故意重复 AddRef 验并发下的幂等)
- GC 与读写并发 1.5s → 实测 11508 次 Put / 604 轮 GC,受保护内容零失败
- Describe 与 Search/Pending 并发 → 无 database is locked
- 容量上限持续加压 → 上限 256KB 收尾 98KB,有引用项全存活
- 重度 churn 后重开 → 磁盘文件数 == 元数据条数,无双向孤儿
- 4MB 单文件往返(see_video 10 帧 × 2MB 是现实上限附近)
- data URL 往返 ×50(SetToolBlocks 给出的实际形态)
-race -count=3 干净。
## 冒烟测试(smoke_test.go,6 场景)
走真实数据路径:真 PNG(自建 IHDR/IDAT/IEND + zlib)、真 data URL、
真 sha256、真 GC、真重启,而不是随机字节。
- 同一张截图连问 5 轮 → 磁盘 1 份、5 个 context 引用
- see_video 6 帧内容各异 → 各存一份、共享一个 owner
- 描述落库后按关键词检索命中(方案 C 最关键的一环:blob 可被淘汰,
描述会长期留在记忆里)
- L0→L2 归档时引用从 context owner 转到 document owner,期间内容可读
- 别的工具留下的一次性图被 GC 清掉,被记忆引用的一个不少
- 全生命周期跨重启:描述、引用、内容、磁盘一致性全部完好
第一次跑挂在「6 帧只搜到 5 条」,看着像存储丢帧,实际是夹具的
palette[(variant+y*3/h)%5] 只有 5 色,variant=0 与 5 产出逐字节相同的
PNG,被 CAS 正确去重。已把 variant 写进像素保证帧间真不同,并把这段
经过记进注释——误报本身证明了去重在工作,也证明冒烟确实有能力发现
「帧数对不上」这类问题。
冒烟原先是 internal/memory/media/smoke/ 下带 //go:build smoke 的独立
main,得记着加 -tags smoke 才跑得到,那种早晚被忘掉。已搬成普通测试,
随 go test ./... 一起跑,冒烟的意义才真正成立。
## 长稳测试(soak_test.go,-short 下跳过)
60 秒五路混合负载。实测:put=281885 get=1644084 gc=9142
describe=53875 search=23268 refOps=187926,零失败。收尾 20 个受保护项
内容字节一致、ref_count 全为 1;8MB 上限下实际占用 139KB / 48 条,
说明 28 万次写入产生的孤儿被持续清理,无无界增长。
描述者从 Pending() 取项再 Describe(),GC 随时可能在这两步之间清掉它。
这是正常竞态,故忽略 unknown digest 并注明原因;5 万多次调用没把它
升级成计数错位,印证了 Describe 对已删项返回错误而非静默建条目的选择。
全仓 go build / go vet / go test 通过,SDK 接口冻结 diff 为 0。
2026-09-04 11:29:18 +08:00
a82267484a
feat(memory): 内容寻址媒体存储(CAS)——图记忆支持二进制多媒体节点的底座
...
此前四层记忆全是纯文本载体,没有任何一层能存二进制:
L0 ContextEvent — Input/Response/ToolResults[].Output 全 string
L1 text.Event — 同上
L2 document.Doc — Summary/Content/Tags 全 string
L3 图库 — sentences.text TEXT UNIQUE,节点身份就是那串文本
于是 multimodal 插件注入的图只在本轮对话内可见(走 message 数组,不经
记忆),下一轮起只剩 ToolResultItem.Output 里那句
"[已将图片注入后续对话] /tmp/x.png"——一条路径字符串。那个文件被删或
被覆盖之后连线索都断了。
## 为何内容寻址而不是存路径
- 路径会失效。/tmp 下的探针图、下载缓存、别的进程的临时产物,记忆里
留个路径等于留个悬空指针。
- 同一内容常被反复注入(连问几轮同一张截图、see_video 相邻帧高度相似),
按 sha256 寻址天然去重。
- 内容即身份,与 L3 图库 sentences.text UNIQUE 思路一致:文本节点用文本
本身做身份,媒体节点用内容摘要做身份。
## 结构
元数据(SQLite media.db)与内容(磁盘 blobs/ 两级前缀分桶)分离,不把
blob 塞进库:单张图动辄几 MB,塞进去让每次 VACUUM/备份都拖着几百 MB 走,
WAL 也会迅速膨胀。
media(digest PK, kind, mime, size, width, height, origin_path, tool,
description, described_by, ref_count, first_seen, last_seen)
media_refs(digest, owner_kind, owner_id, created_at, PK 三列)
digest 既是主键也是文件名,所以没有 Path 字段——路径由 digest 推导,
不落库(落了就又是个会失效的引用)。origin_path 仅供人类溯源,注释里
明确标注不可用于读取。owner_kind 预留 context/document/graph_sentence。
## 几处刻意的决定
- Get 强制校验 digest:CAS 的全部保证建立在「文件名 == 内容摘要」上,
位翻转或外部误改必须被发现——把损坏的图喂给模型只会得到无从追溯的幻觉。
- 先写 .tmp 再 rename:中途崩溃不留半个 blob 被当成完整内容读走。
- AddRef 幂等:只有真插进 media_refs 才递增,否则计数虚高会让 GC 永远
不敢清。DropRef 用 MAX(0,...) 兜底防负数。
- Put 的空描述不冲掉已有描述(先到的可能来自更强的模型),但尺寸/工具名
这类前一次缺失的信息会被补写。Describe 是显式操作,允许覆盖。
- GC 两段 + minAge 保护:刚 Put 还没 AddRef 的项 refcount 也是 0,minAge
防「落地后还没挂上就被清掉」。有引用的项永不删除,即使超容量——宁可
超限也不断引用。
## 测试
21 例,覆盖去重 / MIME 归类 / 损坏检测 / 无残留临时文件 / AddRef 幂等 /
计数不为负 / DropOwner / GC 保留有引用项 / minAge 保护 / 容量淘汰 /
描述覆盖与补写策略 / Search 按描述与 kind 过滤 / Pending / data URL
往返 / Stats / 跨重启持久化。
本 commit 只加存储层,尚未接入 L0/L2/L3 与描述生成。
2026-09-04 11:03:36 +08:00
147d0baaf9
fix: LLM 工具循环 400、中断消息注入、ConPTY 终端支持
...
- agent: 工具轮请求尾部补 user 占位(zen 网关强制),tool 消息正确配对
- agent: 工具提醒/中断以 system 角色注入并带 [中断消息] 前缀,不进用户履历;系统提示词说明中断消息格式
- agentcli: 基于 ConPTY 的交互式终端(ptywin fork),terminal_create/read/write/resize/close/watch
- webui: server 输出通道适配器(保留 reasoning_content/disable_thinking)
- GUI: 沉浸式标题栏、icon 圆角重制、mascot 等打磨
2026-08-14 00:48:40 +08:00
9d5a914941
Phase 0.1/1/3/6: 核心生产问题修复
...
Healthcheck 隔离 (Phase 0.1):
- 新增 internal/sdk/selftest.go: VirtualInstance 完全隔离自检空间
- PluginSDK.Selftest()/SelftestReset() 暴露隔离实例 (含 mutex)
- LLM 自检只读白名单 isSafeReadonlyTool 防写类工具污染生产
- 单测验证: healthcheck 后生产实例内容不变 + 无残留
- 存量清理: 删除 gotest/luatest 残留目录
GraphDB 去重 (Phase 1):
- migrateRelationUnique: 启动自动重建 relations 表加 UNIQUE 约束并去重
- Commit 改为存在性检查, 重复三元组仅刷新 confidence 不重复插入
- 3 个 dedup 单测全绿
配置时长解析 (Phase 3):
- parseDurationExtended 支持 2d/1w/3h 等人类可读单位
- GetDuration 全局生效, 防 2d 静默回退 30m
Agentcli 通知风暴治理 (Phase 6):
- 语义通知: 累积 notify_bytes(2KB) 或间隔 notify_interval(2s) 触发
- 生命周期即时通知: 启动/进程退出/EOF 立即通知
- 可配置 settings, 保留通知机制保证 agent 感知终端存在
- 运维止血: 已杀掉幽灵 PID 3716282 (bash git sparse clone 运行 16h)
Plan.md: 新增设计意图备忘(插件即App/分层记忆), 更新各 Phase 进度
2026-08-12 13:51:40 +08:00
19410b0e26
蒸馏嵌入接线:Distiller/Agent 注入共享 embedder,修复配置缺失时蒸馏零产出
2026-08-05 09:59:33 +08:00
c6ebbfca34
memory 测试自包含:合成 word2vec 模型替代 /tmp 大模型依赖,测试不再联网下载 fastText
2026-08-05 09:59:30 +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
51f190e0b6
core: pass ReasoningContent to assistant messages in process.go
...
- process.go: attach resp.ReasoningContent when building assistant messages
- deepseek.lua v2.1.0: remove last_reasoning closure hack; rely on
core-provided reasoning_content in messages
- openai.lua: strip reasoning_content from messages in transform_request
(not supported by OpenAI API)
2026-07-28 17:07: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
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
d19b7bd13e
fix: 修复记忆系统自循环与计算层污染
...
- 删 syncGraphToDocs(): Graph 快照不再写入 Document,避免污染向量索引和三层隔离
- 删 toolCallRing(): 已被工具 NoMemory/Cleaner 机制取代,不再需要独立环形缓冲
- 加 toolOutputClean 回调线程 Prune→ContextToDoc: 归档时按 NoMemory 跳过、Cleaner 清洗后再过 jieba,原文保留
- 加 eval_status 持久化 (RecallPending/UpdateEvalStatus/ResolveEvaluating): 避免重复 LLM 评估
2026-07-26 19:36:25 +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
4495447b85
fix(document memory): dedup graph sync, filter terminal output from archive, add min relevance threshold
2026-07-19 14:21:04 +08:00
8ae1d19869
refactor: output channel interface (payload/meta/type) + memory fixes
...
- Redesign output_send__ tools: content JSON string -> structured
payload/meta/type params for LLM reliability
- executeOutputSendTool: route by type with capability check
- executeOutputSendHelp: show meta format + type enum
- Updated system prompt rules for new interface
- docToTriples: use jieba exact mode adjacent co-occurrence
- Unify vector space: Doc.Vector field, ContextToDoc vectorizer,
ReindexWithVectorizer on startup
2026-07-19 10:29:21 +08:00
7892d7b0f2
feat: multi-language embedding with CleanTemplateText + three-branch vector strategy
...
- StaticEmbedder: pre-trained ConceptNet Numberbatch/fastText word embeddings,
auto-download with TF-IDF fallback, comma-separated multi-model paths
- CleanTemplateText: regex stripping of QQ tool call templates and noise
- textForVector: per-source vector strategy (agent→Response, user→Input,
cold_storage→both)
- Indexer.BuildContext and ExtractKeywords now clean input before vectorization
- Protect recent 10 events in Prune (regression fix: use local var not const)
2026-07-17 21:02:35 +08:00
7f28b997e6
feat: output channel redesign - per-channel output gates, LLM chain events, SDKConfig
...
- Output channels generate per-channel tools: output_send__{name} (type=output) + output_send__{name}_help
- content is JSON string transparently passed to plugin handler for routing
- EventAgentLLMChain: full LLM response forwarded after each turn for webui/logs
- sdk.New refactored to SDKConfig struct (no more 13 positional args)
- RegisterOutputChannel adds desc param for JSON format documentation
- channelDevice simplified (no Tools method), desc field added
- Child agent permission updated for output_send__ prefix
- System prompt: output gates, multi-call, long messages split
- WebUI: subscribes to EventAgentLLMChain in SSE, no output channel
- Tests updated for new naming convention
2026-07-16 12:11:16 +08:00
fa91b24460
refactor: switch from modernc/sqlite back to mattn/go-sqlite3 (CGo)
2026-07-14 11:43:59 +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
2edc039351
fix: correct context pruning order and vector alignment
...
- Prune context BEFORE processing (LSTM forget gate pattern)
so LLM only sees relevant context, instead of pruning after the fact
- Fix ensureTrained() to recompute all event vectors after retraining
vectorizer, fixing feature-space mismatch between stored vectors and
query vector that made relevance scoring effectively random
- Add read lock to knowledge BuildTree() (data race fix)
- Log writeIndex() errors instead of discarding them
- Fix TOCTOU race in document ContextToDoc() dedup
- Fix healthcheck timing (measure elapsed before cleanup)
- Refactor waiter CLI into separate files (state, conn, config, editor,
history, builtin) for maintainability
- Add CLI plugin API key authentication
2026-07-07 17:07:38 +08:00
b55f1dcf0e
fix: cap distiller startup scan and switch to formal SDK module dependency
...
- replace vendored third_party/homeagent-sdk with formal module dependency
- keep canonical SDK via go.mod pinned commit
- optimize distiller startup loading to stream recent raw records only
- parse timestamps correctly and cap startup load to 5000 records
- remove quadratic string building in raw record parsing
- restore fast startup while preserving memory pipeline
2026-07-06 20:18:13 +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
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
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