roboticus-api 0.11.3

HTTP routes, WebSocket, auth, rate limiting, and dashboard for the Roboticus agent runtime
Documentation
//! Config, stats, circuit breaker, wallet, plugins, browser, agents, workspace, A2A.

use std::collections::HashMap;

use axum::{
    Json,
    extract::{Path, Query, State},
    http::StatusCode,
    http::header,
    response::IntoResponse,
};
use chrono::{Duration, Utc};
use serde::Deserialize;
use serde_json::{Value, json};

use crate::config_runtime;
use roboticus_agent::policy::{PolicyContext, ToolCallRequest};
use roboticus_core::{
    InputAuthority, PolicyDecision, RoboticusConfig, RoboticusError, SurvivalTier,
    input_capability_scan,
};

use super::{
    AppState, JsonError, bad_request, internal_err, not_found, sanitize_html, validate_field,
    validate_short,
};

// ── Key resolution ───────────────────────────────────────────
//
// The canonical resolver lives in `roboticus_core::keystore`. All
// surfaces (API, CLI, dashboard) must use it to avoid drift.

use roboticus_core::keystore::{KeySource, resolve_key_source};

/// Resolve an API key for a provider. Returns `None` when no key is
/// configured (or when the provider is local and doesn't need one).
pub(crate) async fn resolve_provider_key(
    provider_name: &str,
    is_local: bool,
    auth_mode: &str,
    api_key_ref: Option<&str>,
    api_key_env: &str,
    oauth: &roboticus_llm::OAuthManager,
    keystore: &roboticus_core::keystore::Keystore,
) -> Option<String> {
    let source = resolve_key_source(
        provider_name,
        is_local,
        api_key_ref,
        Some(api_key_env),
        Some(auth_mode),
        keystore,
    );
    match source {
        KeySource::NotRequired | KeySource::Missing => None,
        KeySource::OAuth => oauth.resolve_token(provider_name).await
            .inspect_err(|e| tracing::warn!(error = %e, provider = provider_name, "OAuth token resolution failed"))
            .ok(),
        KeySource::Keystore(v) | KeySource::EnvVar(v) => Some(v),
    }
}

/// Check whether a key is present for a provider, returning (status, source).
pub(crate) fn check_key_status(
    provider_name: &str,
    is_local: bool,
    api_key_ref: Option<&str>,
    api_key_env: Option<&str>,
    auth_mode: Option<&str>,
    keystore: &roboticus_core::keystore::Keystore,
) -> (&'static str, &'static str) {
    resolve_key_source(
        provider_name,
        is_local,
        api_key_ref,
        api_key_env,
        auth_mode,
        keystore,
    )
    .status_pair()
}

// ── Approval management routes ───────────────────────────────

include!("admin/approvals.rs");

include!("admin/config_models.rs");
include!("admin/metrics.rs");
include!("admin/revenue.rs");
include!("admin/runtime_health.rs");
include!("admin/operator_tools.rs");
include!("admin/workspace_agents.rs");
include!("admin/advanced_ops.rs");
include!("admin/memory_analytics.rs");
#[cfg(test)]
mod tests;