Initial Agentsd project commit

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 15:09:56 +08:00
commit 1bf1f08f9a
41 changed files with 8106 additions and 0 deletions

View File

@@ -0,0 +1,164 @@
# 01 - 内核系统调用
agentsd 定义 9 个 syscall 接口。类比 Linux 内核 syscall 表——接口稳定,实现可换(由系统插件提供)。
---
## 1. Display
向用户呈现信息。类比: `write(stdout)` / framebuffer / DRM。
**管**:给人看的输出 | **不管**:文件写入、设备控制
```
display.text(content)
display.rich(markup)
display.image(data, format)
display.clear()
display.notify(message)
```
---
## 2. Audio
声音播放与采集。类比: `/dev/snd` / ALSA / PipeWire。
**管**:扬声器输出、麦克风输入 | **不管**:TTS/STT(插件的事)
```
audio.play(data, format)
audio.stop()
audio.volume(level)
audio.record.start(format)
audio.record.stop() -> data
audio.record.stream(callback)
```
---
## 3. FS
文件系统。类比: `open / read / write / stat / readdir / inotify`
**管**:磁盘文件 | **不管**:结构化数据(Memory)
```
fs.read(path) -> data
fs.write(path, data)
fs.delete(path)
fs.rename(from, to)
fs.stat(path) -> metadata
fs.list(dir) -> entries
fs.watch(path, callback)
```
---
## 4. Memory
结构化存储。类比: `mmap / shmem`,但面向 KV + 索引。
**管**:持久数据、查询 | **不管**:文件(FS)
```
memory.read(key) -> value
memory.write(key, value)
memory.delete(key)
memory.list(prefix?) -> keys
memory.search(query) -> results
```
---
## 5. Network
远程通信。类比: `socket / connect / bind / listen / send / recv`
**管**:对外连接、监听 | **不管**:本地 IPC(内核 gRPC 总线)
```
net.request(url, method, body?) -> response
net.connect(addr, protocol) -> conn
net.listen(port, protocol) -> listener
net.send(conn, data)
net.recv(conn) -> data
net.close(conn)
net.available() -> bool
```
---
## 6. Process
子进程管理。类比: `fork / execve / waitpid / kill / pipe`
**管**:子进程生命周期、stdio | **不管**:插件间路由(内核调度)
```
proc.spawn(cmd, args, env?) -> pid
proc.kill(pid)
proc.wait(pid) -> exitcode
proc.stdin(pid, data)
proc.stdout(pid) -> data
proc.signal(pid, sig)
proc.list() -> [pid]
```
---
## 7. Timer
定时调度。类比: `timer_create / timerfd_create`
**管**:时间触发 | **不管**:用户事件(Input)
```
timer.once(delay, callback) -> id # 到期后通过 PluginBridge.StreamCall 投递事件
timer.cron(expr, callback) -> id
timer.cancel(id)
timer.now() -> timestamp
```
---
## 8. HID
屏幕截取与输入模拟。类比: `/dev/input` + `/dev/fb` + uinput。
能力可缺失。
**管**:屏幕读取、输入模拟 | **不管**:向用户展示(Display)、用户主动输入(Input)
```
hid.capture(region?) -> image
hid.mouse(x, y, action)
hid.keyboard(key, action)
hid.ocr(region?) -> text
```
---
## 9. Input
用户主动输入。类比: `read(stdin)` / evdev。
**管**:用户给的东西 | **不管**:文件读(FS)、录音(Audio)、屏幕读(HID)
```
input.text() -> string
input.key() -> keyevent
input.clipboard() -> data
input.event() -> event
```
---
## 设计原则
1. **接口稳定,实现可换** — syscall 签名不变,系统插件可替换(= 换驱动不改应用)
2. **每个独立** — 可单独实现、测试、编译(= 内核模块独立)
3. **能力可缺失** — 无声卡则 Audio 不可用,不崩(= Linux 无设备则驱动不加载)
4. **权限在此层** — 白名单外的 syscall 拒绝(= seccomp)
5. **离线 = Network 不可用** — 其余八个正常(= 拔网线不影响本地)
6. **内核不做业务** — TTS/浏览器/Agent 全是插件(= 内核不含 Web 服务器)

179
docs/02-插件模型.md Normal file
View File

@@ -0,0 +1,179 @@
# 02 - 插件模型
## 三种插件(对标 Linux 三层)
```
┌─────────────────────────────────────────────────────┐
│ 标准插件 ← 应用服务(nginx、docker) │
│ 可依赖基础插件 + 其他标准插件 │
├─────────────────────────────────────────────────────┤
│ 基础插件 ← 基础 daemon(udevd、resolved) │
│ 只依赖 9 个 syscall,无插件依赖 │
├─────────────────────────────────────────────────────┤
│ 系统插件 ← 内核模块 / 设备驱动(.ko) │
│ 注册为 syscall 的实现 │
├─────────────────────────────────────────────────────┤
│ agentsd ← Linux 内核 + systemd(PID 1) │
└─────────────────────────────────────────────────────┘
```
---
### 系统插件(= 内核模块 / 驱动)
为 syscall 提供具体实现。类比 `insmod alsa_driver.ko`
```yaml
id: alsa-audio
type: system
provides: audio
entry: ./libalsa_audio.so
```
- FFI 加载(.so/.dylib/.dll),零开销
- 只限 Rust / C ABI
- 同一 syscall 可有多个驱动,同时只激活一个
- 无依赖
---
### 基础插件(= systemd 基础 unit,无依赖)
只调 syscall,不调其他插件。类比 `systemd-resolved.service`(只用内核网络栈)。
```yaml
id: tts-edge
type: basic
syscalls:
- audio.play
- network.request
exports:
- name: speak
```
- 独立进程,gRPC/TCP 通信(后续切 UDS/Named Pipe)
- 零插件依赖,加载顺序无所谓(= 无 After/Requires)
- 任意语言
---
### 标准插件(= systemd 应用 unit,有依赖)
组合其他插件。类比 `nginx.service`(After=network.target, Requires=...)。
```yaml
id: voice-agent
type: standard
syscalls:
- input.text
- display.text
depends:
- tts-edge
- stt-whisper
- chat-agent
exports:
- name: voice_chat
```
- 可依赖基础插件 + 其他标准插件
- 按依赖拓扑排序加载(= systemd ordering)
- 任意语言
---
## 通信:gRPC(= D-Bus)
类比 Linux 的 D-Bus 进程间通信总线,agentsd 用 gRPC。
### 为什么 gRPC
- protobuf 二进制,快
- 流式 RPC(音频流、文件 watch)
- 所有语言都有库
- `.proto` = 接口契约 + 代码生成
### 传输分层
| 插件类型 | 传输 | 延迟 | Linux 类比 |
|---|---|---|---|
| 系统插件 | FFI | ~纳秒 | 内核态函数调用 |
| 基础/标准(本机,当前) | gRPC/TCP | ~毫秒 | D-Bus over TCP |
| 基础/标准(目标) | gRPC/Unix socket / Windows Named Pipe | ~微秒 | D-Bus over UDS |
| 远程(可选) | gRPC/TCP | ~毫秒 | D-Bus over TCP |
### proto 示例
```protobuf
syntax = "proto3";
service FS {
rpc Read(ReadRequest) returns (ReadResponse);
rpc Write(WriteRequest) returns (WriteResponse);
rpc Delete(DeleteRequest) returns (DeleteResponse);
rpc List(ListRequest) returns (ListResponse);
rpc Watch(WatchRequest) returns (stream WatchEvent);
}
service Audio {
rpc Play(stream AudioChunk) returns (PlayResponse);
rpc Record(RecordRequest) returns (stream AudioChunk);
}
```
### 插件间调用(经内核路由)
```protobuf
service PluginBridge {
rpc Call(CallRequest) returns (CallResponse);
rpc StreamCall(CallRequest) returns (stream CallResponse);
}
message CallRequest {
string target = 1;
string fn = 2;
bytes args = 3;
}
```
---
## 生命周期管理(= systemctl)
| agentsd 命令 | systemd 对标 | 作用 |
|---|---|---|
| `agentsd start <id>` | `systemctl start` | 启动插件 |
| `agentsd stop <id>` | `systemctl stop` | 停止插件 |
| `agentsd restart <id>` | `systemctl restart` | 重启 |
| `agentsd reload <id>` | `systemctl reload` | 热更新 |
| `agentsd status` | `systemctl status` | 状态查询 |
| `agentsd list` | `systemctl list-units` | 列出所有插件 |
| `agentsd logs <id>` | `journalctl -u` | 查日志 |
| `agentsd enable <id>` | `systemctl enable` | 开机自启 |
| `agentsd disable <id>` | `systemctl disable` | 取消自启 |
---
## 加载顺序(= systemd boot)
```
1. 系统插件(FFI,注册 syscall 实现) ← 类比内核模块加载
2. 基础插件(gRPC,任意顺序) ← 类比 basic.target
3. 标准插件(gRPC,拓扑排序) ← 类比 multi-user.target
```
---
## 看门狗(= Restart=always)
插件崩溃 → agentsd 自动重启(可配置策略):
- `always`:总是重启
- `on-failure`:异常退出才重启
- `never`:不重启
---
## 权限(= seccomp + cgroup)
- 系统插件:内核信任,无限制
- 基础插件:按 `syscalls` 白名单精确到方法(如 `fs.list`)校验,也支持 `fs` / `fs.*` / `*` 授权(= seccomp filter)
- 标准插件:syscalls + depends 白名单,未声明的一律拒绝

50
docs/03-实施路线.md Normal file
View File

@@ -0,0 +1,50 @@
# 03 - 实施路线
## 阶段 1:内核骨架(= 跑起来的 PID 1) ✅ 已完成
- [x] Rust workspace:`agentsd` 主二进制
- [x] gRPC server(tonic over TCP,后续切 UDS)
- [x] 实现 FS syscall(read/write/delete/rename/stat/list)
- [x] 实现 Memory syscall(SQLite KV + FTS5 trigram search,默认写入 data/memory.db)
- [x] 实现 Input syscall(stdin)
- [x] 实现 Display syscall(stdout)
- [x] 实现 Process syscall(spawn/kill/wait/stdin/stdout)
- [x] 实现 Timer syscall(once/cancel/now + 回调事件通道)
- [x] 实现 Audio syscall(stub,待系统插件)
- [x] 实现 HID syscall(stub,待系统插件)
- [x] 实现 Network syscall(HTTP via curl,待替换)
- [x] Plugin Bridge(注册/调用路由/心跳,注册状态写入 data/plugins.json)
- [x] 插件加载:gRPC 握手 + 注册
- [x] echo 测试插件(Python)验证基础链路
- [x] ai_test 手动验证插件(Python,默认 disabled/autoload false)覆盖 Display/Memory/FS/Process/Timer/权限拒绝
- [x] proto 定义:完整 9 个 service + PluginBridge
**验证结果**:agentsd 启动 → Python 插件通过 gRPC 注册 → ai_test 调用 Display/Memory/FS/Process/Timer syscall 并验证权限拒绝。
## 阶段 2:完善核心 syscall
- [ ] Network:替换 curl 为 hyper/reqwest 原生 HTTP client
- [ ] FS.Watch:接入 notify-rs 文件监听
- [ ] Timer.Cron:接入 cron 表达式解析
- [ ] Audio:接入系统音频后端(wasapi/alsa)
- [ ] HID:接入屏幕截取(Windows: win32 API)
- [ ] Unix socket / Named pipe 传输(替代 TCP)
## 阶段 3:接入 Agent
- [ ] Agent 插件:Input → LLM(Network) → Display
- [ ] Hermes adapter(Python gRPC 插件)
- [ ] 本地模型插件(llama.cpp via Process syscall)
## 阶段 4:插件管理(= systemctl)
- [ ] agentsd start / stop / restart / status / list / logs
- [ ] 看门狗(崩溃自动重启)
- [ ] 依赖解析 + 拓扑排序
- [ ] install / uninstall / enable / disable
## 阶段 5:生态
- [ ] Web UI 插件(shell)
- [ ] 语音交互(Audio + TTS/STT 插件)
- [ ] 桌面自动化(HID + computer-use 插件)

117
docs/04-项目结构.md Normal file
View File

@@ -0,0 +1,117 @@
# 04 - 项目结构
```
Agentsd/
├── Cargo.toml # workspace 根
├── README.md # 设计总览
├── docs/ # 设计文档
│ ├── 01-内核系统调用.md
│ ├── 02-插件模型.md
│ ├── 03-实施路线.md
│ └── 04-项目结构.md # 本文件
├── proto/ # 协议定义(单一事实来源)
│ └── agentsd.proto # 9 service + PluginBridge
├── core/ # Rust 源码
│ ├── proto/ # gRPC 协议 crate
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ └── src/lib.rs
│ │
│ └── agentsd/ # 主二进制 crate
│ ├── Cargo.toml
│ └── src/
│ ├── main.rs # 入口
│ ├── server.rs # gRPC server
│ ├── plugin.rs # 插件注册表 + data/plugins.json 持久化
│ ├── paths.rs # 程序目录 data/ 路径
│ ├── callback.rs # Timer 回调事件通道
│ ├── permission.rs # syscall 权限白名单校验
│ └── syscall/ # 9 个 syscall 模块
│ ├── mod.rs
│ ├── display.rs
│ ├── audio.rs
│ ├── fs.rs
│ ├── memory.rs
│ ├── network.rs
│ ├── process.rs
│ ├── timer.rs
│ ├── hid.rs
│ └── input.rs
├── data/ # 运行时数据(程序启动后自动创建)
│ ├── memory.db # Memory syscall SQLite 数据库
│ └── plugins.json # 插件注册状态
└── plugins/ # 插件(任意语言)
├── _sdk/ # 共享 Python gRPC stub
│ ├── __init__.py
│ ├── agentsd_pb2.py
│ └── agentsd_pb2_grpc.py
├── echo/ # 测试插件
│ ├── plugin.yaml
│ └── echo_plugin.py
├── ai_test/ # AI 手动验证插件(enabled=false,autoload=false)
│ ├── plugin.yaml
│ └── ai_test_plugin.py
├── hermes/ # Hermes Agent 桥接(63 tool)
│ ├── plugin.yaml
│ └── hermes_plugin.py
└── claudecode/ # Claude Code CLI 桥接
├── plugin.yaml
├── claudecode_plugin.py
└── test_chat.py
```
## 布局原则
| 目录 | 职责 | 规则 |
|---|---|---|
| `docs/` | 设计文档 | 只放 .md |
| `proto/` | 协议定义 | 只放 .proto,单一事实来源 |
| `core/` | Rust 代码 | workspace members |
| `data/` | 运行时数据 | 默认路径为程序所在目录的 data 文件夹 |
| `plugins/` | 所有插件 | 每个插件一个目录,含 plugin.yaml |
| `plugins/_sdk/` | 共享 stub | 生成一次,插件 import 引用,不复制 |
## 构建
```bash
cargo build --release # 约 6.1MB 单二进制
```
## 运行
```bash
# 启动内核
./target/release/agentsd.exe
# 启动插件(各开一个终端)
python plugins/hermes/hermes_plugin.py
python plugins/claudecode/claudecode_plugin.py
```
## 手动验证插件
`plugins/ai_test` 是专门给 AI/人工做端到端验证的插件,`plugin.yaml``enabled: false``autoload: false`,默认不应被自动加载。
```bash
RUST_LOG=agentsd=info ./target/release/agentsd.exe
python plugins/ai_test/ai_test_plugin.py
```
## 重新生成 SDK
```bash
python -m grpc_tools.protoc \
-Iproto \
--python_out=plugins/_sdk \
--grpc_python_out=plugins/_sdk \
proto/agentsd.proto
```