Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 4 additions & 6 deletions src/agent/cortex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2468,9 +2468,8 @@ async fn run_cortex_loop(
tokio::sync::watch::channel(false);
maintenance_task = Some(tokio::spawn(async move {
memory_maintenance::run_maintenance_with_cancel(
memory_search.store(),
memory_search.embedding_table(),
memory_search.embedding_model_arc(),
memory_search.backend().clone(),
memory_search.embedding_model_arc().clone(),
&maintenance_config,
maintenance_cancel_rx,
)
Expand Down Expand Up @@ -4530,8 +4529,7 @@ async fn run_association_pass(
let max_per_pass = cortex_config.association_max_per_pass;
let is_backfill = since.is_none();

let store = deps.memory_search.store();
let embedding_table = deps.memory_search.embedding_table();
let store = deps.memory_search.backend();

// Get the memories to process
let memories = match fetch_memories_for_association(&deps.sqlite_pool, since).await {
Expand All @@ -4555,7 +4553,7 @@ async fn run_association_pass(
}

// Find similar memories via embedding search
let similar = match embedding_table
let similar = match store
.find_similar(memory_id, similarity_threshold, 10)
.await
{
Expand Down
5 changes: 2 additions & 3 deletions src/agent/maintenance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,8 @@ async fn run_maintenance_for_agent(deps: &AgentDeps) -> anyhow::Result<()> {
};
let memory_search = &deps.memory_search;
let report = crate::memory::maintenance::run_maintenance(
memory_search.store(),
memory_search.embedding_table(),
memory_search.embedding_model_arc(),
memory_search.backend().clone(),
memory_search.embedding_model_arc().clone(),
&config,
)
.await
Expand Down
25 changes: 8 additions & 17 deletions src/api/agents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -830,23 +830,14 @@ pub async fn create_agent_internal(
.clone()
};

let memory_store = crate::memory::MemoryStore::new(db.sqlite.clone());
let embedding_table = crate::memory::EmbeddingTable::open_or_create(&db.lance)
.await
.map_err(|error| {
tracing::error!(%error, agent_id = %agent_id, "failed to init embeddings");
format!("failed to init embeddings: {error}")
})?;

if let Err(error) = embedding_table.ensure_fts_index().await {
tracing::warn!(%error, agent_id = %agent_id, "failed to create FTS index");
}

let memory_search = std::sync::Arc::new(crate::memory::MemorySearch::new(
memory_store,
embedding_table,
embedding_model,
));
let backend: std::sync::Arc<dyn crate::memory::MemoryBackend> = {
let memory_store = crate::memory::MemoryStore::with_agent_id(db.sqlite.clone(), &agent_id);
crate::memory::sqlite_backend_arc(memory_store, &db.lance, &agent_id)
.await
.map_err(|e| format!("failed to init memory backend: {e}"))?
};
let memory_search =
std::sync::Arc::new(crate::memory::MemorySearch::new(backend, embedding_model));
let task_store = state
.task_store
.load()
Expand Down
6 changes: 3 additions & 3 deletions src/api/memories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ pub(super) async fn list_memories(
) -> Result<Json<MemoriesListResponse>, StatusCode> {
let searches = state.memory_searches.load();
let memory_search = searches.get(&query.agent_id).ok_or(StatusCode::NOT_FOUND)?;
let store = memory_search.store();
let store = memory_search.backend();

let limit = query.limit.min(200);
let sort = parse_sort(&query.sort);
Expand Down Expand Up @@ -232,7 +232,7 @@ pub(super) async fn memory_graph(
) -> Result<Json<MemoryGraphResponse>, StatusCode> {
let searches = state.memory_searches.load();
let memory_search = searches.get(&query.agent_id).ok_or(StatusCode::NOT_FOUND)?;
let store = memory_search.store();
let store = memory_search.backend();

let limit = query.limit.min(500);
let sort = parse_sort(&query.sort);
Expand Down Expand Up @@ -290,7 +290,7 @@ pub(super) async fn memory_graph_neighbors(
) -> Result<Json<MemoryGraphNeighborsResponse>, StatusCode> {
let searches = state.memory_searches.load();
let memory_search = searches.get(&query.agent_id).ok_or(StatusCode::NOT_FOUND)?;
let store = memory_search.store();
let store = memory_search.backend();

let depth = query.depth.min(3);
let exclude_ids: Vec<String> = query
Expand Down
61 changes: 4 additions & 57 deletions src/conversation/context.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! Context assembly: prompt + identity + memories + status.

use crate::agent::status::StatusBlock;
use crate::error::Result;
use crate::memory::MemoryStore;

/// Assembled context ready for injection into LLM.
#[derive(Debug, Clone)]
Expand All @@ -13,61 +11,10 @@ pub struct AssembledContext {
pub conversation_history: String,
}

/// Build context for a channel.
pub async fn build_channel_context(
base_prompt: &str,
memory_store: &MemoryStore,
status_block: &StatusBlock,
_conversation_id: &str,
) -> Result<String> {
let mut context = String::new();

// Base channel prompt
context.push_str(base_prompt);
context.push_str("\n\n");

// Add status block
let status = status_block.render();
if !status.is_empty() {
context.push_str("## Current Status\n\n");
context.push_str(&status);
context.push('\n');
}

// Add identity memories (always included)
let identity_memories = memory_store
.get_by_type(crate::memory::types::MemoryType::Identity, 10)
.await?;

if !identity_memories.is_empty() {
context.push_str("## Identity\n\n");
for memory in identity_memories {
context.push_str(&format!("- {}\n", memory.content));
}
context.push('\n');
}

// Add high-importance memories
let important_memories = memory_store.get_high_importance(0.8, 5).await?;
let non_identity: Vec<_> = important_memories
.into_iter()
.filter(|m| m.memory_type != crate::memory::types::MemoryType::Identity)
.collect();

if !non_identity.is_empty() {
context.push_str("## Key Context\n\n");
for memory in non_identity {
context.push_str(&format!(
"- [{}] {}\n",
memory.memory_type,
memory.content.lines().next().unwrap_or(&memory.content)
));
}
context.push('\n');
}

Ok(context)
}
// NOTE: `build_channel_context` was removed — it had no callers and took a
// concrete `&MemoryStore`, which would bypass the `MemoryBackend` abstraction
// if ever wired in (followups #13). Context building for channels should go
// through `Arc<dyn MemoryBackend>` instead.

/// Build minimal context for a branch.
pub async fn build_branch_context(base_prompt: &str) -> Result<String> {
Expand Down
20 changes: 6 additions & 14 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2884,23 +2884,15 @@ async fn initialize_agents(
};

// Per-agent memory system
let memory_store =
spacebot::memory::MemoryStore::with_agent_id(db.sqlite.clone(), &agent_config.id);
let project_store = global_project_store.clone();
let embedding_table = spacebot::memory::EmbeddingTable::open_or_create(&db.lance)
.await
.with_context(|| {
format!("failed to init embeddings for agent '{}'", agent_config.id)
})?;

// Ensure FTS index exists for full-text search queries
if let Err(error) = embedding_table.ensure_fts_index().await {
tracing::warn!(%error, agent = %agent_config.id, "failed to create FTS index");
}

let backend: Arc<dyn spacebot::memory::MemoryBackend> = {
let memory_store =
spacebot::memory::MemoryStore::with_agent_id(db.sqlite.clone(), &agent_config.id);
spacebot::memory::sqlite_backend_arc(memory_store, &db.lance, &agent_config.id).await?
};
let memory_search = Arc::new(spacebot::memory::MemorySearch::new(
memory_store,
embedding_table,
backend,
embedding_model.clone(),
));

Expand Down
2 changes: 2 additions & 0 deletions src/memory.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Memory storage and retrieval system.

pub mod backend;
pub mod embedding;
pub mod lance;
pub mod maintenance;
Expand All @@ -8,6 +9,7 @@ pub mod store;
pub mod types;
pub mod working;

pub use backend::{MemoryBackend, SqliteBackend, sqlite_backend_arc};
pub use embedding::EmbeddingModel;
pub use lance::EmbeddingTable;
pub use search::{MemorySearch, SearchConfig, SearchMode, SearchSort, curate_results};
Expand Down
Loading