pub struct Agent { /* private fields */ }Expand description
Manages provider, tool registry, state, and compaction, providing an agentic loop for prompt execution, model switching, tool calls, and fallback.
Supports session continuation, tokio-native event streaming, and deferred model switching (changes are queued while a loop is running and applied after it completes).
Implementations§
Source§impl Agent
impl Agent
Sourcepub fn new(
provider: Arc<dyn Provider>,
config: AgentConfig,
tools: Arc<ToolRegistry>,
) -> Agent
pub fn new( provider: Arc<dyn Provider>, config: AgentConfig, tools: Arc<ToolRegistry>, ) -> Agent
Create a new agent with the given provider, config, and tool registry.
Uses the global oxicode_ai::get_provider() / resolve_model_from_id()
for model switching. For isolated instances, use new_with_resolver.
Sourcepub fn new_with_resolver(
provider: Arc<dyn Provider>,
config: AgentConfig,
tools: Arc<ToolRegistry>,
resolver: Arc<dyn ProviderResolver>,
) -> Agent
pub fn new_with_resolver( provider: Arc<dyn Provider>, config: AgentConfig, tools: Arc<ToolRegistry>, resolver: Arc<dyn ProviderResolver>, ) -> Agent
Create an agent with a custom provider/model resolver.
This is the preferred constructor for SDK usage where provider and model registries must be isolated from global state.
Sourcepub fn new_with_compactor(
provider: Arc<dyn Provider>,
config: AgentConfig,
tools: Arc<ToolRegistry>,
resolver: Arc<dyn ProviderResolver>,
custom_compactor: Option<Arc<dyn Compactor>>,
) -> Agent
pub fn new_with_compactor( provider: Arc<dyn Provider>, config: AgentConfig, tools: Arc<ToolRegistry>, resolver: Arc<dyn ProviderResolver>, custom_compactor: Option<Arc<dyn Compactor>>, ) -> Agent
Create an agent with a custom provider/model resolver and a custom compactor that replaces the default LLM compactor.
The compactor is threaded into every per-run AgentLoop (via
AgentLoopConfig.compactor) — see
crate::agent_loop::config::AgentLoopConfig::compactor for the
replace semantics. oxicode-sdk’s AgentBuilder::with_compactor
uses this constructor.
Sourcepub fn new_empty(provider: Arc<dyn Provider>, config: AgentConfig) -> Agent
pub fn new_empty(provider: Arc<dyn Provider>, config: AgentConfig) -> Agent
Create an agent with an empty tool registry.
Sourcepub fn get_config(&self) -> AgentConfig
pub fn get_config(&self) -> AgentConfig
Get the agent configuration (full clone)
Sourcepub fn todo_provider(&self) -> Option<Arc<dyn TodoStateProvider>>
pub fn todo_provider(&self) -> Option<Arc<dyn TodoStateProvider>>
Get a cheap clone of the configured todo state provider, if any.
Used by hosts (e.g. the TUI) to observe todo phase changes without
cloning the full AgentConfig.
Sourcepub fn resolver(&self) -> &Arc<dyn ProviderResolver> ⓘ
pub fn resolver(&self) -> &Arc<dyn ProviderResolver> ⓘ
Get a reference to the provider resolver.
Sourcepub fn switch_model(&self, model_id: &str) -> Result<(), Error>
pub fn switch_model(&self, model_id: &str) -> Result<(), Error>
Switch the model used for future LLM calls.
Switch model mid-conversation.
If the agent is currently running, the switch is deferred: the new
model and provider are stored in pending_model_switch and applied
automatically when the current loop finishes. This ensures the
running loop completes with a consistent provider/model without
interruption.
If the agent is idle, the switch takes effect immediately.
If the new model uses a different provider API, the conversation
history is automatically transformed for cross-provider compatibility
(e.g. thinking blocks are converted to <thinking> tags).
§Arguments
model_id- New model ID inprovider/modelformat
§Returns
Ok(()) on success, or an error if the model/provider is unknown
§Credentials
The new provider is constructed via ProviderResolver::resolve_provider,
which is the single credential authority — the wired AuthProvider
port (sync fast-path) supplies the API key. The old api_key parameter
was removed in 0.55.0; see issues #39 and #40.
Sourcepub fn switch_to_model(&self, model: &Model) -> Result<(), Error>
pub fn switch_to_model(&self, model: &Model) -> Result<(), Error>
Switch the model using a pre-resolved Model object.
This is useful when the caller has already looked up the model and optionally created the provider.
Like switch_model, if the agent is currently running, the switch
is deferred until the current loop completes.
§Credentials
The new provider is constructed via ProviderResolver::resolve_provider,
the single credential authority (sync AuthProvider fast-path).
The old api_key parameter was removed in 0.55.0; see issues #39/#40.
Sourcepub fn refresh_credentials(&self) -> Result<(), Error>
pub fn refresh_credentials(&self) -> Result<(), Error>
Refresh credentials by re-resolving the current provider via the resolver.
After the resolver-centric credential model (0.55.0), the provider
instance is the single source of truth for API keys. To pick up
credential changes — e.g. the user updated their auth store via the
TUI overlay — call this to re-resolve the current provider and swap
it in. The resolver consults the wired AuthProvider port on every
call, so updates are reflected without rebuilding the engine.
Returns Ok(()) if a fresh provider was resolved and swapped, or an
error if the resolver could not produce a provider (the existing
provider is left untouched on error). Replaces the deprecated
refresh_api_key(&self, api_key) from pre-0.55.0; see issues #39/#40.
Sourcepub fn tools(&self) -> Arc<ToolRegistry> ⓘ
pub fn tools(&self) -> Arc<ToolRegistry> ⓘ
Get a handle to the tool registry.
Sourcepub fn state(&self) -> AgentState
pub fn state(&self) -> AgentState
Get a snapshot of the current agent state.
Sourcepub fn update_state(&self, f: impl FnOnce(&mut AgentState))
pub fn update_state(&self, f: impl FnOnce(&mut AgentState))
Update agent state in-place. Used by compaction to replace messages.
Sourcepub fn add_tool<T>(&self, tool: T)where
T: AgentTool + 'static,
pub fn add_tool<T>(&self, tool: T)where
T: AgentTool + 'static,
Register a tool that the agent can invoke during a run.
Sourcepub fn set_system_prompt(&self, prompt: String)
pub fn set_system_prompt(&self, prompt: String)
Update the system prompt for future interactions.
Sourcepub fn compaction_manager(&self) -> &CompactionManager
pub fn compaction_manager(&self) -> &CompactionManager
Get the compaction manager
Sourcepub fn set_compaction_strategy(&self, strategy: CompactionStrategy)
pub fn set_compaction_strategy(&self, strategy: CompactionStrategy)
Update the compaction strategy for future runs.
The strategy is read fresh from the config at the start of each run
(see run_with_channel_inner), so this takes effect on the next
agent turn — never mid-run. Pair with compaction_manager() for
manual compaction, which is unaffected by the strategy.
Sourcepub fn compaction_strategy(&self) -> CompactionStrategy
pub fn compaction_strategy(&self) -> CompactionStrategy
Get the compaction strategy that will be used on the next run.
This reads from inner.config (mutable via set_compaction_strategy),
not from the compaction_manager field (which retains its
construction-time strategy). The agent loop reads from config fresh
each run, so this is the authoritative value.
Sourcepub async fn run(
&self,
prompt: String,
) -> Result<(Response, Vec<AgentEvent>), Error>
pub async fn run( &self, prompt: String, ) -> Result<(Response, Vec<AgentEvent>), Error>
Run the agent with a prompt, collecting all events into a vector.
Convenience wrapper around run_with_channel that gathers every
AgentEvent produced during the run.
Sourcepub async fn run_with_channel(
&self,
prompt: String,
tx: Sender<AgentEvent>,
) -> Result<Response, Error>
pub async fn run_with_channel( &self, prompt: String, tx: Sender<AgentEvent>, ) -> Result<Response, Error>
Run the agent, delivering events through the provided channel.
Delegates to the agent loop which implements the same 2-level agentic loop matching pi-mono’s architecture:
AgentLoop.run_messages()
Outer loop (follow-up messages):
Inner loop (tool calls + steering):
1. Inject pending messages (steering)
2. Compaction check
3. Stream LLM response (with accumulated partial messages)
4. Execute tool calls if any
5. Emit turn_end
6. Check shouldStopAfterTurn
7. Poll steering messages
Check follow-up messages
ExitSourcepub async fn run_with_channel_message(
&self,
prompt: Message,
tx: Sender<AgentEvent>,
) -> Result<Response, Error>
pub async fn run_with_channel_message( &self, prompt: Message, tx: Sender<AgentEvent>, ) -> Result<Response, Error>
Run with an explicit user Message (supports image content blocks).
Used by RPC prompt with images. The running-guard logic lives here;
run_with_channel delegates after converting
its String prompt into a text-only user message.
Sourcepub fn set_hooks(&self, hooks: AgentHooks)
pub fn set_hooks(&self, hooks: AgentHooks)
Set hooks for the agent loop.
Sourcepub fn add_observability_dispatch(
&self,
f: impl Fn(AgentEvent) + Send + Sync + 'static,
)
pub fn add_observability_dispatch( &self, f: impl Fn(AgentEvent) + Send + Sync + 'static, )
Register a side-dispatch closure called for every AgentEvent
emitted by run, run_with_channel, run_streaming,
run_tokio_stream, and continue_with.
Multiple calls stack: every registered closure is invoked on
every event. Closures run synchronously on the agent-loop emit
thread, so they must be cheap and non-blocking. Long work
should be spawned off (e.g. tokio::spawn) by the closure
itself.
Used by oxicode-sdk to bridge observability types
(Tracer, CostTracker, AuditLog, Authorizer /
AccessGate) into the runtime without leaking those types
into oxicode-agent.
§Example
agent.add_observability_dispatch(|event| match event {
AgentEvent::TurnStart { turn_number } => {
// open a span
}
AgentEvent::Usage { input_tokens, output_tokens } => {
// record cost
}
_ => {}
});Sourcepub fn cancel(&self)
pub fn cancel(&self)
Request cancellation of the current agent run.
Sets a shared cancel_flag that is propagated to the AgentLoop’s
external_stop on every event AND polled every ~500ms by the
streaming loop’s periodic check. This ensures cancellation is
detected quickly even when the provider stream is completely hung
(no events arriving).
Sourcepub fn set_auto_retry(&self, enabled: bool)
pub fn set_auto_retry(&self, enabled: bool)
Toggle auto-retry at runtime (affects the next retry decision in an
active run; does not interrupt an in-progress retry sleep — use
Self::cancel_auto_retry for that).
Sourcepub fn cancel_auto_retry(&self)
pub fn cancel_auto_retry(&self)
Abort any in-progress auto-retry wait immediately. The running turn ends without retrying the error.
Sourcepub fn reset_cancel(&self)
pub fn reset_cancel(&self)
Reset the cancellation flag before starting a new run.
Sourcepub async fn run_streaming<F>(
&self,
prompt: String,
on_event: F,
) -> Result<Response, Error>
pub async fn run_streaming<F>( &self, prompt: String, on_event: F, ) -> Result<Response, Error>
Run the agent, invoking on_event for each AgentEvent produced.
Blocking convenience wrapper suitable for callers that prefer a callback-based API over a channel.
Sourcepub fn export_state(&self) -> Result<Value, Error>
pub fn export_state(&self) -> Result<Value, Error>
Export the agent state as a JSON value.
The serialized state includes conversation messages, token counts,
iteration progress, and stop reason. Use import_state to restore.
Sourcepub fn import_state(&self, value: Value) -> Result<(), Error>
pub fn import_state(&self, value: Value) -> Result<(), Error>
Import agent state from a JSON value.
Restores conversation history, token counts, and iteration progress.
Typically used together with export_state for session persistence.
Sourcepub async fn continue_with(
&self,
prompt: String,
) -> Result<(Response, Vec<AgentEvent>), Error>
pub async fn continue_with( &self, prompt: String, ) -> Result<(Response, Vec<AgentEvent>), Error>
Continue the current session with a new prompt.
Unlike run(), which can be used on a fresh agent, continue_with
preserves the existing conversation state and appends the new prompt.
This enables multi-turn interactions within the same session.
Sourcepub async fn run_tokio_stream(
&self,
prompt: String,
) -> Result<(Receiver<AgentEvent>, JoinHandle<Result<Response, Error>>), Error>
pub async fn run_tokio_stream( &self, prompt: String, ) -> Result<(Receiver<AgentEvent>, JoinHandle<Result<Response, Error>>), Error>
Run the agent with tokio-native event streaming.
Returns a tokio::sync::mpsc::Receiver for events and a
JoinHandle for the response. This is the preferred API for
async runtimes (WebSocket/SSE gateways, tokio-based servers).
§Example
let (rx, handle) = agent.run_tokio_stream("Explain Rust".into()).await?;
while let Some(event) = rx.recv().await {
println!("Event: {:?}", event.type_name());
}
let response = handle.await??;