Skip to content

Commit 193b299

Browse files
author
User
committed
feat(memory): Add VoyageAI embedding support for memory
1 parent 4f28514 commit 193b299

File tree

12 files changed

+349
-332
lines changed

12 files changed

+349
-332
lines changed

huly-coder.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,19 @@ permission_mode: manual_approval
6161
#---------------------------------------
6262
workspace: ./target/workspace
6363

64+
#---------------------------------------
65+
# Memory Embedding Configuration
66+
#---------------------------------------
67+
# Supported embedding providers:
68+
# - fastembed (default)
69+
# - voyage_ai
70+
# type: voyage_ai
71+
# api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
72+
# model: voyage-3.5-lite
73+
# dimensions: 256
74+
memory_embedding:
75+
type: fastembed
76+
6477
#---------------------------------------
6578
# Web Interaction Configuration
6679
#---------------------------------------

src/agent/mod.rs

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::tools::execute_command::tools::TerminateCommandTool;
1919
use crate::tools::execute_command::ProcessRegistry;
2020
use crate::tools::list_files::ListFilesTool;
2121
use crate::tools::memory;
22-
use crate::tools::memory::Entity;
22+
use crate::tools::memory::indexer::MemoryIndexer;
2323
use crate::tools::memory::MemoryManager;
2424
use crate::tools::read_file::ReadFileTool;
2525
use crate::tools::replace_in_file::ReplaceInFileTool;
@@ -40,7 +40,6 @@ use rig::agent::AgentBuilder;
4040
use rig::completion::CompletionError;
4141
use rig::completion::CompletionModel;
4242
use rig::completion::CompletionResponse;
43-
use rig::embeddings::EmbeddingsBuilder;
4443
use rig::message::AssistantContent;
4544
use rig::message::ImageMediaType;
4645
use rig::message::Message;
@@ -50,8 +49,6 @@ use rig::message::UserContent;
5049
use rig::tool::Tool;
5150
use rig::tool::ToolError;
5251
use rig::tool::ToolSetError;
53-
use rig::vector_store::in_memory_store::InMemoryVectorIndex;
54-
use rig::vector_store::in_memory_store::InMemoryVectorStore;
5552
use rig::OneOrMany;
5653
use serde::Deserialize;
5754
use serde::Serialize;
@@ -138,41 +135,27 @@ struct AgentContext {
138135
state: Arc<RwLock<AgentState>>,
139136
sender: mpsc::UnboundedSender<AgentOutputEvent>,
140137
process_registry: Arc<RwLock<ProcessRegistry>>,
141-
memory_index: Arc<RwLock<InMemoryVectorIndex<rig_fastembed::EmbeddingModel, Entity>>>,
138+
memory_index: Arc<RwLock<MemoryIndexer>>,
142139
system_prompt_token_count: u32,
143140
current_input_tokens: u32,
144141
current_completion_tokens: u32,
145142
}
146143

147144
impl Agent {
148145
pub fn new(
149-
data_dir: &str,
146+
_data_dir: &str,
150147
config: Config,
148+
memory: Arc<RwLock<MemoryManager>>,
151149
sender: mpsc::UnboundedSender<AgentOutputEvent>,
152150
) -> Self {
153151
Self {
154152
config,
155153
sender,
156-
memory: Arc::new(RwLock::new(MemoryManager::new(data_dir, false))),
154+
memory,
157155
process_registry: Arc::new(RwLock::new(ProcessRegistry::default())),
158156
}
159157
}
160158

161-
pub async fn init_memory_index(
162-
&mut self,
163-
) -> InMemoryVectorIndex<rig_fastembed::EmbeddingModel, Entity> {
164-
let documents = self.memory.read().await.entities().clone();
165-
let client = rig_fastembed::Client::new();
166-
let model = client.embedding_model(&rig_fastembed::FastembedModel::AllMiniLML6V2);
167-
let embeddings = EmbeddingsBuilder::new(model.clone())
168-
.documents(documents)
169-
.unwrap()
170-
.build()
171-
.await
172-
.unwrap();
173-
InMemoryVectorStore::from_documents(embeddings.into_iter()).index(model)
174-
}
175-
176159
fn add_static_tools<M>(
177160
agent_builder: AgentBuilder<M>,
178161
context: BuildAgentContext<'_>,
@@ -418,7 +401,7 @@ impl Agent {
418401
data_dir: &str,
419402
receiver: mpsc::UnboundedReceiver<AgentControlEvent>,
420403
messages: Vec<Message>,
421-
memory_index: InMemoryVectorIndex<rig_fastembed::EmbeddingModel, Entity>,
404+
memory_index: Arc<RwLock<MemoryIndexer>>,
422405
) {
423406
tracing::info!(
424407
"Run agent: {:?} : {}",
@@ -468,7 +451,6 @@ impl Agent {
468451
.unwrap();
469452

470453
let messages = Arc::new(RwLock::new(messages));
471-
let memory_index = Arc::new(RwLock::new(memory_index));
472454
let sender = self.sender.clone();
473455
let state = Arc::new(RwLock::new(state));
474456
let config_state = Arc::new(RwLock::new(AgentConfigState::new(data_dir)));

src/agent/utils.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,12 @@ use std::sync::Arc;
66

77
use itertools::Itertools;
88
use rig::message::{Message, UserContent};
9-
use rig::vector_store::in_memory_store::InMemoryVectorIndex;
10-
use rig::vector_store::VectorStoreIndex;
119
use tokio::sync::RwLock;
1210

1311
use crate::config::Config;
1412
use crate::templates::{ENV_DETAILS, SYSTEM_PROMPT};
1513
use crate::tools::execute_command::ProcessRegistry;
16-
use crate::tools::memory::{self, Entity};
14+
use crate::tools::memory::indexer::MemoryIndexer;
1715
use crate::HISTORY_PATH;
1816

1917
pub const MAX_FILES: usize = 10000;
@@ -51,9 +49,7 @@ pub async fn prepare_system_prompt(config: &Config) -> String {
5149

5250
pub async fn add_env_message<'a>(
5351
msg: &'a mut Message,
54-
memory_index: Arc<
55-
tokio::sync::RwLock<InMemoryVectorIndex<rig_fastembed::EmbeddingModel, memory::Entity>>,
56-
>,
52+
memory_index: Arc<RwLock<MemoryIndexer>>,
5753
data_dir: &'a Path,
5854
workspace: &'a Path,
5955
process_registry: Arc<RwLock<ProcessRegistry>>,
@@ -98,8 +94,7 @@ pub async fn add_env_message<'a>(
9894
_ => "",
9995
};
10096
if !txt.is_empty() {
101-
let res: Vec<(f64, String, Entity)> = memory_index.top_n(txt, 10).await.unwrap();
102-
let result: Vec<_> = res.into_iter().map(|(_, _, entity)| entity).collect();
97+
let result = memory_index.search(txt, 10).await.unwrap();
10398
memory_entries = serde_yaml::to_string(&result).unwrap();
10499
}
105100

src/config.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,17 @@ pub struct Appearance {
9292
pub user_name: String,
9393
}
9494

95+
#[derive(Debug, Deserialize, Clone)]
96+
#[serde(tag = "type", rename_all = "snake_case")]
97+
pub enum EmbeddingProvider {
98+
VoyageAi {
99+
api_key: String,
100+
model: String,
101+
dimensions: usize,
102+
},
103+
Fastembed,
104+
}
105+
95106
#[derive(Debug, Deserialize, Clone)]
96107
pub struct Config {
97108
pub provider: ProviderKind,
@@ -106,6 +117,7 @@ pub struct Config {
106117
pub mcp: Option<McpConfig>,
107118
pub web_search: Option<WebSearchProvider>,
108119
pub web_fetch: Option<WebFetchProvider>,
120+
pub memory_embedding: EmbeddingProvider,
109121
}
110122

111123
impl Config {

src/main.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::io::stdout;
55
use std::panic::set_hook;
66
use std::panic::take_hook;
77
use std::path::Path;
8+
use std::sync::Arc;
89

910
use crossterm::execute;
1011
use crossterm::terminal::disable_raw_mode;
@@ -15,13 +16,16 @@ use providers::model_info::model_info;
1516
use ratatui::prelude::CrosstermBackend;
1617
use ratatui::DefaultTerminal;
1718
use ratatui::Terminal;
19+
use tokio::sync::RwLock;
1820
use tracing_subscriber::layer::SubscriberExt;
1921
use tracing_subscriber::util::SubscriberInitExt;
2022
use tracing_subscriber::Layer;
2123

2224
use self::config::Config;
2325
use crate::agent::AgentControlEvent;
2426
use crate::agent::AgentOutputEvent;
27+
use crate::tools::memory::indexer::MemoryIndexer;
28+
use crate::tools::memory::MemoryManager;
2529
use clap::Parser;
2630

2731
mod agent;
@@ -145,8 +149,14 @@ async fn main() -> color_eyre::Result<()> {
145149
let model_info = model_info(&args.data, &config).await?;
146150
tracing::info!("Model info: {:?}", model_info);
147151

148-
let mut agent = agent::Agent::new(&args.data, config.clone(), output_sender);
149-
let memory_index = agent.init_memory_index().await;
152+
let memory_index = Arc::new(RwLock::new(MemoryIndexer::new(data_dir, &config)));
153+
let memory = Arc::new(RwLock::new(MemoryManager::new(
154+
&args.data,
155+
memory_index.clone(),
156+
false,
157+
)));
158+
let mut agent = agent::Agent::new(&args.data, config.clone(), memory.clone(), output_sender);
159+
memory_index.write().await.init(memory.clone()).await?;
150160

151161
let messages = history.clone();
152162
let data_dir = args.data.clone();

0 commit comments

Comments
 (0)