mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-24 10:58:13 +00:00
feat: 设备能力矩阵校验 + 设备主动上报事件通道
回应架构讨论: 外接设备各自声明能力, 且补齐设备→agent 单向推送缺口。
1. 能力矩阵 (registry.go):
- capabilityTools 映射: caps 声明 → 可用工具
screen/screensue/screensee, computeruse, clipboard(see/sue),
camera/camerasue, speaker/speakeruse
- SupportsTool 校验: screensee/computeruse/clipboard* 执行前检查
目标设备是否声明对应能力, 未声明直接报错(不再下发到设备端才失败)
- 兼容规则: 声明 cmd/cmdrun 等历史值 → 全能力;
未声明任何已知能力 → 全能力(旧设备兼容);
有已知能力声明则严格匹配
2. 设备主动上报事件 (WS op=event):
- 设备可推 {op:event, type, detail/payload} 无需回执
- 插件层 SetEventHandler 回调: 格式化为人类可读文本,
经 SDK InjectInput 异步注入 agent(source=device/{id}, 回复路由回同通道)
- 同设备同类型事件 10s 节流防传感器风暴
- 场景: 摄像头识别未知人员驻留主动告警, agent 收到后自主处置
测试: 能力矩阵8场景 + 摄像头调screensee被拒 + 事件上报回调(含device_id回退)
This commit is contained in:
@ -9,6 +9,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gitcode.com/JianFeeeee/HomeAgent/internal/plugin"
|
||||
@ -115,6 +116,49 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
||||
log.Printf("[remotedevice] register devicectl channel: %v", err)
|
||||
}
|
||||
|
||||
// ---- 设备主动上报事件 → agent 注入 ----------------
|
||||
// 摄像头发现异常/传感器报警等场景:设备经 WS op=event 上报,
|
||||
// 插件将其格式化为文本经 SDK InjectText 异步注入 agent(source=device/{id},
|
||||
// 回复路由回 device/{id} 通道),同时发 EventBus 供 WebUI 展示。
|
||||
// 节流:同设备同类型事件 10s 内去重,防传感器风暴。
|
||||
lastEventAt := map[string]time.Time{}
|
||||
var eventMu sync.Mutex
|
||||
p.registry.SetEventHandler(func(deviceID string, msg map[string]interface{}) {
|
||||
evtType, _ := msg["type"].(string)
|
||||
if evtType == "" {
|
||||
evtType = "unknown"
|
||||
}
|
||||
key := deviceID + "|" + evtType
|
||||
eventMu.Lock()
|
||||
if last, ok := lastEventAt[key]; ok && time.Since(last) < 10*time.Second {
|
||||
eventMu.Unlock()
|
||||
log.Printf("[remotedevice] event throttled: %s from %s", evtType, deviceID)
|
||||
return
|
||||
}
|
||||
lastEventAt[key] = time.Now()
|
||||
eventMu.Unlock()
|
||||
|
||||
// 组装人类可读的事件文本(agent 可直接理解)
|
||||
detail, _ := msg["detail"].(string)
|
||||
if detail == "" {
|
||||
if d, ok := msg["payload"].(map[string]interface{}); ok {
|
||||
b, _ := json.Marshal(d)
|
||||
detail = string(b)
|
||||
}
|
||||
}
|
||||
text := fmt.Sprintf("【设备事件上报】设备 %s 触发事件 %s", deviceID, evtType)
|
||||
if detail != "" {
|
||||
text += ":" + detail
|
||||
}
|
||||
text += "。请关注此事件并按需处理(如通知用户、调用相关工具核实)。"
|
||||
|
||||
log.Printf("[remotedevice] event from %s: %s", deviceID, evtType)
|
||||
if p.sdk != nil {
|
||||
// 异步注入:不阻塞 WS 读循环;回复路由回 device/{id} 输出通道
|
||||
p.sdk.InjectInput("device/"+deviceID, "device/"+deviceID, "text", map[string]interface{}{"content": text})
|
||||
}
|
||||
})
|
||||
|
||||
// ---- REST 管理面 + WS 设备通道 ----------------
|
||||
p.registerRoutes()
|
||||
p.server = &http.Server{Addr: p.addr, Handler: p.mux}
|
||||
|
||||
Reference in New Issue
Block a user