Files
HomeAgent/README_EN.md
JianFeeeee 7c0eec1b2f docs: 第二层改名 Cold Context,清理四组已不存在的符号名
## 问题

README 与两份 ARCHITECTURE / OVERVIEW 仍在用旧称「Document 层」,
而第二层早已改名 cold context(工具名 `coldcontext_query` / `coldcontext_commit`)。

不止是层名。文档里引用的四个符号在代码里**一个都不存在**:

| 文档里写的 | 代码里实际 |
|---|---|
| `docStore.ContextToDoc` | `coldcontextStore.ContextToColdContext` |
| `FindColdDocs` | `FindColdContexts` |
| `docToTriples` | `coldDocToTriples` |
| `docStore.SetVectorizer` | (已无此调用,embedder 构造期注入) |

四处都用 `grep -rn "\b名字\b" --include=*.go` 确认过:旧名 0 处,新名各自 4 处。

## 改了什么

- `assets/docs/zh/ARCHITECTURE.md` 13 处、`en/ARCHITECTURE.md` 15 处
- `assets/docs/zh|en/OVERVIEW.md` 各 3 处
- README 两版:「文档层」→「冷上下文层」
- `assets/branding/mascot-xiaozhai-guide.md` 的丝带配色表(三色分别对应三层)

## 顺带修正层号

ARCHITECTURE 用的是 **L1 Context / L2 Cold Context / L3 Stable**,
我上一版 README 写成了 L0/L1/L2 —— 少了一层,且与架构文档对不上。已改为 L1/L2/L3。

## 顺带修掉断掉的交叉引用

`internal/agent/core/toolcall.go` 与 `recallcoldcontext_test.go` 的注释写
「ARCHITECTURE「记忆流转」② Document 层的读取分支」,指的正是刚改名的节。
不改就成了悬空引用。三个测试函数名(`TestContextToDoc` 等)指向已删函数,一并改名。

## 验证

- 全仓 `grep` 旧名:`*.md` / `*.go` 均 0 处(排除 build/third_party/.pi)
- `go build ./...` ✓
- `go test ./internal/memory/coldcontext/ ./internal/agent/core/` ✓
2026-10-31 11:39:13 +08:00

173 lines
8.0 KiB
Markdown

> ⚠️ **AI-Assisted Programming Notice**: Parts of this project's code, documentation, and commit history were generated or modified with AI assistance. Key changes have been human-reviewed, but please evaluate and verify before use.
# HologramAgent
> **中文**: [README.md](./README.md)
Self-hosted agent kernel. Runs on your own hardware; plugins attach as separate processes.
```bash
make build build-cli
./build/homed -data /tmp/ha
```
API keys go in the web UI at `http://localhost:8080`. Requires Linux.
The main difference from typical agent frameworks is context handling: instead of truncating
on overflow or asking the model to summarize, it scores history by relevance and sinks the
low-scoring events into cold context, then distills those into a graph. Two other things differ:
startup order is resolved at build time, and plugins launch as soon as their facilities are ready.
## Architecture
```text
homed (kernel)
LLM orchestration · memory · retrieval
│
┌──────────────┼──────────────┐
│ │ │
stdio RPC shared mem event ring
control bulk data notify
│ │ │
└──────────────┼──────────────┘
│
plugins (separate processes)
web UI · QQ · CLI · files · browser
```
The kernel makes no HTTP calls and reads no files. Everything touching the outside world is a
plugin. A plugin crash leaves the kernel running; restarts back off 1s / 2s / 3s, and the 4th
crash within 5 minutes stops automatic restarting for human intervention.
### Context is not "truncate and summarize"
The usual approach drops old turns or asks the model to summarize them. Both share a flaw: what
gets lost is decided by position. Here each historical event is scored against the current input,
and low scorers sink into the cold-context layer.
Scoring uses dense cosine similarity in the same vector space as media and cold context, falling
back to TF-IDF when the model isn't loaded. The most recent N events are always kept, but N is
itself bounded by budget:
```go
// protected count cannot exceed what the budget can hold
budgetCap = ContextTokens / avgEventTokens
pCount = min(configured, budgetCap)
```
That bound came from a measurement: with a 50k window, one event averaged 5800 tokens (tool
results), while the budget was 40000, so "pin 10 events" didn't fit. Every prune hit the
protection floor, the budget was exhausted after two rounds, and the task terminated. Recall
dropped from 44% to 22%. Smaller windows now tighten automatically, and a 1M window can use the
full configured value.
Pruned events aren't discarded, they migrate: the event and the media blocks it holds move into
the cold-context layer with block IDs unchanged, only the holding layer changes. Retrieval uses
`coldcontext_query` in two phases (Peek to confirm, then Remove) rather than delete-then-refill,
which would lose data permanently if the refill failed.
### Three layers migrate, they don't copy
```text
L1 Context relevance pruning, last N always protected
↓ low scorers sink (with media blocks)
L2 Cold Context dense retrieval; ≤2 accesses and 72h stale means sink further
↓ distilled into triples
L3 Stable entities, relations, scene index; recall by scene
```
A block has exactly one holder at any layer, with no reference counting to keep it alive. Media
are not attachments: images and audio are first-class graph nodes with their own vectors,
searchable in the same space as text.
### Memory is partitioned by scene, not by session
Typical agents keep one history per session, so switching topics loses context or crams
everything into one window. Here memory is partitioned by observable scene fingerprint: channel,
conversation partner, tools, topic, time of day, weighted 1.0/1.0/0.8/0.4/0.2.
A scene comes into being only on the second matching fingerprint (`minSceneEvidence = 2`).
Join threshold 0.5, recall 0.35 — recall is looser because failing to recall loses information
while an extra scene costs a few lines of context. Each recurrence adds to scene strength;
scenes that stop recurring decay by half-life.
Two paths run in parallel: **declared** (a plugin states at the injection point which scene this
is) and **emergent** (fingerprints cluster on their own). Declared scenes deliberately don't
absorb the full fingerprint, otherwise they'd score near 1.0 against every later turn and the
emergent path could never grow finer-grained scenes.
### Seven stages
`internal/agent/core/stages.go`
| Stage | When | Plugins can |
|---|---|---|
| `on_input` | message arrives | blocklist, rate limit, short-circuit reply |
| `pre_action` | context ready, before LLM | inject external data |
| `post_action` | LLM returns text and tool calls | filter, force redirect |
| `before_toolcall` | before one tool runs | audit, deny, rewrite args |
| `after_toolcall` | after one tool runs | redact, sort results |
| `before_output` | final text ready | format adaptation |
| `after_output` | after sending | statistics |
`post_action → [before_toolcall → run → after_toolcall] → post_action` is the inner loop. It exits
when the model stops calling tools, all calls are denied, or the limit is reached.
## Everything else
- **Channels**: web UI, CLI, QQ groups and DMs, A2A, ACP in your IDE
- **Tools**: files, shell, code, browser (real Chrome), calendar, notes, RSS, music
- **Modalities**: images, video, voice, screenshots, web pages
28 built-in plugins, 89 model-callable tools. External plugins live one per repo under [github.com/HologramAgent](https://github.com/HologramAgent).
## Downloads
[Releases](https://github.com/JianFeeeee/HologramAgent/releases) ship three variants:
| Variant | Contents | For |
| --- | --- | --- |
| **full** | homed + waiter + desktop GUI + systemd unit | Single-machine, everything |
| **server** | homed + waiter + systemd unit | Servers (no desktop environment) |
| **client** | waiter + desktop GUI | Connecting to a remote HologramAgent |
- Linux: `.deb` (amd64/arm64), `.rpm` (x86_64), `.tar.gz`
- Windows: `HologramAgent_v1.2.0_{Full,Server,Client}_win64.exe` (NSIS installer, includes the AGPL license page). Since v1.2.0 `homed` no longer supports native Windows (it relies on fd inheritance and in-segment offset dereferencing), so the installer bootstraps **WSL2** and installs the Linux packages inside the distribution the same way a Linux host would.
- Portable: `homeagent-bin-<os>_<arch>.tar.gz` (homed/waiter/initconfig)
- Verification: `SHA256SUMS`
The macOS `homed` requires a native macOS build (CGO + sqlite3), so release packages ship only `waiter`/`initconfig`.
## Build
```bash
make build build-cli # Build daemon + CLI
make test # go test ./...
make install # Install to system
```
Dependencies: Go 1.25+, CGo (go-sqlite3), Linux.
> `homed` requires Linux (it relies on fd inheritance and intra-segment offset
dereferencing of the shared memory region; see `cmd/homed/platform_windows.go`).
On Windows only `waiter.exe` is built and `homed` runs under WSL2 (see Downloads).
macOS can build `waiter`/`initconfig`; `homed` must be built on native macOS.
## License
**AGPL-3.0-only**. See [LICENSE](LICENSE).
Bundled third-party components keep their own licenses; full texts ship in
`/usr/share/doc/hologramagent/licenses/`.
### Third-party components shipped with the packages
| Component | License | Location |
| --- | --- | --- |
| Chinese-CLIP ViT-B/16 (ONNX artifacts) | Apache-2.0 | `/usr/lib/hologram/models/chinese-clip-vit-b16-onnx/` |
| ONNX Runtime (`libonnxruntime.so`) | MIT | `/usr/lib/hologram/onnxruntime/` |
| jieba dictionary (embedded in the binary) | MIT | `internal/memory/jiebadict/` |
| Go dependencies (go-sqlite3, gojieba, bubbletea, …) | MIT / BSD-3 / Apache-2.0 | permissive, AGPL-3.0-compatible |
The package metadata declares this package as `AGPL-3.0-only`.