pub mod auth;
pub mod metrics;
pub mod prompts;
pub mod rollback;
mod routes;
pub mod selection;
mod viz;
pub use routes::create_router;
pub use viz::GRAPH_VIZ_HTML;
use cortex_core::{Node, NodeFilter, NodeKind, Storage};
pub(super) fn find_by_title(
storage: &cortex_core::RedbStorage,
kind: &NodeKind,
title: &str,
) -> cortex_core::Result<Option<Node>> {
let nodes = storage.list_nodes(NodeFilter::new().with_kinds(vec![kind.clone()]))?;
Ok(nodes.into_iter().find(|n| n.data.title == title))
}
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use cortex_core::briefing::BriefingEngine;
use cortex_core::prompt::RollbackConfig;
use cortex_core::{
FastEmbedService, GraphEngineImpl, HnswIndex, RedbStorage, RwLockVectorIndex, TrustEngine,
WriteGateConfig,
};
use serde::Serialize;
use std::sync::atomic::AtomicU64;
use std::sync::Arc;
pub use metrics::CortexMetrics;
pub type HttpBriefingEngine = BriefingEngine<
RedbStorage,
Arc<FastEmbedService>,
RwLockVectorIndex<HnswIndex>,
Arc<GraphEngineImpl<RedbStorage>>,
>;
pub type HttpAutoLinker =
cortex_core::AutoLinker<RedbStorage, FastEmbedService, HnswIndex, GraphEngineImpl<RedbStorage>>;
#[derive(Clone)]
pub struct AppState {
pub storage: Arc<cortex_core::RedbStorage>,
pub graph_engine: Arc<cortex_core::GraphEngineImpl<cortex_core::RedbStorage>>,
pub vector_index: Arc<std::sync::RwLock<cortex_core::HnswIndex>>,
pub embedding_service: Arc<cortex_core::FastEmbedService>,
pub auto_linker: Arc<std::sync::RwLock<HttpAutoLinker>>,
pub graph_version: Arc<AtomicU64>,
pub briefing_engine: Arc<HttpBriefingEngine>,
pub metrics: Arc<CortexMetrics>,
pub start_time: std::time::Instant,
pub rollback_config: RollbackConfig,
pub webhooks: Vec<crate::config::WebhookConfig>,
pub score_decay: cortex_core::ScoreDecayConfig,
pub write_gate: WriteGateConfig,
pub event_bus: crate::observability::EventBus,
pub schema_validator: cortex_core::SchemaValidator,
pub hooks: Arc<cortex_core::HookRegistry>,
pub trust_engine: Option<Arc<TrustEngine<RedbStorage>>>,
}
#[derive(Serialize)]
pub struct JsonResponse<T> {
pub success: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<T>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
impl<T: Serialize> JsonResponse<T> {
pub fn ok(data: T) -> Self {
Self {
success: true,
data: Some(data),
error: None,
}
}
pub fn err(msg: impl Into<String>) -> JsonResponse<()> {
JsonResponse {
success: false,
data: None,
error: Some(msg.into()),
}
}
}
pub struct AppError(anyhow::Error);
impl IntoResponse for AppError {
fn into_response(self) -> Response {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(JsonResponse::<()>::err(self.0.to_string())),
)
.into_response()
}
}
impl<E> From<E> for AppError
where
E: Into<anyhow::Error>,
{
fn from(err: E) -> Self {
Self(err.into())
}
}
pub type AppResult<T> = Result<T, AppError>;