Skip to main content

AgentCore

Struct AgentCore 

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

AgentCore - Core runtime infrastructure for LLM-powered agents.

AgentCore provides all the infrastructure needed for an LLM-powered agent:

  • Logging with tracing
  • LLM configuration loading
  • Tokio async runtime
  • LLMController for session management
  • Communication channels
  • User interaction and permission registries

This is the runtime-only version. For TUI support, use the agent-core crate with the tui feature enabled, which provides the run() method.

§Basic Usage (Headless)

use agent_core_runtime::agent::{AgentConfig, AgentCore};

struct MyConfig;
impl AgentConfig for MyConfig {
    fn config_path(&self) -> &str { ".myagent/config.yaml" }
    fn default_system_prompt(&self) -> &str { "You are helpful." }
    fn log_prefix(&self) -> &str { "myagent" }
    fn name(&self) -> &str { "MyAgent" }
}

fn main() -> std::io::Result<()> {
    let mut core = AgentCore::new(&MyConfig)?;
    core.start_background_tasks();

    // Get channels for custom frontend integration
    let tx = core.to_controller_tx();
    let rx = core.take_from_controller_rx();

    // Create a session and interact programmatically
    let (session_id, model, _) = core.create_initial_session()?;
    // ... send messages and receive responses via channels

    core.shutdown();
    Ok(())
}

Implementations§

Source§

impl AgentCore

Source

pub fn new<C>(config: &C) -> Result<AgentCore, Error>
where C: AgentConfig,

Create a new AgentCore with the given configuration.

This initializes:

  • Logging infrastructure
  • LLM configuration from config file or environment
  • Tokio runtime
  • Communication channels
  • LLMController
  • User interaction and permission registries
Source

pub fn with_config( name: impl Into<String>, config_path: impl Into<String>, system_prompt: impl Into<String>, ) -> Result<AgentCore, Error>

Create a new AgentCore with simple configuration parameters.

This is a convenience constructor for quick agent setup without defining a custom config struct.

§Arguments
  • name - Agent name for display (e.g., “my-agent”)
  • config_path - Path to config file (e.g., “~/.config/my-agent/config.yaml”)
  • system_prompt - Default system prompt for the agent
§Example
use agent_core::agent::AgentCore;
use agent_core::tui::AgentCoreExt;

AgentCore::with_config("my-agent", "~/.config/my-agent/config.yaml", "You are helpful.")?
    .into_tui()
    .run()
Source

pub fn set_error_no_session( &mut self, message: impl Into<String>, ) -> &mut AgentCore

Set the error message shown when user submits but no session exists.

This overrides the default message “No active session. Use /new-session to create one.”

§Example
agent.set_error_no_session("No configuration found in ~/.myagent/config.yaml");
Source

pub fn error_no_session(&self) -> Option<&str>

Get the error message for no session, if set.

Source

pub fn set_version(&mut self, version: impl Into<String>)

Set the agent version for display.

Source

pub fn version(&self) -> &str

Get the agent version.

Source

pub fn load_environment_context(&mut self) -> &mut AgentCore

Load environment context into the system prompt.

This adds information about the current execution environment to all LLM session prompts:

  • Current working directory
  • Platform (darwin, linux, windows)
  • OS version
  • Today’s date

The context is wrapped in <env> tags and appended to the system prompt.

§Example
let mut core = AgentCore::new(&config)?;
core.load_environment_context();
Source

pub fn register_tools<F>(&mut self, f: F) -> Result<(), AgentError>

Register tools with the agent.

The callback receives references to the tool registry and interaction registries, and should return the tool definitions to register.

§Example
core.register_tools(|registry, user_reg, perm_reg| {
    tools::register_all_tools(registry, user_reg, perm_reg)
})?;
Source

pub fn register_tools_async<F, Fut>(&mut self, f: F) -> Result<(), AgentError>

Register tools with the agent using an async function.

Similar to register_tools, but accepts an async closure. The closure is executed using the agent’s tokio runtime via block_on.

§Example
core.register_tools_async(|registry, user_reg, perm_reg| async move {
    tools::register_all_tools(&registry, user_reg, perm_reg).await
})?;
Source

pub fn start_background_tasks(&mut self)

Start the controller and input router as background tasks.

This must be called before sending messages or creating sessions. After calling this, the controller is running and ready to accept input.

Source

pub fn create_initial_session( &mut self, ) -> Result<(i64, String, i32), AgentError>

Create an initial session using the default LLM provider.

Returns the session ID, model name, and context limit.

Source

pub fn create_session( &self, config: LLMSessionConfig, ) -> Result<i64, AgentError>

Create a session with the given configuration.

Returns the session ID or an error.

Source

pub fn shutdown(&self)

Signal shutdown to all background tasks and the controller.

Source

pub fn run_with_frontend<E, I, P>( &mut self, event_sink: E, input_source: I, permission_policy: P, ) -> Result<(), Error>

Run the agent with a custom frontend.

This is the primary entry point for custom frontends. It:

  1. Starts background tasks (controller, input router)
  2. Wires the event sink to receive engine events
  3. Wires the input source to provide user input
  4. Applies the permission policy
  5. Runs until the input source closes
§Arguments
  • event_sink - Receives events from the engine
  • input_source - Provides input to the engine
  • permission_policy - Handles permission requests
§Example: Headless with Auto-Approve
use agent_core_runtime::agent::{
    AgentCore, AutoApprovePolicy, StdoutEventSink, ChannelInputSource
};

let mut agent = AgentCore::with_config(
    "my-agent",
    "~/.config/my-agent/config.yaml",
    "You are helpful."
)?;

// Create input channel
let (input_tx, input_source) = ChannelInputSource::channel(100);

// Run with custom frontend (blocks until input_tx is dropped)
agent.run_with_frontend(
    StdoutEventSink::new(),
    input_source,
    AutoApprovePolicy::new(),
)?;
Source

pub fn to_controller_tx(&self) -> Sender<ControllerInputPayload>

Returns a sender for sending messages to the controller.

Source

pub fn take_from_controller_rx(&mut self) -> Option<Receiver<UiMessage>>

Takes the receiver for messages from the controller (can only be called once).

Source

pub fn controller(&self) -> &Arc<LLMController>

Returns a reference to the controller.

Source

pub fn runtime(&self) -> &Runtime

Returns a reference to the runtime.

Source

pub fn runtime_handle(&self) -> Handle

Returns a handle to the runtime.

Source

pub fn user_interaction_registry(&self) -> &Arc<UserInteractionRegistry>

Returns a reference to the user interaction registry.

Source

pub fn permission_registry(&self) -> &Arc<PermissionRegistry>

Returns a reference to the permission registry.

Source

pub async fn remove_session(&self, session_id: i64) -> bool

Removes a session and cleans up all associated resources.

This is the recommended way to remove a session as it orchestrates cleanup across:

  • The LLM session manager (terminates the session)
  • The permission registry (cancels pending permission requests)
  • The user interaction registry (cancels pending user questions)
  • The tool registry (cleans up per-session state in tools)
§Arguments
  • session_id - The ID of the session to remove
§Returns

true if the session was found and removed, false if session didn’t exist

Source

pub fn llm_registry(&self) -> Option<&LLMRegistry>

Returns a reference to the LLM registry.

Source

pub fn take_llm_registry(&mut self) -> Option<LLMRegistry>

Takes the LLM registry (can only be called once).

Source

pub fn cancel_token(&self) -> CancellationToken

Returns the cancellation token.

Source

pub fn name(&self) -> &str

Returns the agent name.

Source

pub fn from_controller_tx(&self) -> Sender<UiMessage>

Returns a clone of the UI message sender.

This can be used to send messages to the frontend’s event loop.

Source

pub fn tool_definitions(&self) -> &[Tool]

Returns a reference to the tool definitions.

Source

pub fn skill_registry(&self) -> &Arc<SkillRegistry>

Returns a reference to the skill registry.

Source

pub fn register_list_skills_tool(&mut self) -> Result<Tool, AgentError>

Register the ListSkillsTool, allowing the LLM to discover available skills.

This registers the list_skills tool with the tool registry and adds its definition to the tool list. Call this after register_tools() if you want the LLM to be able to query available skills.

Returns the LLM tool definition that was added.

Source

pub fn add_skill_path(&mut self, path: PathBuf) -> &mut AgentCore

Add a custom skill search path.

Skills are discovered from directories containing SKILL.md files. By default, $PWD/.skills/ and ~/.agent-core/skills/ are searched.

Source

pub fn load_skills(&mut self) -> (usize, Vec<SkillDiscoveryError>)

Load skills from configured directories.

This scans all configured skill paths and registers discovered skills in the skill registry. Call this after configuring skill paths.

Returns the number of skills loaded and any errors encountered.

Source

pub fn load_skills_from( &self, paths: Vec<PathBuf>, ) -> (usize, Vec<SkillDiscoveryError>)

Load skills from specific paths (one-shot, doesn’t modify default discovery).

This creates a temporary discovery instance with only the provided paths, loads skills from them, and registers them in the skill registry. Unlike add_skill_path() + load_skills(), this doesn’t affect the default discovery paths used by reload_skills().

Returns the number of skills loaded and any errors encountered.

Source

pub fn reload_skills(&mut self) -> SkillReloadResult

Reload skills from configured directories.

This re-scans all configured skill paths and updates the registry:

  • New skills are added
  • Removed skills are unregistered
  • Existing skills are re-registered (silently updated)

Returns information about what changed (added/removed only).

Source

pub fn skills_prompt_xml(&self) -> String

Get skills XML for injection into system prompts.

Returns an XML string listing all available skills that can be included in the system prompt to inform the LLM about available capabilities.

Source

pub async fn refresh_session_skills( &self, session_id: i64, ) -> Result<(), AgentError>

Refresh a session’s system prompt with current skills.

This updates the session’s system prompt to include the current <available_skills> XML from the skill registry.

Note: This appends the skills XML to the existing system prompt. If skills were previously loaded, this may result in duplicate entries.

Trait Implementations§

Source§

impl AgentCoreExt for AgentCore

Source§

fn into_tui(self) -> TuiRunner

Convert this AgentCore into a TuiRunner for TUI operation.

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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
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