mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-01 14:57:38 +00:00
docs: 把「业务语义归插件、联动走事件总线」补进 OVERVIEW 与 PLUGIN_DEV
上一提交只在 ARCHITECTURE 里记了终端归属。本次把这条**通用原则**补到另外两份
文档,避免只读 OVERVIEW / 插件开发指南的人仍旧按旧直觉写代码。
## OVERVIEW(中英)
设计要点新增一条「业务语义留在插件层」:内核不定义业务对象(终端、命令历史、
设备状态、媒体库都是插件域)。以终端为例说明:PTY/生命周期/输出缓冲归
agentcli,WebUI/CLI 订阅总线自攒视图,内核只提供事件总线与注册面 —— 新增一类
能力不需要改内核,也不会在核心里堆出第二套业务真相。
## PLUGIN_DEV(中英)
PluginSDK 章节新增「与其它插件联动 — 走事件总线,不要依赖内核内部组件」:
- 代码示例:订阅 terminal_output + tool_call 自己攒视图
- 两条稳定事件表(谁发布、用途)
- ★ 外部插件只能订阅、不能发布(Publish 属 withheld 能力),所以「能力所有者
需要广播状态」的插件必须内置(agentcli 即此例)
- 指向 internal/pluginview 作为参考实现,并写明「视图不是权威、晚启动会缺早期
事件」
一个准确性修正:公开 SDK **没有** EventTerminalOutput 常量(属内核内部事件
类型),所以示例里外部插件用 sdk.EventType("terminal_output") 字符串订阅,
并注明内置插件可用 internal sdk 常量 —— 避免文档给出编不过的示例。
验证:四份文档代码围栏配对(74/74、0/0);仅文档改动,无代码影响。
This commit is contained in:
@ -18,6 +18,15 @@ Core architecture: a long-running kernel process (`homed`) that connects to vari
|
||||
|
||||
The significance lies in clear responsibility boundaries: the kernel focuses on orchestration and memory management, while plugins handle IO implementation — the two are not coupled.
|
||||
|
||||
**Business semantics stay in plugins** — the kernel does not define business
|
||||
objects: terminals, command history, device state and media libraries all belong to
|
||||
the plugin domain. Take terminals: the PTY, session lifecycle and output buffering
|
||||
all live in `agentcli`; when WebUI or CLI needs a terminal panel it **subscribes to
|
||||
the event bus** (`EventTerminalOutput` + `EventToolCall`) and builds its own view
|
||||
instead of reading a state component inside the kernel. The kernel offers only the
|
||||
event bus and the plugin registration surface — adding a new capability does not
|
||||
require touching the kernel, and no second version of business truth accumulates there.
|
||||
|
||||
**Three-Layer Memory Architecture** — Manages information retention across long agent runtimes through a tiered storage strategy:
|
||||
- **Context Layer**: In-memory pretrained word embedding scored event window (StaticEmbedder word vectors → CosineSimilarity, TF-IDF fallback), maintains recent context in real-time, low-relevance events automatically sink to the next layer
|
||||
- **Document Layer**: JSON files + TF-IDF vector-indexed temporary memory, supports explicit submission and implicit archival, cold data distills to Graph
|
||||
|
||||
@ -460,6 +460,45 @@ unsub := s.Events().Subscribe(sdk.EventToolCall, func(evt *sdk.Event) {
|
||||
defer unsub()
|
||||
```
|
||||
|
||||
#### Inter-plugin Integration — Use the Event Bus, Not Kernel Components
|
||||
|
||||
The kernel carries no business-domain semantics (terminals, device state, media
|
||||
libraries all belong to plugins). Plugins that need to coordinate should therefore
|
||||
**subscribe to the event bus**, not read some state component inside the kernel —
|
||||
the latter creates a second copy of the truth and pushes business logic back into
|
||||
the kernel.
|
||||
|
||||
```go
|
||||
// Panel-style plugins (WebUI/CLI): subscribe to terminal events, build a view
|
||||
// Note: terminal_output has no public constant yet (it is a kernel-internal event
|
||||
// type), so external plugins subscribe by string; built-in plugins can use the
|
||||
// internal SDK's EventTerminalOutput constant.
|
||||
unsubTerm := s.Events().Subscribe(sdk.EventType("terminal_output"), func(evt *sdk.Event) {
|
||||
// evt.Payload: terminal_id / command / output / running
|
||||
})
|
||||
unsubTool := s.Events().Subscribe(sdk.EventToolCall, func(evt *sdk.Event) {
|
||||
// evt.Payload: tool / args / status (cmd_run, terminal_create/close, ...)
|
||||
})
|
||||
defer unsubTerm()
|
||||
defer unsubTool()
|
||||
```
|
||||
|
||||
The two stable events:
|
||||
|
||||
| Event | Publisher | Purpose |
|
||||
|---|---|---|
|
||||
| `EventTerminalOutput` | agentcli | terminal output and lifecycle (create/close/timeout) |
|
||||
| `EventToolCall` | kernel | tool invocations (incl. `cmd_run`, `terminal_create/close`) |
|
||||
|
||||
★ **External plugins can subscribe but cannot publish**: `Publish` is a withheld
|
||||
capability (`withheldCapabilities`), so a plugin that *owns* a capability and must
|
||||
broadcast its state (like agentcli publishing terminal events) has to be built-in.
|
||||
If your plugin is only a consumer, subscribing is enough.
|
||||
|
||||
Reference implementation: `internal/pluginview` (the terminal view shared by WebUI
|
||||
and CLI). It shows how a view is assembled from events, and the boundary that the
|
||||
view is not authoritative — a late starter misses early events.
|
||||
|
||||
#### Capability Access
|
||||
|
||||
```go
|
||||
|
||||
@ -18,6 +18,12 @@ HomeAgent 是一个持续运行的个人智能 Agent 框架。
|
||||
|
||||
这一划分的意义在于职责边界清晰:内核专注于编排与记忆管理,插件负责具体 IO 实现,二者互不耦合。
|
||||
|
||||
**业务语义留在插件层** — 内核不定义业务对象:终端、命令历史、设备状态、媒体库
|
||||
都属于插件域。以终端为例,PTY、会话生命周期与输出缓冲全归 `agentcli`;WebUI 与
|
||||
CLI 需要终端面板时,**订阅事件总线**(`EventTerminalOutput` + `EventToolCall`)
|
||||
自己攒视图,而不是去读内核里的某个状态组件。内核只提供事件总线与插件注册面——
|
||||
新增一类能力不需要改内核,也不会在核心里堆出第二套业务真相。
|
||||
|
||||
**三层记忆架构** — 通过分级存储策略管理 Agent 长周期运行中的信息留存:
|
||||
- **Context 层**:内存中预训练词嵌入评分的事件窗口(StaticEmbedder 词向量 → CosineSimilarity,TF-IDF 回退),实时维护最近上下文,低相关性事件自动下沉到下一层
|
||||
- **Document 层**:JSON 文件 + TF-IDF 向量索引的临时记忆,支持显式提交和隐式归档,冷数据蒸馏到 Graph
|
||||
|
||||
@ -453,6 +453,40 @@ unsub := s.Events().Subscribe(sdk.EventToolCall, func(evt *sdk.Event) {
|
||||
defer unsub()
|
||||
```
|
||||
|
||||
#### 与其它插件联动 — 走事件总线,不要依赖内核内部组件
|
||||
|
||||
内核不承载业务域语义(终端、设备状态、媒体库都是插件的职责),因此插件之间的
|
||||
联动应当**订阅事件总线**,而不是读内核里的某个状态组件——后者会让同一件事出现
|
||||
第二份真相,也会把业务逻辑重新塞回内核。
|
||||
|
||||
```go
|
||||
// 面板类插件(如 WebUI/CLI):订阅终端事件,自己攒视图
|
||||
// 注意:terminal_output 目前没有公开常量(属内核内部事件类型),
|
||||
// 外部插件用字符串形式订阅;内置插件可用 internal sdk 的 EventTerminalOutput。
|
||||
unsubTerm := s.Events().Subscribe(sdk.EventType("terminal_output"), func(evt *sdk.Event) {
|
||||
// evt.Payload: terminal_id / command / output / running
|
||||
})
|
||||
unsubTool := s.Events().Subscribe(sdk.EventToolCall, func(evt *sdk.Event) {
|
||||
// evt.Payload: tool / args / status(cmd_run、terminal_create/close 等)
|
||||
})
|
||||
defer unsubTerm()
|
||||
defer unsubTool()
|
||||
```
|
||||
|
||||
稳定的两条事件:
|
||||
|
||||
| 事件 | 发布者 | 用途 |
|
||||
|---|---|---|
|
||||
| `EventTerminalOutput` | agentcli | 终端输出与生命周期(创建/关闭/超时) |
|
||||
| `EventToolCall` | 内核 | 工具调用(含 `cmd_run`、`terminal_create/close`) |
|
||||
|
||||
★ **外部插件只能订阅,不能发布**:`Publish` 属于不对外授予的能力
|
||||
(`withheldCapabilities`),所以「某项能力的所有者需要向总线广播状态」这类插件
|
||||
(如 agentcli 发终端事件)必须内置。如果你的插件只是消费者,订阅即可。
|
||||
|
||||
参考实现:`internal/pluginview`(WebUI 与 CLI 共用的终端视图)。它演示了视图
|
||||
应当怎么从事件攒出来,以及「视图不是权威、晚启动会缺早期事件」的边界。
|
||||
|
||||
#### 能力访问
|
||||
|
||||
```go
|
||||
|
||||
Reference in New Issue
Block a user