From c9e67d3d556d97f3d49f8c41e43fc00760de8567 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 18 Jul 2026 20:46:58 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E4=BF=AE=E6=AD=A3=E5=85=A8=E9=83=A8?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E4=BD=BF=E5=85=B6=E4=B8=8E=E6=BA=90=E7=A0=81?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主仓库: - 修复 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 代理 --- docs/en/ADAPTER.md | 2 +- docs/en/ARCHITECTURE.md | 4 +-- docs/en/OVERVIEW.md | 2 +- docs/en/PLUGIN_DEV.md | 40 +++++++++++---------- docs/zh/ARCHITECTURE.md | 2 +- docs/zh/PLUGIN_DEV.md | 40 +++++++++++---------- go.mod | 2 +- go.sum | 51 -------------------------- go.work | 5 --- internal/agent/core/agent.go | 65 ++++++++++++++++++++++------------ internal/config/registry.go | 20 +---------- internal/lua/vm.go | 28 +++++++++++++-- internal/plugin/cabi/loader.go | 6 +++- internal/sdk/plugin.go | 3 ++ 14 files changed, 125 insertions(+), 145 deletions(-) delete mode 100644 go.work diff --git a/docs/en/ADAPTER.md b/docs/en/ADAPTER.md index 7b172ce..5f6372a 100644 --- a/docs/en/ADAPTER.md +++ b/docs/en/ADAPTER.md @@ -1,4 +1,4 @@ -**中文** | [English](../zh/ADAPTER.md) +**中文** | [English](../en/ADAPTER.md) # Lua Adapter — LLM Source Adaptation Guide diff --git a/docs/en/ARCHITECTURE.md b/docs/en/ARCHITECTURE.md index 4f42a7e..1aa3fcd 100644 --- a/docs/en/ARCHITECTURE.md +++ b/docs/en/ARCHITECTURE.md @@ -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 | |--------|----------------------|-------------|-------| diff --git a/docs/en/OVERVIEW.md b/docs/en/OVERVIEW.md index 06e6a34..48cda93 100644 --- a/docs/en/OVERVIEW.md +++ b/docs/en/OVERVIEW.md @@ -1,4 +1,4 @@ -**中文** | [English](../zh/OVERVIEW.md) +**中文** | [English](../en/OVERVIEW.md) # HomeAgent — Project Overview diff --git a/docs/en/PLUGIN_DEV.md b/docs/en/PLUGIN_DEV.md index 4db25d1..672a82e 100644 --- a/docs/en/PLUGIN_DEV.md +++ b/docs/en/PLUGIN_DEV.md @@ -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 diff --git a/docs/zh/ARCHITECTURE.md b/docs/zh/ARCHITECTURE.md index 127b445..d7a4ca9 100644 --- a/docs/zh/ARCHITECTURE.md +++ b/docs/zh/ARCHITECTURE.md @@ -249,7 +249,7 @@ VM 内置 `json.encode` / `json.decode` / `log` / `http_get` / `http_post`。 ## 插件系统 -### 三种加载方式 +### 四种加载方式 | 方式 | 注册机制 | 编译 | 用途 | |------|----------|------|------| diff --git a/docs/zh/PLUGIN_DEV.md b/docs/zh/PLUGIN_DEV.md index c94c746..c4db4d8 100644 --- a/docs/zh/PLUGIN_DEV.md +++ b/docs/zh/PLUGIN_DEV.md @@ -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 插件示例 | ### 内置插件 diff --git a/go.mod b/go.mod index 5a09fa8..7082b75 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 362e015..faf3a7f 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/go.work b/go.work deleted file mode 100644 index 855a0b3..0000000 --- a/go.work +++ /dev/null @@ -1,5 +0,0 @@ -go 1.25.0 - -use ( - . -) diff --git a/internal/agent/core/agent.go b/internal/agent/core/agent.go index 069e235..4145fc5 100644 --- a/internal/agent/core/agent.go +++ b/internal/agent/core/agent.go @@ -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 diff --git a/internal/config/registry.go b/internal/config/registry.go index 417272b..183c2d8 100644 --- a/internal/config/registry.go +++ b/internal/config/registry.go @@ -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", "") diff --git a/internal/lua/vm.go b/internal/lua/vm.go index bc7adbd..f3d4ea9 100644 --- a/internal/lua/vm.go +++ b/internal/lua/vm.go @@ -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 })) } diff --git a/internal/plugin/cabi/loader.go b/internal/plugin/cabi/loader.go index cfc82f3..3701581 100644 --- a/internal/plugin/cabi/loader.go +++ b/internal/plugin/cabi/loader.go @@ -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 diff --git a/internal/sdk/plugin.go b/internal/sdk/plugin.go index e61543d..6fd5908 100644 --- a/internal/sdk/plugin.go +++ b/internal/sdk/plugin.go @@ -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