Config

Struct Config 

Source
pub struct Config {
    pub workspace_path: String,
    pub last_path: String,
    pub theme_preference: String,
    pub theme_mode: String,
    pub fast: Provider,
    pub standard: Provider,
    pub thinking: Provider,
    pub extract: Provider,
    pub instruct: Provider,
    pub coder: Provider,
}
Expand description

Persistent configuration for the process.

Stored as TOML at a platform-specific location derived from AppName.

Fields§

§workspace_path: String

Workspace root path.

§last_path: String

Last opened path.

§theme_preference: String

Theme

§theme_mode: String

Theme Mode (light|dark|auto)

§fast: Provider

Provider for fast inference tasks.

§standard: Provider

Provider for standard inference tasks.

§thinking: Provider

Provider for advanced reasoning tasks.

§extract: Provider

Provider for extraction / large-context tasks.

§instruct: Provider

Provider for instruction-following tasks.

§coder: Provider

Provider for coding and AIM formula tasks.

Implementations§

Source§

impl Config

Source

pub fn read_lock() -> Result<RwLockReadGuard<'static, Self>, Box<dyn Error>>

§Acquire a read guard for the global config.
§title: Read Lock

This function acquires a read lock on the global configuration singleton, providing thread-safe access to configuration data for reading operations.

§Returns

Returns a Result<RwLockReadGuard<'static, Config>> containing:

  • Ok(guard) - A read guard that provides immutable access to the configuration
  • Err(error) - An error if the configuration lock is poisoned
§Errors

Returns an error if:

  • The configuration lock is poisoned (indicating a panic occurred while another thread held the lock)
§Behavior

Internally, read_lock() performs the following operations:

  1. Calls Config::get_instance() to obtain a reference to the global configuration singleton
  2. Attempts to acquire a read lock using RwLock::read()
  3. Maps any lock poisoning error to a boxed error type for consistency

The read lock allows multiple threads to concurrently read configuration data while preventing any thread from acquiring a write lock until all read locks are released.

§Side Effects
  • Acquires a read lock on the global configuration, potentially blocking write operations until the guard is dropped
  • No modifications are made to the configuration data
§Usage Pattern
use aimx::Config;

// Acquire read access to configuration
let config_guard = Config::read_lock().expect("Failed to acquire config read lock");

// Read configuration values
let workspace_path = &config_guard.workspace_path;
let fast_provider = &config_guard.fast;

// Configuration is automatically released when guard goes out of scope
§See Also
Source

pub fn write_lock() -> Result<RwLockWriteGuard<'static, Self>, Box<dyn Error>>

§Acquire a write guard for the global config.
§title: Write Lock

Acquires exclusive write access to the global configuration singleton, providing thread-safe access for modifying configuration data.

§Returns

Returns a Result<RwLockWriteGuard<'static, Config>> containing:

  • Ok(guard) - A write guard that provides mutable access to the configuration
  • Err(error) - An error if the configuration lock is poisoned
§Errors

Returns an error if:

  • The configuration lock is poisoned (indicating a panic occurred while another thread held the lock)
§Behavior

Internally, write_lock() performs the following operations:

  1. Calls Config::get_instance() to obtain a reference to the global configuration singleton
  2. Attempts to acquire a write lock using RwLock::write()
  3. Maps any lock poisoning error to a boxed error type for consistency

The write lock provides exclusive access to the configuration, preventing any other thread from reading or writing until the lock is released.

§Side Effects
  • Acquires an exclusive write lock on the global configuration, blocking all other read and write operations until the guard is dropped
  • Allows modification of configuration data through the returned guard
§Usage Pattern
use aimx::Config;

// Acquire write access to configuration
let mut config_guard = Config::write_lock().expect("Failed to acquire config write lock");

// Modify configuration values
config_guard.workspace_path = "/new/workspace/path".to_string();
config_guard.fast.model = "llama3:8b".to_string();
config_guard.standard.url = "https://api.openai.com/v1".to_string();

// Persist changes to disk
config_guard.save().expect("Failed to save configuration");

// Configuration is automatically released when guard goes out of scope

For conditional updates based on current configuration:

use aimx::Config;

let mut config_guard = Config::write_lock().expect("Failed to acquire write lock");

// Check current value before updating
if config_guard.workspace_path.is_empty() {
    config_guard.workspace_path = "/default/workspace".to_string();
}

// Update provider settings
config_guard.fast.model = "mistral:latest".to_string();
config_guard.fast.temperature = 0.3;

// Save changes
config_guard.save().expect("Failed to save configuration");
§File Operations

Configuration modifications require explicit persistence:

  • In-Memory Changes: Modifications through the write guard only affect memory
  • Persistence Required: Call config_guard.save() to write changes to disk
  • Atomic Updates: The entire configuration is written as a single TOML file
  • Error Handling: Save operations can fail due to file system issues
§MVCC Considerations

The configuration uses a reader-writer lock pattern:

  • Exclusive Access: Write lock prevents all concurrent read and write operations
  • Lock Poisoning: If a writer panics, the lock becomes poisoned and returns errors
  • Guard Lifetime: Keep the write guard for minimal duration to avoid blocking readers
  • Deadlock Prevention: Cannot acquire read lock while holding write lock
§Performance Considerations
  • Blocking: Write lock blocks all other configuration access
  • Minimal Duration: Keep write operations brief to minimize blocking
  • Batch Changes: Group multiple configuration changes in a single write lock
  • Avoid Nested Locks: Do not perform I/O or other blocking operations while holding the lock
§Error Handling

Handle lock poisoning and save errors appropriately:

use aimx::Config;

match Config::write_lock() {
    Ok(mut config_guard) => {
        // Modify configuration
        config_guard.workspace_path = "/new/path".to_string();
        
        // Save changes with error handling
        match config_guard.save() {
            Ok(()) => println!("Configuration saved successfully"),
            Err(e) => {
                eprintln!("Failed to save configuration: {}", e);
                // Configuration changes are lost if save fails
            }
        }
    }
    Err(e) => {
        eprintln!("Failed to acquire write lock: {}", e);
        // Configuration lock may be poisoned
    }
}
§See Also
Source

pub fn new() -> Result<Self, Box<dyn Error>>

§Load existing configuration or create and persist defaults.
§title: Config new

This function loads the application configuration from disk, or creates and persists a default configuration if none exists.

§Returns

Returns a Config instance containing the loaded configuration data, or a default configuration if no config file was found.

§Errors

Returns an error if:

  • A configuration file exists but cannot be read from disk
  • A configuration file exists but contains invalid TOML syntax
  • A configuration file exists but cannot be deserialized into the Config structure
  • The default configuration cannot be saved to disk
§Behavior

Internally, new() performs the following operations:

  1. Attempts to load an existing configuration file from the platform-specific config directory
  2. If loading succeeds, returns the loaded configuration
  3. If loading fails (file doesn’t exist or is invalid), creates a default configuration using Config::default()
  4. Saves the default configuration to disk for future use
  5. Returns the default configuration
§Side Effects
  • Creates the platform-specific configuration directory if it doesn’t exist
  • Creates a default configuration file at the platform-specific path if no config exists
  • Persists default provider settings for all inference model types (fast, standard, thinking, extract, instruct, coder)
§Usage Pattern
use aimx::config::Config;

// Load or create default configuration
let config = Config::new().expect("Failed to load configuration");

// Use configuration settings
println!("Workspace path: {}", config.workspace_path);
§See Also
Source

pub fn load() -> Result<Self, Box<dyn Error>>

§Load configuration from disk.
§title: Load configuration

Loads the AIMX application configuration from a TOML file stored in the platform-specific configuration directory.

The configuration file is automatically located based on the current application name (set via AppName::set or defaulting to “aimx”) and the user’s operating system conventions for configuration storage.

§Returns

Returns a Config containing the loaded configuration values if successful, or an error if the file cannot be read or parsed.

§Errors

Returns an error if:

  • The platform-specific configuration directory cannot be determined
  • The configuration file does not exist at the expected path
  • The configuration file cannot be read due to permissions or I/O issues
  • The file content is not valid TOML format
  • The TOML content cannot be deserialized into the Config structure
§Behavior

Internally, load() performs the following operations:

  1. Resolves the configuration file path using Config::path()
  2. Reads the entire file content as a UTF-8 string
  3. Parses the TOML content using toml::from_str()
  4. Returns the deserialized Config instance
§Usage Pattern
use aimx::Config;

// Load configuration (typically done during application startup)
match Config::load() {
    Ok(config) => {
        println!("Loaded workspace path: {}", config.workspace_path);
        println!("Fast model: {}", config.fast.model);
        // Use the configuration...
    }
    Err(error) => {
        eprintln!("Failed to load configuration: {}", error);
        // Handle the error or fall back to defaults
    }
}
§File Operations
  • Reads from the configuration file in the platform-specific config directory
  • File path format: {config_dir}/{app_name}.toml
  • Example paths:
    • Linux: ~/.config/aimx/aimx.toml
    • macOS: ~/Library/Application Support/aimx/aimx.toml
    • Windows: %APPDATA%\aimx\aimx.toml
§See Also
Source

pub fn save(&self) -> Result<(), Box<dyn Error>>

§Persist configuration to disk.
§title: Save configuration

Persists the AIMX application configuration to a TOML file in the platform-specific configuration directory.

The configuration is saved with human-readable formatting using toml::to_string_pretty(), making it easy to read and edit manually if needed. The function automatically creates the configuration directory if it doesn’t already exist.

§Returns

Returns Ok(()) if the configuration was successfully saved to disk, or an error if the operation failed.

§Errors

Returns an error if:

  • The platform-specific configuration directory cannot be determined
  • The configuration directory cannot be created due to permissions or I/O issues
  • The configuration cannot be serialized to TOML format
  • The TOML content cannot be written to the configuration file
§Behavior

Internally, save() performs the following operations:

  1. Resolves the configuration file path using Config::path()
  2. Ensures the parent directory exists by creating it if necessary
  3. Serializes the configuration to pretty-printed TOML format using toml::to_string_pretty()
  4. Writes the TOML content to the configuration file
§Side Effects
  • Creates the platform-specific configuration directory if it doesn’t exist
  • Overwrites any existing configuration file at the target path
  • File path format: {config_dir}/{app_name}.toml
  • Example paths:
    • Linux: ~/.config/aimx/aimx.toml
    • macOS: ~/Library/Application Support/aimx/aimx.toml
    • Windows: %APPDATA%\aimx\aimx.toml
§Usage Pattern
use aimx::Config;
use std::sync::Arc;

// Acquire write access to modify configuration
let mut config = Config::write_lock().expect("Failed to acquire config lock");

// Make changes to the configuration
config.workspace_path = "/my/workspace".to_string();
config.fast.model = "llama2:latest".to_string();

// Persist changes to disk
match config.save() {
    Ok(()) => println!("Configuration saved successfully"),
    Err(error) => eprintln!("Failed to save configuration: {}", error),
}

// Lock is automatically released when `config` goes out of scope
§File Operations

This function performs write operations that modify the configuration file on disk. The operation is atomic at the file level - either the entire configuration is written successfully or the file remains unchanged if an error occurs during writing.

§See Also
Source

pub fn path() -> Result<PathBuf, Box<dyn Error>>

§Platform-specific configuration file path.
§title: Get Config Path

This function returns the platform-specific file path where the AIMX configuration file should be stored and loaded from.

The configuration path is determined using the directories crate, which follows platform conventions:

  • Linux: $HOME/.config/{app_name}/
  • macOS: $HOME/Library/Application Support/{app_name}/
  • Windows: {FOLDERID_RoamingAppData}\{app_name}\

The configuration file itself is named {app_name}.toml where {app_name} is obtained from AppName::get().

§Arguments

This function takes no arguments.

§Returns

Returns a Result<PathBuf> containing the full path to the configuration file, including the filename.

§Errors

Returns an error if:

  • The system’s project directories cannot be determined (rare, typically only in severely misconfigured environments)
§Behavior

Internally, get_config_path() performs the following operations:

  1. Retrieves the application name using AppName::get()
  2. Uses [ProjectDirs::from()] to determine platform-specific directory paths
  3. Constructs the final path by joining the config directory with the filename {app_name}.toml
§File Operations

This function only calculates a file path - it does not perform any file I/O operations. The returned path can be used with standard file operations like reading, writing, or checking file existence.

§Usage Pattern
use aimx::config::Config;
use std::path::PathBuf;

// Get the configuration file path
let config_path: PathBuf = Config::path()
    .expect("Failed to determine config path");

// Check if config file exists
if config_path.exists() {
    println!("Config file exists at: {:?}", config_path);
} else {
    println!("Config file will be created at: {:?}", config_path);
}
§See Also
  • Config::load() - Load configuration from the path returned by this function
  • Config::save() - Save configuration to the path returned by this function
  • AppName::get() - Get the application name used in path construction
  • [ProjectDirs] - The underlying crate used for platform-specific directory resolution
Source

pub fn get_provider(&self, model: &Model) -> &Provider

§Provider configuration for the requested model class.
§title: Get Provider

This function retrieves the configuration for a specific inference model provider from the global configuration.

§Arguments
  • model - A reference to a Model enum value specifying which model configuration to retrieve. The supported model types are:
§Returns

Returns a reference to a Provider configuration containing the API settings, model identifier, and runtime parameters for the requested model type.

§Behavior

The function performs a simple pattern match on the provided model enum and returns the corresponding provider configuration field from the Config struct. This provides type-safe access to model-specific provider settings.

§Usage Pattern
use aimx::{get_config, inference::{Model, Provider}};

// Get a read lock on the global configuration
let config_guard = get_config().unwrap();

// Retrieve the provider configuration for the 'fast' model
let fast_provider: &Provider = config_guard.get_provider(&Model::Fast);

// Access provider settings
println!("Fast model: {}", fast_provider.model);
println!("API: {}", fast_provider.api);
§See Also
  • Config - The main configuration struct containing all provider settings
  • Provider - Provider configuration containing API settings and model parameters
  • Model - Model type enum defining different inference model categories
  • get_config() - Function to access the global configuration singleton

Trait Implementations§

Source§

impl Clone for Config

Source§

fn clone(&self) -> Config

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Config

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Config

Source§

fn default() -> Self

Default configuration used when no config file exists.

Source§

impl<'de> Deserialize<'de> for Config

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl PartialEq for Config

Source§

fn eq(&self, other: &Config) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for Config

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for Config

Auto Trait Implementations§

§

impl Freeze for Config

§

impl RefUnwindSafe for Config

§

impl Send for Config

§

impl Sync for Config

§

impl Unpin for Config

§

impl UnwindSafe for Config

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

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.

§

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

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: 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
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. 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.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

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
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

§

impl<T> ErasedDestructor for T
where T: 'static,