Files
DevFlow/src-tauri/src/state.rs
绝尘 98393b4908 新增: 初始化 DevFlow 项目仓库
Tauri 2 + Vue 3 + Vite 6 桌面应用,Rust workspace 含 13 个 crate
(df-ai / df-storage / df-workflow / df-core / df-execute 等)。
核心能力:AI 聊天 agentic 循环(工具调用+人工审批)、工作流引擎、
任务/想法/项目/阶段管理、可追溯性,及配套前端组件。
2026-06-12 01:31:05 +08:00

283 lines
8.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 应用全局状态 — 数据库、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
}