-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathzep.mnm
More file actions
129 lines (110 loc) · 3 KB
/
Copy pathzep.mnm
File metadata and controls
129 lines (110 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# zep_memory.mnm
# Temporal Knowledge Graph Memory System
config {
storage: sqlite("./data/zep.db")
vector: auto
graph: auto
embedding: openai("text-embedding-3-small")
extractor: openai("gpt-4o-mini")
}
namespace zep_agent {
# === EPISODIC MEMORY ===
# Stores distinct events/interactions
memory Episode {
session_id: string
messages: string[]
summary: string?
created_at: timestamp
@index session_id
}
# === SEMANTIC MEMORY ===
# Stores facts with temporal validity
memory Fact {
content: string
subject: string
predicate: string
object: string
confidence: float[0,1]
valid_from: timestamp
valid_until: timestamp?
superseded_by: string?
@index subject
@index predicate
@invariant valid_from <= valid_until or valid_until == null
}
# === ENTITY MEMORY ===
# Stores entity summaries derived from facts
memory Entity {
name: string
entity_type: string
summary: string
fact_count: int
last_updated: timestamp
@index name
@index entity_type
}
# === HANDLERS ===
# When conversation ends, extrimage.pngact episodes and facts
on conversation_end(session_id: string, messages: Message[]) {
# Store as episode
let episode = Episode {
session_id: session_id,
messages: messages |> map(m => m.content),
summary: messages |> summarize(),
created_at: now()
}
store(episode)
# Extract facts and build graph
messages
|> extract()
|> store() # Auto-routes: facts -> sqlite, embeddings -> qdrant, triplets -> neo4j
}
# === QUERIES ===
# Hybrid retrieval: semantic + graph with aliased scoring
query GetContext(input: string): Fact[] {
from Fact
where semantic_match(input, threshold: 0.6) as sm
and graph_match(input, hops: 2) as gm
and valid_until == null
order by (sm * 0.7 + gm * 0.3) desc
limit 10
}
# Entity timeline: all facts about an entity, chronological
query EntityHistory(entity_name: string): Fact[] {
from Fact
where subject == entity_name or object == entity_name
order by valid_from asc
}
# Cypher: entities connected within 2 hops in the knowledge graph
query RelatedEntities(entity: string): Entity[] {
from Entity
where cypher("
MATCH (e:Entity {name: $entity})-[r*1..2]-(related:Entity)
RETURN DISTINCT related.name as name
")
limit 10
}
# === UPDATE RULES ===
update Fact {
on_conflict(old, new) {
# Temporal superseding: mark old as invalid, link to new
if new.valid_from > old.valid_from {
old.valid_until = new.valid_from
old.superseded_by = new.id
store(new)
} else {
discard(new)
}
}
# No decay - facts persist but get superseded
}
update Entity {
every 6h {
# Regenerate summaries from current facts
let facts = EntityHistory(name)
summary = facts |> summarize()
fact_count = facts |> len()
last_updated = now()
}
}
}