feat: Phase 1+2 架构进化 — 连续思考链/主动消息决策/情感状态机/离线自主思考 (86文件)

Phase 1 (基础设施):
- ThinkChain 思考链连续性 + 差异化思考提示词 (persistent)
- AutonomousToolPolicy 工具安全策略 (safe/unsafe/conditional)
- MessageScheduler 自适应消息节奏 (Idle/Available/Busy)
- SessionEnrichmentStore 渐进式上下文丰富 (5层)
- ConversationBus 事件总线 + ResponseCache (dedup)
- pkg/logger 统一日志 + 所有 handler 替换 fmt.Printf
- NPE 守卫/链路优化/数据库表修复/Go workspace

Phase 2 (人格交互):
- EmotionState/EmotionTracker 情感状态机 (5种心情, 情绪衰减)
- ProactiveGuard 主动消息多维决策 (静默时段/紧急度/频率/校验)
- Gateway↔ai-core 在线状态感知链路 (presence notification)
- 离线思考频率控制 + 重连问候 + 离线消息排队

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-23 15:25:12 +08:00
parent b123a36aae
commit 87214b9441
86 changed files with 3085 additions and 582 deletions
+18 -18
View File
@@ -6,7 +6,7 @@ import (
"encoding/json"
"fmt"
"io"
"log"
"github.com/yourname/cyrene-ai/pkg/logger"
"net/http"
"os"
"sync"
@@ -75,13 +75,13 @@ func (c *IoTClient) GetAllDevices(ctx context.Context) ([]IoTDevice, error) {
// 请求 API
req, err := http.NewRequestWithContext(ctx, "GET", c.baseURL+"/api/v1/devices", nil)
if err != nil {
log.Printf("[IoT客户端] 创建请求失败: %v", err)
logger.Printf("[IoT客户端] 创建请求失败: %v", err)
return nil, fmt.Errorf("创建请求失败: %w", err)
}
resp, err := c.client.Do(req)
if err != nil {
log.Printf("[IoT客户端] 请求失败: %v", err)
logger.Printf("[IoT客户端] 请求失败: %v", err)
return nil, fmt.Errorf("获取设备列表失败: %w", err)
}
defer resp.Body.Close()
@@ -138,27 +138,27 @@ func (c *IoTClient) GetDevice(ctx context.Context, id string) (*IoTDevice, error
// ToggleDevice 切换设备开关状态
func (c *IoTClient) ToggleDevice(id string) error {
log.Printf("[IoT-client] 🔄 切换设备: id=%s, url=%s", id, c.baseURL+"/api/v1/devices/"+id+"/toggle")
logger.Printf("[IoT-client] 🔄 切换设备: id=%s, url=%s", id, c.baseURL+"/api/v1/devices/"+id+"/toggle")
req, err := http.NewRequest(http.MethodPost, c.baseURL+"/api/v1/devices/"+id+"/toggle", nil)
if err != nil {
log.Printf("[IoT-client] ❌ 创建切换请求失败: device=%s, err=%v", id, err)
logger.Printf("[IoT-client] ❌ 创建切换请求失败: device=%s, err=%v", id, err)
return fmt.Errorf("创建切换请求失败: %w", err)
}
resp, err := c.client.Do(req)
if err != nil {
log.Printf("[IoT-client] ❌ 切换设备 HTTP 失败: device=%s, err=%v", id, err)
logger.Printf("[IoT-client] ❌ 切换设备 HTTP 失败: device=%s, err=%v", id, err)
return fmt.Errorf("切换设备 %s 失败: %w", id, err)
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusNotFound {
log.Printf("[IoT-client] ❌ 设备不存在: %s", id)
logger.Printf("[IoT-client] ❌ 设备不存在: %s", id)
return fmt.Errorf("设备 %s 不存在", id)
}
if resp.StatusCode != http.StatusOK {
log.Printf("[IoT-client] ❌ 切换设备返回非200: device=%s, status=%d", id, resp.StatusCode)
logger.Printf("[IoT-client] ❌ 切换设备返回非200: device=%s, status=%d", id, resp.StatusCode)
return fmt.Errorf("切换设备 %s 返回状态码 %d", id, resp.StatusCode)
}
@@ -167,26 +167,26 @@ func (c *IoTClient) ToggleDevice(id string) error {
c.cache = nil
c.mu.Unlock()
log.Printf("[IoT-client] ✅ 切换设备成功: %s", id)
logger.Printf("[IoT-client] ✅ 切换设备成功: %s", id)
return nil
}
// SetDeviceProperty 设置设备属性(温度、亮度、位置、模式、颜色等)
func (c *IoTClient) SetDeviceProperty(id string, field string, value interface{}) error {
log.Printf("[IoT-client] 🔧 设置设备属性: device=%s, field=%s, value=%v, url=%s", id, field, value, c.baseURL+"/api/v1/devices/"+id+"/set")
logger.Printf("[IoT-client] 🔧 设置设备属性: device=%s, field=%s, value=%v, url=%s", id, field, value, c.baseURL+"/api/v1/devices/"+id+"/set")
body, err := json.Marshal(map[string]interface{}{
"field": field,
"value": value,
})
if err != nil {
log.Printf("[IoT-client] ❌ 序列化请求失败: device=%s, err=%v", id, err)
logger.Printf("[IoT-client] ❌ 序列化请求失败: device=%s, err=%v", id, err)
return fmt.Errorf("序列化请求失败: %w", err)
}
req, err := http.NewRequest(http.MethodPost, c.baseURL+"/api/v1/devices/"+id+"/set", nil)
if err != nil {
log.Printf("[IoT-client] ❌ 创建设置请求失败: device=%s, err=%v", id, err)
logger.Printf("[IoT-client] ❌ 创建设置请求失败: device=%s, err=%v", id, err)
return fmt.Errorf("创建设置请求失败: %w", err)
}
req.Header.Set("Content-Type", "application/json")
@@ -194,13 +194,13 @@ func (c *IoTClient) SetDeviceProperty(id string, field string, value interface{}
resp, err := c.client.Do(req)
if err != nil {
log.Printf("[IoT-client] ❌ 设置设备属性 HTTP 失败: device=%s, field=%s, err=%v", id, field, err)
logger.Printf("[IoT-client] ❌ 设置设备属性 HTTP 失败: device=%s, field=%s, err=%v", id, field, err)
return fmt.Errorf("设置设备 %s 属性失败: %w", id, err)
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusNotFound {
log.Printf("[IoT-client] ❌ 设备不存在: %s", id)
logger.Printf("[IoT-client] ❌ 设备不存在: %s", id)
return fmt.Errorf("设备 %s 不存在", id)
}
if resp.StatusCode != http.StatusOK {
@@ -209,10 +209,10 @@ func (c *IoTClient) SetDeviceProperty(id string, field string, value interface{}
}
json.NewDecoder(resp.Body).Decode(&errResp)
if errResp.Error != "" {
log.Printf("[IoT-client] ❌ 设置设备属性失败: device=%s, err=%s", id, errResp.Error)
logger.Printf("[IoT-client] ❌ 设置设备属性失败: device=%s, err=%s", id, errResp.Error)
return fmt.Errorf("设置设备 %s 属性失败: %s", id, errResp.Error)
}
log.Printf("[IoT-client] ❌ 设置设备属性返回非200: device=%s, status=%d", id, resp.StatusCode)
logger.Printf("[IoT-client] ❌ 设置设备属性返回非200: device=%s, status=%d", id, resp.StatusCode)
return fmt.Errorf("设置设备 %s 属性返回状态码 %d", id, resp.StatusCode)
}
@@ -221,7 +221,7 @@ func (c *IoTClient) SetDeviceProperty(id string, field string, value interface{}
c.cache = nil
c.mu.Unlock()
log.Printf("[IoT-client] ✅ 设置设备属性成功: device=%s, field=%s, value=%v", id, field, value)
logger.Printf("[IoT-client] ✅ 设置设备属性成功: device=%s, field=%s, value=%v", id, field, value)
return nil
}
@@ -229,7 +229,7 @@ func (c *IoTClient) SetDeviceProperty(id string, field string, value interface{}
func (c *IoTClient) GetDevicesForContext(ctx context.Context) []IoTDevice {
devices, err := c.GetAllDevices(ctx)
if err != nil {
log.Printf("[IoT客户端] 获取设备状态摘要失败: %v", err)
logger.Printf("[IoT客户端] 获取设备状态摘要失败: %v", err)
return nil
}
return devices