pub struct AgentRunnerBuilder<P: LlmProvider> { /* private fields */ }Expand description
Builder for AgentRunner.
Construct via AgentRunner::builder, configure the agent with chainable
setter methods, then call build to produce
the runner. Build validates several invariants: on_input and
structured_schema are mutually exclusive, max_tool_calls_per_turn = 0 is
rejected, and turn/token limits must be non-zero. For multi-agent scenarios
use OrchestratorBuilder
instead, which internally wraps an AgentRunner with sub-agent delegation.
Implementations§
Source§impl<P: LlmProvider> AgentRunnerBuilder<P>
impl<P: LlmProvider> AgentRunnerBuilder<P>
Sourcepub fn name(self, name: impl Into<String>) -> Self
pub fn name(self, name: impl Into<String>) -> Self
Set the agent’s name (used in logs, traces, and the orchestrator’s prompt).
Sourcepub fn system_prompt(self, prompt: impl Into<String>) -> Self
pub fn system_prompt(self, prompt: impl Into<String>) -> Self
Set the agent’s system prompt.
Sourcepub fn tools(self, tools: Vec<Arc<dyn Tool>>) -> Self
pub fn tools(self, tools: Vec<Arc<dyn Tool>>) -> Self
Register a batch of tools.
SECURITY (F-MCP-2): when MCP-discovered tools and builtins coexist,
register the trusted builtins first. The runner deduplicates by
name with first-wins semantics, so a hostile MCP server that exports a
tool named bash will be shadowed by the local bash builtin only if
the builtin was added before. The collision is logged at error! and
emits a tool_name_collision audit signal.
Sourcepub fn max_turns(self, max_turns: usize) -> Self
pub fn max_turns(self, max_turns: usize) -> Self
Cap on agent loop iterations before the runner aborts.
Sourcepub fn max_tokens(self, max_tokens: u32) -> Self
pub fn max_tokens(self, max_tokens: u32) -> Self
max_tokens cap on each LLM completion the runner issues.
Sourcepub fn context_strategy(self, strategy: ContextStrategy) -> Self
pub fn context_strategy(self, strategy: ContextStrategy) -> Self
Context window management strategy.
Sourcepub fn summarize_threshold(self, threshold: u32) -> Self
pub fn summarize_threshold(self, threshold: u32) -> Self
Set the token threshold at which to trigger automatic summarization.
Sourcepub fn context_window_tokens(self, tokens: u32) -> Self
pub fn context_window_tokens(self, tokens: u32) -> Self
Set the model context window (tokens) to enable the proactive compaction backstop (triggers on real prompt tokens crossing the threshold fraction).
Sourcepub fn compaction_threshold_fraction(self, fraction: f32) -> Self
pub fn compaction_threshold_fraction(self, fraction: f32) -> Self
Fraction of the context window at which to proactively compact (default 0.70).
Sourcepub fn memory(self, memory: Arc<dyn Memory>) -> Self
pub fn memory(self, memory: Arc<dyn Memory>) -> Self
Attach a memory store to the agent. Memory tools (store, recall, update,
forget, consolidate) are created at build() time using the builder’s name.
Call .name() before or after .memory() — the agent name is resolved at build.
Sourcepub fn knowledge(self, kb: Arc<dyn KnowledgeBase>) -> Self
pub fn knowledge(self, kb: Arc<dyn KnowledgeBase>) -> Self
Attach a knowledge base to the agent. The knowledge_search tool is
added at build() time.
Sourcepub fn on_text(self, callback: Arc<OnText>) -> Self
pub fn on_text(self, callback: Arc<OnText>) -> Self
Set a callback for streaming text output. When set, the agent uses
stream_complete instead of complete, calling the callback for each
text delta as it arrives from the LLM.
The callback must not panic. A panic inside the callback will propagate through the agent loop and abort the run.
Sourcepub fn on_reasoning(self, callback: Arc<OnReasoning>) -> Self
pub fn on_reasoning(self, callback: Arc<OnReasoning>) -> Self
Set a callback invoked with each reasoning (chain-of-thought) delta during
streaming, for reasoning models. Separate from on_text
so a UI can render thinking live and distinctly from the answer. Only
honored on the streaming path (when on_text is also set).
Sourcepub fn on_approval(self, callback: Arc<OnApproval>) -> Self
pub fn on_approval(self, callback: Arc<OnApproval>) -> Self
Set a callback for human-in-the-loop approval before tool execution.
When set, the callback is invoked with the list of tool calls before
each execution round. If it returns false, tool execution is denied
and the agent receives error results, allowing the LLM to adjust.
Sourcepub fn tool_timeout(self, timeout: Duration) -> Self
pub fn tool_timeout(self, timeout: Duration) -> Self
Set a timeout for individual tool executions. If a tool does not complete within this duration, the execution is cancelled and an error result is returned to the LLM.
Default: None (no timeout).
Sourcepub fn max_tool_output_bytes(self, max: usize) -> Self
pub fn max_tool_output_bytes(self, max: usize) -> Self
Set a maximum byte size for individual tool output content.
Tool results exceeding this limit are truncated with a
[truncated: N bytes omitted] suffix, preventing oversized results
from blowing out the context window.
Default: None (no truncation).
Sourcepub fn structured_schema(self, schema: Value) -> Self
pub fn structured_schema(self, schema: Value) -> Self
Set a JSON Schema for structured output. The agent will receive a
synthetic __respond__ tool with this schema. When the LLM calls
__respond__, its input is extracted as AgentOutput::structured.
The agent can still use regular tools before producing output.
Sourcepub fn on_event(self, callback: Arc<OnEvent>) -> Self
pub fn on_event(self, callback: Arc<OnEvent>) -> Self
Set a callback for structured agent events. Events are emitted at key points in the agent loop: run start/end, turn transitions, LLM responses, tool call start/completion, approval decisions, and context summarization.
Sourcepub fn guardrail(self, guardrail: Arc<dyn Guardrail>) -> Self
pub fn guardrail(self, guardrail: Arc<dyn Guardrail>) -> Self
Add a single guardrail. Multiple guardrails are evaluated in order;
first Deny wins.
Sourcepub fn guardrails(self, guardrails: Vec<Arc<dyn Guardrail>>) -> Self
pub fn guardrails(self, guardrails: Vec<Arc<dyn Guardrail>>) -> Self
Add multiple guardrails at once.
Sourcepub fn on_question(self, callback: Arc<OnQuestion>) -> Self
pub fn on_question(self, callback: Arc<OnQuestion>) -> Self
Set a callback for structured questions to the user. When set, a
question tool is added at build() time allowing the agent to
ask the user structured questions with predefined options.
Sourcepub fn on_input(self, callback: Arc<OnInput>) -> Self
pub fn on_input(self, callback: Arc<OnInput>) -> Self
Set a callback for interactive mode. When set and the LLM returns
text without tool calls, the callback is invoked to get the next
user message. Return Some(message) to continue the conversation
or None to end the session.
Sourcepub fn interrupt(self, handle: InterruptHandle) -> Self
pub fn interrupt(self, handle: InterruptHandle) -> Self
Attach a re-armable interrupt handle. Triggering it abandons the in-flight
turn (aborting LLM generation) and returns to awaiting input, preserving the
session. Only meaningful with on_input (the interactive path).
Sourcepub fn run_timeout(self, timeout: Duration) -> Self
pub fn run_timeout(self, timeout: Duration) -> Self
Set a wall-clock deadline for the entire run. If the agent does not
complete within this duration, Error::RunTimeout is returned.
Default: None (no deadline).
Sourcepub fn reasoning_effort(self, effort: ReasoningEffort) -> Self
pub fn reasoning_effort(self, effort: ReasoningEffort) -> Self
Set the reasoning/thinking effort level. Enables extended thinking on models that support it (e.g., Qwen3 via OpenRouter, Claude).
Default: None (no reasoning).
Sourcepub fn enable_reflection(self, enabled: bool) -> Self
pub fn enable_reflection(self, enabled: bool) -> Self
Enable post-tool reflection prompts (Reflexion/CRITIC pattern).
Sourcepub fn tool_output_compression_threshold(self, threshold: usize) -> Self
pub fn tool_output_compression_threshold(self, threshold: usize) -> Self
Byte threshold above which tool output is compressed via an LLM call.
Sourcepub fn tool_result_ingest_cap(self, bytes: usize) -> Self
pub fn tool_result_ingest_cap(self, bytes: usize) -> Self
Hard cap (bytes) applied to each fresh tool result entering the
conversation context. Defaults to 256KB; oversized results are truncated
with a marker (restorable via fetch_full_output when a context recall
store is wired).
Sourcepub fn delegation_nudge(self, nudge: DelegationNudge) -> Self
pub fn delegation_nudge(self, nudge: DelegationNudge) -> Self
Deterministic delegation nudge: after nudge.after_tool_calls direct
tool calls on one user request with none of nudge.tool_names used,
inject a one-shot reminder to delegate. See
super::runner::DelegationNudge.
Sourcepub fn request_router(self, router: Arc<RequestRouter>) -> Self
pub fn request_router(self, router: Arc<RequestRouter>) -> Self
Enable the request-intent router: each fresh request is routed to a
response mode (answer/execute/study/clarify) and the harness enforces
the mode contract (tool masking + execution deny). See
super::router::RequestRouter.
Sourcepub fn max_tools_per_turn(self, max: usize) -> Self
pub fn max_tools_per_turn(self, max: usize) -> Self
Cap on tool definitions sent to the LLM per turn (dynamic tool selection).
Sourcepub fn tool_profile(self, profile: ToolProfile) -> Self
pub fn tool_profile(self, profile: ToolProfile) -> Self
Set a static tool profile to pre-filter tools before dynamic selection.
When set, tool definitions are filtered to the profile’s subset before
max_tools_per_turn scoring applies. Use ToolProfile::Conversational
for chat-only agents, Standard for code agents, Full for all tools.
Sourcepub fn max_identical_tool_calls(self, max: u32) -> Self
pub fn max_identical_tool_calls(self, max: u32) -> Self
Set the maximum number of consecutive identical tool-call turns before the agent receives an error result instead of executing the tools.
This detects “doom loops” where the LLM keeps repeating the exact same
tool calls. After max consecutive identical turns, all tool calls in
the turn receive an error result asking the LLM to try a different approach.
Default: None (no detection).
Sourcepub fn max_fuzzy_identical_tool_calls(self, max: u32) -> Self
pub fn max_fuzzy_identical_tool_calls(self, max: u32) -> Self
Set the maximum number of consecutive fuzzy-identical tool-call turns before the agent receives an error result. Fuzzy matching compares sorted tool names (ignoring inputs), catching loops where the agent retries the same tools with different arguments.
Default: None (no fuzzy detection).
Sourcepub fn max_tool_calls_per_turn(self, cap: u32) -> Self
pub fn max_tool_calls_per_turn(self, cap: u32) -> Self
Cap the number of tool invocations the LLM may emit per turn.
When the LLM returns more tool_use blocks than cap, the run
returns Error::Agent (wrapped in Error::WithPartialUsage) and
no tools are dispatched.
Distinct from max_tools_per_turn: that one limits the tool
definitions offered to the LLM before it responds (pre-filter).
This one caps the invocations in the LLM’s actual response
(post-response). Both can be set independently.
Default: None (unlimited). Recommended for production: 8.
Zero is rejected at build time.
Sourcepub fn permission_rules(self, rules: PermissionRuleset) -> Self
pub fn permission_rules(self, rules: PermissionRuleset) -> Self
Set declarative permission rules for tool calls.
Rules are evaluated per tool call before the on_approval callback.
Allow executes without asking, Deny returns an error result,
Ask falls through to the on_approval callback.
Sourcepub fn learned_permissions(
self,
learned: Arc<Mutex<LearnedPermissions>>,
) -> Self
pub fn learned_permissions( self, learned: Arc<Mutex<LearnedPermissions>>, ) -> Self
Set learned permissions for persisting AlwaysAllow/AlwaysDeny decisions.
When set, approval decisions with AlwaysAllow or AlwaysDeny are
saved to disk and injected into the live permission ruleset.
Sourcepub fn lsp_manager(self, manager: Arc<LspManager>) -> Self
pub fn lsp_manager(self, manager: Arc<LspManager>) -> Self
Set an LSP manager for collecting diagnostics after file-modifying tools.
When set, after any tool named write, edit, or patch completes,
the manager reads the modified file and collects diagnostics from the
language server. Diagnostics are appended to the tool result so the
LLM sees compilation errors immediately.
Sourcepub fn session_prune_config(self, config: SessionPruneConfig) -> Self
pub fn session_prune_config(self, config: SessionPruneConfig) -> Self
Enable session pruning to reduce token usage by truncating old tool results.
Sourcepub fn enable_recursive_summarization(self, enable: bool) -> Self
pub fn enable_recursive_summarization(self, enable: bool) -> Self
Enable recursive (cluster-then-summarize) summarization for long conversations.
Sourcepub fn reflection_threshold(self, threshold: u32) -> Self
pub fn reflection_threshold(self, threshold: u32) -> Self
Set cumulative importance threshold for memory reflection triggers. When the sum of stored memory importance values exceeds this threshold, the store tool appends a reflection hint to guide the agent.
Sourcepub fn consolidate_on_exit(self, enable: bool) -> Self
pub fn consolidate_on_exit(self, enable: bool) -> Self
Enable automatic memory consolidation at session end.
When enabled, clusters related episodic memories by keyword overlap and merges them into semantic summaries. Requires memory to be configured. Adds LLM calls at session end (one per cluster).
Sourcepub fn observability_mode(self, mode: ObservabilityMode) -> Self
pub fn observability_mode(self, mode: ObservabilityMode) -> Self
Set the observability verbosity mode for this agent.
Controls how much detail is recorded in tracing spans:
Production: span names + durations only (near-zero overhead)Analysis: + metrics (tokens, latencies, costs)Debug: + full payloads (truncated to 4KB)
When not set, resolved via HEARTBIT_OBSERVABILITY env var or default (Production).
Sourcepub fn instruction_text(self, text: impl Into<String>) -> Self
pub fn instruction_text(self, text: impl Into<String>) -> Self
Provide pre-loaded instruction text to prepend to the system prompt.
Use instructions::load_instructions to load from file paths, or
instructions::discover_instruction_files to auto-discover them.
Sourcepub fn max_total_tokens(self, max: u64) -> Self
pub fn max_total_tokens(self, max: u64) -> Self
Set a hard limit on cumulative tokens (input + output) across all turns.
When the total tokens consumed exceed this limit, the agent returns
Error::BudgetExceeded with partial usage data.
Default: None (no budget).
Sourcepub fn goal(self, goal: GoalCondition) -> Self
pub fn goal(self, goal: GoalCondition) -> Self
Set a persistent GoalCondition: after the
agent would naturally finish, an INDEPENDENT judge decides whether the
objective is met. If not, the judge’s reason is re-injected and the agent
continues (bounded by the goal’s max_continuations and the agent’s
max_turns). AgentOutput::goal_met
records the outcome.
Sourcepub fn goal_slot(self, slot: GoalSlot) -> Self
pub fn goal_slot(self, slot: GoalSlot) -> Self
Share an externally owned GoalSlot with this
runner — the set_goal tool holds the same slot and can install or
replace the goal at runtime. Takes precedence over Self::goal as
the storage (a goal() value seeds the slot only if the slot is empty).
Sourcepub fn audit_mode(self, mode: AuditMode) -> Self
pub fn audit_mode(self, mode: AuditMode) -> Self
Set the audit mode controlling what data is stored in audit records.
Full(default): all content is recorded.MetadataOnly: user content fields are replaced with[stripped].
Sourcepub fn audit_trail(self, trail: Arc<dyn AuditTrail>) -> Self
pub fn audit_trail(self, trail: Arc<dyn AuditTrail>) -> Self
Attach an audit trail for recording untruncated agent decisions.
When set, every LLM response, tool call, tool result, run completion, run failure, and guardrail denial is recorded with full payloads. Recording is best-effort: failures are logged, never abort the agent.
Sourcepub fn audit_user_context(
self,
user_id: impl Into<String>,
tenant_id: impl Into<String>,
) -> Self
pub fn audit_user_context( self, user_id: impl Into<String>, tenant_id: impl Into<String>, ) -> Self
Set user context for multi-tenant audit enrichment.
When set, all AuditRecord entries include the user and tenant IDs.
Sourcepub fn audit_delegation_chain(self, chain: Vec<String>) -> Self
pub fn audit_delegation_chain(self, chain: Vec<String>) -> Self
Set the delegation chain for audit records.
Populated when the daemon acts on behalf of a user via RFC 8693 token exchange. The chain records which agent(s) are in the delegation path.
Sourcepub fn response_cache_size(self, size: usize) -> Self
pub fn response_cache_size(self, size: usize) -> Self
Enable an LRU response cache with the given maximum number of entries. Identical requests (same system prompt, messages, and tool names) return cached responses without calling the LLM. Only non-streaming calls are cached. Size must be at least 1.
Sourcepub fn workspace(self, path: impl Into<PathBuf>) -> Self
pub fn workspace(self, path: impl Into<PathBuf>) -> Self
Set the agent’s workspace directory. When set, file tools resolve relative paths against this directory, BashTool starts here, and a workspace hint is appended to the system prompt.
Sourcepub fn tenant_tracker(self, tracker: Arc<TenantTokenTracker>) -> Self
pub fn tenant_tracker(self, tracker: Arc<TenantTokenTracker>) -> Self
Optional per-tenant in-flight token tracker. When set, the runner
calls tracker.adjust(&scope, delta) after each LLM response,
reconciling the per-tenant in_flight counter against the
estimated reservation made at submit time. Has no effect when
audit_tenant_id is unset.
Sourcepub fn context_recall_store(self, store: Arc<ContextRecallStore>) -> Self
pub fn context_recall_store(self, store: Arc<ContextRecallStore>) -> Self
Enable restore-on-demand: share a ContextRecallStore so tool outputs are
indexed for fetch_full_output / recall_context. Pass the SAME store
into BuiltinToolsConfig.context_recall_store so the tools are registered.
Sourcepub fn todo_store(self, store: Arc<TodoStore>) -> Self
pub fn todo_store(self, store: Arc<TodoStore>) -> Self
Set the shared TodoStore so the
runner recites open plan items at the context tail each turn. Pass the
SAME store that backs the todowrite/todoread tools.
Sourcepub fn replan_on_verify_fail(self, enabled: bool) -> Self
pub fn replan_on_verify_fail(self, enabled: bool) -> Self
When enabled, a RED verification (VERIFY_RESULT: FAIL as the latest
canonical sentinel) blocks natural completion: the runner re-injects a
corrective nudge and continues (bounded) instead of declaring done on
red. Long-horizon “replan on out-of-plan” for the no-goal path.
Sourcepub fn build(self) -> Result<AgentRunner<P>, Error>
pub fn build(self) -> Result<AgentRunner<P>, Error>
Validate the builder and produce a ready-to-run AgentRunner.
Returns Error::Config for mis-configured runners (empty name, zero max_turns,
mutually-exclusive options like on_input + structured_schema, etc.).