Skip to content

Commit 3c3c0f4

Browse files
authored
Merge pull request #27 from sopaco/dev
Dev
2 parents d685e74 + 0d75859 commit 3c3c0f4

17 files changed

Lines changed: 581 additions & 15837 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ logs/
66
config.toml
77
/misc_summaries
88
bots.json
9+
__Litho_Summary_Brief__.md
10+
__Litho_Summary_Detail__.md

cortex-mem-core/src/memory/manager.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -535,13 +535,19 @@ impl MemoryManager {
535535
.search_with_threshold(&query_embedding, filters, limit, threshold)
536536
.await?;
537537

538-
// Sort by combined score: similarity + importance
538+
// Sort by combined score: similarity + importance + time freshness
539539
results.sort_by(|a, b| {
540540
let score_a = a.score * 0.7 + a.memory.metadata.importance_score * 0.3;
541541
let score_b = b.score * 0.7 + b.memory.metadata.importance_score * 0.3;
542-
score_b
543-
.partial_cmp(&score_a)
544-
.unwrap_or(std::cmp::Ordering::Equal)
542+
543+
// First, sort by combined score
544+
match score_b.partial_cmp(&score_a) {
545+
Some(std::cmp::Ordering::Equal) | None => {
546+
// When scores are equal, prefer newer memories
547+
b.memory.created_at.cmp(&a.memory.created_at)
548+
}
549+
Some(ordering) => ordering,
550+
}
545551
});
546552

547553
debug!(

cortex-mem-rig/src/tool.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ pub struct QueryMemoryArgs {
3939
pub topics: Option<Vec<String>>,
4040
pub user_id: Option<String>,
4141
pub agent_id: Option<String>,
42+
pub created_after: Option<String>,
43+
pub created_before: Option<String>,
4244
}
4345

4446
/// List Memories tool arguments
@@ -48,6 +50,8 @@ pub struct ListMemoriesArgs {
4850
pub memory_type: Option<String>,
4951
pub user_id: Option<String>,
5052
pub agent_id: Option<String>,
53+
pub created_after: Option<String>,
54+
pub created_before: Option<String>,
5155
}
5256

5357
/// Get Memory tool arguments

cortex-mem-tools/src/mcp_tools.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ pub fn get_mcp_tool_definitions() -> Vec<McpToolDefinition> {
9595
"agent_id": {
9696
"type": "string",
9797
"description": "Agent ID to filter memories (optional, defaults to configured agent)"
98+
},
99+
"created_after": {
100+
"type": "string",
101+
"description": "Find memories created after this ISO 8601 datetime (e.g., '2025-01-01' or '2025-01-01T10:00:00Z')"
102+
},
103+
"created_before": {
104+
"type": "string",
105+
"description": "Find memories created before this ISO 8601 datetime"
98106
}
99107
},
100108
"required": ["query"]
@@ -134,6 +142,14 @@ pub fn get_mcp_tool_definitions() -> Vec<McpToolDefinition> {
134142
"agent_id": {
135143
"type": "string",
136144
"description": "Agent ID to filter memories (optional, defaults to configured agent)"
145+
},
146+
"created_after": {
147+
"type": "string",
148+
"description": "Find memories created after this ISO 8601 datetime (e.g., '2025-01-01' or '2025-01-01T10:00:00Z')"
149+
},
150+
"created_before": {
151+
"type": "string",
152+
"description": "Find memories created before this ISO 8601 datetime"
137153
}
138154
}
139155
}),
@@ -244,6 +260,15 @@ pub fn map_mcp_arguments_to_payload(
244260
payload.min_salience = Some(min_salience);
245261
}
246262

263+
// Map time range parameters
264+
if let Some(created_after) = arguments.get("created_after").and_then(|v| v.as_str()) {
265+
payload.created_after = Some(created_after.to_string());
266+
}
267+
268+
if let Some(created_before) = arguments.get("created_before").and_then(|v| v.as_str()) {
269+
payload.created_before = Some(created_before.to_string());
270+
}
271+
247272
payload
248273
}
249274

cortex-mem-tools/src/operations.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,15 @@ impl MemoryOperations {
105105
filters.topics = Some(topics);
106106
}
107107

108+
// Apply time range filters
109+
if let Some(created_after) = params.created_after {
110+
filters.created_after = Some(created_after);
111+
}
112+
113+
if let Some(created_before) = params.created_before {
114+
filters.created_before = Some(created_before);
115+
}
116+
108117
match self.memory_manager.search(
109118
&params.query,
110119
&filters,
@@ -159,6 +168,15 @@ impl MemoryOperations {
159168
}
160169
}
161170

171+
// Apply time range filters
172+
if let Some(created_after) = params.created_after {
173+
filters.created_after = Some(created_after);
174+
}
175+
176+
if let Some(created_before) = params.created_before {
177+
filters.created_before = Some(created_before);
178+
}
179+
162180
match self.memory_manager.list(&filters, Some(params.limit)).await {
163181
Ok(memories) => {
164182
let count = memories.len();

cortex-mem-tools/src/types.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ pub struct MemoryOperationPayload {
3939

4040
/// Additional metadata
4141
pub metadata: Option<HashMap<String, serde_json::Value>>,
42+
43+
/// Time range filter: find memories created after this ISO 8601 datetime
44+
pub created_after: Option<String>,
45+
46+
/// Time range filter: find memories created before this ISO 8601 datetime
47+
pub created_before: Option<String>,
4248
}
4349

4450
impl Default for MemoryOperationPayload {
@@ -56,6 +62,8 @@ impl Default for MemoryOperationPayload {
5662
min_salience: None,
5763
k: None,
5864
metadata: None,
65+
created_after: None,
66+
created_before: None,
5967
}
6068
}
6169
}
@@ -127,6 +135,8 @@ pub struct QueryParams {
127135
pub topics: Option<Vec<String>>,
128136
pub user_id: Option<String>,
129137
pub agent_id: Option<String>,
138+
pub created_after: Option<chrono::DateTime<chrono::Utc>>,
139+
pub created_before: Option<chrono::DateTime<chrono::Utc>>,
130140
}
131141

132142
impl QueryParams {
@@ -139,6 +149,15 @@ impl QueryParams {
139149
.or(payload.k)
140150
.unwrap_or(default_limit);
141151

152+
// Parse time range parameters
153+
let created_after = payload.created_after.as_ref()
154+
.and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
155+
.map(|dt| dt.with_timezone(&chrono::Utc));
156+
157+
let created_before = payload.created_before.as_ref()
158+
.and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
159+
.map(|dt| dt.with_timezone(&chrono::Utc));
160+
142161
Ok(Self {
143162
query,
144163
limit,
@@ -147,6 +166,8 @@ impl QueryParams {
147166
topics: payload.topics.clone(),
148167
user_id: payload.user_id.clone(),
149168
agent_id: payload.agent_id.clone(),
169+
created_after,
170+
created_before,
150171
})
151172
}
152173
}
@@ -193,17 +214,30 @@ pub struct FilterParams {
193214
pub agent_id: Option<String>,
194215
pub memory_type: Option<String>,
195216
pub limit: usize,
217+
pub created_after: Option<chrono::DateTime<chrono::Utc>>,
218+
pub created_before: Option<chrono::DateTime<chrono::Utc>>,
196219
}
197220

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

225+
// Parse time range parameters
226+
let created_after = payload.created_after.as_ref()
227+
.and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
228+
.map(|dt| dt.with_timezone(&chrono::Utc));
229+
230+
let created_before = payload.created_before.as_ref()
231+
.and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
232+
.map(|dt| dt.with_timezone(&chrono::Utc));
233+
202234
Ok(Self {
203235
user_id: payload.user_id.clone(),
204236
agent_id: payload.agent_id.clone(),
205237
memory_type: payload.memory_type.clone(),
206238
limit,
239+
created_after,
240+
created_before,
207241
})
208242
}
209243
}

examples/cortex-mem-tars/src/agent.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,17 @@ pub async fn extract_user_basic_info(
176176
memory_type: Some("personal".to_string()), // 使用小写以匹配新API
177177
user_id: Some(user_id.to_string()),
178178
agent_id: Some(agent_id.to_string()),
179+
created_after: None,
180+
created_before: None,
179181
};
180182

181183
let search_args_factual = ListMemoriesArgs {
182184
limit: Some(20),
183185
memory_type: Some("factual".to_string()), // 使用小写以匹配新API
184186
user_id: Some(user_id.to_string()),
185187
agent_id: Some(agent_id.to_string()),
188+
created_after: None,
189+
created_before: None,
186190
};
187191

188192
if let Ok(search_result) = memory_tools

examples/cortex-mem-tars/src/api_server.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use anyhow::{Context, Result};
1+
use anyhow::Result;
22
use axum::{
33
Router,
44
extract::{Query, State},

examples/cortex-mem-tars/src/app.rs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl App {
126126
Ok(response) => {
127127
if response.status().is_success() || response.status().as_u16() == 405 {
128128
// 200 OK 或 405 Method Not Allowed 都表示服务可用
129-
log::info!("服务可用,状态码: {}", response.status());
129+
log::debug!("服务可用,状态码: {}", response.status());
130130
self.ui.service_status = crate::ui::ServiceStatus::Active;
131131
} else {
132132
log::warn!("服务不可用,状态码: {}", response.status());
@@ -176,8 +176,8 @@ impl App {
176176
let tick_rate = Duration::from_millis(100);
177177

178178
loop {
179-
// 更新日志
180-
if last_log_update.elapsed() > Duration::from_secs(1) {
179+
// 更新日志(降低频率到每3秒一次,减少不必要的UI刷新)
180+
if last_log_update.elapsed() > Duration::from_secs(3) {
181181
self.update_logs();
182182
last_log_update = Instant::now();
183183
}
@@ -197,13 +197,19 @@ impl App {
197197
if let Some(last_msg) = self.ui.messages.last_mut() {
198198
if last_msg.role == crate::agent::MessageRole::Assistant {
199199
last_msg.content.push_str(&chunk);
200+
// 只清除当前正在更新的消息的缓存
201+
let last_idx = self.ui.messages.len() - 1;
202+
self.ui.invalidate_render_cache(Some(last_idx));
200203
} else {
201204
// 如果最后一条不是助手消息,创建新的助手消息
202205
self.ui.messages.push(ChatMessage::assistant(chunk));
206+
// 新消息,清除所有缓存(因为索引会变化)
207+
self.ui.invalidate_render_cache(None);
203208
}
204209
} else {
205210
// 如果没有消息,创建新的助手消息
206211
self.ui.messages.push(ChatMessage::assistant(chunk));
212+
self.ui.invalidate_render_cache(None);
207213
}
208214
// 确保自动滚动启用
209215
self.ui.auto_scroll = true;
@@ -216,11 +222,16 @@ impl App {
216222
if let Some(last_msg) = self.ui.messages.last_mut() {
217223
if last_msg.role == crate::agent::MessageRole::Assistant {
218224
last_msg.content = full_response;
225+
// 只清除当前正在更新的消息的缓存
226+
let last_idx = self.ui.messages.len() - 1;
227+
self.ui.invalidate_render_cache(Some(last_idx));
219228
} else {
220229
self.ui.messages.push(ChatMessage::assistant(full_response));
230+
self.ui.invalidate_render_cache(None);
221231
}
222232
} else {
223233
self.ui.messages.push(ChatMessage::assistant(full_response));
234+
self.ui.invalidate_render_cache(None);
224235
}
225236
// 确保自动滚动启用
226237
self.ui.auto_scroll = true;
@@ -292,9 +303,6 @@ impl App {
292303
self.dump_chats();
293304
}
294305
}
295-
crate::ui::KeyAction::ShowBotManagement => {
296-
// 机器人管理弹窗的显示由 UI 处理
297-
}
298306
crate::ui::KeyAction::CreateBot => {
299307
// 创建机器人的逻辑在 UI 中处理
300308
}
@@ -326,13 +334,13 @@ impl App {
326334

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

329-
337+
330338

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

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

335-
343+
336344

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

@@ -348,7 +356,7 @@ impl App {
348356

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

351-
359+
352360

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

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

527536
// 用户发送新消息,重新启用自动滚动
@@ -632,6 +641,7 @@ impl App {
632641
fn clear_chat(&mut self) {
633642
log::info!("清空会话");
634643
self.ui.messages.clear();
644+
self.ui.invalidate_render_cache(None);
635645
self.ui.scroll_offset = 0;
636646
self.ui.auto_scroll = true;
637647
}
@@ -657,11 +667,13 @@ impl App {
657667
log::info!("{}", msg);
658668
let success_message = ChatMessage::assistant(msg);
659669
self.ui.messages.push(success_message);
670+
self.ui.invalidate_render_cache(None);
660671
}
661672
Err(e) => {
662673
log::error!("{}", e);
663674
let error_message = ChatMessage::assistant(format!("❌ {}", e));
664675
self.ui.messages.push(error_message);
676+
self.ui.invalidate_render_cache(None);
665677
}
666678
}
667679
self.ui.auto_scroll = true;
@@ -824,6 +836,7 @@ impl App {
824836
// 添加用户消息到 UI
825837
let user_message = ChatMessage::user(content.clone());
826838
self.ui.messages.push(user_message.clone());
839+
self.ui.invalidate_render_cache(None);
827840

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

931-
/// 获取外部消息发送器的克隆(用于 API server 发送消息)
932-
pub fn get_external_message_sender(&self) -> mpsc::UnboundedSender<String> {
933-
self.external_message_sender.clone()
934-
}
935-
936944
/// 保存机器人(创建或更新)
937945
async fn save_bot(&mut self) -> Result<()> {
938946
let (name, prompt, password) = self.ui.get_bot_input_data();

examples/cortex-mem-tars/src/logger.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ pub fn init_logger(log_dir: &Path) -> Result<Arc<LogManager>> {
108108
// 设置全局 logger
109109
log::set_logger(Box::leak(Box::new(logger)))
110110
.map_err(|e| anyhow::anyhow!("无法设置 logger: {}", e))?;
111-
log::set_max_level(LevelFilter::Debug);
111+
log::set_max_level(LevelFilter::Info);
112112

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

0 commit comments

Comments
 (0)