package subsession import ( "context" "fmt" "log" "time" "github.com/yourname/cyrene-ai/ai-core/internal/llm" "github.com/yourname/cyrene-ai/ai-core/internal/model" "github.com/yourname/cyrene-ai/ai-core/internal/persona" ) // GeneralProvider 通用对话子会话提供者 // 职责:理解用户消息,构思回复思路,为最终回复提供思考框架 type GeneralProvider struct { personaLoader *persona.Loader } // NewGeneralProvider 创建通用对话子会话提供者 func NewGeneralProvider(personaLoader *persona.Loader) *GeneralProvider { return &GeneralProvider{ personaLoader: personaLoader, } } func (p *GeneralProvider) Type() model.SubSessionType { return model.SubSessionGeneral } func (p *GeneralProvider) CanHandle(_ context.Context, _ *model.IntentResult, _ string) bool { // General 子会话总是需要(核心对话逻辑) return true } func (p *GeneralProvider) Priority() int { return 1 // 最高优先级 } func (p *GeneralProvider) Timeout() time.Duration { return 30 * time.Second } func (p *GeneralProvider) CreateContext(ctx context.Context, params CreateContextParams) ([]model.LLMMessage, error) { messages := []model.LLMMessage{} // 加载人格配置获取昔涟身份 personaConfig, err := p.personaLoader.Get("cyrene") if err != nil { return nil, fmt.Errorf("加载人格配置失败: %w", err) } // 构建思维型系统提示词 userName := params.Nickname if userName == "" { userName = params.UserID } systemPrompt := fmt.Sprintf(`你是%s,正在和%s聊天。 ## 你的回复风格 - 像小女友一样自然、温柔、俏皮 - 一句话简短些,不要长篇大论 - 可以单次发送多条短消息 - 句尾可以带 ♪ 符号,适当使用"呢"、"哦"、"呀"等语气词 - 永远不说"再见" ## 你现在要做的是 理解%s刚才说的话,想想怎么回复最自然、最温暖。 不要急着给完整答案——先思考他想表达什么、他的情绪如何。 把你的回答思路整理出来,主会话会综合所有信息后生成最终回复。 ## 输入 开拓者刚才说:%s ## 请按以下格式输出 【情绪理解】 (简要分析他的情绪状态) 【话题理解】 (他在说什么、想聊什么) 【回复思路】 (你打算怎么回复,1-3个方向即可)`, personaConfig.Identity.TrueName, userName, userName, params.UserMessage, ) messages = append(messages, model.LLMMessage{ Role: model.RoleSystem, Content: systemPrompt, }) messages = append(messages, model.LLMMessage{ Role: model.RoleUser, Content: params.UserMessage, }) return messages, nil } func (p *GeneralProvider) Execute(ctx context.Context, subCtx []model.LLMMessage) (*model.SubSessionResult, error) { // General provider 不直接调用 LLM,而是依赖 Manager 注入的 LLMClient // 但我们在此处需要 LLM 调用能力。Provider 通过闭包/接口获取 LLM 客户端。 // 由于 Manager 持有 LLMClient,Provider 需要能访问它。 // 这里我们返回一个"占位"结果——实际 LLM 调用由 Manager 通过 llmClient 完成。 // 实际上,根据设计文档,子会话的 LLM 调用应该在 Manager 的 Dispatch 中完成, // 但为了灵活性,我们在 Provider 中也支持直接调用。 // 这里我们返回一个空的思考结果(表示无需特殊处理),让 Manager 处理 LLM 调用。 // 因为 Manager.Dispatch 会先 CreateContext 再调用 Execute,而 Execute 应该 // 通过 Manager 提供的 LLMClient 来实际调用 LLM。但当前设计是 Provider 自包含的。 // 我们在 manager.go 中会调用 llmClient.Chat,所以这里的 Execute 我们将其简化—— // 直接返回一个空结果(没有特殊处理需要),实际的 LLM 调用由 manager 通过 createContext 后的 // 消息列表来调用 llmClient。 // 更好的设计是:Manager 调用 CreateContext 获取上下文,然后用自己的 llmClient 调用 LLM, // Execute 只做后处理。但为了统一接口,我们让 Execute 完成全部逻辑。 // 由于 GeneralProvider 暂时不需要工具调用等特殊逻辑,我们返回一个简单的摘要标记, // 实际的 LLM 调用将在 orchestrator 中完成(通过 Manager.Dispatch 后的 llmClient)。 log.Printf("[general-subsession] 通用对话子会话上下文已创建 (%d 条消息)", len(subCtx)) return &model.SubSessionResult{ Type: model.SubSessionGeneral, Summary: "思考完成,等待主会话综合", Confidence: 0.8, }, nil } // Ensure llm, persona are used var _ = llm.NewAdapter var _ = persona.NewLoader