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:
@@ -3,7 +3,7 @@ package store
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"github.com/yourname/cyrene-ai/pkg/logger"
|
||||
"time"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
@@ -24,6 +24,7 @@ type Message struct {
|
||||
ID int `json:"id"`
|
||||
SessionID string `json:"session_id"`
|
||||
Role string `json:"role"`
|
||||
MsgType string `json:"msg_type"`
|
||||
Content string `json:"content"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
@@ -60,7 +61,7 @@ func NewSessionStore(databaseURL string) (*SessionStore, error) {
|
||||
return nil, fmt.Errorf("数据库迁移失败: %w", err)
|
||||
}
|
||||
|
||||
log.Println("[SessionStore] PostgreSQL 持久化存储已初始化")
|
||||
logger.Println("[SessionStore] PostgreSQL 持久化存储已初始化")
|
||||
return store, nil
|
||||
}
|
||||
|
||||
@@ -82,11 +83,15 @@ func (s *SessionStore) migrate() error {
|
||||
id SERIAL PRIMARY KEY,
|
||||
session_id VARCHAR(64) REFERENCES sessions(id) ON DELETE CASCADE,
|
||||
role VARCHAR(16) NOT NULL,
|
||||
msg_type VARCHAR(16) DEFAULT 'chat',
|
||||
content TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT NOW()
|
||||
)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_messages_session_id ON messages(session_id)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_messages_created_at ON messages(session_id, created_at)`,
|
||||
|
||||
// 为已存在的数据库添加 msg_type 列 (Phase 0.1)
|
||||
`ALTER TABLE messages ADD COLUMN IF NOT EXISTS msg_type VARCHAR(16) DEFAULT 'chat'`,
|
||||
}
|
||||
|
||||
for _, q := range queries {
|
||||
@@ -200,10 +205,10 @@ func (s *SessionStore) DeleteAllUserSessions(userID string) error {
|
||||
}
|
||||
|
||||
// AddMessage 添加一条消息到会话
|
||||
func (s *SessionStore) AddMessage(sessionID, role, content string) error {
|
||||
func (s *SessionStore) AddMessage(sessionID, role, msgType, content string) error {
|
||||
_, err := s.db.Exec(
|
||||
`INSERT INTO messages (session_id, role, content) VALUES ($1, $2, $3)`,
|
||||
sessionID, role, content,
|
||||
`INSERT INTO messages (session_id, role, msg_type, content) VALUES ($1, $2, $3, $4)`,
|
||||
sessionID, role, msgType, content,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("添加消息失败: %w", err)
|
||||
@@ -221,7 +226,7 @@ func (s *SessionStore) GetMessages(sessionID string, limit, offset int) ([]Messa
|
||||
}
|
||||
|
||||
rows, err := s.db.Query(
|
||||
`SELECT id, session_id, role, content, created_at
|
||||
`SELECT id, session_id, role, COALESCE(msg_type, 'chat'), content, created_at
|
||||
FROM messages WHERE session_id = $1
|
||||
ORDER BY created_at ASC
|
||||
LIMIT $2 OFFSET $3`,
|
||||
@@ -235,7 +240,7 @@ func (s *SessionStore) GetMessages(sessionID string, limit, offset int) ([]Messa
|
||||
var messages []Message
|
||||
for rows.Next() {
|
||||
var msg Message
|
||||
if err := rows.Scan(&msg.ID, &msg.SessionID, &msg.Role, &msg.Content, &msg.CreatedAt); err != nil {
|
||||
if err := rows.Scan(&msg.ID, &msg.SessionID, &msg.Role, &msg.MsgType, &msg.Content, &msg.CreatedAt); err != nil {
|
||||
return nil, fmt.Errorf("扫描消息行失败: %w", err)
|
||||
}
|
||||
messages = append(messages, msg)
|
||||
@@ -262,6 +267,7 @@ type SearchResult struct {
|
||||
SessionID string `json:"session_id"`
|
||||
SessionTitle string `json:"session_title"`
|
||||
Role string `json:"role"`
|
||||
MsgType string `json:"msg_type"`
|
||||
Content string `json:"content"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
@@ -287,7 +293,7 @@ func (s *SessionStore) SearchMessages(userID, query string, limit, offset int) (
|
||||
|
||||
// 分页查询,关联 sessions 获取会话标题
|
||||
rows, err := s.db.Query(
|
||||
`SELECT m.id, m.session_id, COALESCE(s.title, '') AS session_title, m.role, m.content, m.created_at
|
||||
`SELECT m.id, m.session_id, COALESCE(s.title, '') AS session_title, m.role, COALESCE(m.msg_type, 'chat'), m.content, m.created_at
|
||||
FROM messages m
|
||||
JOIN sessions s ON m.session_id = s.id
|
||||
WHERE s.user_id = $1 AND m.content ILIKE '%' || $2 || '%'
|
||||
@@ -303,7 +309,7 @@ func (s *SessionStore) SearchMessages(userID, query string, limit, offset int) (
|
||||
var results []SearchResult
|
||||
for rows.Next() {
|
||||
var r SearchResult
|
||||
if err := rows.Scan(&r.MessageID, &r.SessionID, &r.SessionTitle, &r.Role, &r.Content, &r.CreatedAt); err != nil {
|
||||
if err := rows.Scan(&r.MessageID, &r.SessionID, &r.SessionTitle, &r.Role, &r.MsgType, &r.Content, &r.CreatedAt); err != nil {
|
||||
return nil, 0, fmt.Errorf("扫描搜索结果行失败: %w", err)
|
||||
}
|
||||
results = append(results, r)
|
||||
|
||||
Reference in New Issue
Block a user