mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-15 12:15:16 +00:00
feat(channel): N1a —— inputch 一等化(归属插件/归属 agent/容量/共享登记表)+ 单工具多视图总览
设计:docs/zh/resident-subagent-design.md §4.6(里程碑 N1a)。
## 用户要求
「父 agent 可以看到所有已注册的 inputch 以及 inputch 的划分情况,用**单工具多视图**方式构筑」
## 登记层(internal/agent/io/inputch.go)
inputch 是**最基本的输入路由单位**(由插件注册,一个插件可注册多个),
所以登记表以 inputch 为键,每条记录:
名字 / 归属插件 / 归属 agent(被划给谁) / 容量 / 默认回程 outputch / 记忆策略(ChannelDef)
- 新增 `ChannelRegistry`,设计成**可共享对象**(`*ChannelRegistry`):
根 agent 与驻留子共用同一份,"划入/授权"才有意义;`SetChannelRegistry` 注入。
- **插件重载不得抹掉划分**:重复登记只更新「归属插件 + 策略」,
保留已有 Owner/Capacity/Output(否则一次 reload 就把父做的划分清空)。
- `Assign` 语义按设计 R6 默认:**读写授权,不转移所有权**(Plugin 与 Owner 分别记录)。
- 原 `inputChannels map[string]ChannelDef` 被登记表取代;`GetInputChannelDef` 保持兼容。
- `plugin.Registry` 注册时带上**归属插件名**(此前完全无归属信息)。
## 总览工具(internal/agent/core/inputch.go)
单工具 **`input_channels`** + `view` 参数(不是一堆小工具):
all(默认)= 全部已注册(带归属插件)
mine = 划给本 agent 的
unassigned = 尚未划出的
by_agent = 划分情况总览(按归属分组)
detail = 单个 inputch 全字段(需 name)
未知 view **报错并列出可用值**(拼错不得被静默当成默认视图);登记表为空时明确说明。
## 验收
- `internal/agent/io/inputch_test.go`:归属记录、重载保划分、Assign/视图数据面、
**跨 manager 共享登记表**、策略查询向后兼容 —— 5 项
- `internal/agent/core/inputch_test.go`:单工具多视图逐视图断言(含未知 view 与空表)—— 2 项
- 全仓 `go test ./...` 37 包 ok / 0 FAIL;`-race ./internal/agent/... ./internal/plugin/...` 干净
This commit is contained in:
@ -96,13 +96,13 @@ type OutputEvent struct {
|
||||
}
|
||||
|
||||
type IOManager struct {
|
||||
mu sync.RWMutex
|
||||
devices map[string]Device
|
||||
inputCh chan *InputEvent
|
||||
interruptCh chan *InputEvent
|
||||
outputCh chan *OutputEvent
|
||||
nextReqID int64
|
||||
inputChannels map[string]ChannelDef
|
||||
mu sync.RWMutex
|
||||
devices map[string]Device
|
||||
inputCh chan *InputEvent
|
||||
interruptCh chan *InputEvent
|
||||
outputCh chan *OutputEvent
|
||||
nextReqID int64
|
||||
channelReg *ChannelRegistry
|
||||
|
||||
// toolBlocks:插件工具注入多模态内容块,process.go 在下一条 tool message 时消费。
|
||||
// 用 interface{}[] 避免 import api.ContentBlock 导致的循环依赖。
|
||||
@ -112,11 +112,11 @@ type IOManager struct {
|
||||
|
||||
func NewIOManager() *IOManager {
|
||||
return &IOManager{
|
||||
devices: make(map[string]Device),
|
||||
inputCh: make(chan *InputEvent, 256),
|
||||
interruptCh: make(chan *InputEvent, 64),
|
||||
outputCh: make(chan *OutputEvent, 256),
|
||||
inputChannels: make(map[string]ChannelDef),
|
||||
devices: make(map[string]Device),
|
||||
inputCh: make(chan *InputEvent, 256),
|
||||
interruptCh: make(chan *InputEvent, 64),
|
||||
outputCh: make(chan *OutputEvent, 256),
|
||||
channelReg: NewChannelRegistry(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -444,26 +444,57 @@ func (m *IOManager) EmitTextTo(target, outputChannel, text string) {
|
||||
func (m *IOManager) InputChan() <-chan *InputEvent { return m.inputCh }
|
||||
func (m *IOManager) OutputChan() <-chan *OutputEvent { return m.outputCh }
|
||||
|
||||
// RegisterInputChannel 注册输入通道的记忆行为
|
||||
// RegisterInputChannel 注册一个 inputch(不带插件归属,兼容旧调用)。
|
||||
//
|
||||
// inputch 是**最基本的输入路由单位**;一个插件可以注册多个。
|
||||
// 新代码请用 RegisterInputChannelFrom 以便登记归属插件(可追溯)。
|
||||
func (m *IOManager) RegisterInputChannel(name string, def ChannelDef) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.inputChannels[name] = def
|
||||
_ = m.RegisterInputChannelFrom("", name, def)
|
||||
}
|
||||
|
||||
// UnregisterInputChannel 注销输入通道
|
||||
// RegisterInputChannelFrom 注册一个 inputch 并登记归属插件。
|
||||
func (m *IOManager) RegisterInputChannelFrom(plugin, name string, def ChannelDef) error {
|
||||
return m.channelReg.Register(InputChannel{Name: name, Plugin: plugin, Def: def})
|
||||
}
|
||||
|
||||
// UnregisterInputChannel 注销一个 inputch。
|
||||
func (m *IOManager) UnregisterInputChannel(name string) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
delete(m.inputChannels, name)
|
||||
m.channelReg.Unregister(name)
|
||||
}
|
||||
|
||||
// GetInputChannelDef 查询输入通道的记忆行为定义
|
||||
// AssignInputChannel 把一个 inputch 划给某个 agent(见 ChannelRegistry.Assign)。
|
||||
func (m *IOManager) AssignInputChannel(name, agentID string, capacity int) error {
|
||||
return m.channelReg.Assign(name, agentID, capacity)
|
||||
}
|
||||
|
||||
// SetChannelRegistry 注入一份**共享的**登记表(根 agent 与驻留子共用同一份)。
|
||||
func (m *IOManager) SetChannelRegistry(r *ChannelRegistry) {
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.channelReg = r
|
||||
}
|
||||
|
||||
// ChannelRegistry 返回底层登记表(只读用途;可直接读 Views)。
|
||||
func (m *IOManager) ChannelRegistry() *ChannelRegistry { return m.channelReg }
|
||||
|
||||
// InputChannels 返回全部已注册 inputch(按名字排序)。
|
||||
func (m *IOManager) InputChannels() []InputChannel { return m.channelReg.List() }
|
||||
|
||||
// LookupInputChannel 查询单个 inputch 的完整登记记录。
|
||||
func (m *IOManager) LookupInputChannel(name string) (InputChannel, bool) {
|
||||
return m.channelReg.Lookup(name)
|
||||
}
|
||||
|
||||
// GetInputChannelDef 查询 inputch 的记忆行为定义。
|
||||
func (m *IOManager) GetInputChannelDef(name string) (ChannelDef, bool) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
def, ok := m.inputChannels[name]
|
||||
return def, ok
|
||||
ch, ok := m.channelReg.Lookup(name)
|
||||
if !ok {
|
||||
return ChannelDef{}, false
|
||||
}
|
||||
return ch.Def, true
|
||||
}
|
||||
|
||||
func (m *IOManager) GetAllTools() []ToolDef {
|
||||
|
||||
Reference in New Issue
Block a user