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
impl AgentBuilder
Sourcepub fn new() -> AgentBuilder
pub fn new() -> AgentBuilder
Create an empty ergonomic builder.
Sourcepub fn model(self, model: impl Into<String>) -> AgentBuilder
pub fn model(self, model: impl Into<String>) -> AgentBuilder
Set the primary model.
Sourcepub fn provider_name(self, provider: impl Into<String>) -> AgentBuilder
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.
Sourcepub fn instruction(self, instruction: impl Into<String>) -> AgentBuilder
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.
Sourcepub fn tools<I>(self, tools: I) -> AgentBuilder
pub fn tools<I>(self, tools: I) -> AgentBuilder
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.
Sourcepub fn tool<T>(self, tool: T) -> AgentBuilderwhere
T: Tool + 'static,
pub fn tool<T>(self, tool: T) -> AgentBuilderwhere
T: Tool + 'static,
Add a single custom tool (anything implementing
Tool) to the tool set.
Add a single pre-built shared tool — e.g. BuiltinTool::Read.tool() or a
shared custom tool — to the tool set.
Sourcepub fn api_key(self, api_key: impl Into<String>) -> AgentBuilder
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.
Sourcepub fn mcp_server(self, config: McpServerConfig) -> AgentBuilder
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()?;Sourcepub fn mcp_servers<I>(self, configs: I) -> AgentBuilderwhere
I: IntoIterator<Item = McpServerConfig>,
pub fn mcp_servers<I>(self, configs: I) -> AgentBuilderwhere
I: IntoIterator<Item = McpServerConfig>,
Connect multiple MCP servers. See mcp_server.
Sourcepub fn permission_checker(
self,
checker: Arc<dyn PermissionChecker>,
) -> AgentBuilder
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.
Sourcepub fn bypass_permissions(self) -> AgentBuilder
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.
Sourcepub fn provider(self, provider: Arc<dyn LLMProvider>) -> AgentBuilder
pub fn provider(self, provider: Arc<dyn LLMProvider>) -> AgentBuilder
Inject a pre-built LLM provider, bypassing config-driven creation.
Sourcepub fn default_tools(self, tools: Arc<dyn ToolExecutor>) -> AgentBuilder
pub fn default_tools(self, tools: Arc<dyn ToolExecutor>) -> AgentBuilder
Inject a pre-built default tool executor.
Sourcepub fn config(self, config: Arc<RwLock<Config>>) -> AgentBuilder
pub fn config(self, config: Arc<RwLock<Config>>) -> AgentBuilder
Inject a shared config handle.
Sourcepub async fn with_defaults_for_data_dir(
self,
data_dir: PathBuf,
) -> Result<AgentBuilder, SdkError>
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):
Config::from_data_dir(data_dir)(withapi_keyapplied if set)SessionStoreV2→storage+attachment_readerLockedSessionStore→persistenceSkillManager(+initialize)MetricsCollector::spawn(SqliteMetricsStorage)- provider via
create_provider_with_dir BuiltinToolExecutor::new_with_config→default_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.
Sourcepub fn build(self) -> Result<Agent, SdkError>
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.