Class FlowContext
EasyAI.flow() pipeline, carrying the flow's
original input and the result of every step that has run so far, each keyed by its step name.
This is the heart of the flow() idea: instead of the LLM holding the whole task in
its head and improvising, the state of the process lives in a plain, typed Java object
that you can read, assert on, and log. Each step reads what earlier steps produced
(get(String, Class)), does its work, and its return value is clipped in under its own
name for the steps that follow.
Familiar analogy: the job folder that slides down an assembly line. It starts with the
order form (input()), and each station reads the notes clipped in by earlier stations
and clips in its own before passing it on. At the end you hold the whole folder — every note in
the order it was added (trail()), plus the last one (result()).
Immutability & testability
A FlowContext is an immutable snapshot: Flow.run(Object) builds a
fresh one before each step, holding the results accumulated up to that point. Steps never mutate
it — they return a value and the flow records it. This snapshot design is also what makes a step
testable in isolation: construct a FlowContext yourself with a canned prior result and
pass it straight into your FlowStep — no running flow required.
// Testing a step in isolation, no live LLM:
FlowContext ctx = new FlowContext(
"order 3 blue watches",
Map.of("understand", new OrderRequest("watch", 3, "blue")));
String txn = payStep.run(ctx); // reads ctx.get("understand", OrderRequest.class)
assertEquals("txn-…", txn);
Place in the flow
Flow.run(input)
→ new FlowContext(input, results-so-far) // rebuilt before each step
→ passed into FlowStep.run(ctx) // the step reads input()/get(name, type)
→ (final snapshot returned to the caller of Flow.run)
- See Also:
-
Constructor Summary
ConstructorsConstructorDescriptionFlowContext(Object input, Map<String, Object> results) Builds an immutable context from the flow's input and the results gathered so far. -
Method Summary
Modifier and TypeMethodDescription<T> TReturns the result an earlier step produced, cast to the requested type.booleanTells whether a given step has already produced a result in this context.input()Returns the flow's original input, untyped.<T> TReturns the flow's original input, cast to the requested type.Convenience for the common case where the input is (or should be read as) text — e.g. the user's message the first LLM step needs to understand.result()Returns the most recently produced step result (the previous step's output when read mid-flow, or the final step's output on the snapshot returned byFlow.run).results()Returns an unmodifiable, insertion-ordered view of every step result gathered so far, keyed by step name.trail()Renders a compact, human-readable trace of what has happened so far — one line per completed step,name → value, in order.
-
Constructor Details
-
FlowContext
Builds an immutable context from the flow's input and the results gathered so far.Called by
Flow.run(Object)before every step (with a growing result map), and again at the end to produce the snapshot handed back to the caller. Application code rarely constructs one directly — the main exception is unit tests, where building a context with a canned prior result lets you exercise a singleFlowStepwithout a running flow.- Parameters:
input- the flow's original input (whatever was passed toFlow.run(...)); may benullresults- prior step results keyed by step name; copied defensively, may benullor empty
-
-
Method Details
-
input
Returns the flow's original input, untyped.This is whatever you passed to
Flow.run(...)— often the raw user text that the first ("understand") step feeds to the LLM. Useinput(Class)when you want it typed.- Returns:
- the original input, or
nullif the flow was run withnull
-
input
Returns the flow's original input, cast to the requested type.- Type Parameters:
T- the expected input type- Parameters:
type- the class to cast the input to- Returns:
- the input as
T - Throws:
ClassCastException- if the input is not an instance oftype
-
inputText
Convenience for the common case where the input is (or should be read as) text — e.g. the user's message the first LLM step needs to understand.- Returns:
- the input rendered as a string, or
nullif the input isnull
-
get
Returns the result an earlier step produced, cast to the requested type.This is how a step reads what came before it —
ctx.get("understand", OrderRequest.class)in apaystep, for instance. The name is the exact step name you registered withFlowBuilder.step(name, ...).- Type Parameters:
T- the expected result type- Parameters:
name- the step name whose result you wanttype- the class to cast that result to- Returns:
- the named step's result as
T - Throws:
IllegalArgumentException- if no step namednamehas run (yet)ClassCastException- if that step's result is not an instance oftype
-
has
Tells whether a given step has already produced a result in this context.- Parameters:
name- the step name to check- Returns:
trueif a step namednamehas run and stored a result
-
result
Returns the most recently produced step result (the previous step's output when read mid-flow, or the final step's output on the snapshot returned byFlow.run).- Returns:
- the last stored result, or
nullif no step has produced one yet
-
results
Returns an unmodifiable, insertion-ordered view of every step result gathered so far, keyed by step name.- Returns:
- the step results in the order they were produced (never
null)
-
trail
Renders a compact, human-readable trace of what has happened so far — one line per completed step,name → value, in order.Handy for two things: feeding a final "summarize" LLM step (
EasyAI.chat().build().send("Tell the user what happened:\n" + ctx.trail())) and plain logging/auditing of the run.- Returns:
- a newline-separated
name → valuetrace (empty string if nothing has run yet)
-