mirror of
https://github.com/hanzoai/flow.git
synced 2026-10-17 01:29:18 +00:00
The seam the whole platform composes on. A stdlib-only Go module (core/) that
holds zero domain knowledge and is what every node-pack and execution backend
plugs into. flow is curried over two parameters:
Value type — what travels on an edge (Message / Tensor / connector I/O). The
engine never inspects it; a Step interprets it per its domain.
Mode — execution locality/durability (InProcess | GPUResident | Durable),
a PARAMETER not baked in: media flows keep latents pinned in VRAM
and serialize nothing; automations checkpoint every step on the
durable backend. Same scheduler, different Backend.
So every product is flow applied:
studio = Run(GPUResident, graph-of-Tensor-steps) // comfy nodes
automations = Run(Durable, graph-of-ConnectorIO) // triggers -> actions
llmFlow = Run(InProcess, graph-of-Message-steps) // langflow (lfx) nodes
Contract: Value (opaque, typed by PortType), Port/Step (typed in/out ports + Run),
Graph (Add/Wire/Validate — port typecheck + acyclicity), Mode + Backend (the
locality/durability seam), and Scheduler (the ONE topology walk, curried over
value-domain and Mode). Ships with the reference InProcess backend; GPUResident
(studio VRAM) and Durable (auto/tasks activities) register the same way.
Tests prove it: a domain-agnostic 2-step pipeline runs in order, port type
mismatch is rejected at wire time, AnyType bypasses, cycles are caught by
Validate, and Mode selects the backend over an identical scheduler walk.
Next: studio and langflow delete their private executors and become node-packs
on this scheduler; auto's tasks engine registers as the Durable backend.
51 lines
1.8 KiB
Go
51 lines
1.8 KiB
Go
package flow
|
|
|
|
import "context"
|
|
|
|
// Mode is a graph's execution locality and durability. It is a PARAMETER of a run,
|
|
// not a property of the engine — the single most important decomplection here.
|
|
// The scheduler is identical across modes; Mode only selects the Backend that
|
|
// realizes step execution and value hand-off.
|
|
type Mode int
|
|
|
|
const (
|
|
// InProcess: steps run in-process, values passed by reference in shared memory,
|
|
// nothing serialized, no crash-resume. The default for LLM/agent chains.
|
|
InProcess Mode = iota
|
|
|
|
// GPUResident: values (tensors/latents) stay pinned in device memory between
|
|
// steps and are never serialized to disk. The mode that keeps a diffusion
|
|
// pipeline fast — a Durable backend applied here would serialize a latent per
|
|
// node and destroy throughput, which is exactly why Mode is a parameter.
|
|
GPUResident
|
|
|
|
// Durable: every step is checkpointed so a run resumes after a crash; the
|
|
// backend dispatches steps as activities on the durable workflow engine
|
|
// (hanzoai/tasks). The mode that makes a triggered automation reliable.
|
|
Durable
|
|
)
|
|
|
|
func (m Mode) String() string {
|
|
switch m {
|
|
case InProcess:
|
|
return "in-process"
|
|
case GPUResident:
|
|
return "gpu-resident"
|
|
case Durable:
|
|
return "durable"
|
|
default:
|
|
return "mode(?)"
|
|
}
|
|
}
|
|
|
|
// Backend realizes a Step's execution for one Mode. It is the seam where locality
|
|
// and durability live: an InProcess backend just calls Step.Run; a GPUResident
|
|
// backend pins device memory and reuses it across steps; a Durable backend records
|
|
// the step as a checkpointed activity and replays on resume. A Backend holds NO
|
|
// graph knowledge — the one Scheduler owns topology; a Backend owns only "how does
|
|
// a single step actually run in this mode."
|
|
type Backend interface {
|
|
Mode() Mode
|
|
Exec(ctx context.Context, s Step, in Inputs) (Outputs, error)
|
|
}
|