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:
@@ -4,9 +4,10 @@ import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"log"
|
||||
"github.com/yourname/cyrene-ai/pkg/logger"
|
||||
"sync"
|
||||
|
||||
"github.com/yourname/cyrene-ai/ai-core/internal/bus"
|
||||
"github.com/yourname/cyrene-ai/ai-core/internal/llm"
|
||||
"github.com/yourname/cyrene-ai/ai-core/internal/model"
|
||||
)
|
||||
@@ -17,6 +18,7 @@ type Manager struct {
|
||||
mu sync.RWMutex
|
||||
providers map[model.SubSessionType]Provider
|
||||
llmClient LLMClient
|
||||
eventBus bus.Bus
|
||||
}
|
||||
|
||||
// NewManager 创建子会话管理器
|
||||
@@ -27,12 +29,24 @@ func NewManager(llmClient LLMClient) *Manager {
|
||||
}
|
||||
}
|
||||
|
||||
// SetBus sets the event bus (optional, for Phase 1).
|
||||
func (m *Manager) SetBus(b bus.Bus) {
|
||||
m.eventBus = b
|
||||
}
|
||||
|
||||
func (m *Manager) getBus() bus.Bus {
|
||||
if m.eventBus == nil {
|
||||
return &bus.NopBus{}
|
||||
}
|
||||
return m.eventBus
|
||||
}
|
||||
|
||||
// Register 注册子会话提供者
|
||||
func (m *Manager) Register(provider Provider) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.providers[provider.Type()] = provider
|
||||
log.Printf("[subsession] 注册子会话提供者: %s (优先级=%d, 超时=%v)", provider.Type(), provider.Priority(), provider.Timeout())
|
||||
logger.Printf("[subsession] 注册子会话提供者: %s (优先级=%d, 超时=%v)", provider.Type(), provider.Priority(), provider.Timeout())
|
||||
}
|
||||
|
||||
// RegisterWithOverride 注册或覆盖子会话提供者
|
||||
@@ -40,7 +54,7 @@ func (m *Manager) RegisterWithOverride(provider Provider) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.providers[provider.Type()] = provider
|
||||
log.Printf("[subsession] 注册(覆盖)子会话提供者: %s (优先级=%d, 超时=%v)", provider.Type(), provider.Priority(), provider.Timeout())
|
||||
logger.Printf("[subsession] 注册(覆盖)子会话提供者: %s (优先级=%d, 超时=%v)", provider.Type(), provider.Priority(), provider.Timeout())
|
||||
}
|
||||
|
||||
// GetProvider 获取指定类型的 Provider
|
||||
@@ -82,7 +96,7 @@ func (m *Manager) Dispatch(
|
||||
|
||||
for _, provider := range providers {
|
||||
if !provider.CanHandle(ctx, intent, userMessage) {
|
||||
log.Printf("[subsession] 跳过子会话 %s: CanHandle 返回 false", provider.Type())
|
||||
logger.Printf("[subsession] 跳过子会话 %s: CanHandle 返回 false", provider.Type())
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -91,11 +105,16 @@ func (m *Manager) Dispatch(
|
||||
defer wg.Done()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Printf("[subsession] dispatch goroutine panic 恢复 (type=%s): %v", p.Type(), r)
|
||||
logger.Printf("[subsession] dispatch goroutine panic 恢复 (type=%s): %v", p.Type(), r)
|
||||
}
|
||||
}()
|
||||
|
||||
result := model.SubSessionResult{Type: p.Type()}
|
||||
m.getBus().Publish(bus.BusEvent{
|
||||
Type: bus.EventSubSessionStarted,
|
||||
Payload: bus.SubSessionPayload{SubType: p.Type(), Status: "started"},
|
||||
})
|
||||
|
||||
|
||||
// 创建带超时的 context
|
||||
subCtx, cancel := context.WithTimeout(ctx, p.Timeout())
|
||||
@@ -105,18 +124,18 @@ func (m *Manager) Dispatch(
|
||||
llmMessages, err := p.CreateContext(subCtx, params)
|
||||
if err != nil {
|
||||
result.Error = fmt.Sprintf("创建上下文失败: %v", err)
|
||||
log.Printf("[subsession] %s 创建上下文失败: %v", p.Type(), err)
|
||||
logger.Printf("[subsession] %s 创建上下文失败: %v", p.Type(), err)
|
||||
resultCh <- result
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[subsession] %s 开始执行 (上下文 %d 条消息)", p.Type(), len(llmMessages))
|
||||
logger.Printf("[subsession] %s 开始执行 (上下文 %d 条消息)", p.Type(), len(llmMessages))
|
||||
|
||||
// 执行子会话
|
||||
subResult, execErr := p.Execute(subCtx, llmMessages)
|
||||
if execErr != nil {
|
||||
result.Error = fmt.Sprintf("执行失败: %v", execErr)
|
||||
log.Printf("[subsession] %s 执行失败: %v", p.Type(), execErr)
|
||||
logger.Printf("[subsession] %s 执行失败: %v", p.Type(), execErr)
|
||||
resultCh <- result
|
||||
return
|
||||
}
|
||||
@@ -125,15 +144,20 @@ func (m *Manager) Dispatch(
|
||||
select {
|
||||
case <-subCtx.Done():
|
||||
result.Error = "子会话超时"
|
||||
log.Printf("[subsession] %s 超时 (limit=%v)", p.Type(), p.Timeout())
|
||||
logger.Printf("[subsession] %s 超时 (limit=%v)", p.Type(), p.Timeout())
|
||||
default:
|
||||
if subResult != nil {
|
||||
result = *subResult
|
||||
result.Type = p.Type()
|
||||
log.Printf("[subsession] %s 完成: 摘要=%s", p.Type(), truncate(result.Summary, 50))
|
||||
logger.Printf("[subsession] %s 完成: 摘要=%s", p.Type(), truncate(result.Summary, 50))
|
||||
}
|
||||
}
|
||||
|
||||
m.getBus().Publish(bus.BusEvent{
|
||||
Type: bus.EventSubSessionCompleted,
|
||||
Payload: bus.SubSessionPayload{SubType: p.Type(), Status: resultSummaryStatus(result), Summary: result.Summary, Details: result.Details},
|
||||
})
|
||||
|
||||
resultCh <- result
|
||||
}(provider)
|
||||
}
|
||||
@@ -142,7 +166,7 @@ func (m *Manager) Dispatch(
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Printf("[subsession] wait goroutine panic 恢复: %v", r)
|
||||
logger.Printf("[subsession] wait goroutine panic 恢复: %v", r)
|
||||
}
|
||||
}()
|
||||
wg.Wait()
|
||||
@@ -159,6 +183,14 @@ func generateID() string {
|
||||
return fmt.Sprintf("sub-%x", b)
|
||||
}
|
||||
|
||||
// resultSummaryStatus returns "completed" or "failed" for bus events.
|
||||
func resultSummaryStatus(r model.SubSessionResult) string {
|
||||
if r.Error != "" {
|
||||
return "failed"
|
||||
}
|
||||
return "completed"
|
||||
}
|
||||
|
||||
// truncate 截断字符串
|
||||
func truncate(s string, maxLen int) string {
|
||||
runes := []rune(s)
|
||||
|
||||
Reference in New Issue
Block a user