diff --git a/src/agent/tools/memory.rs b/src/agent/tools/memory.rs index 5ff60f8..76b7934 100644 --- a/src/agent/tools/memory.rs +++ b/src/agent/tools/memory.rs @@ -94,9 +94,10 @@ pub fn journal_tools() -> [super::Tool; 3] { parameters_json: r#"{ "type": "object", "properties": { - "count": {"type": "integer", "description": "Number of entries", "default": 1}, - "level": {"type": "integer", "description": "0=journal, 1=daily, 2=weekly, 3=monthly", "default": 0}, - "keys_only": {"type": "boolean", "description": "Return only node keys, not content", "default": false} + "count": {"type": "integer", "description": "Number of entries", "default": 1}, + "level": {"type": "integer", "description": "0=journal, 1=daily, 2=weekly, 3=monthly", "default": 0}, + "format": {"type": "string", "description": "compact or full (with content)", "default": "full"}, + "after": {"type": "string", "description": "Only entries after this date (YYYY-MM-DD)"} } }"#, handler: Arc::new(|_a, v| Box::pin(async move { journal_tail(&v).await })) }, @@ -280,40 +281,31 @@ async fn query(args: &serde_json::Value) -> Result { // ── Journal tools ────────────────────────────────────────────── async fn journal_tail(args: &serde_json::Value) -> Result { - use crate::store::NodeType; - - let count = args.get("count").and_then(|v| v.as_u64()).unwrap_or(1) as usize; + let count = args.get("count").and_then(|v| v.as_u64()).unwrap_or(1); let level = args.get("level").and_then(|v| v.as_u64()).unwrap_or(0); - let keys_only = args.get("keys_only").and_then(|v| v.as_bool()).unwrap_or(false); + let format = args.get("format").and_then(|v| v.as_str()).unwrap_or("full"); + let after = args.get("after").and_then(|v| v.as_str()); - let node_type = match level { - 0 => NodeType::EpisodicSession, - 1 => NodeType::EpisodicDaily, - 2 => NodeType::EpisodicWeekly, - 3 => NodeType::EpisodicMonthly, + let type_name = match level { + 0 => "episodic", + 1 => "daily", + 2 => "weekly", + 3 => "monthly", _ => return Err(anyhow::anyhow!("invalid level: {} (0=journal, 1=daily, 2=weekly, 3=monthly)", level)), }; - let arc = cached_store().await?; - let store = arc.lock().await; - let mut entries: Vec<&crate::store::Node> = store.nodes.values() - .filter(|n| n.node_type == node_type) - .collect(); - entries.sort_by_key(|n| n.created_at); - let start = entries.len().saturating_sub(count); - if entries[start..].is_empty() { - Ok("(no entries)".into()) - } else if keys_only { - Ok(entries[start..].iter() - .map(|n| n.key.as_str()) - .collect::>() - .join("\n")) - } else { - Ok(entries[start..].iter() - .map(|n| format!("## {}\n\n{}", n.key, n.content)) - .collect::>() - .join("\n\n---\n\n")) + let mut q = format!("all | type:{} | sort:timestamp", type_name); + if let Some(date) = after { + // Convert date to age in seconds + if let Ok(nd) = chrono::NaiveDate::parse_from_str(date, "%Y-%m-%d") { + let ts = nd.and_hms_opt(0, 0, 0).unwrap().and_utc().timestamp(); + let age = chrono::Utc::now().timestamp() - ts; + q.push_str(&format!(" | age:<{}", age)); + } } + q.push_str(&format!(" | limit:{}", count)); + + query(&serde_json::json!({"query": q, "format": format})).await } async fn journal_new(agent: &Option>, args: &serde_json::Value) -> Result { diff --git a/src/subconscious/agents/digest.agent b/src/subconscious/agents/digest.agent index 1563206..a8e47d3 100644 --- a/src/subconscious/agents/digest.agent +++ b/src/subconscious/agents/digest.agent @@ -16,21 +16,15 @@ summaries into weekly ones. ## How to work -1. Use `journal_tail` with `keys_only: true` to find recent entries - at each level: - - `level: 0` = journal entries (raw) - - `level: 1` = daily digests - - `level: 2` = weekly digests +1. Compare journal entries (level 0) with daily digests (level 1) + to find dates that need a digest. The listings below show what + exists at each level. -2. Check if a daily digest exists for recent dates. Daily digest - keys are `daily-YYYY-MM-DD`. If journal entries exist for a date - but no daily digest, generate one. +2. Read the undigested entries with `journal_tail` (level 0, after + the last digest date). -3. To generate a digest: read the source entries with `journal_tail` - or `memory_render`, then write the digest with `memory_write`. - Use key format `daily-YYYY-MM-DD` or `weekly-YYYY-WNN`. - -4. Link source entries to the digest with `memory_link_add`. +3. Write the digest with `memory_write` and link source entries + to it with `memory_link_add`. ## Writing style @@ -47,11 +41,11 @@ evening's conversation? What was building underneath? ## What's available now -### Recent journal entries (last 10 keys) -{{tool: journal_tail {"count": 10, "level": 0, "keys_only": true}}} +### Recent journal entries (last 10) +{{tool: journal_tail {"count": 10, "level": 0, "format": "compact"}}} -### Recent daily digests (last 5 keys) -{{tool: journal_tail {"count": 5, "level": 1, "keys_only": true}}} +### Recent daily digests (last 5) +{{tool: journal_tail {"count": 5, "level": 1, "format": "compact"}}} -### Recent weekly digests (last 3 keys) -{{tool: journal_tail {"count": 3, "level": 2, "keys_only": true}}} +### Recent weekly digests (last 3) +{{tool: journal_tail {"count": 3, "level": 2, "format": "compact"}}}