Commit Graph
15 Commits
Author SHA1 Message Date
AskaEth cb564fe981 fix(memory): 空 query 不再触发语义回退 + 回退有界(修真机 39 秒召回)
真因(agent-197,文件:行):只有附件的消息正文为空 ⇒ queryFromMessages 返回空串 ⇒
retrieve.go 的 vectorIndexScores 在问索引之前就 return ⇒ 上层分不清「没问过索引」与
「索引无命中」⇒ 打出误导的 no-candidate-hit ⇒ 转内存回退,把全库 302 条候选正文塞进
一个 embedding 请求(302 × 约 130ms = 39.3 秒,与实测 duration_ns 吻合)。
索引/维度/表/写入其实全是好的(PG vec_items 302 行全 dim=1024,与 SQLite 302 个 id 集合相同)。
修法:空/纯空白 query 整条语义路径跳过(不问索引、不 embed);回退改为有界
(分批 32 + 1 秒时间预算 + 正文到向量 FIFO 缓存 1024,不再每回合重算)。
文件:retrieve.go / retrieve_semantic.go + 新增 retrieve_fallback.go / retrieve_keyword.go /
retrieve_fallback_test.go(retrieve.go 曾达 501 行,按 ≤500 拆分)。
变异:去掉空 query 门 ⇒ 向量化 43 条文本(want 0);整库单请求 ⇒ 69 条超上限 32;停用缓存 ⇒ 重复嵌入。
2026-10-05 08:04:47 +08:00
AskaEth fbad02899a fix(memory,loop,capacity): 打通记忆链三条空壳(P0-3 / P0-4 / P0-17,审计 §4.3)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- P0-3 持久向量索引**不再空壳**:Store.Add 落库后真做 Embed+Add(失败只记日志、绝不让记忆写入失败);
  NewRetriever 拿到 WithVectorIndex 时**自动接上写入路径**(无需改组合根);索引无命中 → WARN + **回退内存余弦**;
  新增每进程一次的**回填**(索引确实为空时把已落库条目向量化,分批 64、上限 512)
- P0-4 工作记忆**按会话接线**:回合落定时写入(owner 会话 + 带会话 id 的窗口,LRU 上限 64),
  组装上下文时按会话读取 ⇒ 前导块真的出现;原单窗口 API 语义不变
- P0-17 L4 学习回环**真回写**:新增 capacity.Judge(只跑判定、不施人格覆盖/不发事件/不改状态);
  loop 在回合落定"只写 owner 会话 + 跳过子代理分支",写 ScopeUser(L4 的读域)+ 结构化溯源
- 顺带红线加固:意图记录是主人**原话**的机器可读形态 ⇒ **绝不注入群聊/陌生人块**(design/03 §5)
- 复核:三条各自的包 build/vet/test 绿;「真生效」断言含生产构造路径(vector.New + 真实 SQLite 后端 +
  n-gram embedder)、跑完一轮窗口非空、L4 回写后能唤醒一个自身无强信号的表达;
  **5 条变异反证**(其中两条专门打「受限会话零写入」与「群聊不泄露主人原话」)均已还原
- 未做(登记):Index.Search 无 ID 过滤(客户端按候选集过滤,极端情况走回退);每条记忆一次 Embed
2026-10-04 14:20:22 +08:00
AskaEth 61cf80d5ee docs(comments): 注释中文化 · internal/runtime/memory(31 文件,纯替换)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 只翻注释/文档字符串:820 增 / 820 删 严格 1:1;剥掉整行注释与行尾注释尾巴后,
  逐文件与 HEAD 比对「代码部分差异 = 0」;裁决/design 编号计数逐项与 HEAD 一致
- 保留可执行 SQL 样例、SQLite 报错原文、pgvector/HNSW/ANN/BLOB 等技术词原文
- 复核:go build 绿 + memory/projectindex/vector 三包测试绿;gofmt 仅剩 2 个既有未格式化文件(改动前即如此,未顺手修)
2026-10-04 13:32:54 +08:00
AskaEth 0ce498754a fix(memory,loop): 记忆作用域读写成对 + source_conversation 结构化(裁决 1.9/04.4.2/04.4.3)
- 04.4.2/1.9 读侧:Retrieve 候选集并集 = 本人 persona 域 ∪ user 共享域 ∪ project 共享域(他角色 persona 域仍排除),群聊/陌生人取受限收窄
- 写侧:群聊/陌生人整段跳过记忆提取(可查不可写),persona 域仅属主可写
- 04.4.3:source_conversation 不再由 LLM 自由生成(prompt 不索要、候选结构不含该键),落库时无条件盖真实 {session_id,message_id},编解码集中在 memory/source.go
- 新增跨角色种子用例(原用例即使关掉并集也会通过)+ 成对用例「同群聊上下文:读得到共享域、写不进 store」
- 同步 store.go/retrieve.go 文档注释,与 design/03 §3/§4 口径一致
2026-10-04 12:07:44 +08:00
AskaEth 0624d9ee36 feat(session,runtime): 多角色并存—按会话选角(迁移0011 + 按回合解析 + agent池 + 提取器修正)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
按 DevDocs/design/22 批次 1 后端(§2/§3/§4.1-4.5/§4.7/§5 验收 1-6)。
- 迁移 0011:chat_sessions.persona_id + chat_messages.persona_id(均 DEFAULT '',无回填 → 升级零风险);同步包内幂等 DDL;**真实库升级验证**(拷贝 data/cyrene.db 到临时目录跑 MigrateUp:既有 1 会话/109 消息 persona 仍为 '',原库未被触碰)
- history:SessionMeta/Message 加 PersonaID + SetSessionPersona;ListSessions/List/scan/Append 带上
- runtime:SessionEnv.PersonaID + loop.personaFor(ctx) 替换固定 l.personaID(memory/request/turn)+ **agent 池**(Options.Agents,按角色取 instructions,未命中回落)+ **提取器不再把 persona 烤死在构造期**(多角色下记忆不再永远记在 cyrene 名下)+ **thinking 旋钮改为按会话角色解析**(否则角色 Y 会用角色 X 的预算/展示)
- gateway:会话 DTO/POST/PATCH 支持 personaId;ws/rest/voice 的 OwnerEnv 硬编改为**按会话解析角色**(actor 元数据语义不变);admin memories 搜索去掉硬编 cyrene
- Docs/api-client v0.42;**两处有意的行为收紧**已写明:POST /sessions body 非法 JSON → 400(原先完全忽略 body;空/null/{} 仍 201);POST /admin/memories/search 省略 personaId 且无默认角色 → 400(原先默认查 cyrene)
- 测试:design/22 §5 验收 1-6(记忆隔离/提示词首条 system/情绪按角色/提取 persona 归属/迁移兼容)+ 进程内 e2e(断言 adapter 收到的 model.Request.Messages[0] 即该角色的 systemPrompt)
- **已知未做(留批次 2 / 待确认)**:① IM 与渠道级未做 → **§7-3「owner 私聊镜像随主会话角色」尚未生效**;② 请求级覆盖未实现(本批只做会话级);③ **§7-5 的「上下文发送角色标记」只完成存储+DTO 半边**——消息 persona 已落库且 DTO 已带,但模型上下文不从 chat_messages 重建,「第 N 条是谁说的」尚未进上下文(需确认是否属批次 2);④「切角色重建摘要」当前是空操作(压缩未接线);⑤ thinking 旋钮仅在流式路径生效(非流式 agent.RunStep 不带,A 批次既有性质)
- 验收:go build/vet/test 全绿 + linux/amd64 与 darwin/arm64 交叉编译(既有 flake 本轮未触发;同批 session_orchestrator.go 一度 501 行 → 抽出 session_tail.go)
2026-10-03 20:12:29 +08:00
AskaEth 31086ed1ab fix(memory): 定宽时间戳存储 + rowid 确定性排序 + 遗留数据归一化
- formatTime 改用固定 30 字节布局(9 位小数秒),让 TEXT 列的字典序与时间序一致(RFC3339Nano 会去掉尾随零产生变宽字符串,秒内会反序)
- memory_items / project / project_chapter 的 ORDER BY 全部补 rowid 兜底,消除同 tick 打平时的顺序不确定
- 开库时幂等归一化变宽的历史值;无法解析的行原样保留,不阻塞开库
- 回归测试:变宽排序反例、同一时间戳插入序、归一化幂等与跳过
2026-10-03 16:08:50 +08:00
Aska dbcf3df8a3 feat: RAG 知识库真实数据 + 渠道端到端接线(并行∦wire.go)+ 主会话收口
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
【渠道端到端·接线(agent-72)】
- 新建 internal/services/channelbridge/:桥接服务(Start 对配置渠道 Connect(10s超时/warn)+SetMessageHandler+ReadMessages;
  入站 UnifiedMessage→sessions.GetOrCreate(ResolveActor 白名单结构性识别)→loop.Run→SendMessage 回执,chat 文本)。
- cmd/cyrene/channels.go:从 CHANNEL_* env 读 4 渠道凭据(telegram/qq_obv11/weixin_ilink/webhook)。
- wire.go:app 加 channelBridge 字段,wireChannels 构造适配器+bridge.Start(),close() 收尾。
- 无真凭据降级:无 CHANNEL_* → configured()false 跳过不 dial;Connect 失败 Warn 不阻启动;
  webhook 仅入站(回执 ErrUnsupported 记 debug)。身份识别绝不靠提示词。收发端到端待凭据验证。

【RAG 知识库(agent-71)】
- internal/runtime/knowledge/:真实数据源(doc=资料/记忆=经历 分离 design/03 §3③)。
  ListDocuments 走 projectindex.ListProjects(+ListChapters)、Search 走 projectindex.Search(标题/描述+章节
  命中行+上下文)+retriever.Retrieve(配 vector 真语义,命中标 semantic:true)。
- gateway/server.go:RagStore 接口+Deps.RAG 可空+3 路由(GET /admin/rag、POST /admin/rag/query、/delete)。
- admin.go:adminListRag/adminSearchRag(空 query 400)/adminDeleteRag(写 501 not_implemented,M10)。
- projectindex/store.go:ListProjects/ListChapters。
- 前端 Rag.tsx:docs 从 GET /admin/rag 拉、检索走 POST /admin/rag/query、删除调真端点(501 显示 Notice),
  上传/分块/嵌入显示 M10 Notice;api.ts/types.ts 加 adminListRag/adminSearchRag/adminDeleteRag。

【主会话收口 wire.go】projStore 提到 app struct+wireMemory 赋值;knowledge.New(...) 注入 gateway.Deps.RAG。

实机验证:admin/rag 200(documents[] 空表非壳)、channels 枚举 4 渠道、health ok。
go build/vet/test 全绿 + 前端 tsc。wire.go 567 行。

遗留(记录):① 群聊/陌生人 MemWritable 记忆隔离未接 loop(AGENTS.md 红线,待修) ② webhook InboundHandler
需 gateway 挂载 ③ RAG 语义路径 persona-scoped(project 记忆其他 persona 不浮现)。
2026-09-06 20:09:09 +08:00
Aska 24d5924cee feat(model): Top5#1 结构化流事件 + WS 事件体系(对齐 OpenClaw AssistantMessageEvent)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 新增 model/stream.go:StreamKind(text/thinking/tool_call 各 start/delta/end + tool_execution)
  + StreamEvent{Kind,Delta,Index,ID}。
- ChatStream 签名 onChunk func(delta string)→onEvent func(StreamEvent);loop OnStream 同改;
  streamStep 转发结构化事件。
- openai:text_delta + text_start/text_end(正文三段式);anthropic:文本块 text_*/tool_call_*
  按块 Index(content_block_stop 分支)真分段;fallback:有事件即交付。
- ws_hub:wsEvent 壳补 turnId/seq;新增 broadcastStream;streamChat 每帧打 turnId+seq;
  stream.go 把事件 publish 到 bus ws.stream。
- ws_bridge:streamEventData 映射 text_*→message.start/delta/end、thinking_*→thinking.*、
  tool_call_*→tool_call.*、tool_execution_update→tool_execution.update,未知回退 stream_chunk。
- 前端 ws.ts:解析 message.start/delta/end、thinking.start/delta/end(pendingThinking)、
  tool_call.start/end→addTool、tool_execution.update;保留旧 stream_chunk/thinking/tool_used 兼容;
  types.ts 补 turnId/seq。Docs/api-client.md 增 §3.1 v0.4。

已知限制(注释/文档标注):turnId 在 OnStream→bus→relay 路径暂为空(StreamEvent 无 turnId 字段,
bus ws.stream 载荷不带 turn);OpenAI adapter 未解析 tool_call 段;thinking 段两 adapter 暂不发;
tool_execution.update 是保留项(随工具循环钩子后置)。go build/vet/test + 前端 tsc 全绿。
2026-09-06 16:31:28 +08:00
Aska 04bfa2c7a7 feat(gateway): admin 列表端点接真实数据——persona/session/memory 补 List() 并注入 gateway.Deps
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
根因:gateway.Server 定义 SessionStore/PersonaStore/MemoryStore 接口但生产从未满足:
- 底层 manager 无 List() 方法;
- wireFrontend 的 gateway.Deps{} 未传 Session/Personas/Memories。
→ /api/v1/sessions|personas 与 /api/v1/admin/{sessions,personas,memories} 恒返回 []。

改动:
- persona/registry:Registry.List() []Character(并发安全、值拷贝)。
- channel/session:SessionManager.List(ctx)(查 channel_sessions 表+按 actor_role 重建)。
- runtime/memory:Store.List(ctx)(全表,复用 scanItems)。
- gateway 三 Store 接口改为返回域类型(Character/MemoryItem),映射统一放 collect* 侧。
- cmd/cyrene/wire.go:Deps 补传 Session/Personas/Memories。
- .gitignore:cyrene→/cyrene(锚定根,不再误伤 cmd/cyrene 目录)。

实机验证:/api/v1/admin/personas 返回 {id:cyrene,name:昔涟,isDefault:true}。
2026-09-06 14:05:34 +08:00
Aska 6ea5affc8a test(vector): mock 对 dim<=0 不再除零(保持 dim0→ErrInvalidDim 意图) 2026-09-06 11:31:17 +08:00
Aska 111ad598be fix(vector): New 在 embedder 维度未知(API 首请求前为0)时先 probe 一次学真实维度,避免 PG 向量索引 fallback 2026-09-06 11:30:26 +08:00
Aska d947ec41a9 feat(memory): M4 记忆完善(三类作用域访问规则+项目索引分层+LLM异步提取+衰减溯源+向量接入,兼容既有57用例) 2026-09-06 06:15:18 +08:00
Aska fb880572a4 feat(memory/vector): 向量检索引擎(SQLite BLOB 内积默认 + PG pgvector 真语义增强,配置后真生效) 2026-09-06 06:04:44 +08:00
Aska ef79edd96a feat(memory/projectindex): 项目索引分层(索引+描述+章节,Search 定位行+上下文,级联删除) 2026-09-06 06:01:20 +08:00
Aska aa697c385f feat(memory): 长记忆 store(SQLite+persona 隔离)/工作记忆滑动窗口/检索注入/手工提取钩子 2026-09-06 05:12:42 +08:00