pub struct LoopConfig {Show 20 fields
pub stream: Arc<dyn StreamFn>,
pub tools: Arc<ToolRegistry>,
pub event_sink: Arc<dyn EventSink>,
pub protocol: Arc<dyn ProtocolPolicy>,
pub conversation_id: Option<String>,
pub model_id: Option<String>,
pub token_estimator: Arc<dyn TokenEstimator>,
pub default_execution_mode: ExecutionMode,
pub max_tool_calls_per_turn: Option<usize>,
pub temperature: Option<f32>,
pub max_output_tokens: Option<u32>,
pub reasoning: ReasoningEffort,
pub provider_extras: Option<Value>,
pub max_output_tokens_recovery: Option<MaxTokensRecovery>,
pub max_iterations: Option<usize>,
pub empty_outcome_retry_budget: Option<usize>,
pub plain_text_terminal_fallback_tool: Option<String>,
pub plain_text_terminal_fallback_eager: bool,
pub plain_text_terminal_fallback_eager_nudge: bool,
pub grace_iterations: usize,
/* private fields */
}Expand description
Assembled loop configuration. Construct via AgentBuilder.
The system prompt is run state, not builder configuration: callers
provide it through crate::types::AgentContext.
Fields§
§stream: Arc<dyn StreamFn>§tools: Arc<ToolRegistry>§event_sink: Arc<dyn EventSink>§protocol: Arc<dyn ProtocolPolicy>Conversation-protocol policy: the seam that supplies any
product-specific tool vocabulary (plain-text recovery prose,
tool-call alias repair, hidden-tool errors, terminal-tool
classification). Defaults to crate::DefaultProtocolPolicy,
whose behavior is generic and names no specific tools. Downstream
product crates install their own via
AgentBuilder::protocol_policy. See crate::protocol.
conversation_id: Option<String>Optional conversation identifier, surfaced to plugins via
ToolGateContext::conversation_id. The agent core itself does
not use this — it’s metadata for diagnostics and
conversation-scoped policy. None when the loop is invoked
outside a conversation context (tests, isolated subagent runs).
model_id: Option<String>Optional model identifier surfaced to plugins via
crate::plugin::TransformContext::model_id. The loop does not
use this directly — the active StreamFn already knows its
model. Plugins that key per-model behavior (cache-aware
compaction, model-specific token estimators, model-specific
system reminders) read it from here. None when the host
runtime doesn’t surface one.
token_estimator: Arc<dyn TokenEstimator>Token estimator the loop hands to context transforms. Defaults
to CharHeuristicEstimator; apps with a real tokenizer
implement TokenEstimator and supply their own via
AgentBuilder::token_estimator.
default_execution_mode: ExecutionModeDefault tool execution mode. A batch downgrades to Sequential
if any tool in it sets requires_exclusive_sandbox = true.
Set this to Sequential to pin the entire loop to sequential
dispatch regardless of per-tool flags (deterministic eval,
debugging, ordered replay).
max_tool_calls_per_turn: Option<usize>Optional hard cap on limit-counted tool calls executed from a
single assistant turn. When set to 1, the loop preserves every
emitted tool call in the assistant message, executes the first
limit-counted call plus any zero-weight progress signals, appends
synthetic error results for the rest, then asks the model to choose
the next action.
temperature: Option<f32>Optional sampling controls forwarded to the stream transport.
max_output_tokens: Option<u32>§reasoning: ReasoningEffortReasoning-effort knob forwarded to the stream transport on every
turn. The single source of truth for per-request reasoning effort:
the transport reads it here rather than from per-provider extras.
Default is ReasoningEffort::Minimal.
provider_extras: Option<Value>Provider-specific extras forwarded to the stream transport on
every turn (e.g., response_format for structured output
enforcement, custom routing pins). Passed as-is into
crate::StreamRequest::provider_extras; None sends
Value::Null.
max_output_tokens_recovery: Option<MaxTokensRecovery>Recovery strategy for StopReason::MaxTokens truncations. When
Some, the loop discards a truncated assistant turn and
re-streams with a larger cap up to max_attempts times before
accepting the truncated turn. Default None — today’s
behavior. Opt-in because the cost can be large (worst case
8× output tokens with Double × 3 attempts).
max_iterations: Option<usize>Hard ceiling on iterations within a single run. Prevents
runaway loops if neither the model nor tools ever vote to
terminate. None = unbounded.
empty_outcome_retry_budget: Option<usize>Number of no-tool assistant stops the loop may recover from
before treating another no-tool stop as a typed failure. None
preserves the generic core’s historical natural-stop behavior.
plain_text_terminal_fallback_tool: Option<String>Optional terminal-tool compatibility shim for providers that cannot
honor forced tool choice. When set, a non-empty plain assistant text
stop may be converted into this terminal tool result, but only on a
turn whose advertised tool allowlist has already been narrowed to
terminal delivery tools. Default None preserves the strict
“terminal text must arrive through a tool call” contract.
plain_text_terminal_fallback_eager: boolWhen true, Self::plain_text_terminal_fallback_tool fires on the
FIRST plain-text stop instead of waiting for the turn allowlist to
narrow to terminators. Intended for providers in the
“auto-when-forced” class where wire-level tool_choice: "required"
is rejected and so plain text is the model’s default failure mode —
there’s no benefit to running the narrowing-gate nudge cycle first
because the model will emit prose every time. Default false
preserves the post-narrowing gate for everyone else.
plain_text_terminal_fallback_eager_nudge: boolWhen true, the eager plain-text fallback path nudges the model with
an explicit protocol-recovery system message BEFORE synthesizing a
terminal tool result, giving the model a bounded number of retries
to follow the protocol. Only synthesizes as a last-resort after the
nudges are exhausted. Default false preserves the original
silent-synthesize behavior. Has no effect unless both
Self::plain_text_terminal_fallback_tool and
Self::plain_text_terminal_fallback_eager are set.
grace_iterations: usizeNumber of iterations before max_iterations at which the
graceful-turn-limit plugin injects a one-shot wrap-up steering
message. 0 disables the soft warning (behavior identical to
pre-grace versions). Has no effect when max_iterations is None.
Implementations§
Source§impl LoopConfig
impl LoopConfig
Sourcepub fn child_builder(&self) -> AgentBuilder
pub fn child_builder(&self) -> AgentBuilder
Build an AgentBuilder pre-populated for a child run spawned
from this config.
Inherits, by value or Arc:
- stream transport, tool registry, token estimator
- sampling controls (
temperature,max_output_tokens,reasoning) - max-output-tokens recovery ladder
- default execution mode,
max_tool_calls_per_turn - model id, grace iterations
- protocol policy (
ProtocolPolicy) - plain-text-terminal fallback knobs
- every plugin whose
crate::plugin::PluginCapabilities::inheritable_to_childbit is set
Does not inherit:
event_sink— callers install a child-scoped sink beforebuild.max_iterations— children get their own budget; defaults to unbounded until the caller sets one.empty_outcome_retry_budget— child runs make independent recovery decisions.conversation_id— the child should carry its own identity viacrate::AgentContext::identity.- plugins that did not opt in to inheritance — they remain parent-only.
This is the single primitive for “spawn a fresh child agent with the same execution shape as me.” A host runtime still registers any child-specific guards (delivery gates, terminal guards, etc.) on top of the returned builder.
Sourcepub fn plugin_names(&self) -> PluginNames
pub fn plugin_names(&self) -> PluginNames
Plugin names per category, in registration order. The composition order is part of the loop’s external contract — bridges and host runtimes assemble plugins in a specific order so transforms run before token-budget pruning, gates fire before terminator validation, etc. Tests use this to pin the assembled order so silent reorderings during refactors surface as a diff instead of a runtime regression.