Archived
909c1577f1
- crates/ → engrams/ (Rust engrams live here) - bindings/ → receptors/ (cross-language access points into the graph) - Cargo.toml workspace paths updated
122 lines
3.9 KiB
Rust
122 lines
3.9 KiB
Rust
/// Projection API routes.
|
|
///
|
|
/// POST /projections — register a projection schema
|
|
/// GET /projections — list all registered schemas
|
|
/// POST /projections/{name}/query — run activation then project results
|
|
/// GET /projections/{name}/schema — get a schema definition
|
|
use axum::{
|
|
extract::{Path, State},
|
|
http::StatusCode,
|
|
Json,
|
|
};
|
|
use engram_projection::{
|
|
engine::ProjectionEngine,
|
|
schema::{ProjectionResult, ProjectionSchema},
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::sync::Arc;
|
|
use uuid::Uuid;
|
|
|
|
use crate::state::AppState;
|
|
|
|
// ── POST /projections ─────────────────────────────────────────────────────────
|
|
|
|
pub async fn register_projection(
|
|
State(state): State<Arc<AppState>>,
|
|
Json(schema): Json<ProjectionSchema>,
|
|
) -> Result<StatusCode, StatusCode> {
|
|
let mut reg = state
|
|
.projection_registry
|
|
.lock()
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
reg.upsert(schema)
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
Ok(StatusCode::CREATED)
|
|
}
|
|
|
|
// ── GET /projections ──────────────────────────────────────────────────────────
|
|
|
|
#[derive(Serialize)]
|
|
pub struct ListProjectionsResponse {
|
|
pub schemas: Vec<ProjectionSchema>,
|
|
}
|
|
|
|
pub async fn list_projections(
|
|
State(state): State<Arc<AppState>>,
|
|
) -> Result<Json<ListProjectionsResponse>, StatusCode> {
|
|
let reg = state
|
|
.projection_registry
|
|
.lock()
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
let schemas = reg.list().into_iter().cloned().collect();
|
|
Ok(Json(ListProjectionsResponse { schemas }))
|
|
}
|
|
|
|
// ── GET /projections/{name}/schema ────────────────────────────────────────────
|
|
|
|
pub async fn get_projection_schema(
|
|
State(state): State<Arc<AppState>>,
|
|
Path(name): Path<String>,
|
|
) -> Result<Json<ProjectionSchema>, StatusCode> {
|
|
let reg = state
|
|
.projection_registry
|
|
.lock()
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
match reg.get(&name) {
|
|
Ok(schema) => Ok(Json(schema.clone())),
|
|
Err(_) => Err(StatusCode::NOT_FOUND),
|
|
}
|
|
}
|
|
|
|
// ── POST /projections/{name}/query ────────────────────────────────────────────
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct ProjectionQueryRequest {
|
|
/// Seed node IDs for spreading activation.
|
|
pub seeds: Vec<Uuid>,
|
|
/// Query embedding for spreading activation.
|
|
pub query_embedding: Vec<f32>,
|
|
#[serde(default = "default_depth")]
|
|
pub max_depth: u8,
|
|
#[serde(default = "default_limit")]
|
|
pub limit: usize,
|
|
}
|
|
|
|
fn default_depth() -> u8 {
|
|
3
|
|
}
|
|
fn default_limit() -> usize {
|
|
20
|
|
}
|
|
|
|
pub async fn query_projection(
|
|
State(state): State<Arc<AppState>>,
|
|
Path(name): Path<String>,
|
|
Json(req): Json<ProjectionQueryRequest>,
|
|
) -> Result<Json<ProjectionResult>, StatusCode> {
|
|
// Load schema
|
|
let schema = {
|
|
let reg = state
|
|
.projection_registry
|
|
.lock()
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
match reg.get(&name) {
|
|
Ok(s) => s.clone(),
|
|
Err(_) => return Err(StatusCode::NOT_FOUND),
|
|
}
|
|
};
|
|
|
|
// Run spreading activation
|
|
let activated = {
|
|
let db = state.db.lock().map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
db.activate(&req.seeds, &req.query_embedding, req.max_depth, req.limit)
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
|
};
|
|
|
|
// Apply projection
|
|
let result = ProjectionEngine::project(&schema, &activated)
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
|
|
Ok(Json(result))
|
|
}
|