AskaEth
|
3dc1232bc2
|
docs(comments): 注释中文化 · internal/runtime/model + internal/services/backthink(54 文件,纯替换)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 只翻注释/文档字符串:`go/scanner` 剥注释后按 token 序列+literal 逐 token 比对,**54/54 文件 SAME**;
改动文件总行数与 HEAD 漂移 = 0(严格 1:1,无合并/拆行)
- 裁决编号与 design 节号逐字保留(03.4.1/03.4.2/03.4.3/14.4.1/14.4.5/07.4.2-4、design/04 §3.1/§3.2 等);
`chat_template_kwargs` / `enable_thinking` / `reasoning_effort` / `thinking:{type}` 字段名与形状说明未动
- 存疑译法(已登记):`persona` 在叙事语境用「角色」、标识符语境保留 `persona`(仓库既有模块本身混用);
`rung`→「级」;`provider` 存在「提供商/提供者」两种落笔(可按需一键统一)
- 复核:build/vet 绿 + 两包测试绿;gofmt 干净;残留英文注释 0 条
- 既有存量(未修,只报告):`model/anthropic_test.go` 612 行 >500;`applyAnthropicEvent` 115 行 >80
|
2026-10-04 16:27:54 +08:00 |
|
AskaEth
|
f5cf117482
|
refactor(gateway): 图片上限单一真源 —— 以 vision 硬顶为准,配置只能收紧(消除「网关照放、vision 拒」)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 原状:网关与 vision 各有一份同值常量,且网关上限可由 CHAT_IMAGE_MAX_BYTES 调大 ⇒ 调大后
**网关照放、vision 拒绝**(ErrImageTooLarge),base64/URL 路径上「调大配置」失效
- 修法:网关改为**引用 vision 的常量**(`vision.MaxInlineImageBytes` / `InlineImagePrefixAllowance` /
`MaxInlineImageChars`,import 方向与既有的 voice 同层、不违规);`chatImageLimitBytes` 语义=
「configured 生效但**钳在 vision 硬顶**」(只收紧不放宽);默认口径直接用 vision 常量(不再自算)
- 复核:gateway 包测试绿(9 条 ChatImage,含默认逐字节同值、配 1 MiB 生效、配 8 MiB 被钳到硬顶且
同一串在 vision 侧也 ErrImageTooLarge ⇒ 两侧同一答案);**变异两点**(去掉钳位分支 → 断言红;
再清空解析循环 → 实测复现「配 2× 硬顶时网关 200 放行」)均已还原
- 登记:真要支持 > 5 MiB 需给 vision 可注入上限(并把 /upload 的 5 MiB 一起改);`.env.example`/`config.go`
注释/`api-reference` 仍写「上限=CHAT_IMAGE_MAX_BYTES」未提钳位,待同步
|
2026-10-04 16:27:35 +08:00 |
|
AskaEth
|
e64ea0b156
|
fix(vision): SSRF 三层守卫 + base64 长度预检(纵深防御,F3/G3 的收尾)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- SSRF 三层:① 字面主机判定(**链路本地** `169.254.0.0/16`/`fe80::/10`(先 Unmap ⇒ `::ffff:169.254.169.254`
绕不过)+ 云元数据 `100.100.100.200`、`fd00:ec2::/64`);② 重定向逐跳校验 + 上限 5 跳;
③ **建连前校验解析结果并用校验过的 IP 直连**(防 DNS 重绑,拨号器不再二次解析)
- **没打断同源自取**(两条独立证据):`127.0.0.1:<port>/api/v1/files/<32hex>.png` 端到端取回成功、
私网地址**原样交给底层拨号器**;被拒地址则底层拨号器 0 次调用(无真实连接发出)
- 失败文案**不含 URL/查询串签名**;非图片响应仍 `ErrNotImage` 且不泄漏响应体
- base64 路径长度预检(**先于 DecodeString 与 `data:` 短路**,零分配):口径与网关同值同推导
(`((5MiB+2)/3)*4+64`),超限 `ErrImageTooLarge`、文案只含上限与本次长度
- 复核:vision 包 build/vet/测试绿(15 条新用例);**4 条变异反证**(守卫整体短路 → 8 条被拒地址全中;
只短路链路本地分支 → 4 红且实测「无守卫时进程真的去连 169.254.169.254」;预检恒 nil → 3 红;
去掉重定向校验仍全绿 ⇒ 证明第三层独立兜住)
- 登记:`CHAT_IMAGE_MAX_BYTES` 调大 > 默认时「网关照放、vision 拒」的配置耦合(待单一真源对齐)
|
2026-10-04 16:24:56 +08:00 |
|
AskaEth
|
c96a7db7f1
|
feat(gateway,config,web,docs): backthink 实时帧显示打扰原因 + 图片上限可配 + api-reference 端点表补齐
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 前端:`lib/wsParse.ts` 的 `parseBackthinkItem` 现在也读原始 `PushResult` 的 route/detail/bypassed(兼容
camelCase),与历史 DTO 路径**同名同义**(空串 → undefined、未报告的 bool 不编成 false);
Backthink 页 Notice 改为如实描述。证据=用后端两条路径的**真实序列化**喂同一个 PushResult 做逐字段比对
- 图片上限可配:`CHAT_IMAGE_MAX_BYTES`(默认 5242880 = 与 /upload 同口径;**未配置/0/负 一律用默认**,
不存在「禁用上限」);删掉重复的字符常量,换算只留一份 `chatImageCharsFor`;补 3 条用例
(默认值==upload 预算、配 1 MiB 真生效且只有合法那条驱动回合、非正值回落默认)
- `Docs/api-reference.md`:§1 端点表按 `routes.go` **补齐**(auth refresh/logout、upload、files、三支 audio、
/admin/plugins/installed、/admin/llm/catalog、observability/logs、notifications、owner-profile、reminders),
既有编号一律未动(保交叉引用);两张 `historyMessage` 字段表补 `personaId`(+ `clientMsgId`);
修正 §8.1「主人档案保存仍 501」与实现不符(已真实实现)
- 复核:build/vet 绿 + gateway/config 包测试绿 + 前端 tsc 0 错 + vite build 成功
- 登记:§1 各表的编号跨表重复(不重编号以保交叉引用);`admin_plugins.go:217` 注释写错鉴权档(未改);
§6.4 的 WS 事件帧表仍未补全
|
2026-10-04 16:24:36 +08:00 |
|
AskaEth
|
9b01efd796
|
fix(loop): checkpoint 恢复加自洽性判据(纵深防御,堵「旧窗口吞新消息」的最后一层)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 背景:`loadCheckpoint` 恢复时会**整段替换**调用方带来的消息 ⇒ 任何「收尾落定前发起下一回合」的路径都会吞掉
用户刚发的消息。已有两层防护(收尾 defer 只让 tool_calls 可恢复 + 网关回合围栏),本次补 loop 侧判据
- 判据(保守版):**只有在能证明「窗口已被取代」时才改判**——快照窗口的最后一条用户消息**确实出现在本回合
带来的消息里**(说明同一对话谱系),且本回合的最后一条用户消息 ≠ 它(说明带来了更新的输入)⇒ 不恢复、全新回合。
判不出来一律维持既有崩溃语义(fail-open 落在「保留崩溃恢复」一侧)
- 比对键=文本与图片引用按序拼接(纯图片消息也可区分,避免「刚发的一张图」被判成空键而漏判)
- 复核:`internal/runtime/loop` 的 `-count=1`/`-race`/`-shuffle=on` 全绿;**未动任何既有崩溃用例**;
新增 4 条用例/9 条子用例(一致→仍恢复 / 有取代证据→不恢复且不含旧窗口 / 与网关围栏两条路径结论一致 /
边界表含重复播种·纯图片·无交集);**变异两点**(判据恒假 → 4 处红;恒真 → 10 处红,精确打红崩溃用例)
- 待主人拍板(已登记):字面版判据(无交集也改判)会与「崩溃 + 用户随后发不相关新消息」的既有语义冲突;
更彻底的选项是「**恢复旧窗口并追加新消息**(union 而非替换)」——需改那条用例与设计口径
|
2026-10-04 16:21:20 +08:00 |
|
AskaEth
|
3d8822c922
|
feat(loop,gateway): 13.4.5 目标态 —— 回合内 steer(不打断、新消息进同一上下文流)+ steer_ack 帧
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
规格=design/15 末尾「13.4.5 目标态规格」(不变量 I1/I2/I3)。调研依据:豆包无公开技术文档(不编造);
同类成熟 Agent 产品无一做同会话并行回合,共同范式= queue + 回合内 steer(Claude Code / Cline PR #13958 /
Codex Queue·Steer / open-webui / LangGraph)。
- 注入点=**回合内边界**(上一模型步 + 它那批工具调用都已结束、下一次模型调用还没开始):
driveTurn 每 step 组装前调用一次 SteerSource(run.go)——完成 step 只能靠工具批次推进,
故唯一可注入处就是「工具批次结束之后」,循环里没有任何「起第二个回合」的分支(**I1 结构性成立**)
- **I2 恰好一次**:注入只进**本轮 view、绝不写回 msgs**(checkpoint 与记忆提取面保持干净);
被注入的消息从 pending 移除,不会由自己的回合再答一次
- **I3 转向不取消工具**:注入调用点在 runToolCalls **之后**(此刻无工具在飞),循环从不因注入 cancel 任何 ctx;
边界序列有测试钉死(恰为 [1 2 …],无批次中途值)
- 判定口径= **pending ∩ 转录**:候选是本会话 pending 条目,每个边界重读 history.Recent 验证已落库,
按**行 id** 去重、按 pending FIFO 注入。**不用时间戳**(Windows time.Now() 步长 ~0.44ms,连发常同毫秒并列,
任何 ms 基线都会漏注入或重复注入);跨重启不成立也不需要(在飞回合与 pending 都在内存)
- 新下行帧 `steer_ack`:`{type, sessionId, data:{messageId, atStep}}`,语义=「已被本回合吃进、尚未被正面回答」
(驱动前端灰态);**不进 frameReachesAll** ⇒ fail-closed 只发 owner+admin(测试双钉);经 hub 广播、不经 bus
- 组合根**零改动**:per-turn 状态用 ctx 承载(loop.WithSteerSource),编排器在回合启动/续跑时挂
- 守卫:session_orchestrator.go 加完接线后 505 行 ⇒ 按职责纯搬出 session_events.go(常量取值未改、行为零变化)
- 复核:build/vet 绿 + **全树 0 FAIL** + linux/darwin 交叉编译绿;loop 6 例(含 3 子测)+ gateway 2 例 E2E;
**4 条变异反证**(删 consumePending → 模型步数 4≠3;注入写回 msgs → 快照被污染;批次中途注入 → 边界 [1 1 2];
把帧加进白名单 → viewer 收到)均已还原
- 未做(登记):IM 自有 Chatter 落库的消息不参与 steer(有意,避免重复作答);pending 条目无自落库 id
⇒ 配对用 (内容,图片) 逐行认领;同回合超 20 条用户消息时超出者留 pending 由各自回合作答(不丢)
|
2026-10-04 14:53:40 +08:00 |
|
AskaEth
|
8c6c796a29
|
docs(api): api-client → v0.56(协同 A2/G2/G3/G4 契约 + 三个环境变量 + 修正两处错误陈述)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- A2:interrupt 新增 scope({"","all","current"}),三态语义 + 非法值定向 bad_request;
session_interrupted 形状零变化但 dropped 恒为真丢弃数
- G2:stream:true 直达编排器;响应面补 202 {queued} / 409 chat_busy / 503 chat_dispatch_failed;
未接 loop 由 200 改 500 chat_unavailable(行为变更已写明兼容性)
- G3:image 解码后 5 MiB 上限 → 400 image_too_large(指路上传);**如实写明 WS 侧到不了这条判定**
(wsReadLimit=4096 传输层直接断连,发真实图片必须「上传 + URL」)
- G4:新增可选 clientMsgId(两端)⇒ 幂等;REST 200 {duplicate:true,messageId}、WS 新帧 chat_duplicate
(owner+admin,fail-closed);键回填进 message_persisted/channel_persisted/读接口;迁移 0013
- .env.example + api-client 新增三个环境变量:OWNER_IDENTITY_INJECTION(owner_only 默认) /
CONTEXT_MAX_TOKENS(32768;0/负 = 关) / GUARDRAIL_KEYWORDS(留空 = 不挂)
- 修正两处错误陈述:api-reference §6.2 与 §6.6 的「OnStream 只填 seq、不带 turnId」(v0.36 起即带
sessionId+turnId,v0.50 起带 streamId);上传上限 50MB → 5 MiB
|
2026-10-04 14:42:46 +08:00 |
|
AskaEth
|
7512d593c2
|
fix(gateway,history): REST 流式不再静默失败(G2)+ clientMsgId 幂等(G4)(协同 §G,均标「中高/中」)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- G2:`stream:true` 原经**有损总线**且**先回 200** ⇒ 总线饱和时客户端拿到 200 却什么都没发生。
改为**直达编排器**(与 ws chat 帧既有先例同一原则):新文件 chat_stream_dispatch.go;200 变成有意义的
承诺(同步穿过「编排器接收 + 用户消息落库」才回);顺带对齐 `202 {queued,queueDepth}` / `409 chat_busy`;
兜底路径(未接编排器才走总线)现在**返回错误**、ctx 与请求脱钩(WithoutCancel + 30min 上界)→ `503 chat_dispatch_failed`;
未接 loop 由 200 改为 `500 chat_unavailable`(与同步路径同口径,已同步改既有用例并新增钉住用例)
- G4:`chat`(WS 帧 + REST 体)新增**可选** `clientMsgId` ⇒ 幂等。
原子性两层,均非「先查再插」:① 同进程在 `o.mu` 同一临界区内完成「查认领表→查存储→预分配 id→认领」;
② 跨重启靠 `(session_id, client_msg_id)` **部分**唯一索引 + `INSERT … ON CONFLICT DO NOTHING`(命中则读回既有行)。
重复语义:REST `200 {duplicate:true, messageId}`;WS 新帧 `chat_duplicate`(owner/admin 档);重复**不落库、不起回合**。
`clientMsgId` 回填进 DTO ⇒ `message_persisted` 与读接口都可见(客户端可据此对齐本地气泡,不再靠文本相等)
- 迁移 `0013_chat_client_msg_id`(up:加列 + 部分唯一索引 `idx_chat_messages_client_msg_id`;down:先删索引再删列),
已在 `data/cyrene.db` **副本**上验 up → 判重 → down → 再 up
- 拆分:store.go 647→498 行(`log_reads.go` 抽走四个读路径);七个 SELECT 清单抽成 `messageColumns` 一处
- 复核:**全树 `go test ./... -count=1` 0 FAIL** + build/vet 绿 + linux/darwin 交叉编译绿;
四条真断言(总线饱和仍落库出帧且 `ws.chat` 零发布 / 同键两次仅一回合+并发两条也仅一回合 / 省略键逐字不变 /
迁移副本 up-down-up);**3 条变异反证**均已还原
- 越界说明(均已报备):`history.go` DTO 字段(否则「读接口可见」不可能)、`policy_store_test.go`
(0013 使「回滚最后一步 == 0012」前提失效,改为按 schema_migrations 现算)、`extra_test.go`(补 runner)
- 顺带补交 P0-A 遗漏的新测试文件 `loop/memory_writeback_test.go`
|
2026-10-04 14:37:37 +08:00 |
|
AskaEth
|
da3a386daf
|
feat(cyrene,config,loop): 护栏/压缩/身份知识三条落地(P0-5/P0-10/P0-11)+ 身份注入收窄到主人会话
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- P0-5 护栏不再是空壳:挂 WithSensitiveInfo(阻断) + 长度上限(输入 262144 / 输出 65536 字符,依据=
组装完成的请求体量级与「不误伤正常对话」) + 关键词**仅在配置时**挂;正常对话有用例证明放行
- P0-11 上下文压缩默认启用:CONTEXT_MAX_TOKENS 默认 32768(=loop.DefaultMaxContextTokens,两常量由测试锁死),
0/负 = 关闭(行为退回接线前);长对话真压缩且摘要消息进请求首位、最近一轮保留
- P0-10 身份说明书(owner.yaml identityFile)注入人格上下文,并且**收窄为仅主人会话**:
· 新增最小钩子 loop.Options.PersonaKnowledgeFor(env):**按该轮会话环境**解析(不看提示词、不看会话 id),
块只进每轮视图、**不进 messages**(不进 checkpoint、不进记忆提取面)
· 开关 OWNER_IDENTITY_INJECTION:owner_only(默认) / always(仅自测) / off;非法值与读不动 → WARN + 回退默认(不静默)
· **顺手关掉第二条同型泄漏**:channelbridge 群聊参与度判定器的 PersonaPrompt 此前带身份正文 ⇒ 现改为纯人格指令
· 回归:缺文件/目录/未配置逐字节等于旧输出;静态指令与角色池 Instructions() 全不含正文;
文件里点名的陌生账号仍 IsOwner==false(身份知识绝不参与权限判定)
- 复核:build/vet 绿 + cmd/config/loop 包测试绿;四类断言(主人含 / **群聊与陌生人不含** / always·off 两档 /
回归不变)+ 4 条变异反证(含把判定改成恒真 → 提示词里真的出现身份说明书)均已还原
- 未做(登记):knowledge 块启动时读一次(改文件需重启);`.env.example` 的 OWNER_IDENTITY_INJECTION 行随后补;
`internal/user/owner.go` 注释与 design/01 §2.2、design/11 §0 待同步
|
2026-10-04 14:30:26 +08:00 |
|
AskaEth
|
19f296a2ab
|
fix(gateway): 回合围栏堵住「中断后立刻发新消息被旧快照吞掉」的时序竞态(13.4.5 最新性)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 根因(已确定性复现,非测试问题):中断把会话立即置 idle ⇒ 紧随的新消息被当成空闲回合**立即开跑**,
而被取消回合的快照收尾在**它自己的 goroutine** 里、直到 Run 返回前才落定 ⇒ 新回合可能读到上一回合
中途留下的**可恢复**快照(stop_reason=tool_calls)并把调用方刚传进来的消息**整段替换**
(现场证据:DB 里 web:1(step=1,tool_calls) 与 web:2(step=2,stop) 并存,LoadLatest 选中 web:1;
把收尾窗口拉长到 300ms ⇒ 旧码 3/3 必红)
- 修法:新增 session_turn_fence.go —— 把「同一会话最多一个在途回合」从约定变成**可等待的围栏**:
新消息照旧被立即接受、Submit 立即返回(不阻塞硬约束不变),但其**回合启动**等上一回合真正返回
(那时被放弃的快照已落定);等待同时盯本回合 ctx,不收敛的上一回合不会永久挂住会话
- 复核:整包 `go test ./internal/services/gateway/ -count=1` 绿(隔离副本 0/12);`-shuffle=on` ×3 绿;
**全树 `go test ./... -count=1` = 58 包 ok / 0 FAIL**;变异两处(HEAD 原码跑新用例 3/3 红、拿掉等待即红)已还原;
交叉验证:单独打回 loop 的「只有 tool_calls 可恢复」改动后,新用例仍 3/3 红 ⇒ 两侧修法互补
- 顺带:A2 的 `ws_route.go` 一行(定向回 bad_request 需要发送者的 conn;hub 级无按连接寻址入口)
- 遗留(登记):loop 侧 `checkpoint.go` 的恢复会整段替换调用方消息 ⇒ 建议加一致性判据(checkpoint 窗口
最后一条用户消息 ≠ 调用方最新消息则不恢复);围栏未覆盖 orchestrator==nil 的 legacy 直连路径
|
2026-10-04 14:25:13 +08:00 |
|
AskaEth
|
5494c31474
|
feat(gateway): interrupt 支持 scope(当前/全部),默认维持现状(协同 A2)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 原状:interrupt{sessionId} 取消在飞回合**并清空 pending** ⇒ 客户端「打断模式」连发会被静默丢弃
- 修法:新增 scope 三态(与项目既有「省略=保留现状」口径一致)
· 省略 或 "all" = 现状语义(取消当前 + 清 pending)
· "current" = **只取消当前回合、保留 pending**(pending 继续按编排器规则续跑)
· 非法值 → **定向回错误**(只回发送者,不广播),显式报错而非静默当默认
- 下行 session_interrupted 的 dropped 如实反映**真的被丢弃的条数**(scope=current 时通常为 0)
- 复核:gateway 包 build/vet/测试绿(新增 interrupt_scope_* 两组用例);后端 :10942 全程未停
|
2026-10-04 14:21:52 +08:00 |
|
AskaEth
|
decf59c1b4
|
feat(gateway,admin-web): Skill 运行时安装 + backthink 打扰原因 + 建提醒入口(P0-19/P0-20/P0-22,审计 §4.3)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- P0-19:POST /admin/plugins/install 支持 `kind:"skill"`(此前一律 400)——yaml 或 path 二选一、
name 一致性校验、显式错误码(bad_request/name_mismatch/skill_parse_failed/name_conflict)、
装后以 kind:"skill" 出现在 GET /admin/plugins;**文件来源解析错误绝不回显文件内容**(变异验证实测确认
该泄露向量真实存在:yaml 解码器会带出出错值前几字符 ⇒ 只回显路径 + 通用原因,细节进日志)
- P0-20:AdminBackthinkItem 补 route/detail/bypassed(DB 早已存,零迁移),面板 Backthink 展示
- P0-22:新增 POST /admin/automations/reminders(owner-only + 审计),at/message 必填、RFC3339 校验、
409 already_exists;过去时间不作 400(下次轮询立即触发)
- 顺手修真缺陷:新建 id 原用 time.Now().UnixNano(),Windows 时钟粒度粗到毫秒 ⇒ 并行创建撞 id 得假 409;
改用 crypto/rand 128 位 hex(仓库既有 skills/store.go 范式)
- 复核:gateway 包 build/vet/测试绿 + 前端 tsc 0 错;新增 12 用例(含 8 条非法输入显式码);
**4 条变异反证**均已回滚
- 未做(登记):WS 帧侧的 route/detail 未在前端展示(`lib/wsParse.ts` 3 行,需放行);skill 未落
skills.Store(重启后消失,注入点在 cmd/cyrene);提醒无删除入口(CancelReminder 已存在、无路由)
|
2026-10-04 14:21:41 +08:00 |
|
AskaEth
|
3638ed7708
|
fix(gateway): chat 的 image 加上限并显式报错(G3,审计协同 §G)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 原状:image(base64/URL 字符串)在 API 层**无长度上限**、原样落库 ⇒ 一张 5 MiB 的图 ≈ 每页历史重传 6.7 MB
- 修法:入口层(handleChat,位于 stream 分叉**之前** ⇒ 同步与 stream:true 两条路径同拦)按**字符串长度零分配**判定,
超限 → 400 `image_too_large`,文案给出上限并**指路 POST /api/v1/upload**;日志只记 session/chars/limit(不打图片内容)
- 上限口径:**与 POST /upload 的 maxUploadBytes = 5 MiB 取同一个答案**(否则内联 base64 可绕开上传限制);
字符上限 = ceil(n/3)*4 + 64(覆盖 data URI 前缀),**恰好 5 MiB 的整幅图编码后 = 6,990,508 字符,绝不误拒**
- 复核:6 条用例(上限与 upload 同值、边界 ==limit 通过 / +1 拒、超限**0 个回合被驱动**、
stream:true 同样被拒、恰好等于上限逐字节到达 runner、小图行为逐字节不变);
**2 条变异反证**(忘接守卫 / 边界改 `<`)均已还原
- 实测附注:WS 侧今天**已被传输层关死**(wsReadLimit=4096,8KB chat 帧直接断连)⇒ 多 MB base64 无法经 WS 进入;
若日后放宽该上限,必须在 ws 入口补同一个校验(回报里给了精确落点)
- 未做(登记):上限暂不可配置(等 config.go 空闲)、REST 请求体仍整体读入内存(MaxBytesReader 属行为变更)、
vision 层 base64 路径无长度预检(纵深防御)、历史 base64 行需离线批处理(方案已出)
|
2026-10-04 14:21:12 +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
|
983bc49218
|
fix(vision): 服务端自己取回图片 URL 并内联为 data URI,修自部署下取不到图(F3,优先级「高」)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 原缺陷:vision 适配器把 http(s) URL **原样转给上游 provider**,而 upload 返回的是同源局域网地址
⇒ 云 provider 根本取不到 ⇒ **B1(大图绕开 WS 4096 字节上限)在自部署形态下等于没做**
- 修法:① `imageURL` → `localizeRef`:**彻底不再直传 URL**;同源 upload 产物走**本地读取**,
其余 http(s) 由服务端自己取回 → 一律内联为 `data:` URI 再交 provider(OpenAI 与 Anthropic 双协议都能收图)
- 顺手修「类型瞎猜」:新增 `vision/mime.go`,**字节嗅探是唯一裁决**——判得出白名单光栅图就用字节结果;
字节是文本(HTML/PROXY 错误页、SVG)→ `ErrNotImage`;判不定但来源明确声明 `image/*` 才采信声明。
错误信息只含类型名,**不含响应体/URL**(不打印图片内容)
- 防护:取回复用既有 http/https 白名单 + 50MiB 上限,新增 **30s 取回超时**;
本地读取路径 `localUploadPath` 严格认定 `<host>/api/v1/files/<name>`(无 query/fragment、单段路径)+
32 位小写十六进制名 + `filepath.Dir` 包含性第二道 ⇒ `../`、`%2e%2e%2f`、反斜杠等编码变体在触碰 FS 前即拒
- 生产接线(主会话补):`cmd/cyrene/vision.go` 传 `vision.WithUploadsDir(<DataDir>/uploads)`
- 复核:build/vet 绿;新增 51 条断言(含 httptest 真取回 → 断言上游收到 data URI 且不含源 URL、
同源 upload 用不可达 host 证明走本地、HTML 谎报 image/png 被字节否决、越界名 19 例);
**3 条变异反证**(恢复 URL 直传 8 红 / 文本静默回退 png 红 / 去掉穿越检查 12 红)均已还原
- 未做(已登记):历史里 URL 形态图片每轮重新取回(缓解=持久化时内联/缓存);
Anthropic 只认 png/jpeg/gif/webp 而白名单含 bmp;`fetchURL` 无 IP 过滤(链路本地 169.254.169.254 可达)→ 需收紧
|
2026-10-04 14:19:28 +08:00 |
|
AskaEth
|
88d7dd0026
|
fix(loop): 所有非崩溃退出一律废弃可恢复快照(主人 2026-10-04 裁决「修」)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 原状:只有「被取消」的回合把 checkpoint 落定为不可恢复;**模型/工具报错、预算耗尽**等未落定退出
同样留下可恢复快照 ⇒ 下一条消息被旧窗口整段顶掉(用户看到自己刚发的消息像丢了)
- 修法:收尾 defer 改为「**回合未落定就废弃快照**」(不再只看 ctx 是否取消),新增 StopReasonAborted;
checkpoint.resumableStopReason 收紧为「**只有 `tool_calls` 可恢复**」(空 stop reason 不再算);
终态快照改用 context.WithoutCancel 写(修「取消擦肩最终答案」时终态写失败、中途快照留任最新)
- 语义边界(写进用例注释):**只有崩溃**(进程猝死、函数不返回)才允许恢复;控制流一旦回到调用方
就不得留可恢复态。原 resume_test 的用例改名为**崩溃恢复**用例并保留断言(含「新消息不被顶掉」的反面断言在新用例里)
- 复核:build/vet 绿 + loop 包测试与 `-race` 全绿;新增 6 条(模型报错/工具失败+模型报错/预算耗尽/
空 stop reason/取消擦肩最终答案)+ 端到端 TestInterruptThenChatKeepsLatestContextEndToEnd 绿;
**4 条变异反证**(含把废弃快照写回 tool_calls → 精确复现真实劫持现场)均已还原
- 附:修 session_turn_fence.go 里引用旧函数名的陈旧注释
|
2026-10-04 14:17:58 +08:00 |
|
AskaEth
|
5c28ace70d
|
fix(agent,loop): 静音路径工具广告面与流式路径统一(P0-12,审计 §4.3)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 原缺陷:流式路径经 loop.toolSchemas(capacity 允许集 + restrict)过滤,而 agent 静音/内部路径
(RunStep,被 services/automations 等使用)广告 dispatcher **全量** ⇒ 两条路径不一致
- 修法(方案 1):**过滤实现只留一份**(loop.toolSchemas);l.agentStep 调用同一个函数,结果经
agent.WithToolSurface(ctx, …) 下传,agent 的 buildRequest 原样广告(取不到才回退全量,保持既有回退语义)
· 按构造相同:同一次函数调用、同一份输入 ⇒ 不存在第二份可漂移的实现
· 未选「抽共享函数两侧各调一次」:loop 的过滤输入含 loop 私有会话环境 ctx key 与 capacity 判定器,
agent 侧凑齐等于再造一套 ctx 管线,漂移面更大
- 复核:agent/loop 包测试绿;新增 parity 用例(owner 与 group 两组,静音 == 流式);
变异(撤掉下传行)→ parity 必红且精确复现「静音=全量 4 个」,已还原
- 附注:全仓仅剩 `services/automations` 的「无 Loop 回退」仍广告全量(没有循环就没有闸可言);
子代理 ToolWhitelist 是执行期否决、本不参与 schema 过滤(未改)
|
2026-10-04 14:14:05 +08:00 |
|
AskaEth
|
20d452a51a
|
fix(gateway)+docs(api): F5 区分「字段缺失/值为空白」+ E4/E5 契约文档治理
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- F5:PATCH /sessions/{id} 的 400 文案区分两类——都缺 → at least one of title or pinned is required;
存在但空白 → title must not be blank(此前空白也回 title is required,误导排查方向)。
「空串不能清空标题」的既有语义保持不变(用例显式钉住),新增 history_write_test.go 4 段断言
- E4:/auth/logout 的两种真实响应形状(单撤 {revoked} / 全撤 {revoked,revokedCount})+ 错误码;
/auth/refresh 补 role;登录响应与一次性接入段补 refreshToken(两份文档一致)
- E5:api-reference §3.2 补 pinned/unreadCount/lastMessage/personaId 与准确排序规则
(pinned DESC, (type='main') DESC, created_at ASC ⇒ 置顶的次级会话可排在主会话之前);
新增 §3.6a PATCH /sessions/{id}(请求体/错误码/部分更新/title 不可清空)与 §3.6b POST /sessions/{id}/read;
端点表补 read 行
- api-client 删掉「主会话恒在前」的错误断言(两处),PATCH 错误码文案同步
- DevDocs/02-development-constraints.md:上传上限 50MB → **硬 5 MiB**(常量、无配置项)
|
2026-10-04 14:13:27 +08:00 |
|
AskaEth
|
5fb0cf5e19
|
docs(api): api-client → v0.55(安全入口 / OneBot 四端 / 可观测 WS 推送 / 数据目录哨兵)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- ADMIN_PATH 安全入口整段口径(路径式前缀、命中即注入入口页、错前缀 404、API 不藏、用户端永不携带该串)
- DATA_DIR 新增 platform 哨兵(默认/显式路径/显式空值行为不变)
- OneBot v11 四端契约:配置面 transport/api_base_url/report_path + env 兜底 + 四端语义 + mode 取舍 +
端口豁免边界;api-reference §5.24 同步
- 新增 §3.12 可观测实时推送:三个新帧(observability_log/trace/metrics)载荷-上限-触发、
角色门 fail-closed(仅 owner+admin)、"读即订阅"语义、节拍、前端落点、兼容性
- 补记 13.4.5 面内三条与 MCP 换官方 SDK(REST/WS/env 零变更)
- 按实现纠正 5 处:api-reference 版本指针滞后两版、上行 chat 已直达编排器(不再经 bus)、
http+server 的鉴权实为「配了 access_token 才校验」(未配则放行,与 ws+server 同口径,尚无 fail-closed 开关)、
推送帧实际触达所有 owner/admin 连接(订阅只决定循环跑不跑)、remoteURL 回落口径
|
2026-10-04 14:08:10 +08:00 |
|
AskaEth
|
852c327360
|
refactor(web): 随路径式入口清理失效的管理链接(设计:用户端不提供管理入口)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- TopBar / Nav 的 hash 形式管理入口(#/admin、#/admin/system)**删除**(design/07 §0.2:用户端不提供任何
管理入口、bundle 不含该路径串);面板只经 ADMIN_PATH 路径直入
- AdminApp 三处 window.location.hash = "" 改调 router 导出的 navigateUserShell()
- 复核:tsc 0 错 + vite build 成功;用户端源码 grep "#/admin" 0 命中(仅在 channels/useAdapterNav.ts
尚有模块内闭环的 hash 字面量,属另一决策,仅报告未改)
- 局限:无 playwright/puppeteer 且不许加依赖 ⇒ 「布局未塌」为结构+静态样式依赖推断(无子元素数量相关样式)
|
2026-10-04 14:01:43 +08:00 |
|
AskaEth
|
a398dc9b92
|
feat(config,gateway,web): 路径式安全入口 ADMIN_PATH + 数据目录 platform 哨兵(裁决 1.6/16.4.7/12.4.2 + 1.5/12.4.3 核对)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 1.6 + 16.4.7:安全入口=路径式 `/<ADMIN_PATH>`(env `ADMIN_PATH`,默认 `admin`;`xxx/admin` 亦可,
非法值回退 `/admin`)。命中前缀 → 送注入了 `<base href="/">` + `window.__CYRENE_ADMIN_ENTRY__` 的面板入口页
(深链直达);**形如面板入口但前缀不符 → 404**(不回落用户端聊天壳);`/api/*`、`/ws`、webhook 先放行
⇒ **API 不藏**。前端路由改**路径式**(`router.ts` 只读注入,无硬编兜底;移除 hash 入口)
- 1.5 / 12.4.3 核对:暴露面默认 `0.0.0.0` 与裁决一致,无需改代码(仅补注释)
- 12.4.2:`DATA_DIR` 支持 `platform` 哨兵(大小写不敏感)→ 平台标准目录;默认 `./data` 与显式空值行为不变
(显式空值保持原兜底,避免正在运行实例突然换库)
- 复核:build/vet 绿 + config/gateway 包测试绿 + linux/darwin 交叉编译绿;新增 7 条用例,
并用真实构建产物(`webui.Assets()`)跑通「浏览器直开 /admin 能启动面板」(`<base>` 必须在资源引用之前)
- 变异 2 条(关掉错前缀 404 / 前端默认前缀兜底)已还原
- ⚠️ 运行时序:前端已生效而后端 hatch 未生效期间**面板打不开** ⇒ 需紧接一次「build 到位 + restart」
|
2026-10-04 14:00:25 +08:00 |
|
AskaEth
|
9253fef92a
|
feat(qq_obv11): OneBot v11 四端齐备(裁决 1.4 / 12.4.1)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 四端=ws×client / ws×server(原有,补语义注释)+ **http×client**(新增 http_client.go:
调 OneBot HTTP API、请求-响应、retcode 判成败、token 只走 Authorization 头)+
**http×server**(新增 http_server.go:监听 listen_addr 收上报、fail-closed 鉴权、10MiB 体上限)
- 配置面:适配器新增 transport / api_base_url / report_path(json tag 沿用既有口径);
env 兜底 CHANNEL_QQ_OBV11_{TRANSPORT,API_BASE_URL,REPORT_PATH};**默认值=现状**(ws+server)
- 出站分流:session.go 发送路径按 transport 走 WS 写帧或 HTTP POST(不改它则 HTTP 端无法出站)
- 端口豁免边界:http+server 沿用 AGENTS §9 已登记的同一豁免(design/13 §0 原文即含 HTTP server),
且 listen_addr 为空时报错、**绝不开端口**(与 ws 侧同名校验成对)
- 关键取舍(已上报):OneBot 的 HTTP 是「动作 + 上报」两半,mode 决定**哪一半必需**、
另一半给齐字段就一并启用 ⇒ 单个适配器即可「收上报 + 回消息」,四端仍各自可独立选择与测试
- 复核:build/vet 绿 + qq_obv11/cmd 包测试绿 + `-race` 干净;10 条新用例(HTTP 两端全部用本地
httptest 假 OneBot,未连真实 QQ);变异 3 条(伪造 retcode 成功 / 去掉上报鉴权门 / 默认值翻 http)已还原
- 未接:get_group_list(后续)、无 token 时放行(与既有 ws_server 一致,如需 fail-closed 请裁决)
|
2026-10-04 13:58:18 +08:00 |
|
AskaEth
|
0e1f163ef9
|
feat(gateway,admin-web): 可观测面从轮询改为 WS 帧推送(裁决 05.4.3 + 16.4.3-WS)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 新增三个下行帧(纯新增,既有帧名/形状零改动):observability_log / observability_trace /
observability_metrics,各带 ≤1s 节拍、无新数据不发帧、单帧上限(日志 200 / span 100)
- 帧壳 {type,data} 不带 sessionId;**不进 frameReachesAll 白名单** ⇒ fail-closed 只发 owner+admin
(变异验证两次:加进白名单 → viewer 用例必红)
- 推送开启条件=owner/admin 凭据「读过一次」对应 REST(引导数据仍由该次读取返回),
连接全断即退订并停循环(无常驻 goroutine);既有 REST 端点路径/RBAC/形状完全不变
- 前端:删除 logs/metrics/trace 三处 useAutoReload 轮询;新增 observabilityStream(引导+去重合并+窗口)
与 observabilityViews(三个面板 + WS 徽标),长列表统一走已落地的 VirtualList
- 复核:build/vet 绿 + gateway 全包测试绿(含真 bus→真 /ws/chat 三角色帧断言)+ `-race`;
前端 tsc 0 错 + vite build 成功
- 待登记契约:api-client 需新增「可观测实时推送」一节
|
2026-10-04 13:58:03 +08:00 |
|
AskaEth
|
74b12d87ca
|
fix(history,loop,gateway): 上下文续接的最新性/一致性三条(裁决 13.4.5 的面内部分)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
本组只落地「在允许文件面内、且能用 design/15 既有规格推出」的部分;13.4.5 的「真并行 + 动态旧上下文」
与 design/15 §2.1/§2.2 的既有串行续接规格存在读法冲突,按规程**停下上报**(未自创语义)。
- history.Recent(续接窗口)并列打破:created_at DESC, rowid DESC —— Windows time.Now() 步长 ~0.44ms,
用户连发必然同毫秒并列;修复前并列时取**更早**的 ⇒ 丢掉刚发出的最新 n 条且同毫秒内反插入序
- 上行 chat 不再经**可丢弃**的 bus:直达会话编排器的非阻塞 Submit(design/15 §2.1「会话消息不能被 drop」
+ §4「不阻塞是硬约束」);orchestrator 为 nil 时回退 bus,旧断言仍绿
- 被**取消**(中断)的回合把该会话 checkpoint 落定为不可恢复(用 context.WithoutCancel 写,快照保留可查询,
仅在回合未落定时触发)⇒ 不再顶掉下一条消息的上下文
- 复核:build/vet 绿 + loop/gateway/history 三包测试与 -race 全绿;新增 5 条用例(含一条真 WS+真编排器+
真 loop+真 persist 的集成用例);**3 条变异反证**精确复现「新消息被丢弃只见旧窗口」「窗口取早不取新」
「bus 饱和时会话消息静默消失」,均已还原
- 待裁决(已上报主人):① 「同一会话多回合真并行」需改 checkpoint 键(sessionID:step 并发互相覆盖)、
flow 图按轮键控、前端单槽 busy —— 均在本组文件面外;② 「动态吸收新到消息」在 design/15 **无规格**,
属新语义,须先写设计;③ 非取消的错误退出同样留可恢复快照(同机制,未扩范围,因 resume_test 正钉住旧行为)
|
2026-10-04 13:56:35 +08:00 |
|
AskaEth
|
a1083a322f
|
feat(mcp): 协议层换成官方 Model Context Protocol SDK,删自研实现(裁决 10.4.6 + AGENTS §9.5)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 新增依赖:github.com/modelcontextprotocol/go-sdk v1.8.0(direct)+ github.com/google/jsonschema-go v0.4.3
(SDK 自带依赖,直接用于 schema 校验/默认值,避免再造一份);go.sum 纯新增
- 删除自研协议层:rpc.go / stdio.go / http.go / sse.go 及其测试
- 用 SDK 的成熟逻辑:命令传输(stdio 子进程)/ SSE / Streamable HTTP、协议版本协商与
-32022 回退、keepalive(含失败阈值)、tools/list_changed 订阅、能力协商(InitializeResult.Capabilities)
- 保留自研的四件事(其余零自研):配置→传输、发现→registry 注册、能力族推断、schema 缓存(Prepare 命中不重复解析)
- 能力闸诚实化:服务器声明 capabilities 但不含 tools 时 ListTools/DiscoverTools 返回
ErrCapabilityNotDeclared(不静默空集);完全不声明 capabilities 的老式服务器仍按 legacy 处理
- 复核:build 绿 + capability 全包测试绿(mcp 42 用例,含真子进程 stdio / httptest Streamable HTTP /
内存传输三类假 server,不依赖外网)+ `-race` 干净;变异 2 条(featuresFrom 恒 true / 删 applySchema 调用)已还原
- 无 REST/WS/env/数据目录变更;包内 API 有增删(见回报),仓外调用方签名未变(未改 cmd/cyrene 与 plugin/manager)
|
2026-10-04 13:53:47 +08:00 |
|
AskaEth
|
7b05b4bfa9
|
docs(api): api-client → v0.54(渠道配置 patch 语义 + 阶段 6 四项)+ api-reference 同步
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 渠道写路径语义变更:config 从「整条替换」改为**三态补丁**(省略=保留 / 非空=覆盖 / 显式 null 或 ""=清除),
并写明四类数据安全后果与破坏性提示;api-reference §5.24 同步
- 阶段 6 四项登记:16.4.1 静默/活动态与预约切换、16.4.5 会话级消息缓存(非激活帧按 sessionId 入桶、
不再丢弃)、16.4.3/16.4.6 虚拟滚动与专属页只读卡、16.4.4 双档 UI 模式(性能档=现状,持久化 cyrene.ui-mode)
- 修正 4 类过时陈述:① 渠道写路径整条替换;②「忽略非激活会话的帧 / 按激活会话过滤」(api-client 四处
+ api-reference 一处);③ graph_update 无会话归属;④ api-reference 漏记 GET /admin/llm/catalog(补 §4.9.1)
- 自证:旧陈述 0 命中;新词 PatchChannel/补丁/ui-mode-fancy/sessionCache/sess-backthink 均命中
|
2026-10-04 13:48:24 +08:00 |
|
AskaEth
|
4ae714883d
|
fix(gateway,runtimeconfig): 渠道配置写路径改为 patch 语义,修凭据静默丢失(P0 级数据安全)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 新问题(本轮前端组发现):config 是整条替换,而面板只发送用户本次碰过的平台字段 ⇒
① 保存微信(iLink)账号卡(其平台字段只有 cdn_base_url,甚至可为空)会把
bot_token/bot_id/owner_id/get_updates_buf **全部抹掉**(iLink token 是长期凭据);
② Telegram 填 webhook_url 而不重填 token 会因 cleanAccounts「token 空即丢账号」把**整个账号**删掉
- 修法:新增 runtimeconfig.PatchChannel + mergeChannelConfig + isEmptyConfigValue(三态,与 personaId 同构)
· 键省略 / config 整体缺席 / null = **保留已存值**(未给出的键绝不被抹掉)
· 给出非空值 = 覆盖 · 显式 null 或 "" = **清除该键**(0/false 不算空)
· 写路径 UpsertChannel → PatchChannel;非 config 字段(名单/限流/personaId)仍整值替换(不变)
- 回归(真断言落盘内容):微信卡片只带 cdn_base_url / 空卡片三种形态 → 四个凭据键全在;
Telegram 只带 webhook_url → 账号存活且 token 不变;显式 null/"" → 键真被清除;新账号正常写入;
既有 TestAdminSaveChannelConfigPersistsAndReloads 保持绿
- 变异反证 3 条(改回 UpsertChannel → 精确复现两缺陷;去掉清除分支;"" 不再算空)均已还原
- 边界未改:token 要求型平台**显式**清 token 仍按 cleanAccounts 丢账号(主人明确清除凭据的语义);
「本次一个 config 键都没给出」在非 weixin-ilink 平台仍回 400(既有行为,不在授权内放宽)
|
2026-10-04 13:42:37 +08:00 |
|
AskaEth
|
8d70f6d331
|
feat(web): 双档 UI 模式(性能档 = 现状 / Smooth Corner 华丽档)+ 开关挂载(裁决 16.4.4)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- design/uiMode.ts:档位纯逻辑(localStorage `cyrene.ui-mode` 持久化、跨标签页同步、未知值回落默认档),
只改 <html> 类名与 data 属性 ⇒ 不碰 React 树、不重挂载、几何尺寸不变
- 性能档=**现状**:tokens.css / styles/index.css 的改动**全为新增(0 删除)**,且全部限定在
`:root.ui-mode-fancy` 下;75 元素签名比对证明性能档渲染与改动前逐元素一致
- 华丽档对齐六大核心:连续曲率 corner-shape / 多层 Surface 环境光 / 弹簧动效 / 深色优先(浅色单列补偿)/
毛玻璃升级 / Liquid Glass(4 折射 + RGB 色差 + 鼠标跟踪 + 双层动态边框)
- 开关挂载:main.tsx 在 createRoot 之前 initUiMode(零闪烁);TopBar/Nav/AdminTopBar 三处挂载,
窄屏(<640px)按既有约定收起(实测否则 375px 角色块被压到 27px、面板溢出 73px),移动端由侧栏抽屉覆盖
- 复核:tsc 0 错 + vite build 成功;uiMode 38 项 node 测试 + headless Chrome 真渲染 30 项(真点击/真持久化/
真指针事件);变异反证(去掉读回 → 持久化往返必红)
|
2026-10-04 13:41:09 +08:00 |
|
AskaEth
|
c1a98d7c01
|
perf(admin-web): 长列表虚拟滚动 + 专属页只读配置卡(裁决 16.4.3/16.4.6)+ 修限流读写成对的数据丢失
- 16.4.3(效率最高):AdminTable 超阈值走窗口化(DOM 行数与数据量解耦,上下占位行撑滚动条);
新增可复用 VirtualList;适配器消息日志换成窗口化版
- 16.4.6(操作更便利):保留列表页内联编辑,同时把「专属页只读展示该平台完整字段」真正实现
(AdapterConfigSummary,此前专属页一个配置字段都不显示)
- 🔴 顺带修一条静默数据丢失:列表页限流三项原从 acct.config.* 读,而后端把它们存**账号顶层**
⇒ 表单永远回显空、保存时 undefined→0 会把已设限流清空。现改从顶层读、留空则不发该键、非法输入报错中止;
并顺手改正用户可见的错误文案(0 = 保护性默认 6条/分,负值才是关闭)
- 复核:tsc 0 错 + vite build 成功;channel limits 27 / admin virtual scroll 8023 项断言;3 条变异反证
|
2026-10-04 13:41:08 +08:00 |
|
AskaEth
|
b480b04dd0
|
feat(web,ws): 会话级消息缓存 + 图桶 + 忙态按会话过滤(裁决 16.4.5/16.4.2 + 修 16.4.1 的帧缺口)
- 16.4.5:非激活会话的帧**不再丢弃**,按自己的 sessionId 落进该会话桶(新增 store/sessionCache.ts 纯函数 +
useAppStore.sessionMessages/flowGraphs);切会话改为「存回/取出」而非清空;流式增量 O(1) 定位桶、
只延长已存在的助手气泡(不凭一帧 delta 凭空造消息)
- 16.4.2:图按会话入桶(上限 12 个),Backthink 页取 sess-backthink 的图而不再被用户会话图顶替;
空态区分「实时通道未连接」与「尚未产生链路图」;wire_runtime 的图源白名单注释按裁决口径重写(零行为改动)
- 修 16.4.1 的缺口:handlers/session.ts 补 `session_idle` / `session_interrupted`(此前落到未知帧兜底 ⇒
sessionBusy 可能卡 true ⇒ 预约永不落地);忙态**置忙与置闲两侧**统一按 frameIsActive 过滤(只过滤置闲
会让后台会话的忙帧点亮徽标而它自己的 idle 被丢 ⇒ 永久卡忙)
- 清理:删除 lib/streamScope.ts(口径已被 16.4.5 推翻)与只剩测试在用的 messageEventApplies
- 复核:tsc 0 错 + vite build 成功;messageSync 69 / session 19 项逻辑测试;4 条变异反证
|
2026-10-04 13:41:02 +08:00 |
|
AskaEth
|
f454273c5a
|
feat(web): 静默/活动态切换 + 预约生效(裁决 16.4.1)
- 唯一逻辑入口 components/modeSwitch.ts(纯函数判定 + 预约态 + 落地/撤销)+ ModeSelector 组件
- 活动态:她自己切(下行 mode_switch)直接生效,用户此时切换只登记**预约**、不偷偷改、不上行,
且不清除预约(两层不打架)
- 静默态:用户可即时切 + 上行 mode_switch
- **用户提前切 → 下次静默态生效**:`active` 由 true→false 时落地;徽章写「已预约 · X(她静默后生效)」,
不会让人误以为立刻生效
- 「活动/静默」判据=她是否在忙(sessionBusy || 屏上 streaming || sending);若口径要改成 capacity 三态,
只需改 modeSwitch.ts 的一个谓词(已登记)
- 复核:tsc 0 错 + vite build 成功 + node 逻辑测试 28 项;2 条变异反证(去掉活动态分叉 / 去掉 active 守卫)
|
2026-10-04 13:41:00 +08:00 |
|
AskaEth
|
093f38d986
|
docs(comments): 注释中文化 · internal/services/channelbridge(纯替换)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 只翻注释/文档字符串:剥掉注释后代码行逐字节不变(机械校验只剩允许的行尾注释形态)
- 术语对齐既有译法(owner→主人、persona→角色、engage→参与度判定、quiet hours→安静时段、backoff→退避)
- 复核:go build 绿 + channelbridge 包测试绿;gofmt 干净
|
2026-10-04 13:33:06 +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
|
eb1828ee7a
|
docs(comments): 注释中文化 · internal/runtime/orchestration(29 文件,纯替换)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 只翻注释/文档字符串:剥离注释后代码行逐字节不变(机械校验只剩允许的行尾注释形态)
- 裁决编号与 design 节号(02.4.3 / 11.4.2 / design/05 §9 等)逐字保留
- 复核:go build 绿;orchestration 及其子包(audit/comm)测试绿;gofmt 干净
|
2026-10-04 13:30:04 +08:00 |
|
AskaEth
|
fe90f64a56
|
docs(agents): 登记主人新红线「后端常驻」——下一次构建产物就绪前不准关后端
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- AGENTS.md §9 新增一条:运行中的后端(cyrene.exe,:10942)在**下一次构建产物就绪之前不准关**,
除非出现恶性 Bug(进程致命错误/必须阻断的严重故障)
- 推论写入铁律:① 跑 go test/build/git/验收都不需要停后端;② 换二进制只允许「先 build 到位、
再一次 restart」,不留空窗;③ 启动不许用前台阻塞式包装(ctrl.bat start/restart 会守着进程轮询健康,
工具超时会连带杀进程树)——必须确认进程脱离工具;④ 压缩/中断后先探活(netstat + /api/v1/health)再判断
- 同步记进 DevDocs/工作小结/00-当前态.md 的红线区(含本次实测:TaskStop 掉包装后后端存活、PID 文件已写)
|
2026-10-04 13:18:26 +08:00 |
|
AskaEth
|
7afef8d037
|
fix(loop,gateway,persona): awakening 逐 turn 按角色生效 + 修「面板保存角色抹掉 5 个块」的数据丢失(裁决 14.4.3)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- per-role 注入补齐:Options.PersonaAwakening(personaID) → Loop.personaAwakening → l.awakeningFor(ctx)
→ capacity.Input.Awakening(toolSchemas 是全仓唯一构造该 Input 处)
· 按 turn 解析(不绑 Loop 构造期,避免并发会话数据竞争),与既有 personaFor/knobsFor 同构
· 未知角色/空角色/档案无该块 ⇒ 零值 ⇒ 回落 Config.Awakening(不声明者行为与今天构造性一致)
- **数据丢失修复**:persona PUT 是整块替换,此前只保留 thinking ⇒ 保存一次会同时抹掉
awakening / visual(头像·背景) / triggerWords(群聊提醒词) / emotion(情绪机参数) / affection(好感度曲线)。
新增 applyAwakeningEdit + applyPersonaReadOnlyBlocks 逐一保留(cyrene.yaml 五块全写,属必现故障)
- 文件守 500 行:主人档案段原样搬移到 admin_owner_profile.go(零逻辑变更)
- 复核:build/vet 绿 + 全树 `go test ./... -count=1` 0 FAIL;端到端=真 YAML→loader→buildCapacity→真 loop
流式请求→断言工具面(tasky 声明 force_state 唤醒 → 含 web-search;cyrene 不声明 → 与无解析器对照逐字相同);
**8 条变异反证**先红后还原(含逐块删除各自的保留逻辑)
- 残留缺口(登记):wire_runtime.go:254 那一行本身无用例覆盖;loader 非 strict(未知 YAML 键静默忽略,
需主人裁决是否开 KnownFields);POST /admin/personas 仍写不出这五个块
|
2026-10-04 13:07:52 +08:00 |
|
AskaEth
|
58cba0b8d2
|
docs(api): api-client → v0.53(阶段 5 全部契约)+ api-reference 同步 + .env.example 补 9 键
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 新端点 GET /admin/llm/catalog 全契约(200/gzip/503 catalog_unavailable/快照副作用/不进热路径/审计 llm.catalog)
- models.json 组级三键:reasoning.kind(形状)+ personaModels/personaProviders(角色级模型/协议路由),
含「缺省=保留、给出=整块/整表替换」语义、Group.Validate 的 400 口径、回落与 WARN 规则
- GET /admin/llm 新增恒下发的 reasoning 与两个取值域(reasoningKinds/personaProviderOptions)
- 语义修正(此前文档写反):multimodal = 主模型能否收图;LLM_VISION_MODEL/LLM_OCR_MODEL 只配视觉/OCR 工具
- 新工具 image-crop(x/y/width/height、50MiB/16MP/8MiB 上限、越界报错不 clamp、策略默认 owner-only)
- 推理开关按形状下发:替换 v0.41「Qwen 只 WARN 不发」;effort 非法值改为丢弃+WARN(不降档)、effort:none 显式关思考
- .env.example 新增 9 键(LLM_REASONING_KIND / LLM_OCR_MODEL / LLM_LOCAL_* / CAPACITY_L3_*),默认均为保守值
- 权限矩阵计数按 routes.go 校正 56→59(owner/admin 只读档 9→10,含 /admin/llm/catalog)
|
2026-10-04 13:07:09 +08:00 |
|
AskaEth
|
1ac02bd77e
|
feat(gateway,admin-web): 面板可编辑 provider 推理形状 / 角色级路由 / multimodal 真语义(裁决 03.4.2/03.4.1)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 后端:AdminLlmProvider 暴露 reasoning{kind}(恒下发,""=未声明=auto)、personaModels、personaProviders;
顶层新增 reasoningKinds / personaProviderOptions 两个**取值域**(唯一来源= runtimeconfig 导出枚举,
校验错误文案也由枚举拼接 ⇒ 不可能漂移)
- 读写共用同一映射(admin_llm_provider.go),避免「读侧少一个键 ⇒ 面板一保存就抹掉」
- 写侧语义:缺失=保留、给出=整块/整表替换;非法值一律 runtimeconfig.Group.Validate() ⇒ 400 bad_request
(实测非法 kind 返回 400 且 models.json 完全不动,而非 500 静默失败)
- 前端:新增 LlmProviderRouting(推理形状下拉 + multimodal 开关 + 按角色路由编辑器);
目录能力位改三态(true/false/未标注),「未标注」不再谎称「不支持」;目录/角色清单不可用时
**不阻塞编辑**且与「字段为空」是不同状态;绝无 mock/sample 回退
- 复核:build/vet 绿 + gateway/config 包测试绿 + tsc 0 错 + vite build 成功;2 条变异反证(删 reasoning
补丁 → 2 例红;删 Group.Validate → 该 400 用例红)已还原
- 注意(主会话已知):npm run build 把新 SPA 写进 frontend/web/dist,而运行中的二进制优先从磁盘读该目录
⇒ :10942 目前是「新面板 + 旧后端」,等阶段 5 全绿后按红线「先 build 到位、再一次 restart」切换
|
2026-10-04 13:06:54 +08:00 |
|
AskaEth
|
8890c30bb5
|
feat(model): 按 provider 形状独立适配推理开关 + per-persona 提供商链真接线(裁决 03.4.2/08.4.1/03.4.1 余项)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 新增 reasoning_shape.go:**每个 provider 形状一个 resolver,只发自己形状的字段**
· deepseek:thinking{type} + reasoning_effort(依据 DevDocs/reference/deepseek 官方本地副本)
· vllm:chat_template_kwargs.enable_thinking · dashscope:顶层 enable_thinking(**只允许显式声明**)
· openai:仅 reasoning_effort · anthropic:自己的 thinking{budget_tokens}(未改)
· 未知 kind → WARN 且一个字段都不发(不许静默失效)
- 形状载体:models.json 组级 `reasoning.kind`(可热更新,未声明则不写该键)+ env `LLM_REASONING_KIND`
- 红线:`effort:none` 在只有布尔开关的形状上翻成**显式关思考**,绝不降成任何强度档
- 03.4.1 余项:`Request.PersonaID` + `RuntimeLLM.ForPersona(pid)` 视图;
每 persona 协议一条链并消费 `RouteProviderForPersona`;`agent/request.go` 非流式路径同一钩子
- **生产装配(主会话补)**:默认 agent 与 personaAgentPool 都改用 `ForPersona(pid)` 视图——
否则角色级模型/提供商路由在生产里永不被选中(形同虚设)
- 复核:build/vet 绿 + model/agent/config/cmd 包测试绿;5 条变异反证先红后还原
(其中一条「红但没钉住」已改用例:通道读取加 2s 超时,避免整包 panic 掩盖信号)
- 未落:DashScope 的 auto 推断(缺官方依据,只允许显式声明);Qwen `/think` 前导消息
(design/01 §2.1 与 design/11 §3 口径冲突,停手报告)
|
2026-10-04 12:57:55 +08:00 |
|
AskaEth
|
71fefe5fc3
|
feat(persona,capacity): persona awakening 档位真生效 + 当前主角色已填(裁决 14.4.3)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- loader 新增可选 awakening 块(default_state/overrides{min_confidence,force_state}),载入期校验 + 归一化,
非法值显式报错(拒绝「写了却静默无效」);缺失 = nil = 无该档位,不补默认
- 组合根把当前主角色档案的档位填进 capacity.Config.Awakening(未知档位名告警后按无档位处理),
真的参与 Decide → applyAwakening(MinConfidence 优先于全局 0.6;force_state 钉死态)
- 当前主角色 cyrene.yaml 填 default_state=静息 + min_confidence=0.7(设计 §3 陪伴型取静息;
0.7 压掉 L2 趋势(0.66)误唤醒、仍低于 L1 强信号(0.9),温柔陪伴不误打扰)
- 复核:build/vet 绿 + persona/capacity/cmd 包测试绿;端到端 4 例锁定「同回合有无档位判定相反」;
变异两轮(yaml tag 改错 → 8 处红;解析但不接线 → 端到端红)均已还原
- 已知盲区(另派):per-role 注入未接线(loop/request.go 的 Input.Awakening);
面板整块替换 persona 会抹掉 awakening 块(需 applyAwakeningEdit)
|
2026-10-04 12:49:40 +08:00 |
|
AskaEth
|
38b4527949
|
feat(tool,loop): 工具调用软判并回(裁决 14.4.2)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 落点=Dispatcher.Invoke 入口(唯一执行口,覆盖主循环/子代理/编排全部调用方)
- 语义=**不硬阻断**:越界调用照常执行,把 not_allowed 提示与软判理由挂到真实结果上回灌模型
(符合 design/14 §1「状态改变不构成能力边界、紧急时也能调」与 §4「入口前置软判」)
- 允许集单一真源:loop 发布 capacity 过滤后的 schema 名单(= 模型本轮实际看到的工具面),
分发器不在本地另算一套判定
- 审计:复用既有 AuditEvent/OnAudit 通道(what=tool.reject.not_allowed,design/14 §4 原文),
前端小字与审计日志同源;日志带 source=runtime/tool
- ctx 载体:Run 入口每 Run 播种允许集持有者(run.go +6 行,越界但必需——ctx 只能由 Run 或
request.go 播种,后者归 G5-A)
- 与既有硬闸门零重叠:restrict(群聊/陌生人)与 ToolWhitelist(子代理)仍在更早处硬拦 + 各自审计
- 复核:`go build`/`go vet`/tool+loop 包测试绿,`-race` 下 SoftJudge/AllowSet 无竞态;
变异 M1(软判恒空)4 例红、M2(不发布允许集)仅端到端 1 例红 ⇒ 两侧各被独立覆盖
|
2026-10-04 12:45:48 +08:00 |
|
AskaEth
|
3972ea4007
|
refactor(admin-web): 模型目录面板改走既有 API 层(adminGetLlmCatalog)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 新增 lib/api/admin.ts 的 adminGetLlmCatalog({refresh}) + 目录响应类型(lib/types/admin.ts),并由 lib/api.ts 再导出
- LlmCatalogPanel 不再直连 lib/api/core(它曾是全仓唯一这样做的 admin 模块),行为不变:
五种状态判定、gzip 响应、离线粘贴导入均保持
- 复核:grep lib/api/core 全仓前端 0 命中;npx tsc --noEmit 0 错;npm run build 成功
|
2026-10-04 12:45:36 +08:00 |
|
AskaEth
|
fa33c79e11
|
feat(model,capacity,vision,io): per-persona 路由 + 本地三级(默认关) + L3 分类 + OCR 独立模型 + image-crop 工具(裁决 03.4.1/03.4.3/14.4.1/14.4.4/14.4.5)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 03.4.1:per-persona 路由载体选 models.json(组内新增 personaModels/personaProviders + 校验 + PersonaRoute()),
Router/RuntimeLLM 快照绑定、loop 流式路径按该 turn 的 persona 路由;主步用路由结果、降级步钉自己的模型
- 03.4.3:本地第三级降级链(LLM_LOCAL_*,Configured() 含 Enabled ⇒ **默认关**),warn 标注来源
- 14.4.4:capacity 接入 L3(分类器接口 + TTL 缓存 + 严格 JSON 解析),CAPACITY_L3_ENABLED **默认 false**
- 14.4.1:语义修正 —— group.multimodal 才是「主模型能否收图」(env 路径不再臆断),LLM_VISION_MODEL 只配视觉工具;
vision/OCR 可各用不同模型;runtime 不再因有图抢路由(vision.Router 是唯一分层权威)
- 14.4.5:新增 image-crop 工具(工具数 5→6,策略默认 owner-only),schema 支持按区域裁切
- 组合根:wire_runtime 读 group.Multimodal;capacity 装配拆出 wire_capacity.go(守 500 行)
- 复核:`go build`/`go vet`/各包 `go test -count=1` 全绿;**6 条变异反证**先红后还原(含作者自查出的 2 条假阳性变异)
- 未落:按 provider 的 thinking 开关(需 openai_encode.go/openai.go 文件面)、persona awakening(需 loader 文件面)
|
2026-10-04 12:44:52 +08:00 |
|
AskaEth
|
63e5b70e3d
|
feat(gateway,admin-web): 模型目录自动化 —— GET /admin/llm/catalog(裁决 03.4.2 次件)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 新增 GET /api/v1/admin/llm/catalog(owner|admin,?refresh=1 强制刷新):抓 models.dev api.json 并裁剪
(226 供应商 / 8392 模型 → 1.31 MB),写落盘快照 data/llm_catalog.json(无凭据,TTL 24h,gitignore)
- 降级诚实:快照优先 → 在线刷新 → stale 快照兜底(标 stale+warning)→ 都不行回 503 catalog_unavailable,
绝不编造;抓取只发生在该端点内,**不进运行时热路径**
- 前端:新增 llm/LlmCatalogPanel(在线目录 + 粘贴导入落同一份候选 → 一键带出 baseURL/model id/multimodal/
maxTokens);Llm.tsx 挂载面板、删掉硬编码的「主→备→本地」假状态、表单按 id#seq 重挂
- 诚实性:面板把「加载中 / 端点未实现 / 抓取失败或离线 / 响应结构不认识 / 目录为空」分成五种独立状态,
全程无 mock/sample 回退
- 复核:新增 9 条零外网用例全绿;**变异**(Stale:true→false / TS 只认 camelCase)各自红后已还原;
Go 真产出与 TS 解析器双向实测 8392 模型能力位零差异
- 越界说明:routes.go 仅 +3 行(注册该路由);llm/LlmCatalogPanel.tsx 为拆出以守住 Llm.tsx ≤500 行
|
2026-10-04 12:43:04 +08:00 |
|
AskaEth
|
b8fa53e43c
|
docs(api): api-client → v0.52(approval_notice 帧 + 策略落盘 + graph props 新键)+ api-reference 去假陈述
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 新增下行帧 approval_notice(§3.11,主代理代审小字,owner+admin,fail-closed 默认档);
审计口径 who=角色名 / what=approval.<工具> / result=granted|denied
- 工具策略落盘口径写入端点表(载体 tool_policies,迁移 0012,先落库后改内存)
- graph_update 节点 props 新增四类可选键(tool args_keys/args_summary、guardrail、memory、orchestration),
纯增量 + 发布前脱敏;帧名/事件名/顶层字段集未动
- api-reference:439 的「仅内存标记,重启复位」改为「落盘 tool_policies,重启保留」;§4.17 补旁路节点 span
- 按实现修正 7 处表述:args_keys 是「全部参数名」(只有 args_summary 限放行表)、explain 带「」引号、
detail 只截目标部分、allowed=false 还覆盖无代审者/代审报错两条 fail-closed 路径等
|
2026-10-04 12:34:14 +08:00 |
|
AskaEth
|
b99268d019
|
feat(trace,loop,orchestration): memory/guardrail/orchestration 真 span + 参数摘要脱敏 + Guardrail 输出侧异步(裁决 11.4.2/11.4.3/13.4.1)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 11.4.2:三类节点首次真进图 —— memory.recall/memory.write(loop/memory.go 召回与写入点)、
guardrail.input/output(流式主路径两侧 + agent.RunStep 静音路径)、orchestration.spawn
(scheduler 每次派发/收束);新增 trace.ChildSpan 让不持有 Tracer 的叶子包也能开子 span
- 11.4.3(设计先行,规格先写进 design/19 §1.1):tool 节点参数摘要 —— 放行表 argValueKeys +
trace.IsSecretKey 统一判据(密钥类键不给值)+ 单值 80 rune / ≤24 条 + 出图前再清洗;
前端 NodeDetail 新增「参数摘要」区,未放行键显示「值未展示」
- 13.4.1:流式主路径输出侧护栏改后台 goroutine(脱离 context、30s 兜底、不阻塞回合),
输入侧仍在模型调用前同步拦下;拦截闭环到 guardrail 节点 + 审计事件
- 拆文件:scheduler.go 加 span 后 546 行 → 编排 span 助手拆出 scheduler_spans.go(回到 492)
- 契约:无帧名/事件形状变化;graph_update 节点 props 新增**可选**键(tool args_keys/args_summary、
guardrail action/allow/elapsed_ms、memory action/scope/hits/…、orchestration subagent/persona),
文档同步由主会话统一落
|
2026-10-04 12:31:20 +08:00 |
|
AskaEth
|
0dfad675b8
|
fix(admin-web): 删掉面板硬编码假数据,改成诚实的空态/错误态(P0-24,审计 §4.3)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- Automations.tsx / Llm.tsx 原有的 sample 回退("后端在线但列表为空 → 渲样例数据")整段删除
- 后端不可达 → 明确错误态;后端可达但没有数据 → 空列表 + 引导文案(对齐 Users.tsx 已修做法)
- 复核:grep sample 零命中;npx tsc --noEmit 0 错误;npm run build 成功
|
2026-10-04 12:30:38 +08:00 |
|
AskaEth
|
63236c9b00
|
feat(capability,gateway): 工具策略落盘 + 主代理代审真接线(裁决 1.1 核对/1.3/10.4.2/13.4.3)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 1.1(核对):registry 默认两布尔 false 已一致,零代码改动(设计文档已按裁决改写)
- 1.3 + 10.4.2:新增迁移 0012_tool_policy(tool_policies 表,表名复数 + idx_tool_policies_name);
新增 registry.PolicyStore/SQLitePolicyStore,启动 Load 覆盖注册初值、SetPolicy 先落库后改内存
(落盘失败保持旧值并报错);面板保存路径不变但从此重启仍在
- 13.4.3:代审真接线 —— restrict.SensitiveCall 结构化判定(terminal / file write / http POST)、
restrict.Gate/Reviewer/Resolver(无代审者或代审报错一律 fail-closed 拦截),
组合根装进 loop.Options.Hooks 的 CallAdmit;gateway.RecordApproval 落 audit_logs
(who=角色名 / what=approval.<工具> / result=granted|denied)并广播 approval_notice 帧
- 前端:代审小字「xxx 想要干什么,我审查后批准了」进聊天流顶部(帧→store→组件,文案单一来源
复用 audit.Approval.Explain()),附纯 node 逻辑测试
- 复核:迁移在 data/cyrene.db **副本**上 up/down/up 各一次通过;TestRegistry_PolicyStoreSurvivesRestart
与 TestAdminSetPolicySurvivesRestart 证明「重启后策略仍在」;terminal 触发代审 + 审计有行有端到端断言
|
2026-10-04 12:30:16 +08:00 |
|
AskaEth
|
ed5bd92e1b
|
fix(exec): 沙箱子进程不再继承宿主完整环境(P0-7,审计 §4.3)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- buildEnv 不再以 os.Environ() 全集为基,改为「平台最小必需键白名单」裁剪后再叠加 req.Env
· Windows:PATH/PATHEXT/SYSTEMROOT/WINDIR/COMSPEC/TEMP/TMP/USERPROFILE/HOMEDRIVE/HOMEPATH/APPDATA/LOCALAPPDATA/NUMBER_OF_PROCESSORS/OS/PROCESSOR_ARCHITECTURE
· Unix:PATH/HOME/TMPDIR/LANG/LC_ALL/USER/SHELL
- 键名匹配在 Windows 上大小写不敏感(避免宿主写 Path 时漏掉),overlay 覆盖 base 时同口径去重
- envAllowed 语义不变:调用方能显式放行的键照旧,仅改变 base 来源
- 新增 TestTerminal_Env_HostNotInherited(非并行,t.Setenv):父进程设非白名单变量,断言子进程读不到;反证=把该键加进白名单立刻 FAIL
|
2026-10-04 12:29:43 +08:00 |
|
AskaEth
|
09ee561aa7
|
refactor(exec,io): 文件沙箱单入口收进 io 工具、删 exec.FileSandbox(裁决 13.4.4)+ 修一条假阳性安全断言
- 删除未接线的 exec.FileSandbox(含 5 个用例):文件沙箱从此只有 plugins/tools/io/file.go 一处实现
- io 侧取更严一侧:NUL 拒绝(原 io 缺)、写前按最深存在祖先判定落点(避免越界建目录)、roots 归化到真实路径(修 roots 自身是 symlink 时的全误拒)
- exec/sandbox.go 保留并注释说明:那是**终端工作目录守卫**的原语(terminal.go 在用),不是文件沙箱
- 修假阳性:原 NUL 用例断言错误文本含 "NUL",而 t.TempDir() 目录名自带测试函数名 "…RejectsNULBytePath…"、错误又内嵌整条临时路径 ⇒ 删掉安全检查用例照样绿。改为哨兵错误 ErrNullByte + errors.Is(错误文本逐字节不变),修复后同一变异必红
- 同类排查:file_test.go 三处文本断言判定无风险(含空格的串不可能出现在临时目录名里),保留
|
2026-10-04 12:29:39 +08:00 |
|