Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 43 additions & 10 deletions crates/adaptive/src/response_cache/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,18 @@ pub async fn check_backend_health(
Ok(store.backend_kind().to_string())
}

/// Validates the configured backend target without attempting network access.
///
/// Intended for offline `nemo-relay doctor` checks: it rejects malformed
/// backend targets while still skipping live reachability probes.
pub fn validate_backend_target(config: &ResponseCacheConfig) -> std::result::Result<(), String> {
match config.backend.kind.as_str() {
"in_memory" => Ok(()),
"redis" => validate_redis_backend_target(config).map_err(|err| err.to_string()),
other => Err(format!("response_cache: unknown backend kind '{other}'")),
}
}

/// Builds the response-cache backend from config.
///
/// Returns the boxed [`CacheStore`] used by the intercept and the `doctor`
Expand All @@ -465,16 +477,7 @@ pub(crate) async fn build_store(config: &ResponseCacheConfig) -> Result<Arc<dyn
async fn build_redis_store(config: &ResponseCacheConfig) -> Result<Arc<dyn CacheStore>> {
use crate::response_cache::store::RedisCacheStore;

let url = config
.backend
.config
.get("url")
.and_then(Json::as_str)
.ok_or_else(|| {
AdaptiveError::InvalidConfig(
"response_cache: redis backend requires backend.config.url".to_string(),
)
})?;
let url = redis_backend_url(config)?;
let key_prefix = config
.backend
.config
Expand All @@ -496,6 +499,36 @@ async fn build_redis_store(_config: &ResponseCacheConfig) -> Result<Arc<dyn Cach
))
}

fn redis_backend_url(config: &ResponseCacheConfig) -> Result<&str> {
config
.backend
.config
.get("url")
.and_then(Json::as_str)
.ok_or_else(|| {
AdaptiveError::InvalidConfig(
"response_cache: redis backend requires backend.config.url".to_string(),
)
})
}

#[cfg(feature = "redis-backend")]
fn validate_redis_backend_target(config: &ResponseCacheConfig) -> Result<()> {
let url = redis_backend_url(config)?;
redis::Client::open(url)
.map(|_| ())
.map_err(|err| AdaptiveError::Storage(format!("response_cache: redis client: {err}")))
}
Comment thread
willkill07 marked this conversation as resolved.

#[cfg(not(feature = "redis-backend"))]
fn validate_redis_backend_target(_config: &ResponseCacheConfig) -> Result<()> {
Err(AdaptiveError::InvalidConfig(
"response_cache: backend.kind = \"redis\" requires building with the 'redis-backend' \
feature"
.to_string(),
))
}

#[cfg(test)]
#[path = "../../tests/unit/response_cache/store_tests.rs"]
mod tests;
6 changes: 6 additions & 0 deletions crates/cli/src/commands/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ pub(crate) struct DoctorCommand {
pub(crate) install_dir: Option<PathBuf>,
#[arg(long)]
pub(crate) json: bool,
#[arg(
long,
help = "Validate configuration and endpoint syntax without running live network probes"
)]
pub(crate) offline: bool,
}

#[derive(Debug, Clone, Args)]
Expand All @@ -41,6 +46,7 @@ pub(super) async fn execute(
crate::diagnostics::run_doctor(
command.agent.map(Into::into),
command.json,
crate::diagnostics::DoctorProbeMode::from_offline_flag(command.offline),
&gateway_overrides,
logging_fallback_error,
)
Expand Down
9 changes: 8 additions & 1 deletion crates/cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,14 @@ async fn run_default(
.await?;
Ok(ExitCode::SUCCESS)
} else if runtime_configuration::any_config_file_exists() {
runtime_diagnostics::run_doctor(None, false, &runtime_args, None).await
runtime_diagnostics::run_doctor(
None,
false,
runtime_diagnostics::DoctorProbeMode::Live,
&runtime_args,
None,
)
.await
} else {
configure::run(None, None).await?;
Ok(ExitCode::SUCCESS)
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/src/commands/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub(crate) enum Command {
Uninstall(UninstallCommand),
/// Validate and configure model pricing catalogs.
ModelPricing(PricingCommand),
/// Diagnose env, agents, config, observability (optionally scoped to one agent)
/// Diagnose env, agents, config, observability (use --offline to skip live network probes)
Doctor(DoctorCommand),
/// List supported and locally-detected agents (use `--json` for machine output)
Agents(AgentsCommand),
Expand Down
Loading
Loading