Refactor: Fix clippy warnings and introduce AppError
This commit is contained in:
1 parent
3add6c3d31
commit
4e1a633dbd
13 files changed
+129
-103
No files matched your search
Generated
+7
@@ -4010,6 +4010,12 @@ dependencies = [
|
|||||||
"digest 0.11.3",
|
"digest 0.11.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha1_smol"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@@ -5053,6 +5059,7 @@ dependencies = [
|
|||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
|
"sha1_smol",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
# Effective Discourse: LLM Prompting Guide for MCP Memory
|
|
||||||
|
|
||||||
To get the most out of the Antigravity MCP Memory server and its advanced developer tools, use specific phrases that clearly state your intent. This guides the LLM to use the most efficient tools, reducing token consumption, speeding up time-to-resolve (T2R), and avoiding brute-force file reading.
|
|
||||||
|
|
||||||
## 1. Codebase Exploration & Token Efficiency
|
|
||||||
When entering a new file, avoid having the LLM read the entire contents blindly.
|
|
||||||
* **Don't say:** "Read server.rs and tell me what it does." *(Consumes massive tokens)*
|
|
||||||
* **Do say:** "Extract the AST skeleton of server.rs to understand its structure first."
|
|
||||||
* **Tool Triggered:** ␍ead_file_skeleton
|
|
||||||
|
|
||||||
## 2. Debugging & Log Parsing
|
|
||||||
Stop copy-pasting giant walls of logs into the chat interface.
|
|
||||||
* **Don't say:** "Here is the error: [paste 500 lines of logs]"
|
|
||||||
* **Do say:** "The daemon crashed. Fetch the recent logs from daemon.log." or "Watch the process logs for server.log."
|
|
||||||
* **Tool Triggered:** get_recent_logs, watch_process_logs
|
|
||||||
|
|
||||||
## 3. Git & Context Handoff
|
|
||||||
When you've been working independently and need to loop the LLM back in on your current state.
|
|
||||||
* **Don't say:** "I changed some files, here are the diffs..."
|
|
||||||
* **Do say:** "Get the active git worktree context to review my uncommitted changes before we continue."
|
|
||||||
* **Tool Triggered:** get_active_worktree_context
|
|
||||||
|
|
||||||
## 4. Clipboard Watch Mode (Research & Triage)
|
|
||||||
When you are doing intense debugging across StackOverflow, logs, and docs, use the clipboard watcher to auto-ingest your breadcrumbs.
|
|
||||||
* **Action:** Ask the LLM to turn it on: "Enable clipboard watch mode."
|
|
||||||
* **Do say:** "I'm going to reproduce the bug and copy some stack traces and IDs. Give me a minute, then read my latest sticky notes to catch up."
|
|
||||||
* **Tool Triggered:** oggle_clipboard_watch_mode, followed by internal Sticky Note reads.
|
|
||||||
|
|
||||||
## 5. Neovim Ghost Text (Live Previews)
|
|
||||||
Keep your workflow entirely within your editor rather than copy-pasting code blocks from the chat.
|
|
||||||
* **Don't say:** "Write the updated function here so I can copy-paste it."
|
|
||||||
* **Do say:** "Push this refactor to my active Neovim buffer as ghost text so I can review it in-line."
|
|
||||||
* **Tool Triggered:**
|
|
||||||
vim_set_preview
|
|
||||||
|
|
||||||
## 6. Graph & Memory Management
|
|
||||||
Actively instruct the LLM to maintain its own memory constraints and organize data.
|
|
||||||
* **Do say:** "Log this architectural decision in the knowledge graph."
|
|
||||||
* **Do say:** "Add a sticky note with the test database credentials for this session."
|
|
||||||
* **Do say:** "Create a milestone for the 'Rich Clipboard' feature and break it down into active tasks."
|
|
||||||
* **Tools Triggered:** create_entities, log_decision, dd_sticky_note, dd_milestone, dd_task
|
|
||||||
|
|
||||||
By phrasing requests around *actions* rather than *information retrieval*, the LLM is primed to leverage the rich MCP toolset built into the Antigravity Memory Server.
|
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# MCP Tools Review & Enhancement Strategy
|
||||||
|
|
||||||
|
## Part 1: Current Arsenal Review
|
||||||
|
|
||||||
|
Our current MCP ecosystem is highly advanced, utilizing a **Dual-Transport Leader/Stub Architecture** (Windows Host + WSL Proxy) to completely eliminate cross-OS I/O latency.
|
||||||
|
|
||||||
|
### 1. Context & Token Optimization
|
||||||
|
* ␍ead_file_skeleton: Highly effective. Uses ree-sitter to extract ASTs (Rust, Python, TS). **Score: A+ (Massive token savings)**
|
||||||
|
* get_active_worktree_context: Native git2 integration. Bypasses shell parsing for clean JSON diffs. **Score: A**
|
||||||
|
* watch_process_logs / get_recent_logs: Direct file seeking. Prevents LLMs from reading multi-megabyte log files. **Score: A**
|
||||||
|
|
||||||
|
### 2. Neovim IDE Integration (
|
||||||
|
vim-core)
|
||||||
|
*
|
||||||
|
vim_set_preview,
|
||||||
|
vim_goto_line,
|
||||||
|
vim_set_diagnostics,
|
||||||
|
vim_execute_lua,
|
||||||
|
vim_get_active_buffer.
|
||||||
|
* **Review:** Exceptional human QoL. The agent interacts with the code where the human's eyes actually are. Ghost text and diagnostic extmarks provide an IDE-like experience usually reserved for closed-source tools like Cursor. **Score: S-Tier**
|
||||||
|
|
||||||
|
### 3. Clipboard & Workflow
|
||||||
|
* write_clipboard, ␍ead_clipboard, oggle_clipboard_watch_mode.
|
||||||
|
* **Review:** Native cross-OS clipboard-win and rboard implementation. Auto-ingesting into StickyNotes bridges the gap between manual human research and the agent's context. **Score: A**
|
||||||
|
|
||||||
|
### 4. Graph & Memory Management
|
||||||
|
* create_entities, dd_sticky_note, save_context_workspace, handoff_routine.
|
||||||
|
* **Review:** Solid foundation for state persistence across branches and days. **Score: B+** (Could use more automated TTL/decay for outdated context).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Part 2: Proposed Enhancements (Focus: T2R, Token Cost, QoL)
|
||||||
|
|
||||||
|
To push the system to the absolute bleeding edge of autonomous coding, I propose the following 5 new tools/enhancements.
|
||||||
|
|
||||||
|
### 1. ␍eplace_ast_node (Robust Structural Editing)
|
||||||
|
* **The Problem:** The current ␍eplace_file_content uses exact string matching and line numbers. Line numbers change when humans edit simultaneously, and string matching fails on whitespace/indentation.
|
||||||
|
* **The Solution:** An MCP tool that takes (file_path, node_type, node_name, new_content). It uses ree-sitter to find the exact boundary of n execute(...) and replaces just that AST node.
|
||||||
|
* **Impact:** Zero LLM syntax/indentation errors. 100% robust edits. Drastically lowers Time-to-Resolve (T2R) by eliminating failed edit loops.
|
||||||
|
|
||||||
|
### 2. semantic_code_search (Local Vector Embeddings)
|
||||||
|
* **The Problem:** grep_search relies on exact regex. If the LLM guesses the wrong variable name, it wastes tokens searching and reading the wrong files.
|
||||||
|
* **The Solution:** We already have antivy and astembed in our Cargo.toml. We can index the AST blocks of the codebase in the background. The LLM can query *"Where is the auth token validated?"* and get the exact 3 relevant functions instantly.
|
||||||
|
* **Impact:** Massive token cost reduction (no blind file reading). Instant T2R for codebase exploration.
|
||||||
|
|
||||||
|
### 3.
|
||||||
|
vim_send_to_terminal (Interactive Execution QoL)
|
||||||
|
* **The Problem:** When the agent runs a background terminal command (cargo build,
|
||||||
|
pm run dev), the output is hidden from the human, and interactive prompts cause the background task to hang indefinitely.
|
||||||
|
* **The Solution:** A tool that opens a Neovim :term split (or uses a mux pane) and sends the command there.
|
||||||
|
* **Impact:** Massive Human QoL. The human can watch the tests run natively, interact with prompts, see ANSI colors, and press <C-c> to kill it if it loops.
|
||||||
|
|
||||||
|
### 4. ␍ead_directory_architecture (Bird's-Eye View)
|
||||||
|
* **The Problem:** ␍ead_file_skeleton works for one file. When entering a new repository, the LLM usually runs ls -R and then has to guess what files do based on their names.
|
||||||
|
* **The Solution:** A tool that scans a directory structure and uses basic heuristic parsing (or a tiny local embedding lookup) to return a JSON tree of files alongside a 1-sentence summary of what each file is responsible for.
|
||||||
|
* **Impact:** Immediate holistic context. Eliminates the "exploration phase" token tax.
|
||||||
|
|
||||||
|
### 5. query_database_schema (Introspection)
|
||||||
|
* **The Problem:** Working with databases usually involves the LLM writing clunky bash scripts to run psql or sqlite3 to view table definitions, which often fail due to missing env vars or wrong dialects.
|
||||||
|
* **The Solution:** A direct MCP tool that parses the local .env, connects to the database (Postgres/SQLite), and returns a clean Markdown representation of the schema (Tables, Columns, Types, Foreign Keys).
|
||||||
|
* **Impact:** Prevents hallucinations about database structure. Fixes DB-related bugs significantly faster (T2R).
|
||||||
@@ -19,9 +19,9 @@ pub fn spawn_watcher(state: Arc<MemoryState>) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(_clip) = tokio::task::spawn_blocking(|| Clipboard::new_attempts(3)).await.unwrap() {
|
if let Ok(_clip) = tokio::task::spawn_blocking(|| Clipboard::new_attempts(3)).await.unwrap()
|
||||||
if let Ok(text) = get_clipboard::<String, _>(formats::Unicode) {
|
&& let Ok(text) = get_clipboard::<String, _>(formats::Unicode)
|
||||||
if text != last_text && !text.trim().is_empty() {
|
&& text != last_text && !text.trim().is_empty() {
|
||||||
last_text = text.clone();
|
last_text = text.clone();
|
||||||
|
|
||||||
let note = StickyNote {
|
let note = StickyNote {
|
||||||
@@ -40,8 +40,6 @@ pub fn spawn_watcher(state: Arc<MemoryState>) {
|
|||||||
// We use rebuild_index to index the new sticky note
|
// We use rebuild_index to index the new sticky note
|
||||||
state.rebuild_index().await;
|
state.rebuild_index().await;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
+17
-1
@@ -6,6 +6,8 @@ use axum::{
|
|||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, AppError>;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum AppError {
|
pub enum AppError {
|
||||||
#[error("Not Found: {0}")]
|
#[error("Not Found: {0}")]
|
||||||
@@ -19,6 +21,18 @@ pub enum AppError {
|
|||||||
|
|
||||||
#[error("Bad Request: {0}")]
|
#[error("Bad Request: {0}")]
|
||||||
BadRequest(String),
|
BadRequest(String),
|
||||||
|
|
||||||
|
#[error("Serialization Error: {0}")]
|
||||||
|
JsonError(#[from] serde_json::Error),
|
||||||
|
|
||||||
|
#[error("I/O Error: {0}")]
|
||||||
|
IoError(#[from] std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AppError> for String {
|
||||||
|
fn from(err: AppError) -> String {
|
||||||
|
err.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoResponse for AppError {
|
impl IntoResponse for AppError {
|
||||||
@@ -26,8 +40,10 @@ impl IntoResponse for AppError {
|
|||||||
let (status, error_message) = match &self {
|
let (status, error_message) = match &self {
|
||||||
AppError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()),
|
AppError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()),
|
||||||
AppError::Forbidden(msg) => (StatusCode::FORBIDDEN, msg.clone()),
|
AppError::Forbidden(msg) => (StatusCode::FORBIDDEN, msg.clone()),
|
||||||
AppError::Internal(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg.clone()),
|
|
||||||
AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg.clone()),
|
AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg.clone()),
|
||||||
|
AppError::Internal(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg.clone()),
|
||||||
|
AppError::JsonError(e) => (StatusCode::INTERNAL_SERVER_ERROR, format!("JSON Error: {}", e)),
|
||||||
|
AppError::IoError(e) => (StatusCode::INTERNAL_SERVER_ERROR, format!("I/O Error: {}", e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = Json(json!({
|
let body = Json(json!({
|
||||||
|
|||||||
@@ -55,13 +55,7 @@ impl McpTool for ReadFileSkeletonHandler {
|
|||||||
fn extract_skeleton(node: Node, code: &str, out: &mut String, depth: usize) {
|
fn extract_skeleton(node: Node, code: &str, out: &mut String, depth: usize) {
|
||||||
let kind = node.kind();
|
let kind = node.kind();
|
||||||
|
|
||||||
let is_structural = match kind {
|
let is_structural = matches!(kind, "use_declaration" | "import_statement" | "import_from_statement" | "struct_item" | "enum_item" | "trait_item" | "impl_item" | "function_item" | "function_declaration" | "function_definition" | "method_definition" | "interface_declaration" | "type_alias_declaration" | "class_declaration" | "class_definition");
|
||||||
"use_declaration" | "import_statement" | "import_from_statement" => true,
|
|
||||||
"struct_item" | "enum_item" | "trait_item" | "impl_item" => true,
|
|
||||||
"function_item" | "function_declaration" | "function_definition" | "method_definition" => true,
|
|
||||||
"interface_declaration" | "type_alias_declaration" | "class_declaration" | "class_definition" => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if is_structural {
|
if is_structural {
|
||||||
let indent = " ".repeat(depth);
|
let indent = " ".repeat(depth);
|
||||||
@@ -84,7 +78,7 @@ impl McpTool for ReadFileSkeletonHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out.push_str(&indent);
|
out.push_str(&indent);
|
||||||
out.push_str(&signature.trim());
|
out.push_str(signature.trim());
|
||||||
out.push('\n');
|
out.push('\n');
|
||||||
} else if node.is_named() {
|
} else if node.is_named() {
|
||||||
let mut cursor = node.walk();
|
let mut cursor = node.walk();
|
||||||
|
|||||||
@@ -27,11 +27,10 @@ impl McpTool for GetActiveWorktreeContextHandler {
|
|||||||
let repo = git2::Repository::discover(&cwd).map_err(|e| format!("Not in a git repository: {}", e))?;
|
let repo = git2::Repository::discover(&cwd).map_err(|e| format!("Not in a git repository: {}", e))?;
|
||||||
|
|
||||||
let mut branch_name = String::new();
|
let mut branch_name = String::new();
|
||||||
if let Ok(head) = repo.head() {
|
if let Ok(head) = repo.head()
|
||||||
if let Some(name) = head.shorthand() {
|
&& let Some(name) = head.shorthand() {
|
||||||
branch_name = name.to_string();
|
branch_name = name.to_string();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let mut opts = git2::DiffOptions::new();
|
let mut opts = git2::DiffOptions::new();
|
||||||
let mut diff = None;
|
let mut diff = None;
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ impl McpTool for OmniSearchHandler {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
println!("OMNI SEARCH MATCHES: {:?}", matches);
|
// tracing::info!("OMNI SEARCH MATCHES: {:?}", matches);
|
||||||
let q = req.query.clone();
|
let q = req.query.clone();
|
||||||
let query_emb = crate::embedding::generate_embedding_async(q.clone()).await.unwrap_or_default();
|
let query_emb = crate::embedding::generate_embedding_async(q.clone()).await.unwrap_or_default();
|
||||||
|
|
||||||
@@ -846,7 +846,7 @@ mod tests {
|
|||||||
.execute(json!({"query": "Omni"}), state.clone())
|
.execute(json!({"query": "Omni"}), state.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("OMNI RES: {}", omni_res);
|
// tracing::info!("OMNI RES: {}", omni_res);
|
||||||
assert!(
|
assert!(
|
||||||
omni_res.contains("omni-1"),
|
omni_res.contains("omni-1"),
|
||||||
"omni search should return results containing the task id"
|
"omni search should return results containing the task id"
|
||||||
|
|||||||
@@ -32,25 +32,21 @@ impl McpTool for WriteClipboardHandler {
|
|||||||
let mut msgs = Vec::new();
|
let mut msgs = Vec::new();
|
||||||
|
|
||||||
// Handle clipboard_win formats (text, html, files)
|
// Handle clipboard_win formats (text, html, files)
|
||||||
if tool_args.text.is_some() || tool_args.html.is_some() || tool_args.files.is_some() {
|
if (tool_args.text.is_some() || tool_args.html.is_some() || tool_args.files.is_some())
|
||||||
if let Ok(_clip) = Clipboard::new_attempts(3) {
|
&& let Ok(_clip) = Clipboard::new_attempts(3) {
|
||||||
if let Some(text) = &tool_args.text {
|
if let Some(text) = &tool_args.text
|
||||||
if clipboard_win::set_clipboard_string(text).is_ok() {
|
&& clipboard_win::set_clipboard_string(text).is_ok() {
|
||||||
msgs.push("Wrote text");
|
msgs.push("Wrote text");
|
||||||
}
|
}
|
||||||
}
|
if let Some(html) = &tool_args.html
|
||||||
if let Some(html) = &tool_args.html {
|
&& formats::Html::new().unwrap().write_clipboard(html).is_ok() {
|
||||||
if formats::Html::new().unwrap().write_clipboard(html).is_ok() {
|
|
||||||
msgs.push("Wrote HTML");
|
msgs.push("Wrote HTML");
|
||||||
}
|
}
|
||||||
}
|
if let Some(files) = &tool_args.files
|
||||||
if let Some(files) = &tool_args.files {
|
&& raw::set_file_list(files).is_ok() {
|
||||||
if raw::set_file_list(files).is_ok() {
|
|
||||||
msgs.push("Wrote FileList");
|
msgs.push("Wrote FileList");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Handle arboard for image
|
// Handle arboard for image
|
||||||
if let Some(image_path) = &tool_args.image_path {
|
if let Some(image_path) = &tool_args.image_path {
|
||||||
@@ -106,26 +102,23 @@ impl McpTool for ReadClipboardHandler {
|
|||||||
let mut out = serde_json::Map::new();
|
let mut out = serde_json::Map::new();
|
||||||
|
|
||||||
if let Ok(_clip) = Clipboard::new_attempts(3) {
|
if let Ok(_clip) = Clipboard::new_attempts(3) {
|
||||||
if let Ok(text) = get_clipboard::<String, _>(formats::Unicode) {
|
if let Ok(text) = get_clipboard::<String, _>(formats::Unicode)
|
||||||
if !text.trim().is_empty() {
|
&& !text.trim().is_empty() {
|
||||||
out.insert("text".into(), json!(text));
|
out.insert("text".into(), json!(text));
|
||||||
}
|
}
|
||||||
}
|
if let Ok(html) = get_clipboard::<String, _>(formats::Html::new().unwrap())
|
||||||
if let Ok(html) = get_clipboard::<String, _>(formats::Html::new().unwrap()) {
|
&& !html.trim().is_empty() {
|
||||||
if !html.trim().is_empty() {
|
|
||||||
out.insert("html".into(), json!(html));
|
out.insert("html".into(), json!(html));
|
||||||
}
|
}
|
||||||
}
|
if let Ok(files) = get_clipboard::<Vec<String>, _>(formats::FileList)
|
||||||
if let Ok(files) = get_clipboard::<Vec<String>, _>(formats::FileList) {
|
&& !files.is_empty() {
|
||||||
if !files.is_empty() {
|
|
||||||
out.insert("files".into(), json!(files));
|
out.insert("files".into(), json!(files));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(mut clipboard) = arboard::Clipboard::new() {
|
if let Ok(mut clipboard) = arboard::Clipboard::new()
|
||||||
if let Ok(image_data) = clipboard.get_image() {
|
&& let Ok(image_data) = clipboard.get_image()
|
||||||
if let Some(img) = ImageBuffer::<image::Rgba<u8>, _>::from_raw(
|
&& let Some(img) = ImageBuffer::<image::Rgba<u8>, _>::from_raw(
|
||||||
image_data.width as u32,
|
image_data.width as u32,
|
||||||
image_data.height as u32,
|
image_data.height as u32,
|
||||||
image_data.bytes.into_owned(),
|
image_data.bytes.into_owned(),
|
||||||
@@ -152,8 +145,6 @@ impl McpTool for ReadClipboardHandler {
|
|||||||
out.insert("image_path".into(), json!(file_path.to_string_lossy().to_string()));
|
out.insert("image_path".into(), json!(file_path.to_string_lossy().to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Value::Object(out))
|
Ok(Value::Object(out))
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub async fn start_background_indexer(state: Arc<MemoryState>) {
|
|||||||
for result in walker {
|
for result in walker {
|
||||||
match result {
|
match result {
|
||||||
Ok(entry) => {
|
Ok(entry) => {
|
||||||
if entry.file_type().map_or(false, |ft| ft.is_file()) {
|
if entry.file_type().is_some_and(|ft| ft.is_file()) {
|
||||||
let path = entry.path().to_path_buf();
|
let path = entry.path().to_path_buf();
|
||||||
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
|
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
|
||||||
if ["rs", "ts", "js", "jsx", "tsx", "py", "java", "c", "cpp", "go"].contains(&ext) {
|
if ["rs", "ts", "js", "jsx", "tsx", "py", "java", "c", "cpp", "go"].contains(&ext) {
|
||||||
@@ -98,7 +98,7 @@ pub async fn start_background_indexer(state: Arc<MemoryState>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_chunks(node: Node, code: &str, chunks: &mut Vec<(String, String, String)>, ext: &str) {
|
fn extract_chunks(node: Node, code: &str, chunks: &mut Vec<(String, String, String)>, _ext: &str) {
|
||||||
let kind = node.kind();
|
let kind = node.kind();
|
||||||
let is_structural = matches!(
|
let is_structural = matches!(
|
||||||
kind,
|
kind,
|
||||||
@@ -128,7 +128,7 @@ fn extract_chunks(node: Node, code: &str, chunks: &mut Vec<(String, String, Stri
|
|||||||
} else {
|
} else {
|
||||||
let mut cursor = node.walk();
|
let mut cursor = node.walk();
|
||||||
for child in node.named_children(&mut cursor) {
|
for child in node.named_children(&mut cursor) {
|
||||||
extract_chunks(child, code, chunks, ext);
|
extract_chunks(child, code, chunks, _ext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,7 +258,7 @@ impl MemoryIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_task_sync(&self, t: &Task) {
|
pub fn add_task_sync(&self, t: &Task) {
|
||||||
println!("add_task_sync called for task: {}", t.id);
|
// println!("add_task_sync called for task: {}", t.id);
|
||||||
if let Ok(writer) = self.writer.lock() {
|
if let Ok(writer) = self.writer.lock() {
|
||||||
let _res = writer.add_document(doc!(
|
let _res = writer.add_document(doc!(
|
||||||
self.id_field => t.id.as_str(),
|
self.id_field => t.id.as_str(),
|
||||||
@@ -267,12 +267,12 @@ impl MemoryIndex {
|
|||||||
self.type_field => "task",
|
self.type_field => "task",
|
||||||
self.namespace_field => "global"
|
self.namespace_field => "global"
|
||||||
));
|
));
|
||||||
println!("Writer add_document returned id/result");
|
// println!("Writer add_document returned id/result");
|
||||||
self.needs_commit
|
self.needs_commit
|
||||||
.store(true, std::sync::atomic::Ordering::SeqCst);
|
.store(true, std::sync::atomic::Ordering::SeqCst);
|
||||||
println!("Needs_commit set to true in add_task_sync");
|
// println!("Needs_commit set to true in add_task_sync");
|
||||||
} else {
|
} else {
|
||||||
println!("Failed to acquire writer lock in add_task_sync");
|
// println!("Failed to acquire writer lock in add_task_sync");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-7
@@ -1,6 +1,7 @@
|
|||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
use crate::search::MemoryIndex;
|
use crate::search::MemoryIndex;
|
||||||
use crate::store::Store;
|
use crate::store::Store;
|
||||||
|
use crate::vector_db::VectorDB;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
@@ -17,6 +18,7 @@ pub struct MemoryState {
|
|||||||
pub clipboard_watch_mode: tokio::sync::RwLock<bool>,
|
pub clipboard_watch_mode: tokio::sync::RwLock<bool>,
|
||||||
pub graph: Store<KnowledgeGraph>,
|
pub graph: Store<KnowledgeGraph>,
|
||||||
pub search_index: RwLock<MemoryIndex>,
|
pub search_index: RwLock<MemoryIndex>,
|
||||||
|
pub vector_db: tokio::sync::RwLock<Option<VectorDB>>,
|
||||||
pub ledger: Store<Vec<CodeChange>>,
|
pub ledger: Store<Vec<CodeChange>>,
|
||||||
pub sticky: Store<Vec<StickyNote>>,
|
pub sticky: Store<Vec<StickyNote>>,
|
||||||
pub tasks: Store<Vec<Task>>,
|
pub tasks: Store<Vec<Task>>,
|
||||||
@@ -63,6 +65,7 @@ impl MemoryState {
|
|||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
vector_db: tokio::sync::RwLock::new(None),
|
||||||
ledger: Store::new("audit_ledger", db.clone()),
|
ledger: Store::new("audit_ledger", db.clone()),
|
||||||
sticky: Store::new("sticky_notes", db.clone()),
|
sticky: Store::new("sticky_notes", db.clone()),
|
||||||
tasks: Store::new("tasks", db.clone()),
|
tasks: Store::new("tasks", db.clone()),
|
||||||
@@ -144,7 +147,7 @@ impl MemoryState {
|
|||||||
let snippets = self.snippets.read_with(|s| s.clone());
|
let snippets = self.snippets.read_with(|s| s.clone());
|
||||||
let adrs = self.adrs.read_with(|a| a.clone());
|
let adrs = self.adrs.read_with(|a| a.clone());
|
||||||
|
|
||||||
println!(
|
tracing::info!(
|
||||||
"rebuild_index: found {} entities, {} tasks",
|
"rebuild_index: found {} entities, {} tasks",
|
||||||
entities.len(),
|
entities.len(),
|
||||||
tasks.len()
|
tasks.len()
|
||||||
@@ -152,7 +155,7 @@ impl MemoryState {
|
|||||||
|
|
||||||
let idx_clone = idx.clone();
|
let idx_clone = idx.clone();
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
println!("spawn_blocking started in rebuild_index");
|
// tracing::info!("spawn_blocking started in rebuild_index");
|
||||||
for e in entities {
|
for e in entities {
|
||||||
idx_clone.add_entity_sync(&e);
|
idx_clone.add_entity_sync(&e);
|
||||||
}
|
}
|
||||||
@@ -222,13 +225,13 @@ mod tests {
|
|||||||
let idx = arc_state.search_index.read().unwrap();
|
let idx = arc_state.search_index.read().unwrap();
|
||||||
// Force reload reader to ensure it sees the commit made by rebuild_index
|
// Force reload reader to ensure it sees the commit made by rebuild_index
|
||||||
idx.reader.reload().unwrap();
|
idx.reader.reload().unwrap();
|
||||||
println!(
|
// tracing::info!(
|
||||||
"Index reader doc count: {}",
|
// "Index reader doc count: {}",
|
||||||
idx.reader.searcher().num_docs()
|
// idx.reader.searcher().num_docs()
|
||||||
);
|
// );
|
||||||
|
|
||||||
let all_docs = idx.search("Test", None).expect("Search failed");
|
let all_docs = idx.search("Test", None).expect("Search failed");
|
||||||
println!("All docs for 'Test': {:?}", all_docs);
|
// tracing::info!("All docs for 'Test': {:?}", all_docs);
|
||||||
|
|
||||||
// Verify the task added synchronously is actually searchable
|
// Verify the task added synchronously is actually searchable
|
||||||
let results = idx.search("Test", None).expect("Search failed");
|
let results = idx.search("Test", None).expect("Search failed");
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use qdrant_client::Qdrant;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use tracing::{info, error};
|
use tracing::info;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|||||||
Reference in new issue
Block a user