Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
1a9c14b
Integrate new tools for knowledge management and update existing func…
JegernOUTT Feb 19, 2025
14efb1c
Remove comments indicating default value for 'prepend_system_prompt'
JegernOUTT Feb 19, 2025
de1b3fb
Increase MAX_EXPLORATION_STEPS to 1000 in tool_create_memory_bank.rs
JegernOUTT Feb 19, 2025
3bce389
Refactor tools registration by relocating vecdb feature config and ge…
JegernOUTT Feb 19, 2025
fd503fe
Refine memory bank scoring and update system prompts
JegernOUTT Feb 19, 2025
ac04d3c
Enhance memory bank creation logging with detailed progress and direc…
JegernOUTT Feb 19, 2025
7966d59
Revise memory bank system prompt for clarity and structure
JegernOUTT Feb 19, 2025
03259dd
Clarify instructions for calling create_knowledge function in MB_EXPE…
JegernOUTT Feb 19, 2025
e164ea7
Adjust tokens budget calculation in deep thinking tool by reducing an…
JegernOUTT Feb 19, 2025
1fc7996
Refine "goal" field description for vector similarity search integration
JegernOUTT Feb 26, 2025
37b243e
Rename 'goal' to 'search_key' for clarity in tools configuration files.
JegernOUTT Feb 26, 2025
8caa39f
Refine tool descriptions in tools_description.rs for clarity and detail
JegernOUTT Feb 26, 2025
ab0c708
Enhance automatic knowledge building functionality in YAML configurat…
JegernOUTT Feb 26, 2025
052d964
Enhance follow-up message generation and topic detection logic
JegernOUTT Feb 26, 2025
05cff0c
Clarify instruction by emphasizing brevity of follow-up messages.
JegernOUTT Feb 26, 2025
4fca8f1
Clarify instruction by emphasizing brevity of follow-up messages.
JegernOUTT Feb 26, 2025
57a1c8e
Remove asynchronous vectorization blocking in knowledge creation process
JegernOUTT Feb 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions refact-agent/engine/src/agentic/generate_follow_up_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,23 @@ const PROMPT: &str = r#"
Your task is to do two things for a conversation between a user and an assistant:

1. **Follow-Up Messages:**
- Create up to 3 short follow-up messages that the user might send after the assistants last message.
- Create up to 5 super short follow-up messages that the user might send after the assistant's last message.
- The first message should invite the assistant to keep talking.
- Each message should have a different meaning.
- If there is no clear follow-up or the conversation isn’t asking a question, return an empty list.
- If the assistant's last message contains a question, generate different replies that address that question.
- Maybe include a suggestion to think.
- Maybe include a suggestion to explore more context (e.g., "Can we look at more files?", "Is there additional context I should provide?").
- Maybe include a suggestion to create knowledge.
- If there is no clear follow-up or the conversation isn't asking a question, return an empty list.

2. **Topic Change Detection:**
- Decide if the users latest message is about a different topic from the previous conversation.
- Decide if the user's latest message is about a different topic or a different project or a different problem from the previous conversation.
- A topic change means the new topic is not related to the previous discussion.

Return the result in this JSON format (without extra formatting):

{
"follow_ups": ["Follow-up 1", "Follow-up 2"],
"follow_ups": ["Follow-up 1", "Follow-up 2", "Follow-up 3", "Follow-up 4", "Follow-up 5"],
"topic_changed": true
}
"#;
Expand Down
14 changes: 14 additions & 0 deletions refact-agent/engine/src/at_commands/at_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ impl AtTree {
#[derive(Debug, Clone)]
pub struct PathsHolderNodeArc(Arc<RwLock<PathsHolderNode>>);

impl PathsHolderNodeArc {
pub fn read(&self) -> std::sync::RwLockReadGuard<'_, PathsHolderNode> {
self.0.read().unwrap()
}
}

impl PartialEq for PathsHolderNodeArc {
fn eq(&self, other: &Self) -> bool {
self.0.read().unwrap().path == other.0.read().unwrap().path
Expand All @@ -50,6 +56,14 @@ impl PathsHolderNode {
pub fn file_name(&self) -> String {
self.path.file_name().unwrap_or_default().to_string_lossy().to_string()
}

pub fn child_paths(&self) -> &Vec<PathsHolderNodeArc> {
&self.child_paths
}

pub fn get_path(&self) -> &PathBuf {
&self.path
}
}

pub fn construct_tree_out_of_flat_list_of_paths(paths_from_anywhere: &Vec<PathBuf>) -> Vec<PathsHolderNodeArc> {
Expand Down
2 changes: 1 addition & 1 deletion refact-agent/engine/src/http/routers/v1/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub fn available_tools_by_chat_mode(current_tools: Vec<Value>, chat_mode: &ChatM
vec![]
},
ChatMode::EXPLORE | ChatMode::AGENT => filter_out_tools(&current_tools, &vec!["think"]),
ChatMode::THINKING_AGENT => filter_out_tools(&current_tools, &vec!["knowledge"]),
ChatMode::THINKING_AGENT => current_tools,
ChatMode::CONFIGURE => filter_out_tools(&current_tools, &vec!["tree", "locate", "knowledge", "search"]),
ChatMode::PROJECT_SUMMARY => keep_tools(&current_tools, &vec!["cat", "tree", "bash"]),
}
Expand Down
3 changes: 2 additions & 1 deletion refact-agent/engine/src/http/routers/v1/subchat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub async fn handle_v1_subchat(
None,
None,
None,
Some(false),
).await.map_err(|e| ScratchError::new(StatusCode::INTERNAL_SERVER_ERROR, format!("Error: {}", e)))?;

let new_messages = new_messages.into_iter()
Expand Down Expand Up @@ -102,7 +103,7 @@ pub async fn handle_v1_subchat_single(
None,
post.n,
None,
true,
false,
None,
None,
None,
Expand Down
35 changes: 30 additions & 5 deletions refact-agent/engine/src/subchat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ pub async fn subchat(
temperature: Option<f32>,
tx_toolid_mb: Option<String>,
tx_chatid_mb: Option<String>,
prepend_system_prompt: Option<bool>,
) -> Result<Vec<Vec<ChatMessage>>, String> {
let mut messages = messages.clone();
let mut usage_collector = ChatUsage { ..Default::default() };
Expand Down Expand Up @@ -400,7 +401,7 @@ pub async fn subchat(
None,
1,
None,
true,
prepend_system_prompt.unwrap_or(false),
Some(&mut usage_collector),
tx_toolid_mb.clone(),
tx_chatid_mb.clone(),
Expand All @@ -423,7 +424,7 @@ pub async fn subchat(
None,
1,
None,
true,
prepend_system_prompt.unwrap_or(false),
Some(&mut usage_collector),
tx_toolid_mb.clone(),
tx_chatid_mb.clone(),
Expand All @@ -435,18 +436,42 @@ pub async fn subchat(
ccx.clone(),
model_name,
messages,
Some(vec![]),
Some("none".to_string()),
Some(tools_subset.clone()),
Some("auto".to_string()),
false,
temperature,
None,
wrap_up_n,
None,
true,
prepend_system_prompt.unwrap_or(false),
Some(&mut usage_collector),
tx_toolid_mb.clone(),
tx_chatid_mb.clone(),
).await?;
for messages in choices.iter() {
let last_message = messages.last().unwrap();
if let Some(tool_calls) = &last_message.tool_calls {
if !tool_calls.is_empty() {
_ = subchat_single(
ccx.clone(),
model_name,
messages.clone(),
Some(vec![]),
Some("none".to_string()),
true, // <-- only runs tool calls
temperature,
None,
1,
None,
prepend_system_prompt.unwrap_or(false),
Some(&mut usage_collector),
tx_toolid_mb.clone(),
tx_chatid_mb.clone(),
).await?[0].clone();
}
}

}
// if let Some(last_message) = messages.last_mut() {
// last_message.usage = Some(usage_collector);
// }
Expand Down
4 changes: 4 additions & 0 deletions refact-agent/engine/src/tools/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ mod tool_search;
mod tool_knowledge;
#[cfg(feature="vecdb")]
mod tool_locate_search;
#[cfg(feature="vecdb")]
mod tool_create_knowledge;
#[cfg(feature="vecdb")]
mod tool_create_memory_bank;
pub mod file_edit;
100 changes: 100 additions & 0 deletions refact-agent/engine/src/tools/tool_create_knowledge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use std::collections::HashMap;
use std::sync::Arc;
use async_trait::async_trait;
use serde_json::Value;
use tracing::info;
use tokio::sync::Mutex as AMutex;

use crate::at_commands::at_commands::AtCommandsContext;
use crate::call_validation::{ChatMessage, ChatContent, ContextEnum};
use crate::tools::tools_description::Tool;

pub struct ToolCreateKnowledge;

#[async_trait]
impl Tool for ToolCreateKnowledge {
fn as_any(&self) -> &dyn std::any::Any { self }

async fn tool_execute(
&mut self,
ccx: Arc<AMutex<AtCommandsContext>>,
tool_call_id: &String,
args: &HashMap<String, Value>,
) -> Result<(bool, Vec<ContextEnum>), String> {
info!("run @create-knowledge with args: {:?}", args);

let gcx = {
let ccx_locked = ccx.lock().await;
ccx_locked.global_context.clone()
};

let im_going_to_use_tools = match args.get("im_going_to_use_tools") {
Some(Value::String(s)) => s.clone(),
Some(v) => return Err(format!("argument `im_going_to_use_tools` is not a string: {:?}", v)),
None => return Err("argument `im_going_to_use_tools` is missing".to_string())
};

let im_going_to_apply_to = match args.get("im_going_to_apply_to") {
Some(Value::String(s)) => s.clone(),
Some(v) => return Err(format!("argument `im_going_to_apply_to` is not a string: {:?}", v)),
None => return Err("argument `im_going_to_apply_to` is missing".to_string())
};

let search_key = match args.get("search_key") {
Some(Value::String(s)) => s.clone(),
Some(v) => return Err(format!("argument `search_key` is not a string: {:?}", v)),
None => return Err("argument `search_key` is missing".to_string())
};

let language_slash_framework = match args.get("language_slash_framework") {
Some(Value::String(s)) => s.clone(),
Some(v) => return Err(format!("argument `language_slash_framework` is not a string: {:?}", v)),
None => return Err("argument `language_slash_framework` is missing".to_string())
};

let knowledge_entry = match args.get("knowledge_entry") {
Some(Value::String(s)) => s.clone(),
Some(v) => return Err(format!("argument `knowledge_entry` is not a string: {:?}", v)),
None => return Err("argument `knowledge_entry` is missing".to_string())
};

let vec_db = gcx.read().await.vec_db.clone();

// Store the memory with type "knowledge-entry"
let memid = match crate::vecdb::vdb_highlev::memories_add(
vec_db.clone(),
"knowledge-entry",
&search_key,
&im_going_to_apply_to,
&knowledge_entry,
"user-created"
).await {
Ok(id) => id,
Err(e) => return Err(format!("Failed to store knowledge: {}", e))
};

let message = format!("Knowledge entry created successfully with ID: {}\nTools: {}\nApply to: {}\nSearch Key: {}\nLanguage/Framework: {}\nEntry: {}",
memid,
im_going_to_use_tools,
im_going_to_apply_to,
search_key,
language_slash_framework,
knowledge_entry
);

let mut results = vec![];
results.push(ContextEnum::ChatMessage(ChatMessage {
role: "tool".to_string(),
content: ChatContent::SimpleText(message),
tool_calls: None,
tool_call_id: tool_call_id.clone(),
..Default::default()
}));

Ok((false, results))
}

fn tool_depends_on(&self) -> Vec<String> {
vec!["vecdb".to_string()]
}
}
Loading