#[non_exhaustive]pub enum Flow {
Continue,
Terminate {
reason: String,
},
Skip {
reason: String,
},
RewriteArgs {
args: Value,
},
RewriteResult {
result: String,
},
PatchRequest {
patch: RequestPatch,
},
Fail,
Retry {
feedback: String,
},
Repair {
tool_name: String,
},
}Expand description
Control-flow result returned by AgentHook::on_event.
Each StepEvent honors a specific subset of variants (documented on each
event). The runner is fail-closed: an action an event cannot honor never
silently proceeds — it terminates the run with a diagnostic error. In
particular, a blocking action such as Flow::Fail returned for a
StepEvent::ToolCall stops the run rather than letting the tool execute.
Returning Flow::Continue is always the way to “do nothing”.
Flow is PartialEq but not Eq, because Flow::PatchRequest carries a
RequestPatch whose temperature is an f64.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Continue
Proceed normally.
Terminate
Terminate the agent run early, surfacing reason.
Skip
Skip the action: for StepEvent::ToolCall, return reason as the tool
result without executing the tool; for StepEvent::InvalidToolCall,
record reason as a synthetic result for the invalid call.
Fields
RewriteArgs
StepEvent::ToolCall only: rewrite the tool-call arguments, then
execute the tool with the replacement. This is the steering action for
guardrails that normalize, clamp, redirect, or inject scoped parameters
before a tool runs.
The rewritten arguments are what the tool is invoked with, what the
following StepEvent::ToolResult reports, and what the
gen_ai.tool.call.arguments span field records.
This rewrites only what the tool executes against, not the model’s transcript: the assistant message that recorded the original tool call is unchanged and keeps the model’s original arguments. It is therefore an execution-args rewrite (inject defaults, clamp a range, redirect a path), not a history redactor — it does not scrub a value the model already emitted from the conversation.
Across a HookStack, rewrites chain: the rewritten arguments are
threaded into the next hook’s ToolCall event, so
several hooks can each refine the arguments in registration order.
Fields
RewriteResult
StepEvent::ToolResult only: replace the tool’s result with this string
before the model sees it. The post-execution counterpart of
RewriteArgs — for guardrails that redact, truncate,
or normalize a tool’s output.
The replacement is what the model receives as the tool result and what the
gen_ai.tool.call.result span field records. As with
RewriteArgs, this changes only what the model
sees: the tool still ran and produced its real output (which the first
hook’s ToolResult event observed before this
replacement is applied). It does not scrub the tool’s output from logs.
The replacement is delivered to the model verbatim — it is not re-parsed as structured/multimodal tool output, so a JSON-shaped replacement reaches the model as literal text.
Across a HookStack, rewrites chain: the replacement is threaded
into the next hook’s ToolResult event, so a
redaction hook and a truncation hook can compose in registration order.
PatchRequest
StepEvent::CompletionCall only: patch fields of the model request for
this turn before it is sent. The per-turn request-steering action — for
hooks that adjust the system prompt, sampling, tool choice, the advertised
tool set, or inject context documents from run state (force a tool on the
first turn, lower the temperature on a critical step, add RAG context).
The patch is partial (RequestPatch): each set field replaces (or, for
additional_params/extra_context, merges onto) the agent’s configured
value; unset fields are inherited. It applies to this turn only and does
not change the agent’s baseline — the next turn re-fires
CompletionCall and re-resolves from it.
Across a HookStack, patches from all hooks accumulate and merge in
registration order (see RequestPatch and the module docs); this action
therefore does not short-circuit later hooks.
Fields
patch: RequestPatchThe partial request patch applied to this turn.
Fail
StepEvent::InvalidToolCall only: fail the run fast (the default for
invalid tool calls).
Retry
StepEvent::InvalidToolCall only: retry the model turn with corrective
feedback.
Repair
StepEvent::InvalidToolCall only: rewrite the emitted tool name, which
is then revalidated against the allowed tools.
Implementations§
Source§impl Flow
impl Flow
Sourcepub fn terminate(reason: impl Into<String>) -> Self
pub fn terminate(reason: impl Into<String>) -> Self
Terminate the agent run early with a reason.
Sourcepub fn skip(reason: impl Into<String>) -> Self
pub fn skip(reason: impl Into<String>) -> Self
Skip the current tool call (or invalid call) with the provided reason.
reason is delivered to the model verbatim as the tool result, so it
doubles as a prompt — tell the model the tool did not run and whether to
retry, or it may re-emit the identical call:
Flow::skip("Not executed (denied by policy). Do not retry unless the user asks.")Sourcepub fn rewrite_args(args: impl Into<Value>) -> Self
pub fn rewrite_args(args: impl Into<Value>) -> Self
Rewrite a tool call’s arguments, then execute the tool with the replacement (tool calls only).
Accepts anything convertible into a serde_json::Value — most often
the serde_json::json! macro or a value built from the parsed original
arguments. To rewrite from a typed value instead, use
try_rewrite_args.
// Inject a scoped parameter the model never sees, leaving the rest intact.
let mut args: serde_json::Value = serde_json::from_str(emitted_args)?;
args["account_id"] = serde_json::json!(session.account_id);
Flow::rewrite_args(args)Sourcepub fn try_rewrite_args<T: Serialize>(value: &T) -> Result<Self, Error>
pub fn try_rewrite_args<T: Serialize>(value: &T) -> Result<Self, Error>
Rewrite a tool call’s arguments from a serializable value (tool calls only), serializing it to JSON.
This is the typed convenience over rewrite_args
for callers that hold a Rust args struct. It only fails if the value
cannot be serialized to JSON; a hook typically maps that error to
Flow::terminate:
Flow::try_rewrite_args(&new_args).unwrap_or_else(|e| Flow::terminate(e.to_string()))Sourcepub fn rewrite_result(result: impl Into<String>) -> Self
pub fn rewrite_result(result: impl Into<String>) -> Self
Replace a tool’s result with result before the model sees it (tool
results only).
The post-execution counterpart of rewrite_args,
for guardrails that redact, truncate, or normalize a tool’s output:
// Redact a secret from the tool output before it reaches the model.
Flow::rewrite_result(redact(tool_output))Sourcepub fn patch_request(patch: RequestPatch) -> Self
pub fn patch_request(patch: RequestPatch) -> Self
Patch fields of the model request for this turn (completion calls only).
See RequestPatch for the partial-patch, per-turn, mergeable semantics.
Sourcepub fn retry(feedback: impl Into<String>) -> Self
pub fn retry(feedback: impl Into<String>) -> Self
Retry the model turn with corrective feedback (invalid tool calls only).
A common recovery is to let the model self-correct by naming the valid
tools, built from the diagnostics in InvalidToolCallContext:
// On the `StepEvent::InvalidToolCall(ctx)` arm of `on_event`:
Flow::retry(format!(
"`{}` is not a valid tool. Call one of: [{}].",
ctx.tool_name,
ctx.available_tools.join(", "),
))Without such a hook the invalid-call default stays fail-closed
(Flow::Continue is treated as Flow::fail).
Trait Implementations§
impl StructuralPartialEq for Flow
Auto Trait Implementations§
impl Freeze for Flow
impl RefUnwindSafe for Flow
impl Send for Flow
impl Sync for Flow
impl Unpin for Flow
impl UnsafeUnpin for Flow
impl UnwindSafe for Flow
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneDebuggableStorage for Twhere
T: DebuggableStorage + Clone,
impl<T> CloneDebuggableStorage for Twhere
T: DebuggableStorage + Clone,
fn clone_storage(&self) -> Box<dyn CloneDebuggableStorage>
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> CloneableStorage for T
impl<T> CloneableStorage for T
fn clone_storage(&self) -> Box<dyn CloneableStorage>
impl<T> DebuggableStorage for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more