78e3f450c2
- Fix: Session history flash (race condition + WS guard) - Fix: Chat background overlay + sidebar transparency - Fix: IoT device control (Chinese action names, status field) - Feat: Independent memory-service (port 8091, 13 endpoints) - Feat: Independent tool-engine service (port 8092, 13 tools) - Feat: Tool call logs with paginated DevTools panel - Feat: Thinking log records with DevTools panel - Feat: Future development roadmap document - Chore: Updated .gitignore, go.work, DevTools config - Chore: 5-service health check, project review docs
132 lines
3.5 KiB
Go
132 lines
3.5 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/yourname/cyrene-ai/tool-engine/internal/model"
|
|
)
|
|
|
|
// IoTQueryTool IoT 设备查询工具
|
|
type IoTQueryTool struct {
|
|
iotClient IoTClientInterface
|
|
}
|
|
|
|
// NewIoTQueryTool 创建 IoT 查询工具
|
|
func NewIoTQueryTool(iotClient IoTClientInterface) *IoTQueryTool {
|
|
return &IoTQueryTool{iotClient: iotClient}
|
|
}
|
|
|
|
// Definition 返回工具定义
|
|
func (t *IoTQueryTool) Definition() model.ToolDefinition {
|
|
return model.ToolDefinition{
|
|
Name: "iot_query",
|
|
Description: "查询家中智能设备状态。注意:当前设备状态通常已自动注入到系统提示词中,你通常不需要调用此工具即可回答设备状态问题。只有在设备状态信息陈旧或明显不完整时才调用此工具刷新。",
|
|
Parameters: map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"device_id": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "要查询的设备ID(可选,不填则返回所有设备)。可选值: light-livingroom, light-bedroom, ac-livingroom, ac-bedroom, curtain-livingroom, sensor-temperature, sensor-humidity, lock-door",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// Execute 执行查询
|
|
func (t *IoTQueryTool) Execute(ctx context.Context, arguments map[string]interface{}) (*model.ToolResult, error) {
|
|
if t.iotClient == nil {
|
|
return &model.ToolResult{
|
|
Output: "",
|
|
Error: "IoT 客户端未初始化",
|
|
}, nil
|
|
}
|
|
|
|
deviceID, _ := arguments["device_id"].(string)
|
|
|
|
if deviceID != "" {
|
|
// 查询单个设备
|
|
device, err := t.iotClient.GetDevice(deviceID)
|
|
if err != nil {
|
|
return &model.ToolResult{
|
|
Output: "",
|
|
Error: err.Error(),
|
|
}, nil
|
|
}
|
|
return &model.ToolResult{
|
|
Output: formatSingleDevice(device),
|
|
Error: "",
|
|
}, nil
|
|
}
|
|
|
|
// 查询所有设备
|
|
devices, err := t.iotClient.GetAllDevices()
|
|
if err != nil {
|
|
return &model.ToolResult{
|
|
Output: "",
|
|
Error: err.Error(),
|
|
}, nil
|
|
}
|
|
|
|
var result strings.Builder
|
|
result.WriteString(fmt.Sprintf("当前共有 %d 台智能设备:\n\n", len(devices)))
|
|
for _, d := range devices {
|
|
result.WriteString(formatDeviceLine(d) + "\n")
|
|
}
|
|
return &model.ToolResult{
|
|
Output: result.String(),
|
|
Error: "",
|
|
}, nil
|
|
}
|
|
|
|
func formatSingleDevice(d *IoTDevice) string {
|
|
return fmt.Sprintf("设备: %s (%s)\n状态: %s", d.Name, d.Type, formatDeviceLine(*d))
|
|
}
|
|
|
|
func formatDeviceLine(d IoTDevice) string {
|
|
switch d.Type {
|
|
case "light":
|
|
if d.Status == "on" {
|
|
return fmt.Sprintf("💡 %s: 开启 (亮度%d%%, %s)", d.Name, d.Brightness, d.Color)
|
|
}
|
|
return fmt.Sprintf("💡 %s: 关闭", d.Name)
|
|
case "ac":
|
|
if d.Status == "on" {
|
|
mode := d.Mode
|
|
switch mode {
|
|
case "cool":
|
|
mode = "制冷"
|
|
case "heat":
|
|
mode = "制热"
|
|
case "auto":
|
|
mode = "自动"
|
|
}
|
|
return fmt.Sprintf("❄️ %s: 运行中 (%s %.0f°C)", d.Name, mode, d.Temperature)
|
|
}
|
|
return fmt.Sprintf("❄️ %s: 关闭", d.Name)
|
|
case "curtain":
|
|
if d.Status == "open" {
|
|
return fmt.Sprintf("🪟 %s: 已打开", d.Name)
|
|
}
|
|
return fmt.Sprintf("🪟 %s: 已关闭", d.Name)
|
|
case "sensor":
|
|
unit := d.Unit
|
|
if unit == "celsius" {
|
|
unit = "°C"
|
|
} else if unit == "percent" {
|
|
unit = "%"
|
|
}
|
|
return fmt.Sprintf("🌡️ %s: %.1f%s", d.Name, d.Value, unit)
|
|
case "lock":
|
|
status := "已锁定"
|
|
if d.Status == "unlocked" {
|
|
status = "已解锁"
|
|
}
|
|
return fmt.Sprintf("🔒 %s: %s (电量%d%%)", d.Name, status, d.Battery)
|
|
default:
|
|
return fmt.Sprintf("%s: %s", d.Name, d.Status)
|
|
}
|
|
}
|