Skip to content

Commit 63a0b3e

Browse files
密码0000密码0000
authored andcommitted
feat: hippocampal memory system — MemoryStore + memorize/recall tools
1 parent ecc0f23 commit 63a0b3e

15 files changed

Lines changed: 859 additions & 1 deletion

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ members = [
88
"crates/execpolicy",
99
"crates/hooks",
1010
"crates/mcp",
11+
"crates/memory",
1112
"crates/protocol",
1213
"crates/release",
1314
"crates/secrets",

crates/memory/Cargo.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
name = "codewhale-memory"
3+
version.workspace = true
4+
edition.workspace = true
5+
license.workspace = true
6+
repository.workspace = true
7+
description = "Hippocampal memory system — structured entity graph with cross-session recall"
8+
9+
[dependencies]
10+
anyhow.workspace = true
11+
chrono.workspace = true
12+
rusqlite.workspace = true
13+
serde.workspace = true
14+
serde_json.workspace = true
15+
sha2.workspace = true
16+
uuid.workspace = true
17+
18+
[dev-dependencies]
19+
tempfile = "3"

crates/memory/src/lib.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//! # Codewhale Hippocampal Memory System
2+
//!
3+
//! A structured, SQLite-backed memory store that enables the agent to remember
4+
//! facts, entities, and relationships across sessions — the foundation for
5+
//! true infinite-context and cross-session recall.
6+
//!
7+
//! ## Core Concepts
8+
//!
9+
//! - **Entities**: Files, PRs, issues, concepts, people, decisions — anything
10+
//! the model might need to reference later.
11+
//! - **Relations**: Directed edges connecting entities (e.g. `dispatch.rs` is
12+
//! `part_of` `PR #2933`).
13+
//! - **Facts**: Standalone factual statements, optionally bound to an entity.
14+
//! Stored with an importance score (0.0–1.0) for active forgetting.
15+
//!
16+
//! ## Usage
17+
//!
18+
//! ```rust,ignore
19+
//! use codewhale_memory::MemoryStore;
20+
//!
21+
//! let store = MemoryStore::open(&path)?;
22+
//! store.insert_fact(None, "user prefers 4-space indentation", "user", 0.9, None)?;
23+
//! let facts = store.search_facts("indentation", 10)?;
24+
//! ```
25+
26+
pub mod schema;
27+
pub mod store;
28+
29+
pub use store::{Entity, Fact, MemoryStore, Relation};

crates/memory/src/schema.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//! SQLite schema for the hippocampal memory store.
2+
//!
3+
//! Three core tables:
4+
//!
5+
//! - **`entities`**: A "thing" the model might need to remember — a file path,
6+
//! an issue number, a PR, a person, a concept, a decision.
7+
//! - **`relations`**: A directed edge connecting two entities. The `kind` field
8+
//! says what the relationship means (e.g. `"fixes"`, `"part_of"`, `"depends_on"`).
9+
//! - **`facts`**: A standalone statement about something the model learned. May
10+
//! reference an entity via `entity_id`.
11+
12+
use rusqlite::Connection;
13+
14+
/// Create all tables if they don't exist.
15+
pub(crate) fn migrate(conn: &Connection) -> rusqlite::Result<()> {
16+
conn.execute_batch(
17+
"
18+
CREATE TABLE IF NOT EXISTS entities (
19+
id TEXT PRIMARY KEY,
20+
kind TEXT NOT NULL, -- 'file', 'issue', 'pr', 'concept', 'decision', 'person', 'config'
21+
name TEXT NOT NULL, -- human-readable label
22+
description TEXT NOT NULL DEFAULT '',
23+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
24+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
25+
);
26+
27+
CREATE INDEX IF NOT EXISTS idx_entities_kind ON entities(kind);
28+
CREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name);
29+
30+
CREATE TABLE IF NOT EXISTS relations (
31+
id TEXT PRIMARY KEY,
32+
source_id TEXT NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
33+
target_id TEXT NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
34+
kind TEXT NOT NULL, -- 'fixes', 'part_of', 'depends_on', 'contains', 'references', 'implements'
35+
strength REAL NOT NULL DEFAULT 1.0, -- 0.0–1.0 confidence/importance
36+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
37+
session_id TEXT, -- which session created this relation
38+
UNIQUE(source_id, target_id, kind)
39+
);
40+
41+
CREATE INDEX IF NOT EXISTS idx_relations_source ON relations(source_id);
42+
CREATE INDEX IF NOT EXISTS idx_relations_target ON relations(target_id);
43+
CREATE INDEX IF NOT EXISTS idx_relations_kind ON relations(kind);
44+
45+
CREATE TABLE IF NOT EXISTS facts (
46+
id TEXT PRIMARY KEY,
47+
entity_id TEXT REFERENCES entities(id) ON DELETE SET NULL,
48+
content TEXT NOT NULL, -- the factual statement
49+
source TEXT NOT NULL DEFAULT '', -- where this fact came from (tool call, session, user)
50+
importance REAL NOT NULL DEFAULT 0.5, -- 0.0–1.0
51+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
52+
session_id TEXT
53+
);
54+
55+
CREATE INDEX IF NOT EXISTS idx_facts_entity ON facts(entity_id);
56+
CREATE INDEX IF NOT EXISTS idx_facts_importance ON facts(importance DESC);
57+
58+
-- Full-text search over facts (enables pattern-completion-like queries)
59+
CREATE VIRTUAL TABLE IF NOT EXISTS facts_fts USING fts5(
60+
content,
61+
content=facts,
62+
content_rowid=rowid
63+
);
64+
65+
-- Triggers to keep FTS index in sync
66+
CREATE TRIGGER IF NOT EXISTS facts_ai AFTER INSERT ON facts BEGIN
67+
INSERT INTO facts_fts(rowid, content) VALUES (new.rowid, new.content);
68+
END;
69+
70+
CREATE TRIGGER IF NOT EXISTS facts_ad AFTER DELETE ON facts BEGIN
71+
INSERT INTO facts_fts(facts_fts, rowid, content) VALUES('delete', old.rowid, old.content);
72+
END;
73+
74+
CREATE TRIGGER IF NOT EXISTS facts_au AFTER UPDATE ON facts BEGIN
75+
INSERT INTO facts_fts(facts_fts, rowid, content) VALUES('delete', old.rowid, old.content);
76+
INSERT INTO facts_fts(rowid, content) VALUES (new.rowid, new.content);
77+
END;
78+
",
79+
)
80+
}

0 commit comments

Comments
 (0)