coreason-runtime 0.1.0

Kinetic Plane execution engine for the CoReason Tripartite Cybernetic Manifold
Documentation
// Copyright (c) 2026 CoReason, Inc.
// All rights reserved.

//! Oracle API routes.
//!
//! Replaces `coreason_runtime/api/oracle.py`.
//! Proxies oracle query and status requests to the Python sidecar.

use axum::{
    extract::State,
    http::StatusCode,
    response::{IntoResponse, Response},
    routing::{get, post},
    Json, Router,
};
use std::sync::Arc;

use crate::GatewayState;

// ── Proxy helpers ───────────────────────────────────────────────────────

async fn proxy_get(state: &GatewayState, path: &str) -> Response {
    let url = format!("{}{}", state.sidecar_url, path);
    match ureq::get(&url).call() {
        Ok(res) => {
            let status = StatusCode::from_u16(res.status()).unwrap_or(StatusCode::OK);
            let body: serde_json::Value = res.into_json().unwrap_or(serde_json::Value::Null);
            (status, Json(body)).into_response()
        }
        Err(ureq::Error::Status(code, res)) => {
            let status = StatusCode::from_u16(code).unwrap_or(StatusCode::BAD_REQUEST);
            let body: serde_json::Value = res.into_json().unwrap_or(serde_json::Value::Null);
            (status, Json(body)).into_response()
        }
        Err(e) => (
            StatusCode::INTERNAL_SERVER_ERROR,
            Json(serde_json::json!({
                "status": "error",
                "message": format!("Failed to proxy GET {} to sidecar: {}", path, e),
            })),
        )
            .into_response(),
    }
}

async fn proxy_post(state: &GatewayState, path: &str, payload: &serde_json::Value) -> Response {
    let url = format!("{}{}", state.sidecar_url, path);
    match ureq::post(&url).send_json(payload) {
        Ok(res) => {
            let status = StatusCode::from_u16(res.status()).unwrap_or(StatusCode::OK);
            let body: serde_json::Value = res.into_json().unwrap_or(serde_json::Value::Null);
            (status, Json(body)).into_response()
        }
        Err(ureq::Error::Status(code, res)) => {
            let status = StatusCode::from_u16(code).unwrap_or(StatusCode::BAD_REQUEST);
            let body: serde_json::Value = res.into_json().unwrap_or(serde_json::Value::Null);
            (status, Json(body)).into_response()
        }
        Err(e) => (
            StatusCode::INTERNAL_SERVER_ERROR,
            Json(serde_json::json!({
                "status": "error",
                "message": format!("Failed to proxy POST {} to sidecar: {}", path, e),
            })),
        )
            .into_response(),
    }
}

// ── Handlers ────────────────────────────────────────────────────────────

/// POST /api/v1/oracle/query
///
/// Submit a query to the reasoning oracle via the sidecar.
async fn oracle_query(
    State(state): State<Arc<GatewayState>>,
    Json(payload): Json<serde_json::Value>,
) -> Response {
    proxy_post(&state, "/api/v1/oracle/query", &payload).await
}

/// GET /api/v1/oracle/status
///
/// Retrieve the oracle service status from the sidecar.
async fn oracle_status(State(state): State<Arc<GatewayState>>) -> Response {
    proxy_get(&state, "/api/v1/oracle/status").await
}

// ── Router ──────────────────────────────────────────────────────────────

/// Build the oracle router.
pub fn router() -> Router<Arc<GatewayState>> {
    Router::new()
        .route("/api/v1/oracle/query", post(oracle_query))
        .route("/api/v1/oracle/status", get(oracle_status))
}