mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 09:28:14 +00:00
- manager/main.js:makeChannelRuntime(dispatchReplyWithBufferedBlockDispatcher 入站 + deliver 出站 绑定 + typingCallbacks)、startChannels/stopChannels(gateway.startAccount fire-and-forget 生命周期 桥、listAccountIds/resolveAccount 规范签名 cfg 传参)、tools/call 通道分支无 outbound 走 deliver 事件式发送、SIGTERM 优雅停靠、console 输出重定向 stderr 防 JSON-RPC 流污染 - plugin.go:channel_input 改 InjectInputSync 同步注入取回复并经 CallTool 回发通道(修复 InjectInterruptText 无 ResponseCh 致回复静默丢弃);channel_status/channel_output 通知接入 - registry.go:channelStatus 状态缓存 - SDK:公共 IOInjector 增加 InjectInputSync(source, channel, text) string + ioAdapter 实现 - 生产验证:微信发消息 → pollLoop → dispatchReply → mock LLM 回文本 → deliver → ilink/bot/sendmessage status=200 送达
289 lines
8.1 KiB
Go
289 lines
8.1 KiB
Go
package sdk
|
|
|
|
import (
|
|
"log"
|
|
|
|
pubsdk "gitcode.com/JianFeeeee/homeagent-sdk/sdk"
|
|
agentIO "gitcode.com/JianFeeeee/HomeAgent/internal/agent/io"
|
|
"gitcode.com/JianFeeeee/HomeAgent/internal/events"
|
|
)
|
|
|
|
// SDKVersion 是对外 SDK 版本号,与核心 meta.Version 保持一致。
|
|
var SDKVersion = pubsdk.SDKVersion
|
|
|
|
type Plugin interface {
|
|
Name() string
|
|
Start(sdk *PluginSDK) error
|
|
Stop() error
|
|
}
|
|
|
|
type ToolHandler = pubsdk.ToolHandler
|
|
type StageHandler = pubsdk.StageHandler
|
|
|
|
type Stage = pubsdk.Stage
|
|
|
|
const (
|
|
StageOnInput = pubsdk.StageOnInput
|
|
StagePreAction = pubsdk.StagePreAction
|
|
StagePostAction = pubsdk.StagePostAction
|
|
StageBeforeToolcall = pubsdk.StageBeforeToolcall
|
|
StageAfterToolcall = pubsdk.StageAfterToolcall
|
|
StageBeforeOutput = pubsdk.StageBeforeOutput
|
|
StageAfterOutput = pubsdk.StageAfterOutput
|
|
)
|
|
|
|
type StageContext = pubsdk.StageContext
|
|
type MemItem = pubsdk.MemItem
|
|
type ToolCall = pubsdk.ToolCall
|
|
type ToolResult = pubsdk.ToolResult
|
|
type ToolDef = pubsdk.ToolDef
|
|
type IOInjector = pubsdk.IOInjector
|
|
type ToolRegistrar = pubsdk.ToolRegistrar
|
|
type StageRegistrar = pubsdk.StageRegistrar
|
|
type StageScope = pubsdk.StageScope
|
|
|
|
const (
|
|
StageScopeGlobal = pubsdk.StageScopeGlobal
|
|
StageScopeOwnTools = pubsdk.StageScopeOwnTools
|
|
)
|
|
type APIRegistrar = pubsdk.APIRegistrar
|
|
type OutputChannelRegistrar = pubsdk.OutputChannelRegistrar
|
|
type InputChannelRegistrar = pubsdk.InputChannelRegistrar
|
|
type ChannelDef = pubsdk.ChannelDef
|
|
|
|
type DisabledPluginInfo struct {
|
|
Name string `json:"name"`
|
|
DisabledAt string `json:"disabled_at"`
|
|
DisabledBy string `json:"disabled_by"`
|
|
}
|
|
|
|
// PluginMeta is the display-name metadata for a plugin (from plg.json / RegisterPluginMeta).
|
|
type PluginMeta struct {
|
|
NameZh string `json:"name_zh"`
|
|
NameEn string `json:"name_en"`
|
|
}
|
|
|
|
type PluginManager interface {
|
|
ListLoadedPlugins() []string
|
|
ListDisabledPlugins() []DisabledPluginInfo
|
|
IsPluginDisabled(name string) bool
|
|
DisablePlugin(name, by string) error
|
|
EnablePlugin(name string) error
|
|
ReloadPlugins() (string, error)
|
|
PluginMetas() map[string]PluginMeta
|
|
PluginDir() string
|
|
}
|
|
|
|
type PluginSDK struct {
|
|
*pubsdk.PluginSDK
|
|
settings SettingsAPI
|
|
memory MemoryAPI
|
|
textMem TextMemoryAPI
|
|
docMem DocMemoryAPI
|
|
know KnowledgeAPI
|
|
llm LLMAPI
|
|
|
|
iom *agentIO.IOManager
|
|
eventBus *events.Bus
|
|
logger *log.Logger
|
|
pluginMgr PluginManager
|
|
|
|
status StatusAPI
|
|
supervisor SupervisorAPI
|
|
adapter AdapterAPI
|
|
tracker TrackerAPI
|
|
config ConfigAPI
|
|
tool ToolAPI
|
|
indexer IndexerAPI
|
|
}
|
|
|
|
func (s *PluginSDK) PluginMgr() PluginManager { return s.pluginMgr }
|
|
|
|
// 以下访问器遮蔽公共 SDK 的同名方法,返回内置插件可用的全量接口。
|
|
|
|
func (s *PluginSDK) Settings() SettingsAPI { return s.settings }
|
|
func (s *PluginSDK) Memory() MemoryAPI { return s.memory }
|
|
func (s *PluginSDK) TextMemory() TextMemoryAPI { return s.textMem }
|
|
func (s *PluginSDK) DocMemory() DocMemoryAPI { return s.docMem }
|
|
func (s *PluginSDK) Knowledge() KnowledgeAPI { return s.know }
|
|
func (s *PluginSDK) LLM() LLMAPI { return s.llm }
|
|
|
|
// ioAdapter 桥接 IOManager 到公共 SDK 的 IOInjector 接口,
|
|
// 确保外部插件通过 s.InjectText() 等方法的调用能被路由到内核 IO 层。
|
|
type ioAdapter struct{ iom *agentIO.IOManager }
|
|
|
|
func (a ioAdapter) InjectInterruptText(source, channel, text string) {
|
|
if a.iom != nil {
|
|
a.iom.InjectInterrupt(source, channel, map[string]interface{}{"type": "text", "content": text})
|
|
}
|
|
}
|
|
|
|
// InjectInputSync 同步注入输入并等待回复(阻塞直至 agent 处理完成),返回回复文本。
|
|
func (a ioAdapter) InjectInputSync(source, channel, text string) string {
|
|
if a.iom == nil {
|
|
return ""
|
|
}
|
|
out := a.iom.InjectInputSyncTo(source, channel, "text", map[string]interface{}{
|
|
"content": text,
|
|
})
|
|
if out == nil {
|
|
return ""
|
|
}
|
|
reply, _ := out.Payload["content"].(string)
|
|
return reply
|
|
}
|
|
|
|
func (a ioAdapter) InjectText(source, channel, text string) {
|
|
if a.iom != nil {
|
|
a.iom.InjectInputTo(source, channel, "text", map[string]interface{}{"content": text})
|
|
}
|
|
}
|
|
|
|
func (a ioAdapter) InjectTextNoMemory(source, channel, text string) {
|
|
if a.iom != nil {
|
|
a.iom.InjectInputTo(source, channel, "text", map[string]interface{}{"content": text, "no_memory": true})
|
|
}
|
|
}
|
|
|
|
// SDKConfig holds all dependencies for creating a PluginSDK.
|
|
type SDKConfig struct {
|
|
IOManager *agentIO.IOManager
|
|
EventBus *events.Bus
|
|
Memory MemoryAPI
|
|
TextMemory TextMemoryAPI
|
|
DocMemory DocMemoryAPI
|
|
Knowledge KnowledgeAPI
|
|
LLM LLMAPI
|
|
Settings SettingsAPI
|
|
RegTool ToolRegistrar
|
|
RegStage StageRegistrar
|
|
RegAPI APIRegistrar
|
|
RegOutput OutputChannelRegistrar
|
|
RegInput InputChannelRegistrar
|
|
PluginMgr PluginManager
|
|
|
|
Status StatusAPI
|
|
Supervisor SupervisorAPI
|
|
Adapter AdapterAPI
|
|
Tracker TrackerAPI
|
|
Config ConfigAPI
|
|
Tool ToolAPI
|
|
Indexer IndexerAPI
|
|
}
|
|
|
|
func New(name string, cfg SDKConfig) *PluginSDK {
|
|
base := pubsdk.New(name, cfg.Settings, cfg.RegTool, cfg.RegStage, cfg.RegAPI, cfg.RegOutput)
|
|
if cfg.IOManager != nil {
|
|
base.SetIOInjector(ioAdapter{iom: cfg.IOManager})
|
|
}
|
|
if cfg.RegInput != nil {
|
|
base.SetInputChannelRegistrar(cfg.RegInput)
|
|
}
|
|
base.SetMemoryAPI(cfg.Memory)
|
|
base.SetTextMemoryAPI(cfg.TextMemory)
|
|
base.SetDocMemoryAPI(cfg.DocMemory)
|
|
base.SetKnowledgeAPI(cfg.Knowledge)
|
|
base.SetLLMAPI(cfg.LLM)
|
|
return &PluginSDK{
|
|
PluginSDK: base,
|
|
settings: cfg.Settings,
|
|
memory: cfg.Memory,
|
|
textMem: cfg.TextMemory,
|
|
docMem: cfg.DocMemory,
|
|
know: cfg.Knowledge,
|
|
llm: cfg.LLM,
|
|
|
|
iom: cfg.IOManager,
|
|
eventBus: cfg.EventBus,
|
|
logger: log.Default(),
|
|
pluginMgr: cfg.PluginMgr,
|
|
|
|
status: cfg.Status,
|
|
supervisor: cfg.Supervisor,
|
|
adapter: cfg.Adapter,
|
|
tracker: cfg.Tracker,
|
|
config: cfg.Config,
|
|
tool: cfg.Tool,
|
|
indexer: cfg.Indexer,
|
|
}
|
|
}
|
|
|
|
func (s *PluginSDK) Status() StatusAPI { return s.status }
|
|
func (s *PluginSDK) Supervisor() SupervisorAPI { return s.supervisor }
|
|
func (s *PluginSDK) Adapter() AdapterAPI { return s.adapter }
|
|
func (s *PluginSDK) Tracker() TrackerAPI { return s.tracker }
|
|
func (s *PluginSDK) Config() ConfigAPI { return s.config }
|
|
func (s *PluginSDK) Tool() ToolAPI { return s.tool }
|
|
func (s *PluginSDK) Indexer() IndexerAPI { return s.indexer }
|
|
|
|
func (s *PluginSDK) InjectInput(source, channel, eventType string, payload map[string]interface{}) {
|
|
if s.iom != nil {
|
|
s.iom.InjectInputTo(source, channel, eventType, payload)
|
|
}
|
|
}
|
|
|
|
func (s *PluginSDK) InjectInputSync(source, channel, eventType string, payload map[string]interface{}) *agentIO.OutputEvent {
|
|
if s.iom != nil {
|
|
return s.iom.InjectInputSyncTo(source, channel, eventType, payload)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *PluginSDK) InjectInterrupt(source, channel, eventType string, payload map[string]interface{}) {
|
|
if s.iom != nil {
|
|
if payload == nil {
|
|
payload = map[string]interface{}{}
|
|
}
|
|
payload["type"] = eventType
|
|
s.iom.InjectInterrupt(source, channel, payload)
|
|
}
|
|
}
|
|
|
|
func (s *PluginSDK) InjectTextSync(source, channel, text string) *agentIO.OutputEvent {
|
|
return s.InjectInputSync(source, channel, "text", map[string]interface{}{"content": text})
|
|
}
|
|
|
|
func (s *PluginSDK) InjectTextSyncNoMemory(source, channel, text string) *agentIO.OutputEvent {
|
|
return s.InjectInputSync(source, channel, "text", map[string]interface{}{"content": text, "no_memory": true})
|
|
}
|
|
|
|
func (s *PluginSDK) OutputChan() <-chan *agentIO.OutputEvent {
|
|
if s.iom != nil {
|
|
return s.iom.OutputChan()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *PluginSDK) RegisterChannel(name string, dev agentIO.Device) error {
|
|
if s.iom != nil {
|
|
return s.iom.RegisterDevice(dev)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *PluginSDK) UnregisterChannel(name string) {
|
|
if s.iom != nil {
|
|
s.iom.UnregisterDevice(name)
|
|
}
|
|
}
|
|
|
|
func (s *PluginSDK) ListChannels() []agentIO.ChannelInfo {
|
|
if s.iom != nil {
|
|
return s.iom.ListChannels()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *PluginSDK) Publish(evt *events.Event) {
|
|
if s.eventBus != nil {
|
|
s.eventBus.Publish(evt)
|
|
}
|
|
}
|
|
|
|
func (s *PluginSDK) Subscribe(eventType events.EventType, handler events.Handler) func() {
|
|
if s.eventBus != nil {
|
|
return s.eventBus.Subscribe(eventType, handler)
|
|
}
|
|
return func() {}
|
|
}
|