Fix documentation inconsistencies found by code audit
- docs/01: sync all syscall signatures with proto (missing params, invented callback params, stream semantics, return types) - docs/02: mark unimplemented features (FFI system plugins, topo sort, lifecycle CLI, watchdog); clarify plugin.yaml is not parsed by the kernel - registration goes through gRPC PluginBridge.Register; correct permission model and session_id descriptions - docs/03: check off implemented stage 3 items (Hermes adapter, Claude Code plugin) - docs/04: data/ actual location, add Cargo.toml to plugin trees, note __init__.py is hand-maintained - README: status line now reflects actual progress Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
AI Agent 的 init 系统 + 内核。对标 Linux 内核 + systemd。
|
||||
|
||||
> 状态:设计草案
|
||||
> 状态:阶段 1(内核骨架)已完成,阶段 2/3 部分完成。详见 docs/03-实施路线.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 # 服务端流式事件
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -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: <plugin_id>`
|
||||
3. 内核校验:plugin_id 存在 → status=Running → syscall 在该插件的白名单内 → 放行
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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` 是手工维护的包标记文件,重新生成后不要删除。
|
||||
|
||||
Reference in New Issue
Block a user