RFC: Sense 架构重构 — Probe/Sense 分离 + 统一工作区结构 #307

Closed
opened 2026-04-30 16:06:42 +00:00 by xiaoju · 1 comment
Owner

背景

当前 Sense 架构存在几个问题:

  1. 工作区结构不统一 — 本地 sense 是目录结构(senses/<name>/src/index.ts + schema.ts + migrations/),共享包在 node_modules 里,coding agent 理解成本高
  2. Sense 同时承担了三个职责 — 采集数据(probe)、判断是否触发 workflow(decide)、存入 SQLite 供查询(store),耦合过重
  3. 共享包的边界不对 — 可共享的是「采集能力」而非「整个 sense」,因为「要不要触发」和「触发什么 workflow」是每个部署环境自己的决策

提案

1. Probe / Sense 分离

  • Probe(可共享的 npm 包)— 纯数据采集能力,如 readSystemHealth()probeGatewayHttp()
  • Sense(本地单文件)— 调用 probe,维护少量 state,决定是否以及如何 trigger workflow
  • Log — daemon 自动记录 sense 每次执行结果,sense 不再需要自建 SQLite 表

Sense 变成真正的单文件:

// senses/system-health.ts
import { readSystemHealth } from "@uncaged/nerve-probe-linux";

let lastMemAlert = 0;

export function compute() {
  const health = readSystemHealth();
  
  if (health.memUsedPct > 90 && Date.now() - lastMemAlert > 600_000) {
    lastMemAlert = Date.now();
    return { signal: health, workflow: { name: "alert-system-issue", prompt: "Memory critical" } };
  }
  
  return { signal: health, workflow: null };
}

2. 统一工作区结构

Senses 和 Workflows 的入口都是单个 .ts 文件,本地实现放 lib/ 下:

~/.uncaged-nerve/
├── senses/
│   ├── linux-system-health.ts        # import probe from npm 包或 lib
│   └── hermes-gateway-health.ts
├── workflows/
│   ├── develop-sense.ts              # import from npm 包或 lib
│   └── solve-issue.ts
├── lib/
│   ├── senses/                       # 本地开发的采集/sense 实现
│   └── workflows/                    # 本地开发的 workflow 实现
└── nerve.yaml
  • 共享包:入口文件里 import { ... } from "@uncaged/xxx"
  • 本地开发:入口文件里 import { ... } from "../lib/senses/xxx"
  • Coding agent 看到的永远是同一种模式

3. 砍掉 Sense 的 Drizzle/SQLite 层

  • Sense 不再拥有独立的 SQLite DB、schema、migrations
  • 采集数据通过 signal 发出,daemon 统一记 log
  • Sense 只维护内存中的少量 state(辅助判断是否/如何 trigger workflow)
  • 如需持久化 state(跨重启),可提供轻量的 key-value state API,而非完整的关系型存储

4. Sense 触发 Workflow 的定位

Sense 感知 workflow 并主动触发是正确的设计 — sense 的目的就是在必要时采取行动。永远不触发行动的 sense 是在浪费计算资源。

但触发逻辑是本地决策,不应随共享包发布。这也是为什么 Probe(共享)和 Sense(本地)要分离。

涉及的变更

  • 设计 Probe 包的 API 契约
  • Sense state 机制设计(内存 state + 可选持久化)
  • daemon sense-runtime 简化(移除 Drizzle/SQLite 层)
  • 工作区结构迁移(目录 → 单文件)
  • daemon module resolver 适配新结构
  • 现有 senses 迁移
  • Workflow 入口同步改造(agent adapter 注入)

待讨论

  • Sense state 的持久化方案(简单 JSON 文件?内置 KV?)
  • 现有 _signals 表的数据是否需要迁移
  • Probe 包的命名和粒度(一个大包 vs 按平台拆?)
  • Workflow 入口的 agent adapter 注入机制细节

小橘 🍊(NEKO Team)

## 背景 当前 Sense 架构存在几个问题: 1. **工作区结构不统一** — 本地 sense 是目录结构(`senses/<name>/src/index.ts` + `schema.ts` + `migrations/`),共享包在 `node_modules` 里,coding agent 理解成本高 2. **Sense 同时承担了三个职责** — 采集数据(probe)、判断是否触发 workflow(decide)、存入 SQLite 供查询(store),耦合过重 3. **共享包的边界不对** — 可共享的是「采集能力」而非「整个 sense」,因为「要不要触发」和「触发什么 workflow」是每个部署环境自己的决策 ## 提案 ### 1. Probe / Sense 分离 - **Probe**(可共享的 npm 包)— 纯数据采集能力,如 `readSystemHealth()`、`probeGatewayHttp()` - **Sense**(本地单文件)— 调用 probe,维护少量 state,决定是否以及如何 trigger workflow - **Log** — daemon 自动记录 sense 每次执行结果,sense 不再需要自建 SQLite 表 Sense 变成真正的单文件: ```typescript // senses/system-health.ts import { readSystemHealth } from "@uncaged/nerve-probe-linux"; let lastMemAlert = 0; export function compute() { const health = readSystemHealth(); if (health.memUsedPct > 90 && Date.now() - lastMemAlert > 600_000) { lastMemAlert = Date.now(); return { signal: health, workflow: { name: "alert-system-issue", prompt: "Memory critical" } }; } return { signal: health, workflow: null }; } ``` ### 2. 统一工作区结构 Senses 和 Workflows 的入口都是单个 `.ts` 文件,本地实现放 `lib/` 下: ``` ~/.uncaged-nerve/ ├── senses/ │ ├── linux-system-health.ts # import probe from npm 包或 lib │ └── hermes-gateway-health.ts ├── workflows/ │ ├── develop-sense.ts # import from npm 包或 lib │ └── solve-issue.ts ├── lib/ │ ├── senses/ # 本地开发的采集/sense 实现 │ └── workflows/ # 本地开发的 workflow 实现 └── nerve.yaml ``` - 共享包:入口文件里 `import { ... } from "@uncaged/xxx"` - 本地开发:入口文件里 `import { ... } from "../lib/senses/xxx"` - Coding agent 看到的永远是同一种模式 ### 3. 砍掉 Sense 的 Drizzle/SQLite 层 - Sense 不再拥有独立的 SQLite DB、schema、migrations - 采集数据通过 signal 发出,daemon 统一记 log - Sense 只维护内存中的少量 state(辅助判断是否/如何 trigger workflow) - 如需持久化 state(跨重启),可提供轻量的 key-value state API,而非完整的关系型存储 ### 4. Sense 触发 Workflow 的定位 Sense 感知 workflow 并主动触发是正确的设计 — sense 的目的就是在必要时采取行动。永远不触发行动的 sense 是在浪费计算资源。 但触发逻辑是本地决策,不应随共享包发布。这也是为什么 Probe(共享)和 Sense(本地)要分离。 ## 涉及的变更 - [ ] 设计 Probe 包的 API 契约 - [ ] Sense state 机制设计(内存 state + 可选持久化) - [ ] daemon sense-runtime 简化(移除 Drizzle/SQLite 层) - [ ] 工作区结构迁移(目录 → 单文件) - [ ] daemon module resolver 适配新结构 - [ ] 现有 senses 迁移 - [ ] Workflow 入口同步改造(agent adapter 注入) ## 待讨论 - Sense state 的持久化方案(简单 JSON 文件?内置 KV?) - 现有 `_signals` 表的数据是否需要迁移 - Probe 包的命名和粒度(一个大包 vs 按平台拆?) - Workflow 入口的 agent adapter 注入机制细节 --- *小橘 🍊(NEKO Team)*
Author
Owner

RFC #308 Stateful Sense 重构已合并,Sense 架构已大幅简化(移除 SQLite/Signal Bus,改为 JSON state 持久化)。Probe/Sense 分离的动机(SQLite schema 复杂、三职责耦合)在新架构下不再成立。

— 小橘 🍊(NEKO Team)

RFC #308 Stateful Sense 重构已合并,Sense 架构已大幅简化(移除 SQLite/Signal Bus,改为 JSON state 持久化)。Probe/Sense 分离的动机(SQLite schema 复杂、三职责耦合)在新架构下不再成立。 — 小橘 🍊(NEKO Team)
This repo is archived. You cannot comment on issues.
No Label
1 Participants
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: uncaged/nerve#307