Sagents.Mode.Steps (Sagents v0.10.0)
Copy MarkdownSagents-specific pipeline steps for custom execution modes.
These steps handle concerns that belong at the agent layer, not the LLMChain layer: HITL interrupts and state propagation from tool results.
Summary
Functions
Check if the LLM response contains tool calls that need human approval.
Until-tool termination that fires only on a successful matching result.
Decide whether to loop or return, with until_tool contract enforcement.
Fold a step's {:pause, chain, reason} into custom_context.pause_reason
and return the {:pause, chain} 2-tuple LLMChain.run/2 documents.
Propagate state updates from tool results into the chain's custom_context.
Functions
Check if the LLM response contains tool calls that need human approval.
Reads middleware list from opts :middleware. Inspects chain.exchanged_messages
for tool calls that match the HITL policy.
Returns {:interrupt, chain, interrupt_data} if approval is needed.
Until-tool termination that fires only on a successful matching result.
Like LangChain's check_until_tool/2, but ignores tool results with
is_error: true. When the target tool is called but returns an error, the
pipeline continues ({:continue, chain}) so the loop re-runs and the LLM
sees the error result and can correct the call. This is the default behavior
for until_tool; pass until_tool_success: false to use name-only matching.
Reads :tool_names from opts (a list of tool-name strings, populated by
Sagents.Modes.AgentExecution).
Decide whether to loop or return, with until_tool contract enforcement.
This is a safer variant of LangChain's continue_or_done/3 that adds
enforcement of the "until_tool" contract: if the LLM stops (needs_response
becomes false) without ever calling the target tool, it returns an error
instead of {:ok, chain}.
If the target tool WAS called, check_until_tool/2 would have already
converted the pipeline to {:ok, chain, tool_result}, which passes
through here as a terminal.
When until_tool_active is false or absent in opts
{:continue, chain}withneeds_response: true-> callsrun_fn.(chain, opts)(loop){:continue, chain}withneeds_response: false->{:ok, chain}(normal completion)- Any terminal tuple -> pass through unchanged
When until_tool_active is true in opts
{:continue, chain}withneeds_response: true-> callsrun_fn.(chain, opts)(loop){:continue, chain}withneeds_response: false->{:error, chain, %LangChainError{...}}- Any terminal tuple -> pass through unchanged
Fold a step's {:pause, chain, reason} into custom_context.pause_reason
and return the {:pause, chain} 2-tuple LLMChain.run/2 documents.
A pipeline step that pauses for a cause it knows precisely (a draining node,
an unreachable backing store) returns {:pause, chain, reason}; this step,
applied to the mode's final result, carries the reason on the chain so the
agent layer can read it back onto State.pause_reason.
The 3-tuple must not escape the mode. LangChain.Chains.LLMChain.Mode's
run_result() type admits only {:pause, chain}, and a 3-tuple returned
from Mode.run/2 breaks under with_fallbacks: — try_chain_with_llm/4
has no catch-all clause, so the unmatched shape raises CaseClauseError,
is swallowed by that function's rescue, and retries against each fallback
LLM until the run reports "Failed all attempts to generate response".
The pause becomes an error and the reason is lost. Applying this step to
the mode's final result is what keeps that from happening.
Every other result — including a bare {:pause, chain}, which keeps a nil
reason — passes through unchanged.
Propagate state updates from tool results into the chain's custom_context.
After tool execution, tools may have returned State structs as
processed_content. This step extracts those deltas and merges them
into custom_context.state.