用户可见文案 + 后端错误信息 + LLM 工具描述/系统提示词 + store toast + 注释统一改灵感: i18n zh-CN(ideas/aiTool/projectDetail) + idea.rs 错误 + tool_registry/prompt LLM + stores/project toast + api/views 注释 en 版待定(用 Ideas/Idea)+ docs/crates 注释低优先本轮略;cargo check/vue-tsc 0 error
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
|
|
}
|