diff --git a/src/config/agent.rs b/src/config/agent.rs index 569ec48..2630129 100644 --- a/src/config/agent.rs +++ b/src/config/agent.rs @@ -185,7 +185,7 @@ impl Agent { &rag_path_clone, &document_paths, abort, - false, + true, ) .await }) @@ -1025,7 +1025,7 @@ async fn init_graph_rags( { bail!("rag node '{node_id}': {message}"); } - let config = rag_init_config(rag_node); + let mut config = rag_init_config(rag_node); let fully_specified = config.embedding_model.is_some() && config.chunk_size.is_some() && config.chunk_overlap.is_some(); @@ -1051,6 +1051,10 @@ async fn init_graph_rags( initialized. RAG initialization is required for this agent." ); } + + if config.driver.is_none() { + config.driver = Some(crate::rag::select_rag_driver()?); + } } let document_paths = diff --git a/src/rag/mod.rs b/src/rag/mod.rs index 69e6ea9..a71d7b7 100644 --- a/src/rag/mod.rs +++ b/src/rag/mod.rs @@ -267,31 +267,10 @@ impl Rag { } println!("⚙ Initializing RAG..."); let (embedding_model, chunk_size, chunk_overlap) = Self::create_config(app)?; - // Only interactive named-RAG creation offers a driver choice. Temp RAGs and - // agent startup pass `false`; an explicit flag is used rather than inferring - // from the name because the agent path passes the literal name "rag", which is - // indistinguishable from a user creating a RAG genuinely named `rag`. let driver = if prompt_for_driver { - let options = vec![ - "yaml — portable, in-memory HNSW; usable from several Coyote processes at once (default)", - "duckdb — persistent on-disk store; vectors and content survive restarts; HNSW approximate search.", - ]; - let sel = Select::new("RAG storage driver:", options) - .with_starting_cursor(0) - .prompt()?; - if sel.starts_with("duckdb") { - println!( - "Note: several Coyote processes can query a duckdb RAG at the same time, \ - but while one process is ingesting or rebuilding it the others cannot \ - read it until that finishes. Changing its driver later means deleting \ - and recreating the RAG." - ); - "duckdb" - } else { - "yaml" - } + select_rag_driver()? } else { - "yaml" + "yaml".to_string() }; let reranker_model = app.rag_reranker_model.clone(); let top_k = app.rag_top_k; @@ -318,7 +297,7 @@ impl Rag { graph_hops: Some(graph_hops), }, ); - data.driver = driver.to_string(); + data.driver = driver; let mut rag = Self::create(app, name, save_path, data)?; let mut paths = doc_paths.to_vec(); if paths.is_empty() { @@ -1867,6 +1846,27 @@ fn select_embedding_model(models: &[&Model]) -> Result { Ok(result.value) } +pub(crate) fn select_rag_driver() -> Result { + let options = vec![ + "yaml — portable, in-memory HNSW; usable from several Coyote processes at once (default)", + "duckdb — persistent on-disk store; vectors and content survive restarts; HNSW approximate search.", + ]; + let sel = Select::new("RAG storage driver:", options) + .with_starting_cursor(0) + .prompt()?; + if sel.starts_with("duckdb") { + println!( + "Note: several Coyote processes can query a duckdb RAG at the same time, \ + but while one process is ingesting or rebuilding it the others cannot \ + read it until that finishes. Changing its driver later means deleting \ + and recreating the RAG." + ); + Ok("duckdb".to_string()) + } else { + Ok("yaml".to_string()) + } +} + const EXTRACTOR_SKIP: &str = "Skip"; fn select_extractor_model(app: &AppConfig) -> Result> {