Skip to main content

AgentBuilder

Struct AgentBuilder 

Source
pub struct AgentBuilder { /* private fields */ }
Expand description

Ergonomic builder for Agent.

Holds the configured instruction (system-prompt fragment), tool set, model, and api key alongside the wrapped engine builder. Call with_defaults_for_data_dir to assemble the runtime dependencies, then build.

Implementations§

Source§

impl AgentBuilder

Source

pub fn new() -> AgentBuilder

Create an empty ergonomic builder.

Source

pub fn model(self, model: impl Into<String>) -> AgentBuilder

Set the primary model.

Source

pub fn provider_name(self, provider: impl Into<String>) -> AgentBuilder

Select the provider by name (anthropic, openai, gemini, copilot, bodhi) for with_defaults_for_data_dir, overriding config.json’s provider. A following api_key applies to this provider. The name is lower-cased (config matching is case-sensitive).

Note: this drives the eager provider creation inside with_defaults_for_data_dir and can fail there (e.g. missing key). A later provider injection replaces the created provider but does NOT skip creation — so if you inject your own provider, either don’t set provider_name, or ensure the named provider can still be constructed.

Source

pub fn instruction(self, instruction: impl Into<String>) -> AgentBuilder

Set the instruction — the caller’s portion of the system prompt. The engine assembles the complete prompt (tool guides, runtime context, …) around it at run time.

Source

pub fn tools<I>(self, tools: I) -> AgentBuilder
where I: IntoIterator<Item = Arc<dyn Tool>>,

Set the agent’s tool set — the actual tools it may use, as Arc<dyn Tool>. Built-ins come from the BuiltinTool catalog via BuiltinTool::tool; custom tools are any impl Tool wrapped in an Arc. Replaces any previous selection.

agent.tools([BuiltinTool::WebSearch.tool(), BuiltinTool::Read.tool()]);

Leaving this unset uses the full default built-in tool surface.

Source

pub fn tool<T>(self, tool: T) -> AgentBuilder
where T: Tool + 'static,

Add a single custom tool (anything implementing Tool) to the tool set.

Source

pub fn tool_shared(self, tool: Arc<dyn Tool>) -> AgentBuilder

Add a single pre-built shared tool — e.g. BuiltinTool::Read.tool() or a shared custom tool — to the tool set.

Source

pub fn api_key(self, api_key: impl Into<String>) -> AgentBuilder

Set the API key applied to the active provider’s config in with_defaults_for_data_dir.

Source

pub fn mcp_server(self, config: McpServerConfig) -> AgentBuilder

Connect an MCP server and merge its tools into the agent’s tool surface.

Only takes effect via with_defaults_for_data_dir, which starts every configured server (in call order) and composes their tools with the built-in surface via CompositeToolExecutor — built-ins are tried first, falling back to MCP on NotFound. Each server’s initialize instructions (if any) are folded into the tool guidance the engine injects into the system prompt automatically (no extra wiring needed).

A later tools/tool selection REPLACES the whole assembled executor at build time (existing behavior, unchanged by this method) — so an explicit tool selection currently excludes MCP tools. Select tools via allowed_tools on the server config instead if you need to restrict without losing MCP.

use bamboo_sdk::agent::McpServerConfig;
use bamboo_mcp::{StdioConfig, TransportConfig};

let agent = Agent::builder()
    .model("claude-sonnet-4-6")
    .mcp_server(McpServerConfig {
        id: "fs".into(),
        name: Some("filesystem".into()),
        enabled: true,
        transport: TransportConfig::Stdio(StdioConfig {
            command: "npx".into(),
            args: vec!["-y".into(), "@modelcontextprotocol/server-filesystem".into()],
            cwd: None,
            env: Default::default(),
            env_encrypted: Default::default(),
            startup_timeout_ms: 20_000,
        }),
        request_timeout_ms: 60_000,
        healthcheck_interval_ms: 30_000,
        reconnect: Default::default(),
        allowed_tools: Vec::new(),
        denied_tools: Vec::new(),
    })
    .with_defaults_for_data_dir(data_dir).await?
    .build()?;
Source

pub fn mcp_servers<I>(self, configs: I) -> AgentBuilder
where I: IntoIterator<Item = McpServerConfig>,

Connect multiple MCP servers. See mcp_server.

Source

pub fn permission_checker( self, checker: Arc<dyn PermissionChecker>, ) -> AgentBuilder

Gate the built-in tool executor behind a permission checker (e.g. bamboo_tools::permission::ConfigPermissionChecker).

Only takes effect via with_defaults_for_data_dir. The SDK’s historical default (no checker configured) is bypass everything — no tool call is ever gated — so this is purely opt-in; see bypass_permissions to make that intent explicit at the call site.

Once gated, a tool call that needs approval suspends the run (a NeedClarification/ToolApprovalRequested event, session pending_question set) exactly like a conclusion_with_options clarification — resolve it with Agent::answer.

Source

pub fn bypass_permissions(self) -> AgentBuilder

Explicitly request the SDK’s default: no permission checker, so every tool call runs unprompted. A no-op relative to never calling permission_checker — provided so callers can say what they mean instead of relying on silent default behavior.

Source

pub fn provider(self, provider: Arc<dyn LLMProvider>) -> AgentBuilder

Inject a pre-built LLM provider, bypassing config-driven creation.

Source

pub fn default_tools(self, tools: Arc<dyn ToolExecutor>) -> AgentBuilder

Inject a pre-built default tool executor.

Source

pub fn config(self, config: Arc<RwLock<Config>>) -> AgentBuilder

Inject a shared config handle.

Source

pub async fn with_defaults_for_data_dir( self, data_dir: PathBuf, ) -> Result<AgentBuilder, SdkError>

Assemble the eight runtime dependencies rooted at data_dir, using only the infrastructure / engine / tools layers (never bamboo-server):

  1. Config::from_data_dir(data_dir) (with api_key applied if set)
  2. SessionStoreV2storage + attachment_reader
  3. LockedSessionStorepersistence
  4. SkillManager (+ initialize)
  5. MetricsCollector::spawn(SqliteMetricsStorage)
  6. provider via create_provider_with_dir
  7. BuiltinToolExecutor::new_with_configdefault_tools

The engine builder is last-write-wins, so this method does NOT preserve dependencies set before it. Call with_defaults_for_data_dir FIRST, then override individual dependencies (e.g. provider) AFTER it to make those overrides take precedence.

§Precondition

<data_dir>/config.json must define the active provider with a non-empty api_key (the same config bamboo serve reads). A fresh data dir with no config.json defaults to the anthropic provider with no key, so step 6 (create_provider_with_dir) returns SdkError::ProviderInit. The copilot provider is the only one that can authenticate keyless (via its cached OAuth token). Set the key via the config file, or pass it on the builder with api_key before calling this method.

If mcp_server/mcp_servers were configured, each server is connected here (in call order) and its tools merged into the built-in tool surface; a connection failure fails the whole call with SdkError::McpServerStart. If permission_checker was configured, it gates the built-in tool executor from this point on.

Source

pub fn build(self) -> Result<Agent, SdkError>

Finalize into an Agent.

If a tool set was configured via tools / tool, the agent’s default tool executor is built from exactly those tools, so the advertised tool surface is precisely the caller’s selection (this REPLACES any MCP composition from mcp_server/mcp_servers — existing behavior, unchanged). With no selection, the full default built-in (+ MCP, if configured) surface is used. The configured instruction and model are carried onto the Agent for Agent::run.

Trait Implementations§

Source§

impl Default for AgentBuilder

Source§

fn default() -> AgentBuilder

Returns the “default value” for a type. Read more

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

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> NoneValue for T
where T: Default,

Source§

type NoneType = T

Source§

fn null_value() -> T

The none-equivalent value.
Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
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<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

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