mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-04 00:03:59 +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:
@ -391,6 +391,9 @@ func (d *devicectlDevice) screensee(args map[string]interface{}) (interface{}, e
|
||||
if !m.Online {
|
||||
return nil, fmt.Errorf("device %s 不在线", id)
|
||||
}
|
||||
if !d.reg.SupportsTool(id, "screensee") {
|
||||
return nil, fmt.Errorf("device %s 未声明 screensee 能力(caps=%v),无法截屏", id, m.Caps)
|
||||
}
|
||||
reqID := newReqID()
|
||||
if err := d.reg.PushCmd(id, reqID, "screensee", "homeagent"); err != nil {
|
||||
return nil, fmt.Errorf("下发截屏命令失败: %w", err)
|
||||
@ -439,6 +442,9 @@ func (d *devicectlDevice) computeruse(args map[string]interface{}) (interface{},
|
||||
if !m.Online {
|
||||
return nil, fmt.Errorf("device %s 不在线", id)
|
||||
}
|
||||
if !d.reg.SupportsTool(id, "computeruse") {
|
||||
return nil, fmt.Errorf("device %s 未声明 computeruse 能力(caps=%v),无法操控鼠标键盘", id, m.Caps)
|
||||
}
|
||||
|
||||
// 构造 GUI 端约定的 JSON 参数(坐标相对 screensueDisplay 所选屏)
|
||||
params := map[string]interface{}{"action": action}
|
||||
@ -492,8 +498,9 @@ func (d *devicectlDevice) computeruse(args map[string]interface{}) (interface{},
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// clipboardCheck 检查设备可操作性(存在/已授权/在线),返回错误或 nil。
|
||||
func (d *devicectlDevice) clipboardCheck(id, verb string) error {
|
||||
// clipboardCheck 检查设备可操作性(存在/已授权/在线/能力声明),返回错误或 nil。
|
||||
// tool 为空时跳过能力校验(如 device_ctl_cmdrun 由自身逻辑处理)。
|
||||
func (d *devicectlDevice) clipboardCheck(id, verb, tool string) error {
|
||||
if id == "" {
|
||||
return fmt.Errorf("device_id required")
|
||||
}
|
||||
@ -507,6 +514,9 @@ func (d *devicectlDevice) clipboardCheck(id, verb string) error {
|
||||
if !m.Online {
|
||||
return fmt.Errorf("device %s 不在线", id)
|
||||
}
|
||||
if tool != "" && !d.reg.SupportsTool(id, tool) {
|
||||
return fmt.Errorf("device %s 未声明 %s 能力(caps=%v),无法执行此操作", id, tool, m.Caps)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -514,7 +524,7 @@ func (d *devicectlDevice) clipboardCheck(id, verb string) error {
|
||||
// 协议(GUI 配套):homeagent-clipboardsee → 回执 output 字段为剪切板文字。
|
||||
func (d *devicectlDevice) clipboardsee(args map[string]interface{}) (interface{}, error) {
|
||||
id, _ := args["device_id"].(string)
|
||||
if err := d.clipboardCheck(id, "读取"); err != nil {
|
||||
if err := d.clipboardCheck(id, "读取", "clipboardsee"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqID := newReqID()
|
||||
@ -551,7 +561,7 @@ func (d *devicectlDevice) clipboardsue(args map[string]interface{}) (interface{}
|
||||
if text == "" {
|
||||
return nil, fmt.Errorf("text required(要写入剪切板的内容)")
|
||||
}
|
||||
if err := d.clipboardCheck(id, "写入"); err != nil {
|
||||
if err := d.clipboardCheck(id, "写入", "clipboardsue"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqID := newReqID()
|
||||
|
||||
Reference in New Issue
Block a user