AskaEth
|
378faf212e
|
feat(browser): 取正文能力 + web-fetch 浏览器降级档接线(解封 Z5/B5)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
Z5(c2e413e)把 web-fetch 的降级链与注入点做完了,但「取正文」入口缺失 ⇒
组合根拿不到 BodyRenderer、这一档实际关着(当时如实登记)。本片补上:
- internal/capability/browser/render.go:新增 Manager.RenderText(ctx,url)
(导出的进程内能力)—— 先过 GuardURL(与全仓同一份 SSRF 判定源)、复用
withSession/session、等 readyState=complete 之后才取 body.innerText;
渲染失败 = 分类错误,渲染成功但正文为空 = 空串+无错(不冒充成功/失败)。
- cmd/cyrene/wire_body_fallback.go:适配器 + 挂载点,把 Manager 适配成
io.BodyRenderer 并用 WithBrowserFallback 挂上;web_runtime 里把浏览器
接线**上移到 io 工具集之前**(顺序颠倒会静默关死这一档)。
- plugins/tools/browser/tool.go:新增 Tool.Manager(),供组合根取驱动句柄。
开关口径(裁决,依据 design/28 §1 M5 / §7 判据 4 / §8 B5):**有可用浏览器
就挂,没有就不挂**,不新增开关 ——
① 设计把 M5/B5 写成要落地生效的降级档,不是永远关着的空壳;
② 设计 §8 的可调项清单里没有这条降级档的开关,`.env` 已冻结 ⇒ 自造开关属
「自行发挥」;
③ io 库层「不传 = 默认关」的语义一字未改,本片只把组合根从「永远关」改成
「没来源就关」,并留带来源的 WARN(reason=no-usable-browser)。
⚠️ 若日后要「有浏览器也需显式开启」,得先给设计定开关落点,代码侧一行改回。
验收(主会话复跑 + 亲自变异):go build ./... + 三包 vet 绿;browser/io 两包
测试绿(cmd/cyrene 由子代理跑过全绿);我用 -overlay 把 GuardURL 的判定对象
换成常量 URL(绕过被拒目标)⇒ TestManager_RenderTextBlockedURLRejectedBeforeAnyProcess
变红,证明判定确实**在起任何进程之前**跑。
⚠️ 生产端到端未验:按红线没重启后端、没起真 Chrome ⇒「真页面 → browser 取到
正文」这条链只有假 CDP + 组合根接线级证据。
⚠️ design/28 有 6 处表述与代码现状冲突(归属 web-fetch vs web-search、extract
动作归属、B5 排期、状态过期等),已登记待我同步文档。
|
2026-10-07 09:59:56 +08:00 |
|
AskaEth
|
e0a6bca501
|
feat(browser): B3 截图→上下文闭环 + B4 面板声明页(Y4)
- B3:截图落盘后**自动**并入本轮视图(能收图 ⇒ 真 image 部件挂 user 消息;收不了 ⇒ vision/OCR 文字;
大图先经 image-crop 裁切;取走即消费、每会话 ≤4 张、TTL 10min、跨会话隔离)
- B4:browser 面板**声明**(配置表单 + 运行状态/指纹自检/最近截图三张只读表 + 拍一张/重新自检)
+ 六个动作走 PLG-2 的通用动作端点(**不开新路由**)+ 保存事务(不可用则回滚 409)+ 热重载
- 读面**不启动浏览器**(计数型假 dialer 证明 0 次拨号);行数据不含路径/URL/内容
- 3 个变异(短路主路/行与列 key 脱钩/保存不回滚)
⚠️ **两行接线未落**(不在我文件面):wire_runtime.go 的 TransformContext + wire_frontend.go 的
wireBrowserPanel —— 落地前 B3/B4 只是「组件就绪」,跑着的后端里不存在(Y4 已写盯梢用例)
|
2026-10-06 21:48:50 +08:00 |
|
AskaEth
|
2d211c2d16
|
feat(backthink,browser): 自排工具面 C1-3 + 浏览器两处偏离收口(X2+X3 同文件一并落)
X2 C1-3(自排工具面与提示词):
- request_think(thinktool.go,照 transcode/tool.go 范式)+ reason 必填/urgency 闭集 + 双守门
(安全闸 + owner 判定:群聊/陌生人一律拒)
- **成对**进两张唤醒态允许集(quiet + awake;CAPACITY_TOOL_SETS 是整体替换)
- 提示词抽共用段落 + 自排前缀优先(不枚举工具清单);面板加 self_wake 标签与筛选轴
- 4 个变异自检(拿掉 owner 判定/只加一张表/放宽 urgency/前端标签恒等)
X3 收口(与 X2 共用 wire_services.go ⇒ 一并落):
- 删掉第三份 SSRF 实现(guard.go),改由 io.ValidateRequestURL 唯一判定 + 薄门面(保两个错误身份)
- 浏览器会话挂进 a.close(真机:真 Chrome 被关、无残留、生产未扰动)
- a.wireBrowser() 归位到 wire_runtime.go,删掉 ioToolOptions 的临时挂点
- 5 个变异自检
顺带补提交 C1-2 漏掉的 internal/config/runtimeconfig/backthink_test.go(ed50053 漏 add)。
|
2026-10-06 21:16:23 +08:00 |
|
AskaEth
|
f1fbc249fd
|
feat(browser): B1 接线 + B2 薄层工具面(V5)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- browsercfg 接进组合根:配置读 $DATA_DIR/config/plugins/browser.json(零 env)→ 探测(本机
Chromium → 已在跑的 CDP)→ 不可用就不注册(原因码入日志)
- 自研最小出站 CDP 客户端(不 Enabled Runtime、隔离世界求值、不发 --enable-automation)+
导航 + 截图 0600 落盘 + 指纹自检;工具 browser(open/screenshot/info,owner-only)
- 3 个变异自检(启动恢复 --enable-automation/无视可用性/空闲回收失效)
- 真机对照(两站各 1 次,**如实结论**):两侧都 pass ⇒ 「headless 被拦 / headful 通过」**未被证明**;
但测到两处硬差异:无头 UA 带 HeadlessChrome、screen 800 vs 2632;两模式 webdriver 均 false
(把 L6 的推断变成实测)。跑完 0 残留 Chrome、无对外监听端口
⚠️ 未做:MCP 自动接入(口径委派未落地)/自动注入上下文/面板页/搜索降级/docker 配方/Windows 用
pipe(Go ExtraFiles 不支持);SSRF 落了第三份同策实现待收口;浏览器会话未挂进程关闭链
|
2026-10-06 20:25:16 +08:00 |
|
AskaEth
|
4a04ad43fe
|
feat(skills): 示例技能 + 端到端验收(V3)
- configs/skills/daily-brief/skill.yaml:真能跑的工作流(4 步依赖图 + 2 条 guardrail + allowed-tools)
- example_skill_e2e_test.go:真 Loader + 真 registry + 真 loop 三轮断言 —— 第1轮只有清单、
第2轮命中展开正文且工具面只剩 allowed(B 工具不可见)、第3轮正文保留而工具面恢复、BodyRenders==1
- 3 个变异自检(triggers 清空/关掉收缩/正文漏进清单)
⚠️ 生产未验:当前后端启动早于技能落盘 ⇒ 需一次 restart 才会出现 skills registered;
隔离实例(临时端口/临时 DATA_DIR)已 GREEN,含面板链四条真实回执
|
2026-10-06 20:25:14 +08:00 |
|
AskaEth
|
a30f4a49ff
|
feat(search): provider 热重载 + primary/fallback(W3)
- 保存被包成事务:快照 → 落盘 → 按新配置重建工具 → 原子替换注册表条目(registry.ReplaceTool
窄方法,保留运行期 Policy);下一轮即生效,不要求重启
- 若新配置会让后端下次起不来(主家未配齐 fail-fast)⇒ 文件按字节回滚 + 409 config_unstartable
- 声明面补 primary + fallback[](可配可生效);否决「另开 form」方案(会破坏既有 reauth 回填)
- 主 provider 解析口径核查结论:没被 PLG-4 改坏(顺手修了一处日志缺陷)
- 4 个变异自检(丢 Policy/不换条目/回滚 no-op/忽略 fallback)
|
2026-10-06 15:59:12 +08:00 |
|
AskaEth
|
2e1c3ed3fd
|
feat(plugins): 面板动作执行器接线 —— 动作真可用,不再 501 兜底(L1)
- 插件管理器加生产动作处理器登记面(RegisterActions);未登记处理器/未声明动作仍 404
- web-search 四个动作真读写真源 + 真发 HTTP 探针:plugin.listProviders/saveProvider/
testProvider/reauthProvider(配置落 $DATA_DIR/config/plugins/web-search.json,0600)
- 失败回结构化错误码(不含上游原文)+ 审计带 code 字段;501 文案改为「未登记处理器」
- 拆出 panelactions.go(动作索引推导/OptionsActionName/三闸门分发),panels.go 519→347 行
缺口(如实):面板保存后运行中的工具**不热重载**(下一片做);声明面缺 primary/fallback
(按 DECISIONS-2026-10-06 #1/#2 补)。
|
2026-10-06 14:12:23 +08:00 |
|
AskaEth
|
2d21aa553e
|
feat(plugins): 插件管理器接线 —— 面板接入点快照 + 动作分发(PLG-2)
- GET /api/v1/admin/panels:按调用者角色过滤后的接入点快照(PLG-1 的 catalog 挂进插件管理器)
- POST /api/v1/admin/plugins/{id}/actions/{action}:**只接受该插件声明过的动作名**
(未声明 ⇒ 404);写动作 writeAuth + 落审计;插件只给动作名不给 URL ⇒ 不给插件开任意请求面
- 生命周期:install/uninstall/enable/disable 变化后**重算面板集合**并经进程内 bus 推 panels_changed
(前端可热更新;不新开端口)
契约 v0.78 登记由主会话随后统一落(本片报告给了可直接粘贴的契约段)。
|
2026-10-06 09:03:57 +08:00 |
|
AskaEth
|
f75e7a9c9b
|
feat(skills): 技能加载/校验/真执行第一片(design/09 §6 定稿落地)
- 加载器/校验:目录式 configs/skills/<id>/skill.yaml(兼容旧单文件 <id>.yaml,先目录后文件);
新字段 version/when-to-use/invocation(三态)/triggers/paths/allowed-tools/disallowed-tools/
context(ine|fork)/agent/model/effort/metadata;**依赖环 ⇒ 加载期拒**(运行期绝不挂死);
depends 指向不存在步骤 ⇒ 拒;同一工具同时在 allowed 与 disallowed ⇒ 拒;错误可分类(哨兵 + %w)
- Runner.Run 真执行(替换 ErrRunPending):步骤拓扑(无依赖可并行、上限 2)+ guardrail 强制点
(enforced 违反 ⇒ 中止并如实报「哪条、哪一步」;否则 WARN 继续)+ 失败不静默跳过 + ctx 取消传播
- 🔴 能力收缩只收不放:该轮可用工具 = allowed-tools ∩ 安全闸 ∩ 注册表,再减 disallowed-tools
- 另有渐进披露相关的 listing/surface/activation(清单投影与激活判定)
⚠️ 未接线:本片是库与执行器,尚未把技能清单接进模型面(见 report 的分阶段)。
|
2026-10-06 09:03:35 +08:00 |
|
AskaEth
|
29181245ce
|
feat(browser): 浏览器配置与探测库(internal/capability/browsercfg,纯库零接线)
按 design/28 §2/§3 的「配置不进 .env」口径:读 $DATA_DIR/config/plugins/browser.json
(0600 + temp+rename 范式,**不读 env、不加新键**);有头/无头、CDP 端点、profile 目录、
视口/超时/并发(1)/截图上限全部类型化 + 常量默认值;**探测优先级**(本机 Chrome/Chromium
可执行文件 → 已在跑的容器)并返回可分类的「为什么不可用」(供上层如实降级,不假装可用);
profile 目录含凭据 ⇒ 0600 + 不进 git/不进上下文的注释与校验。
本片零既有文件改动(不注册工具、不碰 cmd/),接线留 B2。
|
2026-10-06 09:03:34 +08:00 |
|
AskaEth
|
c9144c1096
|
feat(plugins): 插件「管理面板声明」库——声明模型 + 闭集校验 + catalog(design/09 §5.2/§5.2.1)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
纯库、零接线:不碰 gateway/frontend/Docs/.env*(本片刻意不接线,避免与在途切片争用文件面)。
- pkg/plugins/sdk:面板声明类型(JSON tag 与 design/09 §5.2 示例逐字同形);
字段类型与 section 类型都是**闭集**;When 三态 + **严格 UnmarshalJSON**(未知条件键报错,
不静默丢)
- internal/capability/paneldecl:闭集校验(47 条拒绝用例,断言的是**分类哨兵 + JSON 路径**,
不是错误字符串)· catalog(并发安全、返回拷贝、按 (group, order, 登记序号) 的**全序**稳定排序)·
when 求值(上下文由 Resolver 注入,本包不读环境变量/文件)· 角色过滤(viewer 只留
status/log/table 且摘掉 rowActions,纯写面板整体隐藏;未知角色 fail-closed)
- 拒绝粒度:插件 id 非法 ⇒ 整插件拒绝;单个面板非法 ⇒ 只拒该面板 + 聚合显式报错(理由见报告)
【我的验收】隔离 worktree(19 文件)build/vet/linux/darwin 全过、69 包全绿;
我亲手打红变异:把同组同序的回退比较 反成 ⇒ TestCatalog_StableOrder FAIL。
(记录一条观察:比较器已靠 seq 构成全序,故 sort.SliceStable 的稳定性是冗余保护 ——
我第一次用「SliceStable→Slice」打不红,正是因为全序与算法无关;这不是测试虚护。)
|
2026-10-06 08:06:20 +08:00 |
|
AskaEth
|
321cc3b763
|
feat(backthink): 思考轮工具面补齐(裁决 15)—— 能力面接入 + 只读 capability_list + 本轮状态快照
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 缺口 d:状态在**思考前**读一次,同一份快照既喂思考轮又喂 Decide(读不到 = Known=false,绝不伪装成中性状态)
- 缺口 c:新增只读工具 capability_list(owner-only、三重输出边界、读写隔离),她可自查当下真实可用面
- 缺口 b:内置允许集补 transcode / capability_list(此前 CAPACITY_ENABLED=true 时新工具会从模型可见面消失)
- 缺口 e:guidancePrompt 旧文案承诺的「IoT/日历/提醒」在全仓根本没有对应工具(chat 侧也没有)⇒ 按诚实化改为「与主人对话同等工具面 + 指名自查入口」,不再有空头支票
- (a) 未做且**不自创**:那三把工具无任何设计规格(名字/schema/读写边界/输出上限)⇒ 已报回并登记进 design/20(裁决:走能力/插件/MCP 暴露路线)
- 变异实测:允许集去掉新工具 ⇒ TestDecide_AllowedSets + 组合根跨层测试红;丢掉状态快照 ⇒ TestLoopThinker_Think_InjectsRoundStateBlock 红
- 已知弱项(如实登记):组合根那行 wireCapabilitySurface() 调用本身无测试覆盖(与既有 wireTranscode 同惯例)
|
2026-10-05 13:54:57 +08:00 |
|
AskaEth
|
4a2d276881
|
feat(capability): 转码能力包(vendor 纯 Go AMR-NB 解码器 + 黄金向量逐样本对照 + 8 哨兵 + 注册面)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
|
2026-10-05 13:02:28 +08:00 |
|
AskaEth
|
85abb90067
|
feat(security): 敏感清单补齐 design/11 §4 的 7 类(写数据/对外发消息/访问密钥/改配置,结构化判据)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
|
2026-10-05 11:53:17 +08:00 |
|
AskaEth
|
6066165394
|
test(flake): 清掉最后三条墙钟/条件竞态(mcp 订阅门控 + vision 注入时钟 + voice 兜底期限)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- #6 capability/mcp TestRegistry_ToolListChangedRefreshes:真因**不是慢,而是条件竞态** —— 本机协商到协议 2026-07-28(SEP-2575)时服务器**只**把 notifications/tools/list_changed 投给已登记 subscriptions/listen 的会话,而客户端订阅是 fire-and-forget(Connect 返回 ≠ 服务器已登记),服务器又在变更后 10ms 发一次、丢了不补 ⇒ 订阅登记晚于那个定时器,该次变更**永远**不生效(旧 waitFor(5s) 只能超时)。修法:显式门控 —— 先等服务器 notifications/subscriptions/acknowledged(服务器先登记再回确认)→ 再触发变更 → 再断言刷新由 tools/list_changed 驱动(既有断言一条未少、另加一条更强的驱动断言)。协议回落旧版时门控自动跳过。
- #7 multimodal/vision TestImageCache_RefetchesAfterTTLWhenContentChanges:真因是把**墙钟当判据**(ttl=20ms 下「TTL 内」成立与否只由调度抖动决定,实测空载≈0、并行负载下 >20ms 会同时打红两条断言)。修法:注入可手动推进的 testClock(生产本就有 cache.now 字段、默认 time.Now,零生产改动),断言一条未少。
- 附带:修掉 G5 批次遗留的第三条墙钟兜底 —— gateway/voice_turn_test.go 的 waitFrame 3s → 15s。**放宽的是兜底期限、不是断言**:它断言的是「帧确实到达」,帧没到照样 Fatal;实测单跑 -count=20 全绿、只在整树并行下偶红(语音回合要过编排器 → 门控假 runner → 假 TTS → 定向回连接)。
- 主会话独立验收:隔离 worktree(F2 三个测试文件)build/vet 绿、两条目标用例各 -count=20 绿;加本条兜底修复后整树连跑 2 次均 59 ok / 0 FAIL(修前那次整树抓到 voice 那条红 → 归因见上)。
- 子代理自报(已核实并清理):它在加压时用 30 个 yes 做负载、第一次 kill 没杀干净 ⇒ 整机 12 核被占满约 15 分钟(期间所有 go 命令近乎停滞,也解释了本轮测试为何异常慢);已全部终止(Get-Process yes = 0),此后证据均在干净环境重跑。它同时**如实说明**:在纯加压下没能直接撞出这两条原始 flake(窗口极窄),确定性论证建立在「可控对抗条件复现 + 根因」上。
|
2026-10-04 21:11:17 +08:00 |
|
AskaEth
|
5c2189efb0
|
docs(mcp): 存量英文注释中文化(仅注释,代码零字节改动)
- capability/mcp 整包 17 个文件核查:仅 config.go / registry.go 含英文注释(38 行)→ 全部中文化;
其余 15 个文件本就全中文,零改动。
- 保留 YAML/Go/JSON 示例行与字符串字面量(非注释,禁止改动)。
- 验收:机械校验为空;gofmt -l 干净;go build/vet/test ./internal/capability/mcp/... 全绿。
|
2026-10-04 16:58:01 +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
|
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
|
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
|
70c9fba529
|
feat(plugin): 插件热安装(MCP server) — POST /admin/plugins/install 连接+发现+注册工具进registry+落盘plugins.json
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- capability/plugin/manager.go: Manager(Install/Uninstall/List/Restore/Close); Install=连接+发现+mcp:name注册工具,失败不落盘; holder持有*mcp.Registry; boot Restore重装
- config/runtimeconfig/plugins.go: PluginConfig(Normalize/Validate), LoadPlugins/SavePlugins(0600+tmp+rename)/Upsert/Delete/Masked(apiKey+敏感env掩码)
- mcp: MCPConfig加APIKey/Env, http/sse Bearer应用, stdio子进程env合并; registry.ToolNames()
- gateway: adminPluginInstall/Uninstall/ListInstalledPlugins; Deps.Plugins注入
- cmd/cyrene/plugins.go: wirePlugins(boot Restore+close)
- 契约: body{kind:mcp,name,config{transport, endpoint?/command?,args?,apiKey?,env?}} → {installed,name,kind,transport,toolCount}; 失败502不落盘/非法400/未注入501; 卸载连带unregister+删配置
- 测试(manager/plugins/admin/mcp_auth/组合根), build/vet/test绿+3平台交叉编译
- Docs/api-client v0.28 + api-reference install=501改真实; .gitignore加plugins.json
- 前端api.ts仍发旧body(无config)会400, 面板安装表单待后续
|
2026-09-08 23:20:12 +08:00 |
|
Aska
|
b0bd93b15c
|
feat(mcp): Top5#3 对齐 MCP Go SDK——协议版本协商 + list_changed 差量刷新 + keepalive + Streamable HTTP
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
- 协议版本协商:initialize 先发最高版本(2025-11-25)并声明能力集合,遇
UnsupportedProtocolVersionError(-32022)/服务器不支持版本 → negotiateMutuallySupportedVersion
求出双方最高共同版本降级重试(最多2次);无共同版本→ErrUnsupportedProtocolVersion。
协商结果记 negotiatedVersion,HTTP 传输回填 Mcp-Protocol-Version 头。
- tools/list_changed 订阅:capabilities 声明 tools.listChanged:true;传输读无 id 帧路由到
handleServerNotification;refreshPending 原子旗标合并突发 + 新 goroutine 调 onToolListChanged
(避免 stdio lineRPC 重入自锁);Registry 真差量刷新(重新 DiscoverTools→移除消失/注册新增,
跳过同名冲突保外来工具)。
- keepalive:WithKeepAlive(interval,failures) 起 goroutine 定时 Call(ping),连续失败≥阈值关
session(默认3,可配);服务器不支持 ping(-32601)停 keepalive 不误关;ctx+Close 取消不泄漏。
- Streamable HTTP 传输:newTransport 支持 TransportType=http|streamable(保留 stdio/SSE 推断,
空值走旧逻辑不破坏);Call POST+Accept json/event-stream 响应可单 JSON 或 SSE 流找匹配 id;
Mcp-Session-Id 会话 + 独立 GET SSE 流收 server 通知;config 读 MCP_TRANSPORT。
- schema 缓存判定不做:客户端透传 map[string]any 无重复编译,SDK SchemaCache 是服务端
按 Go 类型反射场景,客户端无对应。
go build/vet/test 全绿(count=2 无 flaky) + windows/darwin 交叉编译。
|
2026-09-06 17:27:14 +08:00 |
|
Aska
|
5dae2b9741
|
fix(gateway): 收敛 sdk.Channel 与 adapter.PlatformAdapter 接口漂移,/admin/channels 恢复枚举
根因:sdk.Channel.Connect 为 2 参 (ctx, config any),adapter.PlatformAdapter.Connect 为
1 参 (ctx),Go 无重载 → 4 个渠道(qq-obv11/weixin-ilink/telegram/webhook)只实现 1 参
Connect,类型断言 cap.Value.(sdk.Channel) 恒失败 → /api/v1/admin/channels 恒返回 []。
收敛方向:sdk.Channel.Connect 改 1 参 (ctx),与 PlatformAdapter 生命周期子集一致;
4 个真实适配器自动满足新接口,adminListChannels 枚举成功。最小改动(不改渠道实现、
不引依赖)。同步修正 sdk_test/registry_test/extra_test 的 mock。
|
2026-09-06 14:04:52 +08:00 |
|
Aska
|
488cf9c79c
|
feat(capability/mcp): MCP 客户端(stdlib JSON-RPC over stdio/SSE)+ Registry 自动注册/Unregister(registry 增 Remove)
|
2026-09-06 06:28:38 +08:00 |
|
Aska
|
b3c61aa1ff
|
feat(iot): IoT 插件化(Provider/Manager/mock 8设备/能力约束/bus 事件);feat(capability/restrict): 工具级布尔标记(群聊/陌生人可用,默认关,策略引擎雏形)+ registry ToolPolicy
|
2026-09-06 06:26:21 +08:00 |
|
Aska
|
915aa8a100
|
feat(capability/skills): 可复用工作流技能(Skill 模型 + Store + YAML Loader + Runner 展开 + 注册)
|
2026-09-06 06:25:42 +08:00 |
|
Aska
|
653c2489bf
|
feat(capability): 能力注册中心(类型化注册/按类查询/并发安全)
|
2026-09-06 04:35:31 +08:00 |
|