新增: 初始化 DevFlow 项目仓库
Tauri 2 + Vue 3 + Vite 6 桌面应用,Rust workspace 含 13 个 crate (df-ai / df-storage / df-workflow / df-core / df-execute 等)。 核心能力:AI 聊天 agentic 循环(工具调用+人工审批)、工作流引擎、 任务/想法/项目/阶段管理、可追溯性,及配套前端组件。
This commit is contained in:
282
src-tauri/src/state.rs
Normal file
282
src-tauri/src/state.rs
Normal file
@@ -0,0 +1,282 @@
|
||||
//! 应用全局状态 — 数据库、Repo、事件总线、节点注册表、AI 会话
|
||||
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Result;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use df_ai::ai_tools::{AiToolRegistry, RiskLevel};
|
||||
use df_storage::crud::{
|
||||
AiConversationRepo, AiProviderRepo, AiToolExecutionRepo, IdeaRepo, NodeExecutionRepo,
|
||||
ProjectRepo, ReleaseRepo, TaskRepo, WorkflowRepo,
|
||||
};
|
||||
use df_storage::db::Database;
|
||||
use df_workflow::eventbus::EventBus;
|
||||
use df_workflow::registry::NodeRegistry;
|
||||
|
||||
use crate::commands::ai::AiSession;
|
||||
|
||||
/// 应用全局状态 — 通过 `app.manage()` 注入,command 中以 `State<'_, AppState>` 取用
|
||||
pub struct AppState {
|
||||
/// 数据库句柄(Arc 包装,便于在异步任务中重建 Repo)
|
||||
pub db: Arc<Database>,
|
||||
/// 想法表 Repo
|
||||
pub ideas: IdeaRepo,
|
||||
/// 项目表 Repo
|
||||
pub projects: ProjectRepo,
|
||||
/// 任务表 Repo
|
||||
pub tasks: TaskRepo,
|
||||
/// 发布表 Repo
|
||||
pub releases: ReleaseRepo,
|
||||
/// 工作流执行表 Repo
|
||||
pub workflows: WorkflowRepo,
|
||||
/// 节点执行表 Repo
|
||||
pub node_executions: NodeExecutionRepo,
|
||||
/// 工作流事件总线(tokio broadcast)
|
||||
pub event_bus: EventBus,
|
||||
/// 节点注册表(已注册内置节点)
|
||||
pub registry: Arc<NodeRegistry>,
|
||||
// ── AI ──
|
||||
/// AI 提供商配置 Repo
|
||||
pub ai_providers: AiProviderRepo,
|
||||
/// AI 对话历史 Repo
|
||||
pub ai_conversations: AiConversationRepo,
|
||||
/// AI 工具执行审计 Repo
|
||||
pub ai_tool_executions: AiToolExecutionRepo,
|
||||
/// AI 工具注册表
|
||||
pub ai_tools: Arc<AiToolRegistry>,
|
||||
/// AI 会话状态
|
||||
pub ai_session: Arc<Mutex<AiSession>>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
/// 初始化应用状态:打开(或创建)数据库并执行迁移,构建各 Repo 与节点注册表
|
||||
pub async fn init(db_path: &Path) -> Result<Self> {
|
||||
let db = Arc::new(Database::open(db_path).await?);
|
||||
let ai_tools = Arc::new(build_ai_tool_registry());
|
||||
Ok(Self {
|
||||
ideas: IdeaRepo::new(&db),
|
||||
projects: ProjectRepo::new(&db),
|
||||
tasks: TaskRepo::new(&db),
|
||||
releases: ReleaseRepo::new(&db),
|
||||
workflows: WorkflowRepo::new(&db),
|
||||
node_executions: NodeExecutionRepo::new(&db),
|
||||
ai_providers: AiProviderRepo::new(&db),
|
||||
ai_conversations: AiConversationRepo::new(&db),
|
||||
ai_tool_executions: AiToolExecutionRepo::new(&db),
|
||||
ai_session: Arc::new(Mutex::new(AiSession::new())),
|
||||
db,
|
||||
event_bus: EventBus::new(),
|
||||
registry: Arc::new(build_registry()),
|
||||
ai_tools,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// 构建节点注册表 — 注册内置节点
|
||||
///
|
||||
/// 注意:不使用 `NodeRegistry::default()`,其 script 工厂为占位实现(会 panic),
|
||||
/// 这里注册 df-nodes 提供的真实 ScriptNode 和 HumanNode。
|
||||
fn build_registry() -> NodeRegistry {
|
||||
let mut registry = NodeRegistry::new();
|
||||
registry.register("script", |_config| {
|
||||
Box::new(df_nodes::script_node::ScriptNode)
|
||||
});
|
||||
registry.register("human", |_config| {
|
||||
Box::new(df_nodes::human_node::HumanNode)
|
||||
});
|
||||
registry.register("ai", |_config| {
|
||||
Box::new(df_nodes::ai_node::AiNode)
|
||||
});
|
||||
registry
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// AI 工具注册
|
||||
// ============================================================
|
||||
|
||||
use serde_json::json;
|
||||
|
||||
fn object_schema(fields: Vec<(&str, &str, bool)>) -> serde_json::Value {
|
||||
let mut props = serde_json::Map::new();
|
||||
let mut required = Vec::new();
|
||||
|
||||
for (name, typ, req) in &fields {
|
||||
props.insert(name.to_string(), json!({ "type": typ }));
|
||||
if *req {
|
||||
required.push(name.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
json!({
|
||||
"type": "object",
|
||||
"properties": props,
|
||||
"required": required,
|
||||
})
|
||||
}
|
||||
|
||||
/// 构建 AI 工具注册表 — 注册所有 CRUD 操作为可调用工具
|
||||
fn build_ai_tool_registry() -> AiToolRegistry {
|
||||
let mut registry = AiToolRegistry::new();
|
||||
|
||||
// ── 只读工具 (Low risk) ──
|
||||
|
||||
registry.register(
|
||||
"list_projects",
|
||||
"列出所有项目,返回项目列表(ID、名称、状态、描述)",
|
||||
object_schema(vec![]),
|
||||
RiskLevel::Low,
|
||||
Box::new(|_args| {
|
||||
Box::pin(async { Ok(json!({"note": "工具执行在 IPC 层处理"})) })
|
||||
}),
|
||||
);
|
||||
|
||||
registry.register(
|
||||
"list_tasks",
|
||||
"列出任务,可按 project_id 筛选",
|
||||
object_schema(vec![("project_id", "string", false)]),
|
||||
RiskLevel::Low,
|
||||
Box::new(|_args| {
|
||||
Box::pin(async { Ok(json!({"note": "工具执行在 IPC 层处理"})) })
|
||||
}),
|
||||
);
|
||||
|
||||
registry.register(
|
||||
"list_ideas",
|
||||
"列出所有想法",
|
||||
object_schema(vec![]),
|
||||
RiskLevel::Low,
|
||||
Box::new(|_args| {
|
||||
Box::pin(async { Ok(json!({"note": "工具执行在 IPC 层处理"})) })
|
||||
}),
|
||||
);
|
||||
|
||||
// ── 创建工具 (Medium risk) ──
|
||||
|
||||
registry.register(
|
||||
"update_project",
|
||||
"更新项目的指定字段(name/status/description),需要提供项目 ID、字段名和新值",
|
||||
object_schema(vec![
|
||||
("id", "string", true),
|
||||
("field", "string", true),
|
||||
("value", "string", true),
|
||||
]),
|
||||
RiskLevel::Medium,
|
||||
Box::new(|_args| {
|
||||
Box::pin(async { Ok(json!({"note": "工具执行在 IPC 层处理"})) })
|
||||
}),
|
||||
);
|
||||
|
||||
registry.register(
|
||||
"create_project",
|
||||
"创建新项目",
|
||||
object_schema(vec![
|
||||
("name", "string", true),
|
||||
("description", "string", false),
|
||||
]),
|
||||
RiskLevel::Medium,
|
||||
Box::new(|_args| {
|
||||
Box::pin(async { Ok(json!({"note": "工具执行在 IPC 层处理"})) })
|
||||
}),
|
||||
);
|
||||
|
||||
registry.register(
|
||||
"create_task",
|
||||
"在指定项目下创建新任务",
|
||||
object_schema(vec![
|
||||
("project_id", "string", true),
|
||||
("title", "string", true),
|
||||
("description", "string", false),
|
||||
("priority", "integer", false),
|
||||
]),
|
||||
RiskLevel::Medium,
|
||||
Box::new(|_args| {
|
||||
Box::pin(async { Ok(json!({"note": "工具执行在 IPC 层处理"})) })
|
||||
}),
|
||||
);
|
||||
|
||||
registry.register(
|
||||
"create_idea",
|
||||
"捕获一个新想法",
|
||||
object_schema(vec![
|
||||
("title", "string", true),
|
||||
("description", "string", false),
|
||||
("tags", "string", false),
|
||||
("source", "string", false),
|
||||
]),
|
||||
RiskLevel::Medium,
|
||||
Box::new(|_args| {
|
||||
Box::pin(async { Ok(json!({"note": "工具执行在 IPC 层处理"})) })
|
||||
}),
|
||||
);
|
||||
|
||||
// ── 高风险工具 (High risk) ──
|
||||
|
||||
registry.register(
|
||||
"delete_project",
|
||||
"删除项目及其所有关联数据",
|
||||
object_schema(vec![("id", "string", true)]),
|
||||
RiskLevel::High,
|
||||
Box::new(|_args| {
|
||||
Box::pin(async { Ok(json!({"note": "工具执行在 IPC 层处理"})) })
|
||||
}),
|
||||
);
|
||||
|
||||
registry.register(
|
||||
"run_workflow",
|
||||
"运行指定的工作流 DAG",
|
||||
object_schema(vec![
|
||||
("name", "string", true),
|
||||
("dag", "object", true),
|
||||
]),
|
||||
RiskLevel::High,
|
||||
Box::new(|_args| {
|
||||
Box::pin(async { Ok(json!({"note": "工具执行在 IPC 层处理"})) })
|
||||
}),
|
||||
);
|
||||
|
||||
// ── 文件系统工具 ──
|
||||
|
||||
registry.register(
|
||||
"read_file",
|
||||
"读取文件内容,返回文本内容。支持 offset 和 limit 参数分页读取大文件",
|
||||
object_schema(vec![
|
||||
("path", "string", true),
|
||||
("offset", "integer", false),
|
||||
("limit", "integer", false),
|
||||
]),
|
||||
RiskLevel::Low,
|
||||
Box::new(|_args| {
|
||||
Box::pin(async { Ok(json!({"note": "工具执行在 IPC 层处理"})) })
|
||||
}),
|
||||
);
|
||||
|
||||
registry.register(
|
||||
"list_directory",
|
||||
"列出目录内容,返回文件和子目录列表(名称、类型、大小)",
|
||||
object_schema(vec![
|
||||
("path", "string", true),
|
||||
("recursive", "boolean", false),
|
||||
]),
|
||||
RiskLevel::Low,
|
||||
Box::new(|_args| {
|
||||
Box::pin(async { Ok(json!({"note": "工具执行在 IPC 层处理"})) })
|
||||
}),
|
||||
);
|
||||
|
||||
registry.register(
|
||||
"write_file",
|
||||
"写入或创建文件,自动创建不存在的父目录",
|
||||
object_schema(vec![
|
||||
("path", "string", true),
|
||||
("content", "string", true),
|
||||
]),
|
||||
RiskLevel::Medium,
|
||||
Box::new(|_args| {
|
||||
Box::pin(async { Ok(json!({"note": "工具执行在 IPC 层处理"})) })
|
||||
}),
|
||||
);
|
||||
|
||||
registry
|
||||
}
|
||||
Reference in New Issue
Block a user