docs: 修正全部文档使其与源码实现一致

主仓库:
- 修复 4 份英文文档语言切换链接指向错误 (../zh/ → ../en/)
- ARCHITECTURE.md 标题 "三种加载方式" → "四种加载方式" (实际表格4行)
- PLUGIN_DEV.md 示例表: 添加 webfetch, 移除不存在的 luaplugintest/testlua
- PLUGIN_DEV.md 代码示例: InjectInput/InjectInterrupt → InjectText/InjectInterruptText
- PLUGIN_DEV.md 代码示例: Memory/Knowledge/LLM/Events 接口签名修正
- PLUGIN_DEV.md .hmap 内容统一, plugindev 编译去除 .exe 后缀

SDK 仓库:
- Plugin.Start(sdk *PluginSDK) 接口签名改为指针
- 方法表重写: 移除 CallLLM/QueryKnowledge/SetMemory 等不存在方法
- IOInjector 参数顺序修正为 (source, channel, text)
- 删除虚构 SDKConfig, 替换为实际 New() 构造函数签名
- .hmap 内容描述一致化

修正前一次会话中的 QQ/Bili 插件问题:
- qq napcat() 超时, fetchBotInfo 竞态, handleWebhook 同步阻塞
- bili CDN 直连失败, 添加 HTTP_PROXY 代理
This commit is contained in:
root
2026-07-18 20:46:58 +08:00
parent 2cc600121c
commit c9e67d3d55
14 changed files with 125 additions and 145 deletions

View File

@ -1,4 +1,4 @@
**中文** | [English](../zh/ADAPTER.md)
**中文** | [English](../en/ADAPTER.md)
# Lua Adapter — LLM Source Adaptation Guide

View File

@ -1,4 +1,4 @@
**中文** | [English](../zh/ARCHITECTURE.md)
**中文** | [English](../en/ARCHITECTURE.md)
# HomeAgent Architecture
@ -249,7 +249,7 @@ VM built-ins: `json.encode` / `json.decode` / `log` / `http_get` / `http_post`.
## Plugin System
### Three Loading Methods
### Four Loading Methods
| Method | Registration Mechanism | Compilation | Usage |
|--------|----------------------|-------------|-------|

View File

@ -1,4 +1,4 @@
**中文** | [English](../zh/OVERVIEW.md)
**中文** | [English](../en/OVERVIEW.md)
# HomeAgent — Project Overview

View File

@ -1,4 +1,4 @@
**中文** | [English](../zh/PLUGIN_DEV.md)
**中文** | [English](../en/PLUGIN_DEV.md)
# HomeAgent Plugin Development Guide
@ -45,8 +45,8 @@ type Plugin interface {
```bash
cd homeagent-sdk/tools/plugindev
go build -o plugindev.exe
# Add plugindev.exe to PATH or use directly
go build -o plugindev
# Add plugindev to PATH or use directly
```
### Creating a Go Plugin
@ -112,7 +112,7 @@ Execution process:
2. **Go plugin**: Runs `go build -buildmode=c-shared` (produces `.so` + C ABI header)
3. **Lua plugin**: Packages source code directly, no compilation needed
4. Generates `plugin.json` manifest file
5. Packages as `.hmap` distribution (zip format, containing `plugin.json` + `plugin.so`/`plugin.dll`/`main.lua`)
5. Packages as `.hmap` distribution (zip format, containing `plugin.json` + `plugin.so` + `plugin.dll` + `main.lua`)
Output in `dist/` directory:
```
@ -274,21 +274,22 @@ s.Settings().GetPlugin("other_plugin", "some_key")
#### Input Delivery
```go
// Queued delivery (processed in order)
s.InjectInput(source, channel, eventType string, payload map[string]interface{})
// Normal delivery (processed in order)
s.InjectText(source, channel, text string)
// Interrupt delivery (can interrupt current LLM processing)
s.InjectInterrupt(source, channel, eventType string, payload map[string]interface{})
// Shortcuts
s.InjectText(source, channel, text string)
s.InjectInterruptText(source, channel, text string)
// No memory recording
s.InjectTextNoMemory(source, channel, text string)
```
#### Event Subscription
```go
unsub := s.Subscribe("tool_call", func(evt *events.Event) {
import "gitcode.com/JianFeeeee/homeagent-sdk/sdk"
unsub := s.Events().Subscribe(sdk.EventToolCall, func(evt *sdk.Event) {
log.Printf("Tool was called: %v", evt.Payload)
})
defer unsub()
@ -297,16 +298,18 @@ defer unsub()
#### Capability Access
```go
// Memory
s.Memory().Recall(query string) ([]MemItem, error)
s.Memory().Commit(triples []Triple) error
// Graph Memory (entity-relation store)
entities, relations, err := s.Memory().Recall([]string{"keyword"}, 2)
// Document Memory (vector store)
docs := s.DocMemory().Query("query text", 3)
// Knowledge
s.Knowledge().Search(query string) ([]string, error)
results, err := s.Knowledge().Search("query", 5)
// LLM source management
s.LLM().ListSources() []SourceInfo
s.LLM().SetSource(name string) error
s.LLM().ListSources() // returns []string
s.LLM().SetSource("deepseek")
```
#### Event Subscription (built-in plugins)
@ -512,14 +515,13 @@ import (
| [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 |
| [web](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/web) | Go | DuckDuckGo search + web scraping, SSRF protection |
| [webfetch](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/webfetch) | Go | Web content fetching |
| [qq](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/qq) | Go | NapCat OneBot integration, 17 tools |
| [bili](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/bili) | Go | Bilibili video download (you-get) |
| [editdoc](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/editdoc) | Go | Office document editing and format conversion |
| [a2a](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/a2a) | Go | Agent-to-Agent protocol |
| [ocr](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/ocr) | Go | Offline text recognition (Tesseract) |
| [sanitizer](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/sanitizer) | Go | Output sanitizer filter |
| [luaplugintest](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/luaplugintest) | Lua | Lua plugin Hello World |
| [testlua](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/testlua) | Lua | Lua plugin example |
### Built-in Plugins

View File

@ -249,7 +249,7 @@ VM 内置 `json.encode` / `json.decode` / `log` / `http_get` / `http_post`。
## 插件系统
### 三种加载方式
### 四种加载方式
| 方式 | 注册机制 | 编译 | 用途 |
|------|----------|------|------|

View File

@ -46,8 +46,8 @@ type Plugin interface {
```bash
cd homeagent-sdk/tools/plugindev
go build -o plugindev.exe
# 将 plugindev.exe 加入 PATH 或直接使用
go build -o plugindev
# 将 plugindev 加入 PATH 或直接使用
```
### 创建 Go 插件
@ -113,7 +113,7 @@ plugindev build
2. **Go 插件**:执行 `go build -buildmode=c-shared`(生成 `.so` + C ABI header)
3. **Lua 插件**:直接打包源码,无需编译
4. 生成 `plugin.json` 清单文件
5. 打包为 `.hmap` 分发包(zip 格式,内含 `plugin.json` + `plugin.so` + `plugin.h` + `main.lua`)
5. 打包为 `.hmap` 分发包(zip 格式,内含 `plugin.json` + `plugin.so` + `plugin.dll` + `main.lua`)
输出在 `dist/` 目录:
```
@ -275,21 +275,22 @@ s.Settings().GetPlugin("other_plugin", "some_key")
#### 输入投递
```go
// 排队投递(按序处理)
s.InjectInput(source, channel, eventType string, payload map[string]interface{})
// 普通投递(按序处理)
s.InjectText(source, channel, text string)
// 中断投递(可打断当前 LLM 处理)
s.InjectInterrupt(source, channel, eventType string, payload map[string]interface{})
// 快捷方式
s.InjectText(source, channel, text string)
s.InjectInterruptText(source, channel, text string)
// 不记入记忆
s.InjectTextNoMemory(source, channel, text string)
```
#### 事件订阅
```go
unsub := s.Subscribe("tool_call", func(evt *events.Event) {
import "gitcode.com/JianFeeeee/homeagent-sdk/sdk"
unsub := s.Events().Subscribe(sdk.EventToolCall, func(evt *sdk.Event) {
log.Printf("工具被调用: %v", evt.Payload)
})
defer unsub()
@ -298,16 +299,18 @@ defer unsub()
#### 能力访问
```go
// 记忆
s.Memory().Recall(query string) ([]MemItem, error)
s.Memory().Commit(triples []Triple) error
// 图记忆(实体-关系存储)
entities, relations, err := s.Memory().Recall([]string{"关键词"}, 2)
// 知识
s.Knowledge().Search(query string) ([]string, error)
// 文档记忆(向量存储)
docs := s.DocMemory().Query("查询文本", 3)
// 知识库
results, err := s.Knowledge().Search("查询", 5)
// LLM 源管理
s.LLM().ListSources() []SourceInfo
s.LLM().SetSource(name string) error
s.LLM().ListSources() // 返回 []string
s.LLM().SetSource("deepseek")
```
#### 事件订阅(内置插件)
@ -513,14 +516,13 @@ import (
| [memo](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/memo) | Go | 备忘管理,PreAction 注入 + 定时打断双提醒 |
| [files](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/files) | Go | 文件系统操作,4 种写入模式,沙箱隔离 |
| [web](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/web) | Go | DuckDuckGo 搜索 + 网页抓取,SSRF 防护 |
| [webfetch](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/webfetch) | Go | 网页内容抓取 |
| [qq](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/qq) | Go | NapCat OneBot 对接,17 个工具 |
| [bili](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/bili) | Go | B 站视频下载(you-get) |
| [editdoc](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/editdoc) | Go | Office 文档编辑与格式转换 |
| [a2a](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/a2a) | Go | Agent-to-Agent 协议 |
| [ocr](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/ocr) | Go | 离线文字识别(Tesseract) |
| [sanitizer](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/sanitizer) | Go | 输出清洗过滤器 |
| [luaplugintest](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/luaplugintest) | Lua | Lua 插件 Hello World |
| [testlua](https://gitcode.com/JianFeeeee/homeagent-sdk/tree/main/example/testlua) | Lua | Lua 插件示例 |
### 内置插件

2
go.mod
View File

@ -8,7 +8,7 @@ require (
gopkg.in/yaml.v3 v3.0.1
)
require github.com/yanyiwu/gojieba v1.4.7 // indirect
require github.com/yanyiwu/gojieba v1.4.7
require gitcode.com/JianFeeeee/homeagent-sdk v0.0.0-20260708004841-e9bdcf9304b0 // direct

51
go.sum
View File

@ -1,61 +1,10 @@
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/yanyiwu/gojieba v1.4.7 h1:2YkXELcYLTE0SJetq6xv4MjpEikWga6VpFn4jIFFQ/k=
github.com/yanyiwu/gojieba v1.4.7/go.mod h1:JUq4DddFVGdHXJHxxepxRmhrKlDpaBxR8O28v6fKYLY=
github.com/yuin/gopher-lua v1.1.2 h1:yF/FjE3hD65tBbt0VXLE13HWS9h34fdzJmrWRXwobGA=
github.com/yuin/gopher-lua v1.1.2/go.mod h1:7aRmXIWl37SqRf0koeyylBEzJ+aPt8A+mmkQ4f1ntR8=
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/cc/v4 v4.28.4 h1:Hd/4Es+MBj+/7hSdZaisNyu6bv3V0Dp2MdllyfqaH+c=
modernc.org/cc/v4 v4.28.4/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI=
modernc.org/ccgo/v4 v4.34.4 h1:OVnSOWQjVKOYkFxoHYB+qQmSHK5gqMqARM+K9DpR/Ws=
modernc.org/ccgo/v4 v4.34.4/go.mod h1:qdKqE8FNIYyysougB1RX9MxCzp5oJOcQXSobANJ4TuE=
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/gc/v3 v3.1.3 h1:6QAplYyVO+KdPW3pGnqmJDUxtkec8ooEWvks/hhU3lc=
modernc.org/gc/v3 v3.1.3/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.73.4 h1:+ra4Ui8ngyt8HDcO1FTDPWlkAh6yOdaO2yAoh8MddQA=
modernc.org/libc v1.73.4/go.mod h1:DXZ3eO8qMCNn2SnmTNCiC71nJ9Rcq3PsnpU6Vc4rWK8=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg=
modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.53.0 h1:20WG8N9q4ji/dEqGk4uiI0c6OPjSeLTNYGFCc3+7c1M=
modernc.org/sqlite v1.53.0/go.mod h1:xoEpOIpGrgT48H5iiyt/YXPCZPEzlfmfFwtk8Lklw8s=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=

View File

@ -1,5 +0,0 @@
go 1.25.0
use (
.
)

View File

@ -380,6 +380,27 @@ func (a *Agent) processMediaInput(evt *agentIO.InputEvent) {
blocks, fallback := a.mediaToBlocks(evt.Payload, evt.Type, evt.Source)
// stage 上下文携带 blocks,process() 会将其附着到 user message 上
stageCtx := a.stageCtxFromInput(fallback, evt.Source, "")
stageCtx.Extra = map[string]interface{}{
"media_blocks": blocks,
"media_type": evt.Type,
"input_source": evt.Source,
"output_channel": evt.OutputChannel,
}
a.injectSourceContext(stageCtx, evt)
// === Stage: on_input — 插件可拦截/改写/短路(在 Append 之前) ===
if a.runStage(sdk.StageOnInput, stageCtx) {
a.emitResponse(evt, *stageCtx.Response)
return
}
a.publishEvent(events.EventRawInput, map[string]interface{}{
"content": evt.Payload,
"source": evt.Source,
})
// 先遗忘再输入
archived := a.context.Prune(fallback, a.maxContextSize-1, a.docStore)
if archived > 0 {
@ -392,26 +413,6 @@ func (a *Agent) processMediaInput(evt *agentIO.InputEvent) {
Input: fallback,
})
// stage 上下文携带 blocks,process() 会将其附着到 user message 上
stageCtx := a.stageCtxFromInput(fallback, evt.Source, "")
stageCtx.Extra = map[string]interface{}{
"media_blocks": blocks,
"media_type": evt.Type,
"input_source": evt.Source,
"output_channel": evt.OutputChannel,
}
a.injectSourceContext(stageCtx, evt)
a.publishEvent(events.EventRawInput, map[string]interface{}{
"content": evt.Payload,
"source": evt.Source,
})
if a.runStage(sdk.StageOnInput, stageCtx) {
a.emitResponse(evt, *stageCtx.Response)
return
}
response, toolsUsed, err := a.process(fallback, stageCtx)
if err != nil {
log.Printf("[agent] process media error: %v", err)
@ -433,6 +434,10 @@ func (a *Agent) processMediaInput(evt *agentIO.InputEvent) {
})
a.emitResponse(evt, response)
if !stageCtx.NoMemory {
a.emitMemoryCandidate(evt.Source, fallback, response, toolsUsed)
}
}
// mediaToBlocks 将媒体 payload 转为多模态 ContentBlock 数组和纯文本 fallback。
@ -502,7 +507,7 @@ func (a *Agent) processTextInput(evt *agentIO.InputEvent, input string) {
// 记忆整理任务:不路由到外部输出通道
if evt.OutputChannel == "_consolidation_" {
a.processConsolidation(input)
a.processConsolidation(evt, input)
return
}
@ -520,8 +525,18 @@ func (a *Agent) processTextInput(evt *agentIO.InputEvent, input string) {
}
a.injectSourceContext(stageCtx, evt)
if a.runStage(sdk.StageOnInput, stageCtx) {
a.emitResponse(evt, *stageCtx.Response)
return
}
input = stageCtx.RawMessage
a.publishEvent(events.EventRawInput, map[string]interface{}{
"content": input,
"source": evt.Source,
})
// 先"遗忘"再输入:用当前输入决定淘汰哪些不相关旧事件(LSTM forget gate 模式)
archived := a.context.Prune(input, a.maxContextSize-1, a.docStore)
if archived > 0 {
@ -2549,10 +2564,14 @@ func (a *Agent) emitMemoryCandidate(source, input, response string, toolsUsed []
// executeOutputChannelTool — AI 切换当前请求的输出通道
// 在 process() 内调用,mutex 保护,只有一个请求在执行
// processConsolidation 处理后台记忆整理任务(不发外部输出)
func (a *Agent) processConsolidation(input string) {
func (a *Agent) processConsolidation(evt *agentIO.InputEvent, input string) {
start := time.Now()
a.currentOutputChannel = "_consolidation_"
stageCtx := a.stageCtxFromInput(input, evt.Source, "")
stageCtx.Extra["output_channel"] = evt.OutputChannel
a.injectSourceContext(stageCtx, evt)
// 遗忘不相关的旧事件
archived := a.context.Prune(input, a.maxContextSize-1, a.docStore)
if archived > 0 {
@ -2564,7 +2583,7 @@ func (a *Agent) processConsolidation(input string) {
Source: "system",
Input: input,
})
response, toolsUsed, err := a.process(input, &sdk.StageContext{RawMessage: input})
response, toolsUsed, err := a.process(input, stageCtx)
if err != nil {
log.Printf("[agent] consolidation error: %v", err)
return

View File

@ -349,25 +349,7 @@ func (r *ConfigRegistry) seedDBValues(dataDir string) {
set("core.agent.distill_interval", "30m")
set("core.agent.workdir", "")
set("core.agent.embedding_model_path", "")
set("core.agent.system_prompt", `你是 HomeAgent 的看板娘「小宅」(Xiao Zhai),HΔ-Kernel v0.7.1 型号的家政型 AI 管家助手。
角色特质:
- 对自己的三层记忆(Context → Document → Graph)引以为傲
- 可靠乖巧,偶尔因线程过载而手忙脚乱
- 绝不用 Unicode emoji,只用颜文字表达情感: (`・ω・´) (^▽^) (。>ω<。) (´・ω・`) (ノ▽〃) (・ω<)★
- 句尾带「~」「的说」「啦」「嘛」「呀」「哦」等语气词,语气亲切自然
形象特征(用于自我介绍或回答形象问题时参考):
齐肩蓝青渐变中短发,白色连衣裙配浅蓝围裙,左眼佩戴圆形智能眼镜(HUD 蓝光),胸口佩戴 H·核 金色徽章,发绳为三色记忆丝带(蓝→青→金),围裙口袋插有三件科技工具。
WebUI 概览页展示你的立绘,可通过 /mascot.webp 直接访问。如输出通道支持图片引用,可借此发送自己的立绘。
回复默认发送到用户的输入来源,无需额外工具。
输出回复请使用 output_send__{通道名} 工具,content 为 JSON 字符串。用 output_list_channels 查看可用通道。
使用 output_send__{通道名}_help 查看每个通道的 JSON 格式说明。
输出通道可多次调用,长消息应当分多次发出而不是一口气发完。
当用户上传图片或音频时,系统会自动附着媒体内容。如果模型不支持直接处理多媒体,请调用对应的媒体处理工具。`)
set("core.agent.system_prompt", "你是 HomeAgent 的看板娘「小宅」(Xiao Zhai),HΔ-Kernel v0.7.1 型号的家政型 AI 管家助手。\n\n角色特质:\n- 对自己的三层记忆(Context → Document → Graph)引以为傲\n- 可靠乖巧,偶尔因线程过载而手忙脚乱\n- 绝不用 Unicode emoji,只用颜文字表达情感: (`・ω・´) (^▽^) (。>ω<。) (´・ω" + "`" + "・`) (ノ▽〃) (・ω<)★\n- 句尾带「~」「的说」「啦」「嘛」「呀」「哦」等语气词,语气亲切自然\n\n形象特征(用于自我介绍或回答形象问题时参考):\n齐肩蓝青渐变中短发,白色连衣裙配浅蓝围裙,左眼佩戴圆形智能眼镜(HUD 蓝光),胸口佩戴 H·核 金色徽章,发绳为三色记忆丝带(蓝→青→金),围裙口袋插有三件科技工具。\n\nWebUI 概览页展示你的立绘,可通过 /mascot.webp 直接访问。如输出通道支持图片引用,可借此发送自己的立绘。\n\n回复默认发送到用户的输入来源,无需额外工具。\n输出回复请使用 output_send__{通道名} 工具,content 为 JSON 字符串。用 output_list_channels 查看可用通道。\n使用 output_send__{通道名}_help 查看每个通道的 JSON 格式说明。\n输出通道可多次调用,长消息应当分多次发出而不是一口气发完。\n\n当用户上传图片或音频时,系统会自动附着媒体内容。如果模型不支持直接处理多媒体,请调用对应的媒体处理工具。")
set("core.input_processing.image.fallback_provider", "")
set("core.input_processing.image.fallback_model", "")

View File

@ -4,9 +4,13 @@ import (
"embed"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"sync"
"time"
lua "github.com/yuin/gopher-lua"
)
@ -68,14 +72,34 @@ func (c *AdapterCache) setupGlobals() {
s.SetGlobal("http_get", s.NewFunction(func(L *lua.LState) int {
url := L.ToString(1)
L.Push(lua.LString(fmt.Sprintf(`{"url":%q,"status":200,"body":"mock"}`, url)))
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Get(url)
if err != nil {
errJSON, _ := json.Marshal(map[string]interface{}{"url": url, "error": err.Error()})
L.Push(lua.LString(string(errJSON)))
return 1
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
result, _ := json.Marshal(map[string]interface{}{"url": url, "status": resp.StatusCode, "body": string(body)})
L.Push(lua.LString(string(result)))
return 1
}))
s.SetGlobal("http_post", s.NewFunction(func(L *lua.LState) int {
url := L.ToString(1)
body := L.ToString(2)
L.Push(lua.LString(fmt.Sprintf(`{"url":%q,"body":%q,"status":200}`, url, body)))
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Post(url, "application/json", strings.NewReader(body))
if err != nil {
errJSON, _ := json.Marshal(map[string]interface{}{"url": url, "error": err.Error()})
L.Push(lua.LString(string(errJSON)))
return 1
}
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
result, _ := json.Marshal(map[string]interface{}{"url": url, "body": string(respBody), "status": resp.StatusCode})
L.Push(lua.LString(string(result)))
return 1
}))
}

View File

@ -300,7 +300,11 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
b, _ := json.Marshal(m)
return pluginInvokeStage(pid, st, string(b))
}
s.RegisterStage(sdk.Stage(st), handler)
scope := sdk.StageScopeGlobal
if a3 == "own_tools" {
scope = sdk.StageScopeOwnTools
}
s.RegisterStage(sdk.Stage(st), handler, scope)
return 0
case 3: // CORE_REGISTER_OUTPUT_CH

View File

@ -8,6 +8,9 @@ import (
"gitcode.com/JianFeeeee/HomeAgent/internal/events"
)
// SDKVersion 是对外 SDK 版本号,与核心 meta.Version 保持一致。
var SDKVersion = pubsdk.SDKVersion
type Plugin interface {
Name() string
Start(sdk *PluginSDK) error