ralph_workflow/agents/opencode_api/mod.rs
1//! `OpenCode` API catalog module.
2//!
3//! This module handles fetching, caching, and querying the `OpenCode` model catalog
4//! from <https://models.dev/api.json>. The catalog contains available providers and models
5//! that `OpenCode` supports, enabling dynamic agent configuration.
6//!
7//! # Module Structure
8//!
9//! - `types` - API catalog data structures
10//! - `cache` - File-based caching with TTL
11//! - `fetch` - HTTP fetching logic
12//!
13//! # Dependency Injection
14//!
15//! The [`CatalogLoader`] trait enables dependency injection for testing.
16//! Production code uses [`RealCatalogLoader`] which fetches from the network,
17//! while tests can provide mock implementations.
18
19mod cache;
20mod fetch;
21mod types;
22
23pub use cache::{load_api_catalog, CacheError};
24pub use types::{ApiCatalog, Model, Provider};
25
26/// `OpenCode` API endpoint for model catalog.
27pub const API_URL: &str = "https://models.dev/api.json";
28
29/// Default cache TTL in seconds (24 hours).
30pub const DEFAULT_CACHE_TTL_SECONDS: u64 = 24 * 60 * 60;
31
32/// Environment variable for customizing cache TTL.
33pub const CACHE_TTL_ENV_VAR: &str = "RALPH_OPENCODE_CACHE_TTL_SECONDS";
34
35/// Trait for loading the `OpenCode` API catalog.
36///
37/// This trait enables dependency injection for catalog loading, allowing
38/// tests to provide mock implementations that don't make network calls.
39pub trait CatalogLoader: Send + Sync {
40 /// Load the API catalog.
41 ///
42 /// Returns the catalog or an error if loading fails.
43 ///
44 /// # Errors
45 ///
46 /// Returns error if the operation fails.
47 fn load(&self) -> Result<ApiCatalog, CacheError>;
48}
49
50/// Production implementation of [`CatalogLoader`] that fetches from the network.
51///
52/// This loader uses the standard caching mechanism:
53/// 1. Check for a valid cached catalog
54/// 2. If cache is missing or expired, fetch from the API
55/// 3. Cache the fetched result for future use
56#[derive(Debug, Default, Clone)]
57pub struct RealCatalogLoader;
58
59impl CatalogLoader for RealCatalogLoader {
60 fn load(&self) -> Result<ApiCatalog, CacheError> {
61 load_api_catalog()
62 }
63}