第一个流程图

两种构建方式

构建流程图有两种方式:

| 方式 | 适用场景 | 特点 | |------|----------|------| | `FlowGraph` API | 代码动态构建 | 直接操作图,需手动管理 NodeId | | `FlowDocument` 数据驱动 | 从 JSON/配置加载 | 声明式,节点用索引引用 |

推荐使用 **FlowDocument 数据驱动**——它可序列化、可从文件加载,且与持久化协议一致。

方式一:FlowGraph API 构建

适合需要运行时动态增删节点的场景:

use rust_agent_flow::{Edge, FlowGraph};

let mut graph = FlowGraph::new();

// 添加节点(kind + data)
let start = graph.add_node("start", serde_json::json!({"label": "开始"}));
let action = graph.add_node("action", serde_json::json!({"label": "执行"}));
let end = graph.add_node("end", serde_json::json!({"label": "结束"}));

// 连线
graph.add_edge(Edge::new(start, action));
graph.add_edge(Edge::new(action, end));

- `add_node(kind, data)` 返回 `NodeId`(slotmap 稳定键) - `Edge::new(source, target)` 创建边 - 节点尺寸默认 180×64,由 `sync_node_sizes` 在布局时按 schema 修正

方式二:FlowDocument 数据驱动(推荐)

声明式定义,可从 JSON 加载:

use rust_agent_flow::{EdgeDef, FlowDocument, NodeDef};

let mut doc = FlowDocument::new("我的流程");

let start = doc.add_node(NodeDef::new("start", serde_json::json!({"label": "开始"})));
let action = doc.add_node(NodeDef::new("action", serde_json::json!({"label": "执行"})));
let end = doc.add_node(NodeDef::new("end", serde_json::json!({"label": "结束"})));

doc.add_edge(EdgeDef::new(start, action));
doc.add_edge(EdgeDef::new(action, end));

// 转为 FlowGraph
let graph = FlowGraph::from_document(&doc);

`doc.add_node` 返回**节点索引**(usize),边用索引引用——这保证了序列化稳定性(不依赖 slotmap 内部 key)。

从 JSON 加载

FlowDocument 可直接从 JSON 反序列化:

let json = r#"{
  "version": "1.0",
  "metadata": { "name": "简单流程", "description": null },
  "nodes": [
    { "kind": "start", "data": {"label":"开始"}, "size": null, "position": null },
    { "kind": "end",   "data": {"label":"结束"}, "size": null, "position": null }
  ],
  "edges": [
    { "source": 0, "target": 1, "source_port": null, "target_port": null, "edge_type": null }
  ]
}"#;

let doc: FlowDocument = serde_json::from_str(json).unwrap();
let graph = FlowGraph::from_document(&doc);

带端口的连线

结构化节点(Condition/Loop)需要指定端口:

use rust_agent_flow::{EdgeDef, FlowDocument, NodeDef};

let mut doc = FlowDocument::new("条件流程");
let cond = doc.add_node(NodeDef::new("condition", serde_json::json!({
    "label": "检查",
    "conditions": [{"id":"if_0","label":"x > 0"}]
})));
let yes = doc.add_node(NodeDef::new("action", serde_json::json!({"label":"是"})));
let no  = doc.add_node(NodeDef::new("action", serde_json::json!({"label":"否"})));

// condition 的 if_0 出口 → yes
doc.add_edge(EdgeDef::new(cond, yes).with_source_port("if_0"));
// condition 的 else 出口 → no
doc.add_edge(EdgeDef::new(cond, no).with_source_port("else"));

端口 ID 与 `NodeSchema.ports` 中的 `PortSpec.id` 对应。

完整示例:显示流程图

use rust_agent_flow::{EdgeDef, FlowDocument, FlowGraph, NodeDef};
use rust_agent_flow_gpui::{CombinedAssets, FlowEditorView};

fn build_graph() -> FlowGraph {
    let mut doc = FlowDocument::new("第一个流程");
    let s = doc.add_node(NodeDef::new("start", serde_json::json!({"label":"开始"})));
    let a = doc.add_node(NodeDef::new("action", serde_json::json!({"label":"处理"})));
    let e = doc.add_node(NodeDef::new("end",   serde_json::json!({"label":"结束"})));
    doc.add_edge(EdgeDef::new(s, a));
    doc.add_edge(EdgeDef::new(a, e));
    FlowGraph::from_document(&doc)
}

fn main() {
    gpui_platform::application()
        .with_assets(CombinedAssets)
        .run(move |cx: &mut gpui::App| {
            rust_agent_flow_gpui::init(cx);
            cx.spawn(async move |cx| {
                cx.open_window(gpui::WindowOptions::default(), |window, cx| {
                    let graph = build_graph();
                    let view = cx.new(|cx| {
                        let mut editor = FlowEditorView::new(graph, cx);
                        editor.auto_layout(cx);
                        editor
                    });
                    cx.new(|cx| gpui_component::Root::new(view, window, cx))
                }).expect("Failed to open window");
            }).detach();
        });
}

运行后你会看到三个节点自动排成一行:`开始 → 处理 → 结束`,带 SmoothStep 圆角连线。

节点 data 的字段

每种节点的 `data` 字段由其 `NodeSchema.fields` 定义。常用字段:

| kind | 关键字段 | |------|----------| | `start` | `label`、`params`(数组)、`variables`(数组) | | `end` | `label`、`returns`(数组) | | `action` | `label`、`code` | | `condition` | `label`、`conditions`(数组:id + label) | | `loop` | `label`、`loop_mode`、`loop_expr` |

`label` 是所有节点通用字段,显示在标题栏。

小结

推荐用 `FlowDocument` 数据驱动构建流程图——声明式、可序列化、与持久化协议一致。端口通过 `with_source_port`/`with_target_port` 指定,与 Schema 端口 ID 对应。

下一节:[运行、调试与验证](run-and-debug.md)