diff --git a/README.md b/README.md index dac6843..ed655f0 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ AI Agent 的 init 系统 + 内核。对标 Linux 内核 + systemd。 -> 状态:设计草案 +> 状态:阶段 1(内核骨架)已完成,阶段 2/3 部分完成。详见 docs/03-实施路线.md ## 对标 diff --git a/docs/01-内核系统调用.md b/docs/01-内核系统调用.md index 18da565..40450f5 100644 --- a/docs/01-内核系统调用.md +++ b/docs/01-内核系统调用.md @@ -12,7 +12,7 @@ agentsd 定义 9 个 syscall 接口。类比 Linux 内核 syscall 表——接 ``` display.text(content) -display.rich(markup) +display.rich(markup, format) display.image(data, format) display.clear() display.notify(message) @@ -27,12 +27,12 @@ display.notify(message) **管**:扬声器输出、麦克风输入 | **不管**:TTS/STT(插件的事) ``` -audio.play(data, format) +audio.play(stream AudioChunk{data, format}) # 客户端流式上传音频帧 audio.stop() audio.volume(level) -audio.record.start(format) -audio.record.stop() -> data -audio.record.stream(callback) +audio.record_start(format) +audio.record_stop() -> data +audio.record_stream(format) -> stream AudioChunk # 服务端流式返回录音帧 ``` --- @@ -44,13 +44,13 @@ audio.record.stream(callback) **管**:磁盘文件 | **不管**:结构化数据(Memory) ``` -fs.read(path) -> data -fs.write(path, data) +fs.read(path, offset?, length?) -> data +fs.write(path, data, append?) fs.delete(path) fs.rename(from, to) fs.stat(path) -> metadata fs.list(dir) -> entries -fs.watch(path, callback) +fs.watch(path) -> stream FsWatchEvent{path, kind} ``` --- @@ -65,8 +65,8 @@ fs.watch(path, callback) memory.read(key) -> value memory.write(key, value) memory.delete(key) -memory.list(prefix?) -> keys -memory.search(query) -> results +memory.list(prefix?, limit?) -> keys +memory.search(query, limit?) -> results ``` --- @@ -99,13 +99,13 @@ gRPC 流式语义:OpenConn/Listen 返回 `stream ConnEvent{conn_id, data, kind}` **管**:子进程生命周期、stdio | **不管**:插件间路由(内核调度) ``` -proc.spawn(cmd, args, env?) -> pid +proc.spawn(cmd, args, env?, cwd?) -> pid proc.kill(pid) proc.wait(pid) -> exitcode proc.stdin(pid, data) -proc.stdout(pid) -> data +proc.stdout(pid) -> stream DataChunk # 服务端流式输出 proc.signal(pid, sig) -proc.list() -> [pid] +proc.list() -> [ProcInfo{pid, cmd, status}] ``` --- @@ -134,10 +134,10 @@ timer.now() -> timestamp **管**:屏幕读取、输入模拟 | **不管**:向用户展示(Display)、用户主动输入(Input) ``` -hid.capture(region?) -> image -hid.mouse(x, y, action) -hid.keyboard(key, action) -hid.ocr(region?) -> text +hid.capture(x, y, width, height) -> image +hid.mouse(x, y, action, button) +hid.keyboard(key, action, modifiers?) +hid.ocr(x, y, width, height) -> text ``` --- @@ -152,7 +152,7 @@ hid.ocr(region?) -> text input.text() -> string input.key() -> keyevent input.clipboard() -> data -input.event() -> event +input.events() -> stream InputEvent # 服务端流式事件 ``` --- diff --git a/docs/02-插件模型.md b/docs/02-插件模型.md index f7fa487..71e4b20 100644 --- a/docs/02-插件模型.md +++ b/docs/02-插件模型.md @@ -19,21 +19,23 @@ --- -### 系统插件(= 内核模块 / 驱动) +### 系统插件(= 内核模块 / 驱动)⏳ 设计目标,未实现 为 syscall 提供具体实现。类比 `insmod alsa_driver.ko`。 ```yaml +# 设计示意(provides 字段与 FFI 加载尚未实现) id: alsa-audio type: system provides: audio entry: ./libalsa_audio.so ``` -- FFI 加载(.so/.dylib/.dll),零开销 +- FFI 加载(.so/.dylib/.dll),零开销 —— **未实现**,当前无动态库加载代码 - 只限 Rust / C ABI - 同一 syscall 可有多个驱动,同时只激活一个 - 无依赖 +- 当前内核仅拒绝外部进程注册 `type: system`(防止权限提升),加载机制本身待实现 --- @@ -43,12 +45,16 @@ entry: ./libalsa_audio.so ```yaml id: tts-edge +name: Edge TTS +version: 0.1.0 type: basic syscalls: - audio.play - network.request exports: - name: speak + description: Text to speech +entry: python tts_plugin.py ``` - 独立进程,gRPC/TCP 通信(后续切 UDS/Named Pipe) @@ -63,6 +69,8 @@ exports: ```yaml id: voice-agent +name: Voice Agent +version: 0.1.0 type: standard syscalls: - input.text @@ -73,12 +81,18 @@ depends: - chat-agent exports: - name: voice_chat + description: Voice conversation loop +entry: cargo run -p voice-agent ``` - 可依赖基础插件 + 其他标准插件 -- 按依赖拓扑排序加载(= systemd ordering) +- 按依赖拓扑排序加载(= systemd ordering)—— **未实现**:`depends` 当前仅随注册存储,不做解析/排序/校验(阶段 4) - 任意语言 +> **plugin.yaml 的当前角色**:内核**不会**扫描或解析 plugin.yaml——它目前是给开发者看的清单(entry/port 供手动启动用)。 +> 实际注册机制是插件进程启动后主动调用 `PluginBridge.Register`(gRPC),传 protobuf `PluginInfo{id, name, version, plugin_type, syscalls, depends, exports, endpoint}`。 +> 基于 YAML 的自动发现/自动加载属于阶段 4 的插件管理目标。 + --- ## 通信:gRPC(= D-Bus) @@ -96,7 +110,7 @@ exports: | 插件类型 | 传输 | 延迟 | Linux 类比 | |---|---|---|---| -| 系统插件 | FFI | ~纳秒 | 内核态函数调用 | +| 系统插件(未实现) | FFI | ~纳秒 | 内核态函数调用 | | 基础/标准(本机,当前) | gRPC/TCP | ~毫秒 | D-Bus over TCP | | 基础/标准(目标) | gRPC/Unix socket / Windows Named Pipe | ~微秒 | D-Bus over UDS | | 远程(可选) | gRPC/TCP | ~毫秒 | D-Bus over TCP | @@ -137,7 +151,9 @@ message CallRequest { --- -## 生命周期管理(= systemctl) +## 生命周期管理(= systemctl)⏳ 阶段 4 目标,未实现 + +以下命令为规划中的 CLI,当前内核仅提供 gRPC server,无任何子命令: | agentsd 命令 | systemd 对标 | 作用 | |---|---|---| @@ -153,7 +169,9 @@ message CallRequest { --- -## 加载顺序(= systemd boot) +## 加载顺序(= systemd boot)⏳ 设计目标,未实现 + +当前插件由开发者手动启动,启动后自行注册。规划中的加载顺序: ``` 1. 系统插件(FFI,注册 syscall 实现) ← 类比内核模块加载 @@ -163,7 +181,7 @@ message CallRequest { --- -## 看门狗(= Restart=always) +## 看门狗(= Restart=always)⏳ 阶段 4 目标,未实现 插件崩溃 → agentsd 自动重启(可配置策略): - `always`:总是重启 @@ -175,8 +193,8 @@ message CallRequest { ## 权限(= seccomp + cgroup) - 系统插件:内核信任,无限制 -- 基础插件:按 `syscalls` 白名单精确到方法(如 `fs.list`)校验,也支持 `fs` / `fs.*` / `*` 授权(= seccomp filter) -- 标准插件:syscalls + depends 白名单,未声明的一律拒绝 +- 基础/标准插件:按 `syscalls` 白名单精确到方法(如 `fs.list`)校验,也支持 `fs` / `fs.*` / `*` 授权(= seccomp filter) +- `depends` 字段当前仅声明、随注册存储,不参与权限校验(依赖校验属阶段 4) ### 身份认证 @@ -184,7 +202,7 @@ message CallRequest { 这是第一道安全边界——即使 server 监听 TCP,未注册的进程也无法调用任何 syscall。 认证流程: -1. 插件通过 `PluginBridge.Register` 注册,获得 `session_id` +1. 插件通过 `PluginBridge.Register` 注册(返回的 `session_id` 目前仅作回执,不参与后续校验) 2. 后续所有 syscall 请求须在 gRPC metadata 中带 `x-plugin-id: ` 3. 内核校验:plugin_id 存在 → status=Running → syscall 在该插件的白名单内 → 放行 diff --git a/docs/03-实施路线.md b/docs/03-实施路线.md index 80deac4..0ad5d6e 100644 --- a/docs/03-实施路线.md +++ b/docs/03-实施路线.md @@ -23,7 +23,7 @@ **验证结果**:agentsd 启动 → Rust 插件通过 gRPC 注册 → ai_test 调用 Display/Memory/FS/Process/Timer syscall 并验证权限拒绝。 -## 阶段 2:完善核心 syscall ✅ 部分完成 +## 阶段 2:完善核心 syscall 🔶 部分完成 - [x] Network:reqwest 原生 HTTP client(阶段 1 已完成) - [x] Network TCP 流:open_conn/send/close/listen 双向 TCP 通信 @@ -33,10 +33,11 @@ - [ ] HID:接入屏幕截取(Windows: win32 API) - [ ] Unix socket / Named pipe 传输(替代 TCP) -## 阶段 3:接入 Agent +## 阶段 3:接入 Agent 🔶 部分完成 - [ ] Agent 插件:Input → LLM(Network) → Display -- [ ] Hermes adapter(Python gRPC 插件) +- [x] Hermes adapter:`hermes_plugin.py` 桥接 Hermes 工具注册表;Rust 版 hermes 插件提供 echo 验证路由,bridge.call 路由已验证 +- [x] Claude Code 插件(Rust,standard 类型,depends: hermes,导出 chat/code/review/ask/run) - [ ] 本地模型插件(llama.cpp via Process syscall) ## 阶段 4:插件管理(= systemctl) diff --git a/docs/04-项目结构.md b/docs/04-项目结构.md index e7987e1..1dd47a0 100644 --- a/docs/04-项目结构.md +++ b/docs/04-项目结构.md @@ -41,7 +41,7 @@ Agentsd/ │ ├── hid.rs │ └── input.rs │ -├── data/ # 运行时数据(程序启动后自动创建) +├── data/ # 运行时数据(实际位于可执行文件旁,即 target/debug|release/data/) │ ├── memory.db # Memory syscall SQLite 数据库 │ └── plugins.json # 插件注册状态 │ @@ -51,19 +51,28 @@ Agentsd/ │ ├── agentsd_pb2.py │ └── agentsd_pb2_grpc.py │ + ├── plugin-sdk/ # Rust 插件 SDK crate(连接/注册/元数据辅助) + │ ├── Cargo.toml + │ └── src/lib.rs + │ ├── echo/ # 测试插件(Rust) + │ ├── Cargo.toml │ ├── plugin.yaml │ └── src/main.rs │ ├── ai_test/ # AI 手动验证插件(Rust,enabled=false,autoload=false) + │ ├── Cargo.toml │ ├── plugin.yaml │ └── src/main.rs │ - ├── hermes/ # Hermes Agent 桥接(Python,Rust 版仅 stub) + ├── hermes/ # Hermes Agent 桥接(Python 桥接工具注册表;Rust 版提供 echo 验证路由) + │ ├── Cargo.toml │ ├── plugin.yaml - │ └── hermes_plugin.py + │ ├── hermes_plugin.py + │ └── src/main.rs │ └── claudecode/ # Claude Code CLI 桥接(Rust) + ├── Cargo.toml ├── plugin.yaml └── src/main.rs ``` @@ -114,3 +123,5 @@ python -m grpc_tools.protoc \ --grpc_python_out=plugins/_sdk \ proto/agentsd.proto ``` + +注:protoc 只生成 `agentsd_pb2.py` 和 `agentsd_pb2_grpc.py`;`plugins/_sdk/__init__.py` 是手工维护的包标记文件,重新生成后不要删除。