Skip to content
Merged

Dev #27

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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ logs/
config.toml
/misc_summaries
bots.json
__Litho_Summary_Brief__.md
__Litho_Summary_Detail__.md
14 changes: 10 additions & 4 deletions cortex-mem-core/src/memory/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,13 +535,19 @@ impl MemoryManager {
.search_with_threshold(&query_embedding, filters, limit, threshold)
.await?;

// Sort by combined score: similarity + importance
// Sort by combined score: similarity + importance + time freshness
results.sort_by(|a, b| {
let score_a = a.score * 0.7 + a.memory.metadata.importance_score * 0.3;
let score_b = b.score * 0.7 + b.memory.metadata.importance_score * 0.3;
score_b
.partial_cmp(&score_a)
.unwrap_or(std::cmp::Ordering::Equal)

// First, sort by combined score
match score_b.partial_cmp(&score_a) {
Some(std::cmp::Ordering::Equal) | None => {
// When scores are equal, prefer newer memories
b.memory.created_at.cmp(&a.memory.created_at)
}
Some(ordering) => ordering,
}
});

debug!(
Expand Down
4 changes: 4 additions & 0 deletions cortex-mem-rig/src/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ pub struct QueryMemoryArgs {
pub topics: Option<Vec<String>>,
pub user_id: Option<String>,
pub agent_id: Option<String>,
pub created_after: Option<String>,
pub created_before: Option<String>,
}

/// List Memories tool arguments
Expand All @@ -48,6 +50,8 @@ pub struct ListMemoriesArgs {
pub memory_type: Option<String>,
pub user_id: Option<String>,
pub agent_id: Option<String>,
pub created_after: Option<String>,
pub created_before: Option<String>,
}

/// Get Memory tool arguments
Expand Down
25 changes: 25 additions & 0 deletions cortex-mem-tools/src/mcp_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ pub fn get_mcp_tool_definitions() -> Vec<McpToolDefinition> {
"agent_id": {
"type": "string",
"description": "Agent ID to filter memories (optional, defaults to configured agent)"
},
"created_after": {
"type": "string",
"description": "Find memories created after this ISO 8601 datetime (e.g., '2025-01-01' or '2025-01-01T10:00:00Z')"
},
"created_before": {
"type": "string",
"description": "Find memories created before this ISO 8601 datetime"
}
},
"required": ["query"]
Expand Down Expand Up @@ -134,6 +142,14 @@ pub fn get_mcp_tool_definitions() -> Vec<McpToolDefinition> {
"agent_id": {
"type": "string",
"description": "Agent ID to filter memories (optional, defaults to configured agent)"
},
"created_after": {
"type": "string",
"description": "Find memories created after this ISO 8601 datetime (e.g., '2025-01-01' or '2025-01-01T10:00:00Z')"
},
"created_before": {
"type": "string",
"description": "Find memories created before this ISO 8601 datetime"
}
}
}),
Expand Down Expand Up @@ -244,6 +260,15 @@ pub fn map_mcp_arguments_to_payload(
payload.min_salience = Some(min_salience);
}

// Map time range parameters
if let Some(created_after) = arguments.get("created_after").and_then(|v| v.as_str()) {
payload.created_after = Some(created_after.to_string());
}

if let Some(created_before) = arguments.get("created_before").and_then(|v| v.as_str()) {
payload.created_before = Some(created_before.to_string());
}

payload
}

Expand Down
18 changes: 18 additions & 0 deletions cortex-mem-tools/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ impl MemoryOperations {
filters.topics = Some(topics);
}

// Apply time range filters
if let Some(created_after) = params.created_after {
filters.created_after = Some(created_after);
}

if let Some(created_before) = params.created_before {
filters.created_before = Some(created_before);
}

match self.memory_manager.search(
&params.query,
&filters,
Expand Down Expand Up @@ -159,6 +168,15 @@ impl MemoryOperations {
}
}

// Apply time range filters
if let Some(created_after) = params.created_after {
filters.created_after = Some(created_after);
}

if let Some(created_before) = params.created_before {
filters.created_before = Some(created_before);
}

match self.memory_manager.list(&filters, Some(params.limit)).await {
Ok(memories) => {
let count = memories.len();
Expand Down
34 changes: 34 additions & 0 deletions cortex-mem-tools/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ pub struct MemoryOperationPayload {

/// Additional metadata
pub metadata: Option<HashMap<String, serde_json::Value>>,

/// Time range filter: find memories created after this ISO 8601 datetime
pub created_after: Option<String>,

/// Time range filter: find memories created before this ISO 8601 datetime
pub created_before: Option<String>,
}

impl Default for MemoryOperationPayload {
Expand All @@ -56,6 +62,8 @@ impl Default for MemoryOperationPayload {
min_salience: None,
k: None,
metadata: None,
created_after: None,
created_before: None,
}
}
}
Expand Down Expand Up @@ -127,6 +135,8 @@ pub struct QueryParams {
pub topics: Option<Vec<String>>,
pub user_id: Option<String>,
pub agent_id: Option<String>,
pub created_after: Option<chrono::DateTime<chrono::Utc>>,
pub created_before: Option<chrono::DateTime<chrono::Utc>>,
}

impl QueryParams {
Expand All @@ -139,6 +149,15 @@ impl QueryParams {
.or(payload.k)
.unwrap_or(default_limit);

// Parse time range parameters
let created_after = payload.created_after.as_ref()
.and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
.map(|dt| dt.with_timezone(&chrono::Utc));

let created_before = payload.created_before.as_ref()
.and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
.map(|dt| dt.with_timezone(&chrono::Utc));

Ok(Self {
query,
limit,
Expand All @@ -147,6 +166,8 @@ impl QueryParams {
topics: payload.topics.clone(),
user_id: payload.user_id.clone(),
agent_id: payload.agent_id.clone(),
created_after,
created_before,
})
}
}
Expand Down Expand Up @@ -193,17 +214,30 @@ pub struct FilterParams {
pub agent_id: Option<String>,
pub memory_type: Option<String>,
pub limit: usize,
pub created_after: Option<chrono::DateTime<chrono::Utc>>,
pub created_before: Option<chrono::DateTime<chrono::Utc>>,
}

impl FilterParams {
pub fn from_payload(payload: &MemoryOperationPayload, default_limit: usize) -> crate::errors::MemoryToolsResult<Self> {
let limit = payload.limit.or(payload.k).unwrap_or(default_limit);

// Parse time range parameters
let created_after = payload.created_after.as_ref()
.and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
.map(|dt| dt.with_timezone(&chrono::Utc));

let created_before = payload.created_before.as_ref()
.and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
.map(|dt| dt.with_timezone(&chrono::Utc));

Ok(Self {
user_id: payload.user_id.clone(),
agent_id: payload.agent_id.clone(),
memory_type: payload.memory_type.clone(),
limit,
created_after,
created_before,
})
}
}
4 changes: 4 additions & 0 deletions examples/cortex-mem-tars/src/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,17 @@ pub async fn extract_user_basic_info(
memory_type: Some("personal".to_string()), // 使用小写以匹配新API
user_id: Some(user_id.to_string()),
agent_id: Some(agent_id.to_string()),
created_after: None,
created_before: None,
};

let search_args_factual = ListMemoriesArgs {
limit: Some(20),
memory_type: Some("factual".to_string()), // 使用小写以匹配新API
user_id: Some(user_id.to_string()),
agent_id: Some(agent_id.to_string()),
created_after: None,
created_before: None,
};

if let Ok(search_result) = memory_tools
Expand Down
2 changes: 1 addition & 1 deletion examples/cortex-mem-tars/src/api_server.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use anyhow::{Context, Result};
use anyhow::Result;
use axum::{
Router,
extract::{Query, State},
Expand Down
36 changes: 22 additions & 14 deletions examples/cortex-mem-tars/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ impl App {
Ok(response) => {
if response.status().is_success() || response.status().as_u16() == 405 {
// 200 OK 或 405 Method Not Allowed 都表示服务可用
log::info!("服务可用,状态码: {}", response.status());
log::debug!("服务可用,状态码: {}", response.status());
self.ui.service_status = crate::ui::ServiceStatus::Active;
} else {
log::warn!("服务不可用,状态码: {}", response.status());
Expand Down Expand Up @@ -176,8 +176,8 @@ impl App {
let tick_rate = Duration::from_millis(100);

loop {
// 更新日志
if last_log_update.elapsed() > Duration::from_secs(1) {
// 更新日志(降低频率到每3秒一次,减少不必要的UI刷新)
if last_log_update.elapsed() > Duration::from_secs(3) {
self.update_logs();
last_log_update = Instant::now();
}
Expand All @@ -197,13 +197,19 @@ impl App {
if let Some(last_msg) = self.ui.messages.last_mut() {
if last_msg.role == crate::agent::MessageRole::Assistant {
last_msg.content.push_str(&chunk);
// 只清除当前正在更新的消息的缓存
let last_idx = self.ui.messages.len() - 1;
self.ui.invalidate_render_cache(Some(last_idx));
} else {
// 如果最后一条不是助手消息,创建新的助手消息
self.ui.messages.push(ChatMessage::assistant(chunk));
// 新消息,清除所有缓存(因为索引会变化)
self.ui.invalidate_render_cache(None);
}
} else {
// 如果没有消息,创建新的助手消息
self.ui.messages.push(ChatMessage::assistant(chunk));
self.ui.invalidate_render_cache(None);
}
// 确保自动滚动启用
self.ui.auto_scroll = true;
Expand All @@ -216,11 +222,16 @@ impl App {
if let Some(last_msg) = self.ui.messages.last_mut() {
if last_msg.role == crate::agent::MessageRole::Assistant {
last_msg.content = full_response;
// 只清除当前正在更新的消息的缓存
let last_idx = self.ui.messages.len() - 1;
self.ui.invalidate_render_cache(Some(last_idx));
} else {
self.ui.messages.push(ChatMessage::assistant(full_response));
self.ui.invalidate_render_cache(None);
}
} else {
self.ui.messages.push(ChatMessage::assistant(full_response));
self.ui.invalidate_render_cache(None);
}
// 确保自动滚动启用
self.ui.auto_scroll = true;
Expand Down Expand Up @@ -292,9 +303,6 @@ impl App {
self.dump_chats();
}
}
crate::ui::KeyAction::ShowBotManagement => {
// 机器人管理弹窗的显示由 UI 处理
}
crate::ui::KeyAction::CreateBot => {
// 创建机器人的逻辑在 UI 中处理
}
Expand Down Expand Up @@ -326,13 +334,13 @@ impl App {

log::trace!("状态检查: previous_state={:?}, current_state={:?}", self.previous_state, self.ui.state);



if self.previous_state != Some(self.ui.state) {

log::info!("🔄 状态变化: {:?} -> {:?}", self.previous_state, self.ui.state);



// 如果从 BotSelection 或 PasswordInput 切换到 Chat,启动 API 服务器

Expand All @@ -348,7 +356,7 @@ impl App {

self.ui.state == crate::ui::AppState::Chat);



if (self.previous_state == Some(crate::ui::AppState::BotSelection)

Expand Down Expand Up @@ -522,6 +530,7 @@ impl App {
// 添加用户消息
let user_message = ChatMessage::user(input_text);
self.ui.messages.push(user_message.clone());
self.ui.invalidate_render_cache(None);
self.ui.clear_input();

// 用户发送新消息,重新启用自动滚动
Expand Down Expand Up @@ -632,6 +641,7 @@ impl App {
fn clear_chat(&mut self) {
log::info!("清空会话");
self.ui.messages.clear();
self.ui.invalidate_render_cache(None);
self.ui.scroll_offset = 0;
self.ui.auto_scroll = true;
}
Expand All @@ -657,11 +667,13 @@ impl App {
log::info!("{}", msg);
let success_message = ChatMessage::assistant(msg);
self.ui.messages.push(success_message);
self.ui.invalidate_render_cache(None);
}
Err(e) => {
log::error!("{}", e);
let error_message = ChatMessage::assistant(format!("❌ {}", e));
self.ui.messages.push(error_message);
self.ui.invalidate_render_cache(None);
}
}
self.ui.auto_scroll = true;
Expand Down Expand Up @@ -824,6 +836,7 @@ impl App {
// 添加用户消息到 UI
let user_message = ChatMessage::user(content.clone());
self.ui.messages.push(user_message.clone());
self.ui.invalidate_render_cache(None);

// 用户发送新消息,重新启用自动滚动
self.ui.auto_scroll = true;
Expand Down Expand Up @@ -928,11 +941,6 @@ impl App {
Ok(())
}

/// 获取外部消息发送器的克隆(用于 API server 发送消息)
pub fn get_external_message_sender(&self) -> mpsc::UnboundedSender<String> {
self.external_message_sender.clone()
}

/// 保存机器人(创建或更新)
async fn save_bot(&mut self) -> Result<()> {
let (name, prompt, password) = self.ui.get_bot_input_data();
Expand Down
2 changes: 1 addition & 1 deletion examples/cortex-mem-tars/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ pub fn init_logger(log_dir: &Path) -> Result<Arc<LogManager>> {
// 设置全局 logger
log::set_logger(Box::leak(Box::new(logger)))
.map_err(|e| anyhow::anyhow!("无法设置 logger: {}", e))?;
log::set_max_level(LevelFilter::Debug);
log::set_max_level(LevelFilter::Info);

log::info!("日志系统初始化完成");
log::info!("日志文件路径: {}", log_dir.display());
Expand Down
Loading