remem-ai 0.3.8

Persistent memory for Claude Code — single binary, zero subprocesses
Documentation
use axum::{
    extract::{Query, State},
    http::StatusCode,
    response::IntoResponse,
    Json,
};

use crate::memory_service;

use super::super::helpers::{error_response, memory_to_item, open_request_db};
use super::super::types::{DbState, MemoryItem, Meta, MultiHopInfo, SearchParams, SearchResponse};

pub(in crate::api) fn search_request_from_params(
    params: SearchParams,
) -> memory_service::SearchRequest {
    let limit = params.limit.unwrap_or(20).min(100);
    let offset = params.offset.unwrap_or(0).max(0);

    memory_service::SearchRequest {
        query: params.query,
        project: params.project,
        memory_type: params.memory_type,
        limit,
        offset,
        include_stale: params.include_stale.unwrap_or(false),
        branch: params.branch,
        multi_hop: params.multi_hop.unwrap_or(false),
    }
}

pub(in crate::api) async fn handle_search(
    State(_state): State<DbState>,
    Query(params): Query<SearchParams>,
) -> impl IntoResponse {
    let conn = match open_request_db() {
        Ok(conn) => conn,
        Err(response) => return response,
    };
    let req = search_request_from_params(params);
    let limit = req.limit;
    let offset = req.offset;

    match memory_service::search_memories(&conn, &req) {
        Ok(results) => {
            let count = results.memories.len();
            let items: Vec<MemoryItem> = results.memories.iter().map(memory_to_item).collect();
            Json(SearchResponse {
                data: items,
                meta: Meta {
                    count,
                    has_more: results.has_more,
                    limit,
                    offset,
                },
                multi_hop: results.multi_hop.map(|meta| MultiHopInfo {
                    hops: meta.hops,
                    entities_discovered: meta.entities_discovered,
                }),
            })
            .into_response()
        }
        Err(err) => error_response(
            StatusCode::INTERNAL_SERVER_ERROR,
            "search_failed",
            &err.to_string(),
        )
        .into_response(),
    }
}