|
NeoGraph 0.10.0
A C++17 Graph Agent Engine Library — LangGraph for C++
|
Immutable routing oracle for a compiled graph. More...
#include <scheduler.h>
Public Member Functions | |
| const BarrierSpecs & | barrier_specs () const |
| Read-only view of declared barriers (mainly for tests). | |
| NextStepPlan | plan_next_step (const std::vector< std::string > &just_ran, const std::vector< NodeResult > &results, const GraphState &state) const |
| Convenience overload: pair up ready[i] with results[i]. | |
| NextStepPlan | plan_next_step (const std::vector< std::string > &just_ran, const std::vector< NodeResult > &results, const GraphState &state, BarrierState &barrier_state) const |
| NodeResult-taking barrier-aware overload. | |
| NextStepPlan | plan_next_step (const std::vector< StepRouting > &routings, const GraphState &state) const |
| Decide the next ready set from this super-step's routing. | |
| NextStepPlan | plan_next_step (const std::vector< StepRouting > &routings, const GraphState &state, BarrierState &barrier_state) const |
| Barrier-aware planning. | |
| std::vector< std::string > | plan_start_step () const |
Nodes directly routed from __start__ at step 0. | |
| std::vector< std::string > | resolve_next_nodes (const std::string ¤t, const GraphState &state) const |
| Resolve the direct successors of a node. | |
| Scheduler (const std::vector< Edge > &edges, const std::vector< ConditionalEdge > &conditional_edges, BarrierSpecs barrier_specs={}) | |
| Bind the scheduler to the graph's edge topology. | |
Immutable routing oracle for a compiled graph.
Scheduler is constructed once per engine compile and shared across all runs on that engine. It reads (but never mutates) the edge vectors passed at construction, so it is inherently thread-safe for concurrent plan_next_step / resolve_next_nodes calls — provided the caller-supplied GraphState is read-thread-safe (which GraphState guarantees via its shared_mutex).
Definition at line 87 of file scheduler.h.
| neograph::graph::Scheduler::Scheduler | ( | const std::vector< Edge > & | edges, |
| const std::vector< ConditionalEdge > & | conditional_edges, | ||
| BarrierSpecs | barrier_specs = {} |
||
| ) |
Bind the scheduler to the graph's edge topology.
| edges | Regular (unconditional) edges. |
| conditional_edges | Edges that route on a runtime condition. |
| barrier_specs | Optional declaration of barrier nodes and their required upstream signal sets. Copied by value so caller ownership is simple. |
edges and conditional_edges must out-live the Scheduler — typical usage has GraphEngine own them and pass references.
| NextStepPlan neograph::graph::Scheduler::plan_next_step | ( | const std::vector< std::string > & | just_ran, |
| const std::vector< NodeResult > & | results, | ||
| const GraphState & | state | ||
| ) | const |
Convenience overload: pair up ready[i] with results[i].
The engine's super-step guarantees results is pushed in the same order as just_ran in both the single- and parallel-node paths. This overload bakes that pairing — plus the Command.goto_node extraction — into the scheduler so the engine doesn't have to restate the invariant at the call site (where forgetting to zip correctly is the kind of mistake today's multi-node checkpoint bug came from).
just_ran and results must be the same size; mismatched lengths throw std::invalid_argument rather than silently truncating.
| just_ran | Node names executed in this super-step, in order. |
| results | NodeResults parallel to just_ran. |
| state | State snapshot for conditional-edge evaluation. |
| NextStepPlan neograph::graph::Scheduler::plan_next_step | ( | const std::vector< StepRouting > & | routings, |
| const GraphState & | state | ||
| ) | const |
Decide the next ready set from this super-step's routing.
Rules:
command_goto, that node wins — ALL regular edge routing from this super-step is discarded. When multiple Commands fire in the same super-step the LAST iteration's value wins (matching the engine's historical last-writer-wins behavior under parallel dispatch; note this is intrinsically non-deterministic under Taskflow).resolve_next_nodes(n, state) for every n in routings. Any END_NODE occurrence trips hit_end and is excluded from ready.Note: this does NOT implement an implicit AND-join. A downstream that is signalled across super-steps (asymmetric path lengths) will fire once per reaching super-step — that is the documented contract of signal dispatch.
| routings | Signals from nodes that just executed. |
| state | State snapshot to evaluate conditional edges against. |
| NextStepPlan neograph::graph::Scheduler::plan_next_step | ( | const std::vector< StepRouting > & | routings, |
| const GraphState & | state, | ||
| BarrierState & | barrier_state | ||
| ) | const |
Barrier-aware planning.
Identical to the 2-arg form, except any candidate listed in barrier_specs_ is gated on accumulated upstream signals. When a candidate b would normally be added to ready, the scheduler:
b into barrier_state[b].barrier_state[b] ⊇ barrier_specs_[b], the barrier has all required upstream signals → it fires this super-step (added to ready) and barrier_state[b] is CLEARED so the next round starts fresh (important for graphs that loop back through the barrier).barrier_state[b] for the next call).Engines call this with a persistent barrier_state owned across super-steps. Ephemeral callers (unit tests, single-shot routing decisions) can use the 2-arg overload, which ignores barrier_specs_ entirely — there's no memory to gate against.
Note: under the current implementation barrier state is per-run and in-memory only — a checkpoint/resume round trip drops all partial signals. See module docs for the follow-up schema-versioned persistence plan.
| std::vector< std::string > neograph::graph::Scheduler::plan_start_step | ( | ) | const |
Nodes directly routed from __start__ at step 0.
e.to for edges with from == START_NODE, excluding any that target END_NODE. | std::vector< std::string > neograph::graph::Scheduler::resolve_next_nodes | ( | const std::string & | current, |
| const GraphState & | state | ||
| ) | const |
Resolve the direct successors of a node.
If a conditional edge originates from current, the condition is evaluated against state and the matching route is returned as a single-element vector. If the route key is missing from the routes map, the LAST entry (by map ordering) is used as a fallback — matching the pre-refactor engine behavior.
Otherwise, every regular edge with from == current contributes its to to the result. If no edge matches at all, {END_NODE} is returned so callers can uniformly check for termination.
| current | Node whose successors to resolve. |
| state | Snapshot used to evaluate any conditional-edge predicate originating from current. |
{END_NODE}.