Skip to main content

LoopConfig

Struct LoopConfig 

Source
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: ExecutionMode

Default 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: ReasoningEffort

Reasoning-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: bool

When 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: bool

When 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: usize

Number 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

Source

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_child bit is set

Does not inherit:

  • event_sink — callers install a child-scoped sink before build.
  • 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 via crate::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.

Source

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.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more