feat(embedding,vision): candle embeddings with offline fallback, on-demand clipboard vision capture, and concurrency audit

This commit is contained in:
Riz Ashraf committed 2026-10-07 06:36:09 +01:00
1 parent 5bd8b1587a
commit e4a0fe72df
47 files changed
+6292 -3503

No files matched your search

+32 -21
View File
@@ -4,7 +4,6 @@
)]
pub mod api;
pub mod clipboard_watcher;
pub mod db;
pub mod embedding;
pub mod error;
@@ -18,7 +17,6 @@ pub mod search;
pub mod state;
pub mod store;
pub mod tools;
pub mod vector_db;
pub mod watcher;
use crate::api::rest::GateSetReq;
@@ -164,6 +162,7 @@ pub async fn condense_graph_worker(state: Arc<MemoryState>) {
observations: vec![condensed_sticky_content],
namespace: crate::models::default_namespace(),
git_branch: None,
..Default::default()
},
);
});
@@ -196,6 +195,7 @@ pub async fn condense_graph_worker(state: Arc<MemoryState>) {
observations: vec![condensed_snippet_content],
namespace: crate::models::default_namespace(),
git_branch: None,
..Default::default()
},
);
});
@@ -216,7 +216,6 @@ pub async fn run_server(state: Arc<MemoryState>) -> Result<(), Box<dyn std::erro
tokio::spawn(index_committer_worker(Arc::clone(&state)));
tokio::spawn(ttl_sweeper_worker(Arc::clone(&state)));
tokio::spawn(condense_graph_worker(Arc::clone(&state)));
crate::clipboard_watcher::spawn_watcher(Arc::clone(&state));
crate::watcher::spawn_watcher(Arc::clone(&state));
let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel();
let app_state = Arc::new(AppState {
@@ -315,7 +314,8 @@ pub async fn run_server(state: Arc<MemoryState>) -> Result<(), Box<dyn std::erro
if let Some(home) = dirs::home_dir() {
let nvim_dir = home.join(".gemini");
let nvim_txt_path = nvim_dir.join("active_nvim.txt");
let tmp_path = nvim_dir.join(format!("active_nvim_{}.tmp", std::process::id()));
let tmp_path =
nvim_dir.join(format!("active_nvim_{}.tmp", std::process::id()));
if tokio::fs::create_dir_all(&nvim_dir).await.is_ok()
&& tokio::fs::write(&tmp_path, session).await.is_ok()
{
@@ -561,16 +561,6 @@ pub fn run_cli() -> Result<(), Box<dyn std::error::Error>> {
rt.block_on(async {
let state = Arc::new(MemoryState::new(&base.to_string_lossy()));
match crate::vector_db::VectorDB::new("http://localhost:6334", "mcp_memory").await {
Ok(vdb) => {
tracing::info!("Successfully connected to Qdrant vector database");
*state.vector_db.write().await = Some(vdb);
}
Err(e) => {
tracing::warn!("Failed to initialize Qdrant vector database: {}. Vector search will fallback to manual embedding loop. (Is Qdrant running on localhost:6334?)", e);
}
}
if let Err(e) = run_server(state).await {
tracing::error!("Server error: {}", e);
}
@@ -594,7 +584,13 @@ mod tests {
#[test]
fn test_cli_parsing_exit_and_target() {
let cli = Cli::try_parse_from(&["mcp-memory-server", "--exit", "--target", "http://localhost:3000"]).unwrap();
let cli = Cli::try_parse_from(&[
"mcp-memory-server",
"--exit",
"--target",
"http://localhost:3000",
])
.unwrap();
assert!(cli.exit);
assert_eq!(cli.target.as_deref(), Some("http://localhost:3000"));
}
@@ -615,7 +611,17 @@ mod tests {
])
.unwrap();
if let Some(Commands::Gate { subcmd: GateCommands::Set { action, target, authorize, reason, .. } }) = cli.command {
if let Some(Commands::Gate {
subcmd:
GateCommands::Set {
action,
target,
authorize,
reason,
..
},
}) = cli.command
{
assert_eq!(action, "git_push");
assert_eq!(target, "master");
assert!(authorize);
@@ -639,7 +645,16 @@ mod tests {
])
.unwrap();
if let Some(Commands::Gate { subcmd: GateCommands::Verify { action, target, consume, .. } }) = cli.command {
if let Some(Commands::Gate {
subcmd:
GateCommands::Verify {
action,
target,
consume,
..
},
}) = cli.command
{
assert_eq!(action, "deploy");
assert_eq!(target, "prod");
assert!(consume);
@@ -709,7 +724,3 @@ mod tests {
server_handle.abort();
}
}