kiromi-ai-cli 0.2.2

Operator and developer CLI for the kiromi-ai-memory store: append, search, snapshot, regenerate, migrate-scheme, gc, audit-tail.
// SPDX-License-Identifier: Apache-2.0 OR MIT
//! `kiromi-ai-memory search`.

use std::str::FromStr;

use kiromi_ai_memory::{PartitionPath, Query};

use crate::cli::{GlobalArgs, SearchArgs};
use crate::error::{CliError, ExitCode};
use crate::output;
use crate::runtime::Runtime;

pub(crate) async fn run(args: SearchArgs, globals: &GlobalArgs) -> Result<(), CliError> {
    let rt = Runtime::open(globals).await?;
    let mut q = if args.semantic {
        Query::semantic(&args.query)
    } else if args.text {
        Query::text(&args.query)
    } else {
        // hybrid is default
        let mut h = Query::hybrid(&args.query);
        if let Some(a) = args.alpha {
            h = h.alpha(a);
        }
        h
    };

    if let Some(scope) = args.within {
        let path = PartitionPath::from_str(&scope).map_err(|e| CliError {
            kind: ExitCode::Config,
            source: anyhow::anyhow!("--within {scope:?}: {e}"),
        })?;
        q = q.within(path);
    }
    let hits = rt.mem.search(q, args.top).await?;

    if globals.json {
        let wire: Vec<_> = hits
            .iter()
            .map(|h| {
                serde_json::json!({
                    "score": h.score,
                    "id": h.r#ref.id.to_string(),
                    "partition": h.r#ref.partition.as_str(),
                })
            })
            .collect();
        println!("{}", output::to_json(&wire));
    } else {
        println!("{}", output::hits_table(&hits));
    }
    rt.mem.close().await?;
    Ok(())
}