mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 09:28:14 +00:00
C ABI v2: invoke_stage 写回 + ABI 版本对齐核心版本号 (v0.9.0)
- C ABI invoke_stage 增加 result 输出参数,外部插件 stage 回调可将修改后的 StageContext(RawMessage/LLMText/FinalText/Response/ToolResults) 写回内核 - ABI 标识版本改为字符串 semver 与核心 Version 对齐(ABIVersion="0.9.0"), C 层协商用派生整数 CABINum=900(major*100+minor),不再使用独立数字编码 - version_min 保证 v0.8.x(800) 旧插件向后兼容可加载 - 修复工具循环 zen 兼容补位误伤首轮 system 上下文(仅尾部为 assistant/tool 时补位) - 更新 README 项目状态说明
This commit is contained in:
@ -15,6 +15,7 @@ homed(内核零 IO) ← PluginSDK → 插件(所有 IO 能力)
|
||||
**核心域与应用域分离** — 内核职责限定为 LLM 编排、记忆管理与知识检索;所有 IO 能力(消息收发、文件读写、网络请求、硬件交互等)由插件实现。这种划分在 Agent 框架层面进行领域边界界定,内核与插件各有其责任范围。
|
||||
|
||||
**三层记忆架构** — 通过分级存储策略管理 Agent 长期运行中的信息留存:
|
||||
|
||||
- **Context 层**:预训练词嵌入 / TF-IDF 回退的相关性评分事件窗口,保护最近 10 条,维护 topK 条上下文
|
||||
- **Document 层**:临时记忆,冷数据自动下沉,也支持用户主动提交
|
||||
- **Graph 层**:SQLite 图数据库,持久化实体关系和语义记忆,支持蒸馏管道从原始对话中提取三元组
|
||||
@ -171,6 +172,8 @@ internal/
|
||||
|
||||
## 项目状态
|
||||
|
||||
**v0.9.0** — C ABI v2:外部插件 Stage 回调支持写回(`invoke_stage` 增加 result 输出,插件可在 OnInput/AfterToolcall/PostAction 修改 RawMessage/LLMText/ToolResults 等并同步回内核),ABI 版本随内核 minor 对齐(v0.9.x → ABIVersion=2,`version_min=1` 向后兼容旧插件)。同步修复工具循环 zen 兼容补位误伤首轮 system 上下文的问题。配套 SDK 提供增强版 sanitizer 示例(坏 UTF-8/U+FFFD/ANSI 转义全链路清洗)。
|
||||
|
||||
**v0.8.0** — 核心可用,插件系统增强。内置 20+ 插件,外部插件开发见 [homeagent-sdk](https://gitcode.com/JianFeeeee/homeagent-sdk) 仓库。新增输入通道 `NoMemory`/`Cleaner`、`ChannelDef`、插件禁用/启用系统(CLI + WebUI),`plugindev` 工具链完成 C ABI `ChannelDef` 传递。
|
||||
|
||||
## 文档
|
||||
@ -189,4 +192,4 @@ make test # go test ./...
|
||||
make install # 安装到系统
|
||||
```
|
||||
|
||||
依赖:Go 1.25+, CGo (go-sqlite3), Linux/Windows。
|
||||
依赖:Go 1.25+, CGo (go-sqlite3), Linux/Windows。
|
||||
|
||||
@ -15,6 +15,7 @@ homed (kernel, zero IO) ← PluginSDK → plugins (all IO capabilities)
|
||||
**Separation of Core Domain and Application Domain** — The kernel's responsibilities are limited to LLM orchestration, memory management, and knowledge retrieval; all IO capabilities (message send/receive, file read/write, network requests, hardware interaction, etc.) are implemented by plugins. This separation defines domain boundaries at the Agent framework level, with distinct responsibility scopes for the kernel and plugins.
|
||||
|
||||
**Three-Layer Memory Architecture** — Manages information retention in long-running agents through a tiered storage strategy:
|
||||
|
||||
- **Context Layer**: Pretrained word embedding / TF-IDF fallback relevance-scored event window, protects last 10 entries, maintains topK context entries
|
||||
- **Document Layer**: Temporary memory with automatic cold data sinking, also supports user-initiated submissions
|
||||
- **Graph Layer**: SQLite graph database, persists entity relationships and semantic memory, supports distillation pipelines to extract triples from conversations
|
||||
@ -171,6 +172,8 @@ External plugin development: see [homeagent-sdk](https://gitcode.com/JianFeeeee/
|
||||
|
||||
## Project Status
|
||||
|
||||
**v0.9.0** — C ABI v2: external plugin Stage callbacks can now write back (`invoke_stage` gained a result out-param; plugins may mutate RawMessage/LLMText/ToolResults etc. in OnInput/AfterToolcall/PostAction and have them synced to the core). ABI version now tracks core minor releases (v0.9.x → ABIVersion=2, `version_min=1` keeps old plugins loadable). Also fixes the tool-loop zen-compat placeholder that wrongly fired on first-turn system context tail. The SDK ships an enhanced sanitizer example (bad-UTF-8 / U+FFFD / ANSI-escape scrub across the whole pipeline).
|
||||
|
||||
**v0.8.0** — Core is functional, plugin system enhanced. 20+ built-in plugins. External plugin development via [homeagent-sdk](https://gitcode.com/JianFeeeee/homeagent-sdk) repo. Added input channel `NoMemory`/`Cleaner`, `ChannelDef`, plugin disable/enable system (CLI + WebUI), `plugindev` toolchain C ABI `ChannelDef` support.
|
||||
|
||||
## Documentation
|
||||
|
||||
@ -70,7 +70,9 @@ func (a *Agent) process(input string, stageCtx *sdk.StageContext) (response stri
|
||||
|
||||
// zen 兼容网关要求请求的最后一条消息必须是 user(thinking 续写模式校验),
|
||||
// 工具轮产出的 tool/assistant 消息作结尾会被 400 拒绝,故补一条 user 占位。
|
||||
if last := msgs[len(msgs)-1]; last.Role != "user" {
|
||||
// 注意:仅当尾部确为工具轮产物(assistant/tool)时才补位;首轮 system 上下文结尾不补,
|
||||
// 否则会错误覆盖实际用户输入(如 injectSourceContext 追加的 system 说明)。
|
||||
if last := msgs[len(msgs)-1]; last.Role == "assistant" || last.Role == "tool" {
|
||||
msgs = append(msgs, agentAPI.Message{
|
||||
Role: "user",
|
||||
Content: "请根据以上工具结果继续。",
|
||||
@ -211,14 +213,14 @@ func (a *Agent) process(input string, stageCtx *sdk.StageContext) (response stri
|
||||
for _, interrupt := range a.drainInterrupts() {
|
||||
msgs = append(msgs, agentAPI.Message{Role: "system", Content: "[中断消息] " + interrupt})
|
||||
}
|
||||
a.publishEvent(events.EventToolCall, map[string]interface{}{
|
||||
"tool": tc.Name,
|
||||
"plugin": a.resolveToolPlugin(tc.Name),
|
||||
"args": tc.Arguments,
|
||||
"status": "interrupted",
|
||||
"reason": "user interrupt before execution",
|
||||
"channel": a.currentOutputChannel,
|
||||
})
|
||||
a.publishEvent(events.EventToolCall, map[string]interface{}{
|
||||
"tool": tc.Name,
|
||||
"plugin": a.resolveToolPlugin(tc.Name),
|
||||
"args": tc.Arguments,
|
||||
"status": "interrupted",
|
||||
"reason": "user interrupt before execution",
|
||||
"channel": a.currentOutputChannel,
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
@ -233,14 +235,14 @@ func (a *Agent) process(input string, stageCtx *sdk.StageContext) (response stri
|
||||
result := fmt.Sprintf("工具 %s 已被插件拒绝", tc.Name)
|
||||
msgs = append(msgs, agentAPI.Message{Role: "assistant", ToolCalls: []agentAPI.ToolCall{tc}})
|
||||
msgs = append(msgs, agentAPI.Message{Role: "tool", ToolCallID: tc.ID, Content: result})
|
||||
a.publishEvent(events.EventToolCall, map[string]interface{}{
|
||||
"tool": tc.Name,
|
||||
"plugin": pluginName,
|
||||
"args": tc.Arguments,
|
||||
"result": result,
|
||||
"status": "denied",
|
||||
"channel": a.currentOutputChannel,
|
||||
})
|
||||
a.publishEvent(events.EventToolCall, map[string]interface{}{
|
||||
"tool": tc.Name,
|
||||
"plugin": pluginName,
|
||||
"args": tc.Arguments,
|
||||
"result": result,
|
||||
"status": "denied",
|
||||
"channel": a.currentOutputChannel,
|
||||
})
|
||||
continue
|
||||
}
|
||||
tc.Arguments = stageCtx.ToolCalls[0].Arguments
|
||||
|
||||
@ -7,7 +7,7 @@ package meta
|
||||
var (
|
||||
// Version 是 HomeAgent 内核版本号。
|
||||
// 通过 `-ldflags="-X gitcode.com/JianFeeeee/HomeAgent/internal/meta.Version=vX.Y.Z"` 注入。
|
||||
Version = "0.8.0"
|
||||
Version = "0.9.0"
|
||||
|
||||
// Commit 是构建时的 Git commit hash。
|
||||
Commit = "unknown"
|
||||
@ -19,7 +19,7 @@ var (
|
||||
KernelName = "HomeAgent"
|
||||
|
||||
// SDKCompatibleVersion 是此内核可兼容的最高 SDK 版本(semver)。
|
||||
SDKCompatibleVersion = "0.8.0"
|
||||
SDKCompatibleVersion = "0.9.0"
|
||||
)
|
||||
|
||||
// FullVersion 返回完整的版本字符串。
|
||||
@ -28,61 +28,74 @@ func FullVersion() string {
|
||||
}
|
||||
|
||||
// ---- ABI 版本(C ABI 协议版本,插件与内核通信用) ----
|
||||
// ABI 版本直接取内核版本号字符串(semver),与核心 Version 保持一致,不再使用独立数字编码。
|
||||
// 协商层(C 结构体 int version 字段)使用 CABINum:由版本字符串派生的整数(major*100 + minor)。
|
||||
// 映射:v0.8.x → CABINum=800;v0.9.x → CABINum=900(invoke_stage 写回)。
|
||||
// 小版本(patch)演进不影响 ABI,CABINum 不变。version_min 保证旧 ABI 插件仍可加载。
|
||||
|
||||
var (
|
||||
// ABIVersion 是 ABI 标识版本(字符串 semver,与核心 Version 对齐)。
|
||||
ABIVersion = Version
|
||||
// ABIVersionMin 是兼容的最低 ABI 标识版本。
|
||||
ABIVersionMin = "0.8.0"
|
||||
)
|
||||
|
||||
const (
|
||||
ABIVersion = 1
|
||||
ABIVersionMin = 1
|
||||
// CABINum 是 C 层协商用的整数版本(major*100 + minor),随 ABIVersion 派生。
|
||||
CABINum = 900
|
||||
// CABINumMin 是 C 层兼容的最低整数版本。
|
||||
CABINumMin = 800
|
||||
)
|
||||
|
||||
// ---- Dispatch Method IDs ----
|
||||
// 核心→插件:这些 ID 通过 CoreAPI.dispatch 传递,标识 SDK 调用。
|
||||
// 插件端的 C enum 定义在 plugindev 的 C ABI header 模板中。
|
||||
const (
|
||||
CoreRegisterTool = 1
|
||||
CoreRegisterStage = 2
|
||||
CoreRegisterOutputCh = 3
|
||||
CoreRegisterPluginAPI = 4
|
||||
CoreInjectText = 5
|
||||
CoreInjectInterruptText = 6
|
||||
CoreInjectTextNoMemory = 7
|
||||
CoreSetAutoRestart = 8
|
||||
CoreMemoryRecall = 9
|
||||
CoreMemoryCommit = 10
|
||||
CoreMemoryIntrospect = 11
|
||||
CoreMemoryMerge = 12
|
||||
CoreMemoryPurge = 13
|
||||
CoreDocQuery = 14
|
||||
CoreKnowledgeSearch = 15
|
||||
CoreSettingsGet = 16
|
||||
CoreSettingsSet = 17
|
||||
CoreSettingsRegisterDef = 18
|
||||
CoreLLMListSources = 19
|
||||
CoreLLMSetSource = 20
|
||||
CoreSocialGetPerson = 21
|
||||
CoreSocialGetNetwork = 22
|
||||
CoreSubscribe = 23
|
||||
CoreUnsubscribe = 24
|
||||
CoreFreeString = 25
|
||||
CoreSettingsGetCore = 26
|
||||
CoreSettingsSetCore = 27
|
||||
CoreSettingsListCore = 28
|
||||
CoreSettingsGetPlugin = 29
|
||||
CoreSettingsSetPlugin = 30
|
||||
CoreSettingsListPlugin = 31
|
||||
CoreDocInsert = 32
|
||||
CoreDocRemove = 33
|
||||
CoreDocStats = 34
|
||||
CoreKnowledgeAdd = 35
|
||||
CoreKnowledgeList = 36
|
||||
CoreLLMCurrentSource = 37
|
||||
CoreSocialGetTrait = 38
|
||||
CoreSocialGetRelations = 39
|
||||
CoreSocialListPersons = 40
|
||||
CoreTextMemoryAppend = 41
|
||||
CoreSettingsList = 42
|
||||
CoreSettingsDefs = 43
|
||||
CoreSettingsDump = 44
|
||||
CoreSettingsPlugins = 45
|
||||
CoreRegisterInputCh = 46
|
||||
CoreInjectInputSync = 47
|
||||
CoreRegisterTool = 1
|
||||
CoreRegisterStage = 2
|
||||
CoreRegisterOutputCh = 3
|
||||
CoreRegisterPluginAPI = 4
|
||||
CoreInjectText = 5
|
||||
CoreInjectInterruptText = 6
|
||||
CoreInjectTextNoMemory = 7
|
||||
CoreSetAutoRestart = 8
|
||||
CoreMemoryRecall = 9
|
||||
CoreMemoryCommit = 10
|
||||
CoreMemoryIntrospect = 11
|
||||
CoreMemoryMerge = 12
|
||||
CoreMemoryPurge = 13
|
||||
CoreDocQuery = 14
|
||||
CoreKnowledgeSearch = 15
|
||||
CoreSettingsGet = 16
|
||||
CoreSettingsSet = 17
|
||||
CoreSettingsRegisterDef = 18
|
||||
CoreLLMListSources = 19
|
||||
CoreLLMSetSource = 20
|
||||
CoreSocialGetPerson = 21
|
||||
CoreSocialGetNetwork = 22
|
||||
CoreSubscribe = 23
|
||||
CoreUnsubscribe = 24
|
||||
CoreFreeString = 25
|
||||
CoreSettingsGetCore = 26
|
||||
CoreSettingsSetCore = 27
|
||||
CoreSettingsListCore = 28
|
||||
CoreSettingsGetPlugin = 29
|
||||
CoreSettingsSetPlugin = 30
|
||||
CoreSettingsListPlugin = 31
|
||||
CoreDocInsert = 32
|
||||
CoreDocRemove = 33
|
||||
CoreDocStats = 34
|
||||
CoreKnowledgeAdd = 35
|
||||
CoreKnowledgeList = 36
|
||||
CoreLLMCurrentSource = 37
|
||||
CoreSocialGetTrait = 38
|
||||
CoreSocialGetRelations = 39
|
||||
CoreSocialListPersons = 40
|
||||
CoreTextMemoryAppend = 41
|
||||
CoreSettingsList = 42
|
||||
CoreSettingsDefs = 43
|
||||
CoreSettingsDump = 44
|
||||
CoreSettingsPlugins = 45
|
||||
CoreRegisterInputCh = 46
|
||||
CoreInjectInputSync = 47
|
||||
)
|
||||
|
||||
@ -6,9 +6,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// HOMEAGENT_ABI_VERSION 与 internal/meta/meta.go ABIVersion 同步。
|
||||
// HOMEAGENT_ABI_VERSION 与 internal/meta/meta.go CABINum 同步(major*100+minor,v0.9.x→900)。
|
||||
// C ABI 通过 version/version_min 协商,旧插件不受影响。
|
||||
#define HOMEAGENT_ABI_VERSION 1
|
||||
#define HOMEAGENT_ABI_VERSION 900
|
||||
|
||||
// PluginAPI — provided by the plugin
|
||||
typedef struct {
|
||||
@ -17,7 +17,7 @@ typedef struct {
|
||||
int (*start_plugin)(void*, int, char**);
|
||||
int (*stop_plugin)(char**);
|
||||
int (*invoke_tool)(char*, char*, char**, char**);
|
||||
int (*invoke_stage)(char*, char*, char**);
|
||||
int (*invoke_stage)(char*, char*, char**, char**);
|
||||
int (*invoke_output)(char*, char*, char*, char**);
|
||||
void (*free_string)(char*);
|
||||
} plugin_api_t;
|
||||
@ -75,5 +75,5 @@ int call_init_plugin(plugin_api_t* api, char* name, char* config, char** err) {
|
||||
int call_start_plugin(plugin_api_t* api, void* core, int ver, char** err) { return api->start_plugin(core, ver, err); }
|
||||
int call_stop_plugin(plugin_api_t* api, char** err) { return api->stop_plugin(err); }
|
||||
int call_invoke_tool(plugin_api_t* api, char* n, char* a, char** r, char** e) { return api->invoke_tool(n, a, r, e); }
|
||||
int call_invoke_stage(plugin_api_t* api, char* s, char* c, char** e) { return api->invoke_stage(s, c, e); }
|
||||
int call_invoke_stage(plugin_api_t* api, char* s, char* c, char** r, char** e) { return api->invoke_stage(s, c, r, e); }
|
||||
int call_invoke_output(plugin_api_t* api, char* c, char* m, char* p, char** e) { return api->invoke_output(c, m, p, e); }
|
||||
|
||||
@ -6,9 +6,10 @@ package cabi
|
||||
#cgo LDFLAGS: -ldl
|
||||
#include <stdlib.h>
|
||||
|
||||
// HOMEAGENT_ABI_VERSION 是当前内核的 ABI 版本号,与 internal/meta/meta.go ABIVersion 保持同步。
|
||||
// 旧插件使用低版本 ABI 不受影响——C ABI wrapper 通过 version/version_min 字段协商兼容。
|
||||
#define HOMEAGENT_ABI_VERSION 1
|
||||
// HOMEAGENT_ABI_VERSION 是当前内核的 C ABI 整数协商版本,由 internal/meta/meta.go CABINum 派生
|
||||
// (major*100 + minor,随核心版本号映射:v0.8.x→800,v0.9.x→900)。
|
||||
// 旧插件使用低整数版本不受影响——C ABI wrapper 通过 version/version_min 字段协商兼容。
|
||||
#define HOMEAGENT_ABI_VERSION 900
|
||||
|
||||
// PluginAPI — provided by the plugin via plugin_init()
|
||||
typedef struct {
|
||||
@ -17,7 +18,7 @@ typedef struct {
|
||||
int (*start_plugin)(void*, int, char**);
|
||||
int (*stop_plugin)(char**);
|
||||
int (*invoke_tool)(char*, char*, char**, char**);
|
||||
int (*invoke_stage)(char*, char*, char**);
|
||||
int (*invoke_stage)(char*, char*, char**, char**);
|
||||
int (*invoke_output)(char*, char*, char*, char**);
|
||||
void (*free_string)(char*);
|
||||
} plugin_api_t;
|
||||
@ -36,7 +37,7 @@ extern int call_init_plugin(plugin_api_t*, char*, char*, char**);
|
||||
extern int call_start_plugin(plugin_api_t*, void*, int, char**);
|
||||
extern int call_stop_plugin(plugin_api_t*, char**);
|
||||
extern int call_invoke_tool(plugin_api_t*, char*, char*, char**, char**);
|
||||
extern int call_invoke_stage(plugin_api_t*, char*, char*, char**);
|
||||
extern int call_invoke_stage(plugin_api_t*, char*, char*, char**, char**);
|
||||
extern int call_invoke_output(plugin_api_t*, char*, char*, char*, char**);
|
||||
extern void api_free_string(plugin_api_t*, char*);
|
||||
extern void* lib_open(const char*);
|
||||
@ -62,10 +63,10 @@ var (
|
||||
)
|
||||
|
||||
type pluginState struct {
|
||||
id int32
|
||||
name string
|
||||
sdk *sdk.PluginSDK
|
||||
api *C.plugin_api_t
|
||||
id int32
|
||||
name string
|
||||
sdk *sdk.PluginSDK
|
||||
api *C.plugin_api_t
|
||||
}
|
||||
|
||||
// Handle represents a loaded C ABI plugin.
|
||||
@ -96,9 +97,14 @@ func Load(soPath, name string, config map[string]interface{}) (*Handle, error) {
|
||||
C.lib_close(lib)
|
||||
return nil, fmt.Errorf("plugin %s: invalid PluginAPI (version=%d)", name, int(api.version))
|
||||
}
|
||||
if int(api.version) > ABIVersion {
|
||||
if int(api.version) > CABINum {
|
||||
C.lib_close(lib)
|
||||
return nil, fmt.Errorf("plugin %s: ABI version %d > core %d, requires newer HomeAgent core", name, int(api.version), ABIVersion)
|
||||
return nil, fmt.Errorf("plugin %s: ABI version %d > core %d (v%s), requires newer HomeAgent core", name, int(api.version), CABINum, ABIVersion)
|
||||
}
|
||||
|
||||
if int(api.version) < CABINumMin {
|
||||
C.lib_close(lib)
|
||||
return nil, fmt.Errorf("plugin %s: ABI version %d < core min %d (v%s), plugin too old", name, int(api.version), CABINumMin, ABIVersionMin)
|
||||
}
|
||||
|
||||
id := atomic.AddInt32(&nextID, 1)
|
||||
@ -119,7 +125,10 @@ func Load(soPath, name string, config map[string]interface{}) (*Handle, error) {
|
||||
|
||||
if ret := int(C.call_init_plugin(api, cName, cConfig, &initErr)); ret != 0 {
|
||||
errMsg := ""
|
||||
if initErr != nil { errMsg = C.GoString(initErr); C.api_free_string(api, initErr) }
|
||||
if initErr != nil {
|
||||
errMsg = C.GoString(initErr)
|
||||
C.api_free_string(api, initErr)
|
||||
}
|
||||
handle.Close()
|
||||
return nil, fmt.Errorf("init_plugin %s: %s", name, errMsg)
|
||||
}
|
||||
@ -131,7 +140,9 @@ func Load(soPath, name string, config map[string]interface{}) (*Handle, error) {
|
||||
// The CoreAPI dispatches all SDK calls back to Go, routing to the plugin's PluginSDK.
|
||||
func (h *Handle) CreateCoreAPI(s *sdk.PluginSDK) unsafe.Pointer {
|
||||
core := C.make_core_api()
|
||||
if core == nil { return nil }
|
||||
if core == nil {
|
||||
return nil
|
||||
}
|
||||
h.core = core
|
||||
h.pstate.sdk = s
|
||||
|
||||
@ -152,9 +163,12 @@ func (h *Handle) FreeCoreAPI() {
|
||||
// Start calls the plugin's Start with a CoreAPI pointer.
|
||||
func (h *Handle) Start(corePtr unsafe.Pointer) error {
|
||||
var cErr *C.char
|
||||
if ret := int(C.call_start_plugin(h.api, corePtr, C.int(ABIVersion), &cErr)); ret != 0 {
|
||||
if ret := int(C.call_start_plugin(h.api, corePtr, C.int(CABINum), &cErr)); ret != 0 {
|
||||
errMsg := ""
|
||||
if cErr != nil { errMsg = C.GoString(cErr); C.api_free_string(h.api, cErr) }
|
||||
if cErr != nil {
|
||||
errMsg = C.GoString(cErr)
|
||||
C.api_free_string(h.api, cErr)
|
||||
}
|
||||
return fmt.Errorf("start_plugin: %s", errMsg)
|
||||
}
|
||||
return nil
|
||||
@ -165,7 +179,10 @@ func (h *Handle) Stop() error {
|
||||
var cErr *C.char
|
||||
if ret := int(C.call_stop_plugin(h.api, &cErr)); ret != 0 {
|
||||
errMsg := ""
|
||||
if cErr != nil { errMsg = C.GoString(cErr); C.api_free_string(h.api, cErr) }
|
||||
if cErr != nil {
|
||||
errMsg = C.GoString(cErr)
|
||||
C.api_free_string(h.api, cErr)
|
||||
}
|
||||
return fmt.Errorf("stop_plugin: %s", errMsg)
|
||||
}
|
||||
return nil
|
||||
@ -182,13 +199,20 @@ func (h *Handle) InvokeTool(name string, args map[string]interface{}) (map[strin
|
||||
|
||||
if ret := int(C.call_invoke_tool(h.api, cName, cArgs, &result, &cErr)); ret != 0 {
|
||||
errMsg := ""
|
||||
if cErr != nil { errMsg = C.GoString(cErr); C.api_free_string(h.api, cErr) }
|
||||
if cErr != nil {
|
||||
errMsg = C.GoString(cErr)
|
||||
C.api_free_string(h.api, cErr)
|
||||
}
|
||||
return nil, fmt.Errorf("invoke_tool %s: %s", name, errMsg)
|
||||
}
|
||||
if result == nil { return nil, nil }
|
||||
if result == nil {
|
||||
return nil, nil
|
||||
}
|
||||
defer C.api_free_string(h.api, result)
|
||||
var r map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(C.GoString(result)), &r); err != nil { return nil, err }
|
||||
if err := json.Unmarshal([]byte(C.GoString(result)), &r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
@ -204,9 +228,13 @@ func (h *Handle) Close() {
|
||||
|
||||
func pluginInvokeTool(pluginID int32, name, argsJSON string) (string, error) {
|
||||
v, ok := pluginMap.Load(pluginID)
|
||||
if !ok { return "", fmt.Errorf("plugin %d not found", pluginID) }
|
||||
if !ok {
|
||||
return "", fmt.Errorf("plugin %d not found", pluginID)
|
||||
}
|
||||
ps := v.(*pluginState)
|
||||
if ps.api == nil { return "", fmt.Errorf("plugin %d: nil api", pluginID) }
|
||||
if ps.api == nil {
|
||||
return "", fmt.Errorf("plugin %d: nil api", pluginID)
|
||||
}
|
||||
cName := C.CString(name)
|
||||
cArgs := C.CString(argsJSON)
|
||||
var result, cErr *C.char
|
||||
@ -214,19 +242,28 @@ func pluginInvokeTool(pluginID int32, name, argsJSON string) (string, error) {
|
||||
defer C.free(unsafe.Pointer(cArgs))
|
||||
if ret := int(C.call_invoke_tool(ps.api, cName, cArgs, &result, &cErr)); ret != 0 {
|
||||
errMsg := ""
|
||||
if cErr != nil { errMsg = C.GoString(cErr); C.api_free_string(ps.api, cErr) }
|
||||
if cErr != nil {
|
||||
errMsg = C.GoString(cErr)
|
||||
C.api_free_string(ps.api, cErr)
|
||||
}
|
||||
return "", fmt.Errorf("invoke_tool %s: %s", name, errMsg)
|
||||
}
|
||||
if result == nil { return "", nil }
|
||||
if result == nil {
|
||||
return "", nil
|
||||
}
|
||||
defer C.api_free_string(ps.api, result)
|
||||
return C.GoString(result), nil
|
||||
}
|
||||
|
||||
func pluginInvokeOutput(pluginID int32, channel, payload string) error {
|
||||
v, ok := pluginMap.Load(pluginID)
|
||||
if !ok { return fmt.Errorf("plugin %d not found", pluginID) }
|
||||
if !ok {
|
||||
return fmt.Errorf("plugin %d not found", pluginID)
|
||||
}
|
||||
ps := v.(*pluginState)
|
||||
if ps.api == nil { return fmt.Errorf("plugin %d: nil api", pluginID) }
|
||||
if ps.api == nil {
|
||||
return fmt.Errorf("plugin %d: nil api", pluginID)
|
||||
}
|
||||
cCh := C.CString(channel)
|
||||
cPayload := C.CString(payload)
|
||||
var cErr *C.char
|
||||
@ -234,27 +271,92 @@ func pluginInvokeOutput(pluginID int32, channel, payload string) error {
|
||||
defer C.free(unsafe.Pointer(cPayload))
|
||||
if ret := int(C.call_invoke_output(ps.api, cCh, nil, cPayload, &cErr)); ret != 0 {
|
||||
errMsg := ""
|
||||
if cErr != nil { errMsg = C.GoString(cErr); C.api_free_string(ps.api, cErr) }
|
||||
if cErr != nil {
|
||||
errMsg = C.GoString(cErr)
|
||||
C.api_free_string(ps.api, cErr)
|
||||
}
|
||||
return fmt.Errorf("invoke_output %s: %s", channel, errMsg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func pluginInvokeStage(pluginID int32, stage, ctxJSON string) error {
|
||||
// applyStageResult 将插件回传的修改后上下文应用回内核 StageContext。
|
||||
// 只回写插件有权改写的字段(RawMessage/LLMText/FinalText/Response/ToolResults/NoMemory)。
|
||||
func applyStageResult(sc *sdk.StageContext, resultJSON string) {
|
||||
var m map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(resultJSON), &m); err != nil {
|
||||
return
|
||||
}
|
||||
sc.Lock()
|
||||
defer sc.Unlock()
|
||||
if v, ok := m["raw_message"].(string); ok {
|
||||
sc.RawMessage = v
|
||||
}
|
||||
if v, ok := m["llm_text"].(string); ok {
|
||||
sc.LLMText = v
|
||||
}
|
||||
if v, ok := m["final_text"].(string); ok {
|
||||
sc.FinalText = v
|
||||
}
|
||||
if v, ok := m["user_id"].(string); ok {
|
||||
sc.UserID = v
|
||||
}
|
||||
if v, ok := m["group_id"].(string); ok {
|
||||
sc.GroupID = v
|
||||
}
|
||||
if v, ok := m["no_memory"].(bool); ok {
|
||||
sc.NoMemory = v
|
||||
}
|
||||
if v, ok := m["response"].(string); ok {
|
||||
vv := v
|
||||
sc.Response = &vv
|
||||
}
|
||||
if v, ok := m["tool_calls"].([]interface{}); ok && len(v) > 0 {
|
||||
if b, err := json.Marshal(v); err == nil {
|
||||
var tcs []sdk.ToolCall
|
||||
if json.Unmarshal(b, &tcs) == nil {
|
||||
sc.ToolCalls = tcs
|
||||
}
|
||||
}
|
||||
}
|
||||
if v, ok := m["tool_results"].([]interface{}); ok && len(v) > 0 {
|
||||
if b, err := json.Marshal(v); err == nil {
|
||||
var trs []sdk.ToolResult
|
||||
if json.Unmarshal(b, &trs) == nil {
|
||||
sc.ToolResults = trs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pluginInvokeStage(pluginID int32, stage, ctxJSON string, resultOut *string) error {
|
||||
v, ok := pluginMap.Load(pluginID)
|
||||
if !ok { return fmt.Errorf("plugin %d not found", pluginID) }
|
||||
if !ok {
|
||||
return fmt.Errorf("plugin %d not found", pluginID)
|
||||
}
|
||||
ps := v.(*pluginState)
|
||||
if ps.api == nil { return fmt.Errorf("plugin %d: nil api", pluginID) }
|
||||
if ps.api == nil {
|
||||
return fmt.Errorf("plugin %d: nil api", pluginID)
|
||||
}
|
||||
cStage := C.CString(stage)
|
||||
cCtx := C.CString(ctxJSON)
|
||||
var cErr *C.char
|
||||
var cResult *C.char
|
||||
defer C.free(unsafe.Pointer(cStage))
|
||||
defer C.free(unsafe.Pointer(cCtx))
|
||||
if ret := int(C.call_invoke_stage(ps.api, cStage, cCtx, &cErr)); ret != 0 {
|
||||
// 仅当调用方要求回传时传 &cResult,否则传 NULL(兼容无需写回的阶段)。
|
||||
if ret := int(C.call_invoke_stage(ps.api, cStage, cCtx, &cResult, &cErr)); ret != 0 {
|
||||
errMsg := ""
|
||||
if cErr != nil { errMsg = C.GoString(cErr); C.api_free_string(ps.api, cErr) }
|
||||
if cErr != nil {
|
||||
errMsg = C.GoString(cErr)
|
||||
C.api_free_string(ps.api, cErr)
|
||||
}
|
||||
return fmt.Errorf("invoke_stage %s: %s", stage, errMsg)
|
||||
}
|
||||
if resultOut != nil && cResult != nil {
|
||||
*resultOut = C.GoString(cResult)
|
||||
C.api_free_string(ps.api, cResult)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -264,10 +366,14 @@ func pluginInvokeStage(pluginID int32, stage, ctxJSON string) error {
|
||||
func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1, i2 C.int, result **C.char, errorOut **C.char) C.int {
|
||||
pluginID := int32(uintptr(ctx))
|
||||
v, ok := pluginMap.Load(pluginID)
|
||||
if !ok { return 1 }
|
||||
if !ok {
|
||||
return 1
|
||||
}
|
||||
ps := v.(*pluginState)
|
||||
s := ps.sdk
|
||||
if s == nil { return 1 }
|
||||
if s == nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
a1, a2, a3 := goStr(s1), goStr(s2), goStr(s3)
|
||||
n1, n2 := int(i1), int(i2)
|
||||
@ -275,15 +381,22 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
switch int(methodID) {
|
||||
case 1: // CORE_REGISTER_TOOL
|
||||
var def sdk.ToolDef
|
||||
if err := json.Unmarshal([]byte(a2), &def); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := json.Unmarshal([]byte(a2), &def); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
def.Plugin = ps.name
|
||||
pid := pluginID
|
||||
toolName := a1
|
||||
_ = s.RegisterTool(a1, def, func(args map[string]interface{}) (interface{}, error) {
|
||||
argsJSON, _ := json.Marshal(args)
|
||||
r, err := pluginInvokeTool(pid, toolName, string(argsJSON))
|
||||
if err != nil { return nil, err }
|
||||
if r == "" { return nil, nil }
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r == "" {
|
||||
return nil, nil
|
||||
}
|
||||
var res map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(r), &res); err != nil {
|
||||
return r, nil
|
||||
@ -303,12 +416,27 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
"llm_text": sc.LLMText, "final_text": sc.FinalText,
|
||||
"no_memory": sc.NoMemory,
|
||||
}
|
||||
if sc.Response != nil { m["response"] = *sc.Response }
|
||||
if len(sc.ToolCalls) > 0 { m["tool_calls"] = sc.ToolCalls }
|
||||
if len(sc.ToolResults) > 0 { m["tool_results"] = sc.ToolResults }
|
||||
if sc.Response != nil {
|
||||
m["response"] = *sc.Response
|
||||
}
|
||||
if len(sc.ToolCalls) > 0 {
|
||||
m["tool_calls"] = sc.ToolCalls
|
||||
}
|
||||
if len(sc.ToolResults) > 0 {
|
||||
m["tool_results"] = sc.ToolResults
|
||||
}
|
||||
sc.RUnlock()
|
||||
b, _ := json.Marshal(m)
|
||||
return pluginInvokeStage(pid, st, string(b))
|
||||
|
||||
// ABI v2: 插件可回传修改后的上下文写回内核 sc(如 RawMessage/LLMText/Response/ToolResults)。
|
||||
var result string
|
||||
if err := pluginInvokeStage(pid, st, string(b), &result); err != nil {
|
||||
return err
|
||||
}
|
||||
if result != "" {
|
||||
applyStageResult(sc, result)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
scope := sdk.StageScopeGlobal
|
||||
if a3 == "own_tools" {
|
||||
@ -373,7 +501,10 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
case 9: // CORE_MEMORY_RECALL
|
||||
if mem := s.Memory(); mem != nil {
|
||||
entities, relations, err := mem.Recall([]string{a1}, n1)
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(map[string]interface{}{"entities": entities, "relations": relations})
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -382,15 +513,24 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
case 10: // CORE_MEMORY_COMMIT
|
||||
if mem := s.Memory(); mem != nil {
|
||||
var triples []sdk.Triple
|
||||
if err := json.Unmarshal([]byte(a1), &triples); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := mem.Commit(triples); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := json.Unmarshal([]byte(a1), &triples); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
if err := mem.Commit(triples); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
|
||||
case 11: // CORE_MEMORY_INTROSPECT
|
||||
if mem := s.Memory(); mem != nil {
|
||||
r, err := mem.Introspect()
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(r)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -398,17 +538,28 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
|
||||
case 12: // CORE_MEMORY_MERGE
|
||||
if mem := s.Memory(); mem != nil {
|
||||
if _, err := mem.MergeEntities(a1, a2); err != nil { setErr(errorOut, err); return 1 }
|
||||
if _, err := mem.MergeEntities(a1, a2); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
|
||||
case 13: // CORE_MEMORY_PURGE
|
||||
if mem := s.Memory(); mem != nil {
|
||||
var criteria map[string]string
|
||||
if err := json.Unmarshal([]byte(a1), &criteria); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := json.Unmarshal([]byte(a1), &criteria); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
mode := "soft"
|
||||
if n1 != 0 { mode = "hard" }
|
||||
if _, err := mem.Purge(criteria, mode); err != nil { setErr(errorOut, err); return 1 }
|
||||
if n1 != 0 {
|
||||
mode = "hard"
|
||||
}
|
||||
if _, err := mem.Purge(criteria, mode); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
|
||||
@ -422,7 +573,10 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
case 15: // CORE_KNOWLEDGE_SEARCH
|
||||
if kn := s.Knowledge(); kn != nil {
|
||||
results, err := kn.Search(a1, n1)
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(results)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -431,7 +585,10 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
case 16: // CORE_SETTINGS_GET
|
||||
if sett := s.Settings(); sett != nil {
|
||||
v, err := sett.Get(a1)
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(v)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -441,14 +598,20 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
if sett := s.Settings(); sett != nil {
|
||||
var v interface{}
|
||||
json.Unmarshal([]byte(a2), &v)
|
||||
if err := sett.Set(a1, v); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := sett.Set(a1, v); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
|
||||
case 18: // CORE_SETTINGS_REGISTER_DEF
|
||||
if sett := s.Settings(); sett != nil {
|
||||
var def sdk.ConfigDef
|
||||
if err := json.Unmarshal([]byte(a1), &def); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := json.Unmarshal([]byte(a1), &def); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
sett.RegisterDef(def)
|
||||
}
|
||||
return 0
|
||||
@ -462,14 +625,20 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
|
||||
case 20: // CORE_LLM_SET_SOURCE
|
||||
if llm := s.LLM(); llm != nil {
|
||||
if err := llm.SetSource(a1); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := llm.SetSource(a1); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
|
||||
case 21: // CORE_SOCIAL_GET_PERSON
|
||||
if social := s.Social(); social != nil {
|
||||
p, err := social.GetPerson(a1)
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(p)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -478,7 +647,10 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
case 22: // CORE_SOCIAL_GET_NETWORK
|
||||
if social := s.Social(); social != nil {
|
||||
profiles, err := social.GetNetwork(a1, n1)
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(profiles)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -493,13 +665,18 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
return 0
|
||||
|
||||
case 25: // CORE_FREE_STRING
|
||||
if s1 != nil { C.free(unsafe.Pointer(s1)) }
|
||||
if s1 != nil {
|
||||
C.free(unsafe.Pointer(s1))
|
||||
}
|
||||
return 0
|
||||
|
||||
case 26: // CORE_SETTINGS_GET_CORE
|
||||
if sett := s.Settings(); sett != nil {
|
||||
v, err := sett.GetCore(a1)
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(v)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -509,14 +686,20 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
if sett := s.Settings(); sett != nil {
|
||||
var v interface{}
|
||||
json.Unmarshal([]byte(a2), &v)
|
||||
if err := sett.SetCore(a1, v); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := sett.SetCore(a1, v); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
|
||||
case 28: // CORE_SETTINGS_LIST_CORE
|
||||
if sett := s.Settings(); sett != nil {
|
||||
keys, err := sett.ListCore(a1)
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(keys)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -525,7 +708,10 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
case 29: // CORE_SETTINGS_GET_PLUGIN
|
||||
if sett := s.Settings(); sett != nil {
|
||||
v, err := sett.GetPlugin(a1, a2)
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(v)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -535,14 +721,20 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
if sett := s.Settings(); sett != nil {
|
||||
var v interface{}
|
||||
json.Unmarshal([]byte(a3), &v)
|
||||
if err := sett.SetPlugin(a1, a2, v); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := sett.SetPlugin(a1, a2, v); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
|
||||
case 31: // CORE_SETTINGS_LIST_PLUGIN
|
||||
if sett := s.Settings(); sett != nil {
|
||||
keys, err := sett.ListPlugin(a1, a2)
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(keys)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -551,8 +743,14 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
case 32: // CORE_DOC_INSERT
|
||||
if dm := s.DocMemory(); dm != nil {
|
||||
var doc sdk.Doc
|
||||
if err := json.Unmarshal([]byte(a1), &doc); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := dm.Insert(&doc); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := json.Unmarshal([]byte(a1), &doc); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
if err := dm.Insert(&doc); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
|
||||
@ -571,14 +769,20 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
|
||||
case 35: // CORE_KNOWLEDGE_ADD
|
||||
if kn := s.Knowledge(); kn != nil {
|
||||
if err := kn.Add(a1, a2); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := kn.Add(a1, a2); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
|
||||
case 36: // CORE_KNOWLEDGE_LIST
|
||||
if kn := s.Knowledge(); kn != nil {
|
||||
list, err := kn.List()
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(list)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -602,7 +806,10 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
case 39: // CORE_SOCIAL_GET_RELATIONS
|
||||
if social := s.Social(); social != nil {
|
||||
rels, err := social.GetRelations(a1)
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(rels)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -611,7 +818,10 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
case 40: // CORE_SOCIAL_LIST_PERSONS
|
||||
if social := s.Social(); social != nil {
|
||||
persons, err := social.ListPersons()
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(persons)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -620,15 +830,24 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
case 41: // CORE_TEXT_MEMORY_APPEND
|
||||
if tm := s.TextMemory(); tm != nil {
|
||||
var evt sdk.TextEvent
|
||||
if err := json.Unmarshal([]byte(a1), &evt); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := tm.Append(evt); err != nil { setErr(errorOut, err); return 1 }
|
||||
if err := json.Unmarshal([]byte(a1), &evt); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
if err := tm.Append(evt); err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
|
||||
case 42: // CORE_SETTINGS_LIST
|
||||
if sett := s.Settings(); sett != nil {
|
||||
keys, err := sett.List(a1)
|
||||
if err != nil { setErr(errorOut, err); return 1 }
|
||||
if err != nil {
|
||||
setErr(errorOut, err)
|
||||
return 1
|
||||
}
|
||||
b, _ := json.Marshal(keys)
|
||||
setResult(result, string(b))
|
||||
}
|
||||
@ -673,7 +892,9 @@ func go_core_dispatch(methodID C.int, ctx unsafe.Pointer, s1, s2, s3 *C.char, i1
|
||||
}
|
||||
|
||||
func goStr(s *C.char) string {
|
||||
if s == nil { return "" }
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
return C.GoString(s)
|
||||
}
|
||||
|
||||
|
||||
@ -3,11 +3,18 @@ package cabi
|
||||
import "gitcode.com/JianFeeeee/HomeAgent/internal/meta"
|
||||
|
||||
// ABI version constants — single source of truth is meta.go
|
||||
const (
|
||||
// ABIVersion/ABIVersionMin 是字符串 semver(var 转发,因 meta 侧 Version 为注入变量);
|
||||
// CABINum/CABINumMin 是 C 层整数协商版本。
|
||||
var (
|
||||
ABIVersion = meta.ABIVersion
|
||||
ABIVersionMin = meta.ABIVersionMin
|
||||
)
|
||||
|
||||
const (
|
||||
CABINum = meta.CABINum
|
||||
CABINumMin = meta.CABINumMin
|
||||
)
|
||||
|
||||
// Dispatch method IDs — single source of truth is meta.go
|
||||
const (
|
||||
CoreRegisterTool = meta.CoreRegisterTool
|
||||
|
||||
22
third_party/homeagent-sdk/meta/meta.go
vendored
22
third_party/homeagent-sdk/meta/meta.go
vendored
@ -6,7 +6,7 @@ package meta
|
||||
var (
|
||||
// Version 是 HomeAgent SDK 版本号。
|
||||
// 通过 `-ldflags="-X gitcode.com/JianFeeeee/homeagent-sdk/meta.Version=vX.Y.Z"` 注入。
|
||||
Version = "0.8.0"
|
||||
Version = "0.9.0"
|
||||
|
||||
// Commit 是构建时的 Git commit hash。
|
||||
Commit = "unknown"
|
||||
@ -21,7 +21,7 @@ var (
|
||||
CoreModule = "gitcode.com/JianFeeeee/HomeAgent"
|
||||
|
||||
// CoreVersion 是此 SDK 所兼容的最低核心版本。
|
||||
CoreVersion = "0.8.0"
|
||||
CoreVersion = "0.9.0"
|
||||
)
|
||||
|
||||
// FullVersion 返回完整的版本字符串。
|
||||
@ -30,11 +30,23 @@ func FullVersion() string {
|
||||
}
|
||||
|
||||
// ---- ABI 版本(与核心仓 internal/meta/meta.go 同步) ----
|
||||
// 修改时需确保核心仓与 SDK 仓的值一致。
|
||||
// ABI 标识版本直接取内核版本号字符串(semver),与核心 Version 保持一致,不使用独立数字编码。
|
||||
// 协商层(C 结构体 int version 字段)使用 CABINum:由版本字符串派生的整数(major*100 + minor)。
|
||||
// 映射:v0.8.x → CABINum=800;v0.9.x → CABINum=900(invoke_stage 写回)。
|
||||
// 小版本(patch)演进不影响 ABI,CABINum 不变。version_min 保证旧 ABI 插件仍可加载。
|
||||
|
||||
var (
|
||||
// ABIVersion 是 ABI 标识版本(字符串 semver,与 SDK CoreVersion 对齐)。
|
||||
ABIVersion = CoreVersion
|
||||
// ABIVersionMin 是兼容的最低 ABI 标识版本。
|
||||
ABIVersionMin = "0.8.0"
|
||||
)
|
||||
|
||||
const (
|
||||
ABIVersion = 1
|
||||
ABIVersionMin = 1
|
||||
// CABINum 是 C 层协商用的整数版本(major*100 + minor),随 ABIVersion 派生。
|
||||
CABINum = 900
|
||||
// CABINumMin 是 C 层兼容的最低整数版本。
|
||||
CABINumMin = 800
|
||||
)
|
||||
|
||||
// ---- Dispatch Method IDs(与核心仓 internal/meta/meta.go 同步) ----
|
||||
|
||||
Reference in New Issue
Block a user