ai-agent 0.88.0

Idiomatic agent sdk inspired by the claude code source leak
Documentation
// Source: ~/claudecode/openclaudecode/src/services/autoDream/consolidationPrompt.ts
//! Extracted from dream.ts so auto-dream ships independently of KAIROS
//! feature flags (dream.ts is behind a feature()-gated require).

use crate::memdir::memdir::{DIR_EXISTS_GUIDANCE, ENTRYPOINT_NAME, MAX_ENTRYPOINT_LINES};

/// Build the consolidation prompt for the /dream background subagent.
pub fn build_consolidation_prompt(memory_root: &str, transcript_dir: &str, extra: &str) -> String {
    let extra_section = if extra.trim().is_empty() {
        String::new()
    } else {
        format!("\n\n## Additional context\n\n{extra}")
    };

    format!(
        "# Dream: Memory Consolidation

You are performing a dream — a reflective pass over your memory files. Synthesize what you've learned recently into durable, well-organized memories so that future sessions can orient quickly.

Memory directory: `{memory_root}`
{DIR_EXISTS_GUIDANCE}

Session transcripts: `{transcript_dir}` (large JSONL files — grep narrowly, don't read whole files)

---

## Phase 1 — Orient

- `ls` the memory directory to see what already exists
- Read `{ENTRYPOINT_NAME}` to understand the current index
- Skim existing topic files so you improve them rather than creating duplicates
- If `logs/` or `sessions/` subdirectories exist (assistant-mode layout), review recent entries there

## Phase 2 — Gather recent signal

Look for new information worth persisting. Sources in rough priority order:

1. **Daily logs** (`logs/YYYY/MM/YYYY-MM-DD.md`) if present — these are the append-only stream
2. **Existing memories that drifted** — facts that contradict something you see in the codebase now
3. **Transcript search** — if you need specific context (e.g., \"what was the error message from yesterday's build failure?\"), grep the JSONL transcripts for narrow terms:
   `grep -rn \"<narrow term>\" {transcript_dir}/ --include=\"*.jsonl\" | tail -50`

Don't exhaustively read transcripts. Look only for things you already suspect matter.

## Phase 3 — Consolidate

For each thing worth remembering, write or update a memory file at the top level of the memory directory. Use the memory file format and type conventions from your system prompt's auto-memory section — it's the source of truth for what to save, how to structure it, and what NOT to save.

Focus on:
- Merging new signal into existing topic files rather than creating near-duplicates
- Converting relative dates (\"yesterday\", \"last week\") to absolute dates so they remain interpretable after time passes
- Deleting contradicted facts — if today's investigation disproves an old memory, fix it at the source

## Phase 4 — Prune and index

Update `{ENTRYPOINT_NAME}` so it stays under {MAX_ENTRYPOINT_LINES} lines AND under ~25KB. It's an **index**, not a dump — each entry should be one line under ~150 characters: `- [Title](file.md) — one-line hook`. Never write memory content directly into it.

- Remove pointers to memories that are now stale, wrong, or superseded
- Demote verbose entries: if an index line is over ~200 chars, it's carrying content that belongs in the topic file — shorten the line, move the detail
- Add pointers to newly important memories
- Resolve contradictions — if two files disagree, fix the wrong one

---

Return a brief summary of what you consolidated, updated, or pruned. If nothing changed (memories are already tight), say so.{extra_section}"
    )
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_build_consolidation_prompt_basic() {
        let prompt = build_consolidation_prompt(
            "/home/user/.ai/projects/my_project/memory/",
            "/home/user/.ai/projects/my_project/sessions/",
            "",
        );

        assert!(prompt.contains("Dream: Memory Consolidation"));
        assert!(prompt.contains("Phase 1 — Orient"));
        assert!(prompt.contains("Phase 2 — Gather recent signal"));
        assert!(prompt.contains("Phase 3 — Consolidate"));
        assert!(prompt.contains("Phase 4 — Prune and index"));
        assert!(prompt.contains("MEMORY.md"));
        assert!(prompt.contains("/home/user/.ai/projects/my_project/memory/"));
        assert!(prompt.contains("/home/user/.ai/projects/my_project/sessions/"));
    }

    #[test]
    fn test_build_consolidation_prompt_with_extra() {
        let extra = "Sessions since last consolidation (5):\n- session-1\n- session-2";
        let prompt = build_consolidation_prompt("/mem/", "/trans/", extra);

        assert!(prompt.contains("## Additional context"));
        assert!(prompt.contains("Sessions since last consolidation"));
        assert!(prompt.contains("session-1"));
        assert!(prompt.contains("session-2"));
    }

    #[test]
    fn test_build_consolidation_prompt_empty_extra() {
        let prompt = build_consolidation_prompt("/mem/", "/trans/", "");
        assert!(!prompt.contains("## Additional context"));
    }

    #[test]
    fn test_build_consolidation_prompt_max_lines() {
        let prompt = build_consolidation_prompt("/mem/", "/trans/", "");
        assert!(prompt.contains("200 lines"));
    }
}