mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-02 15:23:57 +00:00
docs: 全面按当前源码更新文档 + 删除已过时文档
## 删除(内容已落地/已被替换,保留只会误导)
- demo.md ................... failback 与 recoverydiag 均已实现,0 引用
- docs/defect-qq-output-send-loop.md .. 已修复(本身也标了「已修复」),0 引用
- docs/embedding-comparison.md ....... 一次性选型报告,仅被 agent 产物引用
- docs/zh/plan.md ............ 描述的旧 nav 布局已重写、死配置已清,全部完成
- docs/zh/plugin-migration-plan.md ... 迁移已上生产,纯过程稿(Part 0~6 全完成)
## 更新(按当前源码核对)
- assets/docs/{zh,en}/ARCHITECTURE.md(README 指向的用户文档,最重要):
把只讲 cancel/intercept 的旧「中断机制」章节重写为「输入调度器与中断机制」——
补上两类别 + 四级中断(L1~L4,默认 L1、外部插件 L4 夹到 L3)+ 抢占/挂起/中断栈
+ 饥饿防护(PreemptCount 提升,封顶 L4)+ 抢占冷却(2s)+ 停止语义(cancelBudget)
+ 驻留子/分诊助手/残余任务;新增「上下文预算」章节(窗口 ≠ 工作面,600K 封顶,
预算是上限非填充目标)。中英章节数现已对齐(各 13 节)。
- assets/docs/{zh,en}/PLUGIN_DEV.md:插件示例表补 6 个缺失项
(acp/deepsearch/plugindev/recoverydiag/vanblog/vikunja);qq 工具数 17 → 20(实测)。
- README.md / README_EN.md:补 v1.3.x 线(此前只到 v1.2.0,而 1.3.x 已发布 12 个 patch)——
驻留式子 agent、输出通道寻址、输入调度器、轻量内核 profile、积压及时反馈。
- plan.md:开头两个「⚠️ 紧急/正在持续污染」是过期告警(实测 残留 = 0),
改为「已解决」并加文档定位说明;§13 仍是活跃路线图故保留。
- docs/zh/plugin-interface-matrix.md + 两处源码注释:清理指向已删文档的断链。
全仓 md 断链检查:仅剩 1 处,位于 third_party 的 oh_modules(第三方依赖,非本项目)。
This commit is contained in:
@ -455,7 +455,74 @@ Extended fields:
|
||||
- Relation extension: Confidence
|
||||
|
||||
|
||||
## Interrupt Mechanism
|
||||
## Input Scheduler & Interrupt Mechanism
|
||||
|
||||
Inputs do not go straight to the LLM — they first enter the **input scheduler**
|
||||
(`internal/agent/core/scheduler.go`). Full design:
|
||||
[`docs/zh/input-scheduler-design.md`](../../../docs/zh/input-scheduler-design.md).
|
||||
|
||||
### Two task classes
|
||||
|
||||
| Class | Level | Meaning |
|
||||
|-------|-------|---------|
|
||||
| `TaskQueued` | none (always 0) | Pending work. Any interrupt (≥ L1) preempts it |
|
||||
| `TaskInterrupt` | L1–L4 | "How urgent is this", declared by the source via `InjectOptions.Priority` |
|
||||
|
||||
### Four interrupt levels
|
||||
|
||||
| Level | Meaning | Typical source |
|
||||
|-------|---------|----------------|
|
||||
| L1 Background | Fully deferrable | QQ/WeChat messages, bulk notifications |
|
||||
| L2 Message | General notice | Plugin hints that should be seen soon but aren't urgent |
|
||||
| L3 Interactive | Needs timely handling | Timer expiry, terminal output, resident-agent reports |
|
||||
| L4 Critical | **Kernel-exclusive** | panic, kernel events, kernel-level plugin stop button |
|
||||
|
||||
When no level is declared it defaults to **L1** — "explicit is a privilege", so a new
|
||||
plugin never gets preemption rights by accident. L4 declared by an external plugin is
|
||||
**clamped to L3** (`clampPluginLevel`).
|
||||
|
||||
### Preemption and suspension
|
||||
|
||||
- **Same level never preempts same level** (`canPreempt` requires strictly greater) —
|
||||
this is why messages normally wait for the running task to finish.
|
||||
- A preempted task is pushed onto the **interrupt stack** (LIFO) with its frame saved,
|
||||
and resumed later; the stack is never re-sorted by priority.
|
||||
- **Starvation guard**: preemption count raises the effective level
|
||||
(`effectiveLevel = Level + min(PreemptCount, 2)`, capped at L4).
|
||||
- **Preemption cooldown**: a just-preempted task cannot be preempted again for
|
||||
`preemptCooldown` (2s), so a high-priority stream cannot interrupt the same task forever.
|
||||
- The interrupt stack depth is structurally bounded (chain = queued ← L1 ← L2 ← L3 ← L4).
|
||||
|
||||
### Stop (user presses stop / `/stop`)
|
||||
|
||||
Stop is not an empty interrupt. It does two things: ① cancel the current LLM inference;
|
||||
② short-circuit the x messages **already queued at the moment of stop** during their
|
||||
pre-action phase (`cancelBudget` snapshot), instead of running them as new input.
|
||||
Inputs arriving **after** the stop are unaffected.
|
||||
|
||||
`PendingInputs()` must include the segment still sitting in `io.inputCh` (not yet moved
|
||||
into the queue by `pumpInbox`) — during a stop the scheduler is usually busy running a
|
||||
task, and counting only `sched.queue` yields 0.
|
||||
|
||||
### Resident sub-agents and timely feedback
|
||||
|
||||
Design: [`docs/zh/resident-subagent-design.md`](../../../docs/zh/resident-subagent-design.md).
|
||||
|
||||
- A **resident** is an independent lightweight-kernel agent: its own scheduler, its own
|
||||
temp graph memory, sharing the channel registry.
|
||||
- Parent→child control plane: `resident_agents`
|
||||
(list / create / send / inspect / compress / reclaim / destroy).
|
||||
- **Backlog feedback**: when the main agent is busy for a long time (default > 5m,
|
||||
configurable), the kernel hands queued inputs to a temporary **triage assistant**
|
||||
(`offload_*` config): simple ones are handled directly, ones needing the main agent
|
||||
get an immediate "busy, please wait". Users no longer wait 10+ minutes in silence.
|
||||
- The triage assistant gets **no inputch** (it receives no plugin user input) and
|
||||
**all output channels** (results must reach the original channel).
|
||||
- On reclaim/destroy, its **residual tasks are decided explicitly by the parent**:
|
||||
`residual=keep` (returned to the parent queue, default) or `drop` (explicitly
|
||||
discarded with a per-item log entry).
|
||||
|
||||
### Legacy three-path view (still present, now a layer beneath the scheduler)
|
||||
|
||||
```
|
||||
interceptLoop (goroutine)
|
||||
@ -465,15 +532,28 @@ interceptLoop (goroutine)
|
||||
└── (c) InjectInput() → Trigger new processing when idle
|
||||
```
|
||||
|
||||
Three delivery paths:
|
||||
Code: `internal/agent/core/scheduler.go` (scheduler), `eventloop.go` (intercept loop).
|
||||
|
||||
| Path | Effect | Timing |
|
||||
|------|--------|--------|
|
||||
| cancelLLM | Cancel current HTTP request | On context.Canceled |
|
||||
| interceptCh | Insert `[interrupt message]` in process() | Before each LLM call |
|
||||
| InjectInput | Trigger new processing when eventLoop is idle | No ongoing request |
|
||||
## Context Budget
|
||||
|
||||
Code: `internal/agent/core/eventloop.go` — `interceptLoop` / `drainInterrupts`
|
||||
`internal/agent/core/tokenbudget.go` — `ComputeTokenBudget`:
|
||||
|
||||
```
|
||||
maxCtx = provider.MaxContextTokens() // declared window (per-source context_window wins)
|
||||
targetUsage = min(maxCtx × 0.8, 600000) // working band, capped at 600K
|
||||
├── memory recall budget = (targetUsage - fixed) / 3
|
||||
└── context events budget = remaining 2/3
|
||||
```
|
||||
|
||||
★ **Window ≠ working band**: a source's real window may reach 1M, but near-full windows
|
||||
lose attention and cost/latency rise linearly, so `maxTargetTokens=600000` caps the
|
||||
working band separately. If the model name (e.g. `AUTO`) yields no window,
|
||||
`ModelContextWindow` **logs a warning** and falls back conservatively; operators should
|
||||
declare `core.llm.sources.<name>.context_window` explicitly.
|
||||
|
||||
**Budgets are ceilings, not fill targets**: memory is recall-ranked (it stops when nothing
|
||||
is relevant) and the timeline is taken newest-first within budget. Measured: with a 400K
|
||||
budget, actual injection was still a few hundred characters.
|
||||
|
||||
|
||||
## Configuration System
|
||||
|
||||
@ -804,7 +804,7 @@ Internal: records are stored in SQLite `disabled_plugins` table (`name`, `disabl
|
||||
|---------|------|----------|
|
||||
| [weather](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/weather) | Go | Weather queries (wttr.in); demonstrates NoMemory/Cleaner/stage hooks/channels/text memory |
|
||||
| [luademo](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/luademo) | Lua | Full-featured Lua example covering the whole v0.8.0 Lua SDK surface |
|
||||
| [qq](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/qq) | Go | NapCat OneBot integration, 17 tools, full input/output channel wiring |
|
||||
| [qq](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/qq) | Go | NapCat OneBot integration, 20 tools, full input/output channel wiring |
|
||||
| [memo](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/memo) | Go | Memo management, PreAction injection + timed interrupt dual reminder |
|
||||
| [files](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/files) | Go | File system operations, 4 write modes, sandbox isolation |
|
||||
| [browser](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/browser) | Go | Web search + HTTP fetch (SSRF) + Chromium render (merged from web/webfetch) |
|
||||
@ -817,6 +817,12 @@ Internal: records are stored in SQLite `disabled_plugins` table (`name`, `disabl
|
||||
| [rss](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/rss) | Go | RSS subscriptions |
|
||||
| [ai_image](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/ai_image) | Go | AI image generation |
|
||||
| [music](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/music) | Go | Music playback |
|
||||
| [vikunja](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/vikunja) | Go | Vikunja task management (projects/tasks/labels CRUD) |
|
||||
| [vanblog](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/vanblog) | Go | VanBlog publishing and management |
|
||||
| [deepsearch](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/deepsearch) | Go | Multi-round deep search (progressive focus + cited summary) |
|
||||
| [acp](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/acp) | Go | Agent Client Protocol (external editors/IDEs drive this agent) |
|
||||
| [recoverydiag](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/recoverydiag) | Go | Five-part fault diagnosis (triage / sqlite check / log signatures / diff / ranked conclusions); core plugin of failback mode |
|
||||
| [plugindev](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/plugindev) | Go | Plugin scaffolding: generate, build, install — lets the agent develop plugins itself |
|
||||
|
||||
### Built-in Plugins
|
||||
|
||||
|
||||
Reference in New Issue
Block a user