Skip to content

Branch a flow

View as Markdown

This guide puts a condition on an edge, so a step runs only when it holds, and writes the "otherwise" branch.

An edge with a when condition fires only when the condition holds. Two edges out of one step, with opposite conditions, make an if/else.

  • A pack with the tools from Write a flow and Pass data between steps: acme.get-order, acme.hold-order and acme.confirm-order.
  • A runtime such as kindgi dev, with Kindgi 0.1's CLI.

Ask your coding agent: "I want a flow that holds an order over 1000 USD and confirms the rest." Kindgi's skills in your pack tell it how (How it knows Kindgi). For reference, the flow looks like this. This guide calls it acme.review-order:

flows/review-order/index.ts
import { defineFlow } from '@kindgi/sdk/define';
const isLarge = {
op: 'gt',
left: { path: 'nodeOutputs.order.total' },
right: { literal: 1000 },
} as const;
const defined = defineFlow({
id: 'acme.review-order',
version: '0.1.0',
name: 'Review an order',
description: 'Holds a large order for review and confirms the rest.',
nodes: [
{
id: 'order',
kind: 'tool',
ref: 'acme.get-order',
inputMapping: { orderId: { path: 'runInput.orderId' } },
},
{
id: 'hold',
kind: 'tool',
ref: 'acme.hold-order',
inputMapping: {
orderId: { path: 'runInput.orderId' },
reason: { literal: 'Over 1000 USD' },
},
},
{
id: 'confirm',
kind: 'tool',
ref: 'acme.confirm-order',
inputMapping: { orderId: { path: 'runInput.orderId' } },
},
],
edges: [
{ id: 'e1', from: '$start', to: 'order' },
{ id: 'e2', from: 'order', to: 'hold', when: isLarge },
{ id: 'e3', from: 'order', to: 'confirm', when: { op: 'not', child: isLarge } },
{ id: 'e4', from: 'hold', to: '$end' },
{ id: 'e5', from: 'confirm', to: '$end' },
],
});
if (defined.kind === 'err') throw new Error(defined.error.message);
export default defined.value;

e2 fires when the order's total is over 1000, and e3 when it isn't. The condition is defined once and wrapped in not for the other branch.

Run it:

Terminal window
pnpm exec kindgi runs start --flow=acme.review-order --input='{"orderId":"A-200"}'

--flow is the flow, and --input its input. It prints the run:

{
…
"flowId": "acme.review-order",
"status": "completed",
…
"output": {
"status": "held",
"orderId": "A-200"
},
…
}
Excerpt

A-200's total is 1250, so the order is held. With A-100, whose total is 42.50, e3 fires and the order is confirmed.

Every edge the run evaluates is in the journal with its decision. A step whose edge didn't fire is skipped and has no entries:

Terminal window
pnpm exec kindgi runs journal <run-id>

<run-id> is the run's id. It prints:

{"sequence": 4, "kind": "edge.evaluated", "payload": {"edgeId": "e2", "decision": true}, …}
{"sequence": 5, "kind": "edge.evaluated", "payload": {"edgeId": "e3", "decision": false}, …}
{"sequence": 6, "kind": "step.started", "nodeId": "hold", "payload": {"input": {"reason": "Over 1000 USD", "orderId": "A-200"}}, …}
Excerpt

This shows one entry per line. The command prints them as one JSON document.

A condition is JSON. Each operand is a { path }, with the same roots as inputMapping, or a { literal }:

Operator Shape True when
eq ne lt lte gt gte { op, left, right } the comparison holds. lt and the others compare two numbers or two strings
in notIn { op, value, set } value is, or isn't, an element of the array set
exists notExists { op, value } the path resolves, or doesn't
truthy falsy { op, value } the value is truthy, or falsy. A missing path is falsy
and or { op, children: [...] } all, or any, of the children hold
not { op, child } the child doesn't hold

To branch on what an agent decided, give the agent a typed answer and compare one of its fields: { path: 'nodeOutputs.<step>.output.<field>' }. Wait for an approval branches on nodeOutputs.hold.output.held, a boolean the agent returns.

A step none of whose incoming edges fired is skipped, and so is every step only it leads to. If no edge reaches $end, the run still completes, with no output. Cover every case with your conditions, or bring the branches back together, as Join branches shows.