重构:删 5 零引用 crate(df-evolve/plugin/stages/task/traceability)+ 清死模块、ai.rs 拆 11 子 module、ai.ts 拆 6 composable、i18n 拆目录 功能:知识库全栈(df-project/scan + CRUD + 时间线 + 前端)、Settings 拆分、appSettings KV 迁移、模型池、LLM 并发 Semaphore 修复:审批持久化根治、ConditionEngine 默认拒绝、NodeRegistry unimplemented 清除、promote 补偿删除、工具结果截断 50KB、路径校验防 symlink 逃逸 文档:B-03 人工审批设计、决策记录三分档、规格契约自检、经验记录、todo 看板、PROGRESS 更新 详见 PROGRESS.md。src-tauri/儿童每日打卡应用/ 与本项目无关,已排除。
87 lines
3.8 KiB
Rust
87 lines
3.8 KiB
Rust
//! 系统提示词构建 + 活跃提供商获取
|
|
|
|
use df_storage::models::AiProviderRecord;
|
|
|
|
use crate::state::AppState;
|
|
|
|
/// 获取当前活跃提供商配置
|
|
pub(crate) async fn get_active_provider(state: &AppState) -> Result<AiProviderRecord, String> {
|
|
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
|
|
}
|