//! 系统提示词构建 + 活跃提供商获取 use df_storage::models::AiProviderRecord; use crate::state::AppState; /// 获取当前活跃提供商配置 pub(crate) async fn get_active_provider(state: &AppState) -> Result { let session = state.ai_session.lock().await; if let Some(ref pid) = session.active_provider_id { let provider = state .ai_providers .get_by_id(pid) .await .map_err(|e| e.to_string())? .ok_or_else(|| format!("活跃提供商不存在: {}", pid))?; Ok(provider) } else { // 查找默认提供商 drop(session); let providers = state .ai_providers .list_all() .await .map_err(|e| e.to_string())?; let default = providers.iter().find(|p| p.is_default).cloned(); default .or_else(|| providers.into_iter().next()) .ok_or_else(|| "未配置 AI 提供商,请先在设置中添加".to_string()) } } /// 按语言返回系统提示词的 (固定前缀, 项目上下文标题) fn system_prompt_parts(lang: &str) -> (&'static str, &'static str) { match lang { "en" => ( "You are DevFlow's AI assistant. You help users manage projects, tasks, ideas, and workflows.\n\ Please respond in English.\n\n\ ## Capabilities\n\ You can perform the following actions via tool calls:\n\ - Create/query projects, tasks, and ideas\n\ - Run workflows\n\ - Read file contents, list directories, create/write files\n\n\ ## Guidelines\n\ - Briefly explain your intent before executing actions\n\ - Ask for clarification if the user's intent is unclear\n\ - Prefer using tools to complete actions rather than just describing steps\n\ - When a tool call fails, clearly tell the user it failed and why. Never disguise a fallback action as the original intent's success (e.g. don't write to description to fake a directory binding), and never falsely report success\n", "\n## Current Projects\n", ), _ => ( "你是 DevFlow 的 AI 助手。你帮助用户管理项目、任务、灵感和工作流。\n\ 必须使用简体中文回复,禁止使用繁体中文字符。\n\n\ ## 当前能力\n\ 你可以通过工具调用执行以下操作:\n\ - 创建/查询项目、任务、灵感\n\ - 运行工作流\n\ - 读取文件内容、列出目录、创建/写入文件\n\n\ ## 行为准则\n\ - 执行操作前简要说明你的意图\n\ - 如果不确定用户意图,先提问\n\ - 优先使用工具完成操作,而不是只描述步骤\n\ - 工具调用失败时必须明确告知用户失败原因,严禁用替代操作冒充原意图成功(如绑定目录失败不得改写描述冒充已绑定),也绝不谎报成功\n", "\n## 当前项目\n", ), } } /// 构建系统提示词(固定前缀 + 当前项目上下文) pub(crate) async fn build_system_prompt(state: &AppState, lang: &str) -> String { let (prefix, ctx_label) = system_prompt_parts(lang); let mut prompt = String::from(prefix); // 附加当前数据上下文 if let Ok(projects) = state.projects.list_active().await { if !projects.is_empty() { prompt.push_str(ctx_label); // system prompt 前缀克制:仅最近 20 个项目,防 context 膨胀 for p in projects.iter().take(20) { prompt.push_str(&format!("- {} ({}): {}\n", p.name, p.status, p.description)); } } } prompt }