-
Notifications
You must be signed in to change notification settings - Fork 242
Implementation of knowledge base directory setting #2484
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1881,7 +1881,10 @@ impl ChatSession { | |
ev.is_accepted = true; | ||
}); | ||
|
||
let invoke_result = tool.tool.invoke(os, &mut self.stdout).await; | ||
let invoke_result = tool | ||
.tool | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice |
||
.invoke(os, &mut self.stdout, self.conversation.agents.get_active()) | ||
.await; | ||
|
||
if self.spinner.is_some() { | ||
queue!( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
use std::io::Write; | ||
use std::path::Path; | ||
|
||
use crossterm::queue; | ||
use crossterm::style::{ | ||
|
@@ -7,12 +8,17 @@ use crossterm::style::{ | |
}; | ||
use eyre::Result; | ||
use serde::Deserialize; | ||
use tracing::warn; | ||
use tracing::{ | ||
error, | ||
warn, | ||
}; | ||
|
||
use super::{ | ||
InvokeOutput, | ||
OutputKind, | ||
}; | ||
use crate::cli::agent::Agent; | ||
use crate::cli::chat::cli::knowledge::Settings; | ||
use crate::database::settings::Setting; | ||
use crate::os::Os; | ||
use crate::util::knowledge_store::KnowledgeStore; | ||
|
@@ -305,9 +311,9 @@ impl Knowledge { | |
Ok(()) | ||
} | ||
|
||
pub async fn invoke(&self, os: &Os, _updates: &mut impl Write) -> Result<InvokeOutput> { | ||
pub async fn invoke(&self, os: &Os, _updates: &mut impl Write, agent: Option<&Agent>) -> Result<InvokeOutput> { | ||
// Get the async knowledge store singleton | ||
let async_knowledge_store = KnowledgeStore::get_async_instance().await; | ||
let async_knowledge_store = KnowledgeStore::get_async_instance(Self::get_knowledge_base_dir(agent)).await; | ||
let mut store = async_knowledge_store.lock().await; | ||
|
||
let result = match self { | ||
|
@@ -542,4 +548,22 @@ impl Knowledge { | |
) | ||
} | ||
} | ||
|
||
fn get_knowledge_base_dir(agent: Option<&Agent>) -> Option<impl AsRef<Path> + use<>> { | ||
if agent.is_none() { | ||
return None; | ||
} | ||
|
||
agent.unwrap().tools_settings.get("knowledge")?.get("base_dir"); | ||
match agent.unwrap().tools_settings.get("knowledge") { | ||
Some(settings) => match serde_json::from_value::<Settings>(settings.clone()) { | ||
Ok(settings) => Some(settings.base_dir), | ||
Err(e) => { | ||
error!("Failed to deserialize tool settings for execute_bash: {:?}", e); | ||
None | ||
}, | ||
}, | ||
None => None, | ||
} | ||
} | ||
Comment on lines
+552
to
+568
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a better way to share this function between the knowledge base tool and setting? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, it's fine if the tool has the responsibility to know where this needs to be extracted, careful with usage of unwrap here. So we can gracefully handle failure scenarios. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -107,15 +107,15 @@ impl Tool { | |
} | ||
|
||
/// Invokes the tool asynchronously | ||
pub async fn invoke(&self, os: &Os, stdout: &mut impl Write) -> Result<InvokeOutput> { | ||
pub async fn invoke(&self, os: &Os, stdout: &mut impl Write, agent: Option<&Agent>) -> Result<InvokeOutput> { | ||
match self { | ||
Tool::FsRead(fs_read) => fs_read.invoke(os, stdout).await, | ||
Tool::FsWrite(fs_write) => fs_write.invoke(os, stdout).await, | ||
Tool::ExecuteCommand(execute_command) => execute_command.invoke(stdout).await, | ||
Tool::UseAws(use_aws) => use_aws.invoke(os, stdout).await, | ||
Tool::Custom(custom_tool) => custom_tool.invoke(os, stdout).await, | ||
Tool::GhIssue(gh_issue) => gh_issue.invoke(os, stdout).await, | ||
Tool::Knowledge(knowledge) => knowledge.invoke(os, stdout).await, | ||
Tool::Knowledge(knowledge) => knowledge.invoke(os, stdout, agent).await, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very unsure of this - is there another way for us to pass tool settings? Looks like we've started to pass the agent for requires_acceptance, so figured this would be an acceptable pattern. Again, open to feedback though. |
||
Tool::Thinking(think) => think.invoke(stdout).await, | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
use std::path::Path; | ||
use std::sync::{ | ||
Arc, | ||
LazyLock as Lazy, | ||
|
@@ -32,21 +33,21 @@ pub struct KnowledgeStore { | |
|
||
impl KnowledgeStore { | ||
/// Get singleton instance | ||
pub async fn get_async_instance() -> Arc<Mutex<Self>> { | ||
pub async fn get_async_instance(path: Option<impl AsRef<Path>>) -> Arc<Mutex<Self>> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because any invocation of this could technically create the instance, we need to always pass the path if possible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's the downside of a Lazy singleton |
||
static ASYNC_INSTANCE: Lazy<tokio::sync::OnceCell<Arc<Mutex<KnowledgeStore>>>> = | ||
Lazy::new(tokio::sync::OnceCell::new); | ||
|
||
if cfg!(test) { | ||
Arc::new(Mutex::new( | ||
KnowledgeStore::new() | ||
KnowledgeStore::new(path) | ||
.await | ||
.expect("Failed to create test async knowledge store"), | ||
)) | ||
} else { | ||
ASYNC_INSTANCE | ||
.get_or_init(|| async { | ||
Arc::new(Mutex::new( | ||
KnowledgeStore::new() | ||
KnowledgeStore::new(path) | ||
.await | ||
.expect("Failed to create async knowledge store"), | ||
)) | ||
|
@@ -56,12 +57,21 @@ impl KnowledgeStore { | |
} | ||
} | ||
|
||
pub async fn new() -> Result<Self> { | ||
let client = AsyncSemanticSearchClient::new_with_default_dir() | ||
.await | ||
.map_err(|e| eyre::eyre!("Failed to create client: {}", e))?; | ||
|
||
Ok(Self { client }) | ||
pub async fn new(path: Option<impl AsRef<Path>>) -> Result<Self> { | ||
match path { | ||
Some(path) => { | ||
let client = AsyncSemanticSearchClient::new(path) | ||
.await | ||
.map_err(|e| eyre::eyre!("Failed to create client: {}", e))?; | ||
Ok(Self { client }) | ||
}, | ||
None => { | ||
let client = AsyncSemanticSearchClient::new_with_default_dir() | ||
.await | ||
.map_err(|e| eyre::eyre!("Failed to create client: {}", e))?; | ||
Ok(Self { client }) | ||
}, | ||
} | ||
} | ||
|
||
/// Add context - delegates to async client | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be better to pass the session in here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, the less parameters the better specially if more than 1 parameter has same type.