claude-memory-agent 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +107 -0
- package/README.md +200 -0
- package/agent_card.py +512 -0
- package/bin/cli.js +181 -0
- package/bin/postinstall.js +216 -0
- package/config.py +104 -0
- package/dashboard.html +2689 -0
- package/hooks/README.md +196 -0
- package/hooks/__pycache__/auto-detect-response.cpython-312.pyc +0 -0
- package/hooks/__pycache__/auto_capture.cpython-312.pyc +0 -0
- package/hooks/__pycache__/session_end.cpython-312.pyc +0 -0
- package/hooks/__pycache__/session_start.cpython-312.pyc +0 -0
- package/hooks/auto-detect-response.py +348 -0
- package/hooks/auto_capture.py +255 -0
- package/hooks/detect-correction.py +173 -0
- package/hooks/grounding-hook.py +348 -0
- package/hooks/log-tool-use.py +234 -0
- package/hooks/log-user-request.py +208 -0
- package/hooks/pre-tool-decision.py +218 -0
- package/hooks/problem-detector.py +343 -0
- package/hooks/session_end.py +192 -0
- package/hooks/session_start.py +227 -0
- package/install.py +887 -0
- package/main.py +2859 -0
- package/manager.py +997 -0
- package/package.json +55 -0
- package/requirements.txt +8 -0
- package/run_server.py +136 -0
- package/services/__init__.py +50 -0
- package/services/__pycache__/__init__.cpython-312.pyc +0 -0
- package/services/__pycache__/agent_registry.cpython-312.pyc +0 -0
- package/services/__pycache__/auth.cpython-312.pyc +0 -0
- package/services/__pycache__/auto_inject.cpython-312.pyc +0 -0
- package/services/__pycache__/claude_md_sync.cpython-312.pyc +0 -0
- package/services/__pycache__/cleanup.cpython-312.pyc +0 -0
- package/services/__pycache__/compaction_flush.cpython-312.pyc +0 -0
- package/services/__pycache__/confidence.cpython-312.pyc +0 -0
- package/services/__pycache__/daily_log.cpython-312.pyc +0 -0
- package/services/__pycache__/database.cpython-312.pyc +0 -0
- package/services/__pycache__/embeddings.cpython-312.pyc +0 -0
- package/services/__pycache__/insights.cpython-312.pyc +0 -0
- package/services/__pycache__/llm_analyzer.cpython-312.pyc +0 -0
- package/services/__pycache__/memory_md_sync.cpython-312.pyc +0 -0
- package/services/__pycache__/retry_queue.cpython-312.pyc +0 -0
- package/services/__pycache__/timeline.cpython-312.pyc +0 -0
- package/services/__pycache__/vector_index.cpython-312.pyc +0 -0
- package/services/__pycache__/websocket.cpython-312.pyc +0 -0
- package/services/agent_registry.py +753 -0
- package/services/auth.py +331 -0
- package/services/auto_inject.py +250 -0
- package/services/claude_md_sync.py +275 -0
- package/services/cleanup.py +667 -0
- package/services/compaction_flush.py +447 -0
- package/services/confidence.py +301 -0
- package/services/daily_log.py +333 -0
- package/services/database.py +2485 -0
- package/services/embeddings.py +358 -0
- package/services/insights.py +632 -0
- package/services/llm_analyzer.py +595 -0
- package/services/memory_md_sync.py +409 -0
- package/services/retry_queue.py +453 -0
- package/services/timeline.py +579 -0
- package/services/vector_index.py +398 -0
- package/services/websocket.py +257 -0
- package/skills/__init__.py +6 -0
- package/skills/__pycache__/__init__.cpython-312.pyc +0 -0
- package/skills/__pycache__/admin.cpython-312.pyc +0 -0
- package/skills/__pycache__/checkpoint.cpython-312.pyc +0 -0
- package/skills/__pycache__/claude_md.cpython-312.pyc +0 -0
- package/skills/__pycache__/cleanup.cpython-312.pyc +0 -0
- package/skills/__pycache__/grounding.cpython-312.pyc +0 -0
- package/skills/__pycache__/insights.cpython-312.pyc +0 -0
- package/skills/__pycache__/natural_language.cpython-312.pyc +0 -0
- package/skills/__pycache__/retrieve.cpython-312.pyc +0 -0
- package/skills/__pycache__/search.cpython-312.pyc +0 -0
- package/skills/__pycache__/state.cpython-312.pyc +0 -0
- package/skills/__pycache__/store.cpython-312.pyc +0 -0
- package/skills/__pycache__/summarize.cpython-312.pyc +0 -0
- package/skills/__pycache__/timeline.cpython-312.pyc +0 -0
- package/skills/__pycache__/verification.cpython-312.pyc +0 -0
- package/skills/admin.py +469 -0
- package/skills/checkpoint.py +198 -0
- package/skills/claude_md.py +363 -0
- package/skills/cleanup.py +241 -0
- package/skills/grounding.py +801 -0
- package/skills/insights.py +231 -0
- package/skills/natural_language.py +277 -0
- package/skills/retrieve.py +67 -0
- package/skills/search.py +213 -0
- package/skills/state.py +182 -0
- package/skills/store.py +179 -0
- package/skills/summarize.py +588 -0
- package/skills/timeline.py +387 -0
- package/skills/verification.py +391 -0
- package/start_daemon.py +155 -0
- package/test_automation.py +221 -0
- package/test_complete.py +338 -0
- package/test_full.py +322 -0
- package/update_system.py +817 -0
- package/verify_db.py +134 -0
package/skills/search.py
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""Semantic search skill with context filtering and fallback support."""
|
|
2
|
+
from typing import Dict, Any, Optional, List
|
|
3
|
+
from services.database import DatabaseService
|
|
4
|
+
from services.embeddings import EmbeddingService
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def semantic_search(
|
|
8
|
+
db: DatabaseService,
|
|
9
|
+
embeddings: EmbeddingService,
|
|
10
|
+
query: str,
|
|
11
|
+
limit: int = 10,
|
|
12
|
+
memory_type: Optional[str] = None,
|
|
13
|
+
session_id: Optional[str] = None,
|
|
14
|
+
project_path: Optional[str] = None,
|
|
15
|
+
agent_type: Optional[str] = None,
|
|
16
|
+
success_only: bool = False,
|
|
17
|
+
threshold: float = 0.5
|
|
18
|
+
) -> Dict[str, Any]:
|
|
19
|
+
"""
|
|
20
|
+
Search memories using semantic similarity with context filters.
|
|
21
|
+
|
|
22
|
+
Includes automatic fallback to keyword search when Ollama is unavailable.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
db: Database service instance
|
|
26
|
+
embeddings: Embedding service instance
|
|
27
|
+
query: Search query text
|
|
28
|
+
limit: Maximum number of results
|
|
29
|
+
memory_type: Filter by type (session, decision, code, chunk, error)
|
|
30
|
+
session_id: Filter by session ID
|
|
31
|
+
project_path: Filter by project
|
|
32
|
+
agent_type: Filter by agent that created the memory
|
|
33
|
+
success_only: Only return memories marked as successful
|
|
34
|
+
threshold: Minimum similarity threshold (0-1)
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Dict with search results ranked by similarity * importance
|
|
38
|
+
"""
|
|
39
|
+
# Generate embedding for the query (may return None if Ollama unavailable)
|
|
40
|
+
query_embedding = await embeddings.generate_embedding(query)
|
|
41
|
+
|
|
42
|
+
# Determine search method based on embedding availability
|
|
43
|
+
search_method = "semantic"
|
|
44
|
+
results = []
|
|
45
|
+
|
|
46
|
+
if query_embedding is not None:
|
|
47
|
+
# Use semantic search with embeddings
|
|
48
|
+
results = await db.search_similar(
|
|
49
|
+
embedding=query_embedding,
|
|
50
|
+
limit=limit,
|
|
51
|
+
memory_type=memory_type,
|
|
52
|
+
session_id=session_id,
|
|
53
|
+
project_path=project_path,
|
|
54
|
+
agent_type=agent_type,
|
|
55
|
+
success_only=success_only,
|
|
56
|
+
threshold=threshold
|
|
57
|
+
)
|
|
58
|
+
else:
|
|
59
|
+
# Fallback to keyword search
|
|
60
|
+
search_method = "keyword"
|
|
61
|
+
results = await db.keyword_search(
|
|
62
|
+
query=query,
|
|
63
|
+
limit=limit,
|
|
64
|
+
memory_type=memory_type,
|
|
65
|
+
session_id=session_id,
|
|
66
|
+
project_path=project_path,
|
|
67
|
+
agent_type=agent_type,
|
|
68
|
+
success_only=success_only
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
"success": True,
|
|
73
|
+
"query": query,
|
|
74
|
+
"results": results,
|
|
75
|
+
"count": len(results),
|
|
76
|
+
"search_method": search_method,
|
|
77
|
+
"degraded_mode": embeddings.is_degraded(),
|
|
78
|
+
"filters": {
|
|
79
|
+
"type": memory_type,
|
|
80
|
+
"project": project_path,
|
|
81
|
+
"agent": agent_type,
|
|
82
|
+
"success_only": success_only
|
|
83
|
+
},
|
|
84
|
+
"threshold": threshold if search_method == "semantic" else None
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
async def search_patterns(
|
|
89
|
+
db: DatabaseService,
|
|
90
|
+
embeddings: EmbeddingService,
|
|
91
|
+
query: str,
|
|
92
|
+
limit: int = 5,
|
|
93
|
+
problem_type: Optional[str] = None,
|
|
94
|
+
threshold: float = 0.5
|
|
95
|
+
) -> Dict[str, Any]:
|
|
96
|
+
"""
|
|
97
|
+
Search for reusable solution patterns.
|
|
98
|
+
|
|
99
|
+
Includes fallback to keyword search when Ollama is unavailable.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
db: Database service instance
|
|
103
|
+
embeddings: Embedding service instance
|
|
104
|
+
query: Problem description or search query
|
|
105
|
+
limit: Maximum number of results
|
|
106
|
+
problem_type: Filter by problem type
|
|
107
|
+
threshold: Minimum similarity threshold
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Dict with patterns ranked by similarity * success_rate
|
|
111
|
+
"""
|
|
112
|
+
query_embedding = await embeddings.generate_embedding(query)
|
|
113
|
+
|
|
114
|
+
search_method = "semantic"
|
|
115
|
+
results = []
|
|
116
|
+
|
|
117
|
+
if query_embedding is not None:
|
|
118
|
+
results = await db.search_patterns(
|
|
119
|
+
embedding=query_embedding,
|
|
120
|
+
limit=limit,
|
|
121
|
+
problem_type=problem_type,
|
|
122
|
+
threshold=threshold
|
|
123
|
+
)
|
|
124
|
+
else:
|
|
125
|
+
# Fallback: keyword search on patterns table
|
|
126
|
+
search_method = "keyword"
|
|
127
|
+
results = await db.keyword_search_patterns(
|
|
128
|
+
query=query,
|
|
129
|
+
limit=limit,
|
|
130
|
+
problem_type=problem_type
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
"success": True,
|
|
135
|
+
"query": query,
|
|
136
|
+
"patterns": results,
|
|
137
|
+
"count": len(results),
|
|
138
|
+
"search_method": search_method,
|
|
139
|
+
"degraded_mode": embeddings.is_degraded(),
|
|
140
|
+
"problem_type": problem_type
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
async def get_project_context(
|
|
145
|
+
db: DatabaseService,
|
|
146
|
+
embeddings: EmbeddingService,
|
|
147
|
+
project_path: str,
|
|
148
|
+
query: Optional[str] = None,
|
|
149
|
+
limit: int = 10
|
|
150
|
+
) -> Dict[str, Any]:
|
|
151
|
+
"""
|
|
152
|
+
Get all relevant context for a project.
|
|
153
|
+
|
|
154
|
+
Includes fallback to keyword search when Ollama is unavailable.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
db: Database service instance
|
|
158
|
+
embeddings: Embedding service instance
|
|
159
|
+
project_path: Path to the project
|
|
160
|
+
query: Optional query to filter relevant memories
|
|
161
|
+
limit: Max memories to return
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
Dict with project info and relevant memories
|
|
165
|
+
"""
|
|
166
|
+
# Get project info
|
|
167
|
+
project = await db.get_project(project_path)
|
|
168
|
+
|
|
169
|
+
# Get recent decisions for this project
|
|
170
|
+
decisions = await db.get_memories_by_type(
|
|
171
|
+
memory_type="decision",
|
|
172
|
+
project_path=project_path,
|
|
173
|
+
limit=limit
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Get patterns used in this project
|
|
177
|
+
patterns = await db.get_memories_by_type(
|
|
178
|
+
memory_type="code",
|
|
179
|
+
project_path=project_path,
|
|
180
|
+
limit=limit
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# If query provided, search for relevant memories
|
|
184
|
+
relevant = []
|
|
185
|
+
search_method = None
|
|
186
|
+
if query:
|
|
187
|
+
query_embedding = await embeddings.generate_embedding(query)
|
|
188
|
+
if query_embedding is not None:
|
|
189
|
+
search_method = "semantic"
|
|
190
|
+
relevant = await db.search_similar(
|
|
191
|
+
embedding=query_embedding,
|
|
192
|
+
project_path=project_path,
|
|
193
|
+
limit=limit,
|
|
194
|
+
threshold=0.4
|
|
195
|
+
)
|
|
196
|
+
else:
|
|
197
|
+
# Fallback to keyword search
|
|
198
|
+
search_method = "keyword"
|
|
199
|
+
relevant = await db.keyword_search(
|
|
200
|
+
query=query,
|
|
201
|
+
project_path=project_path,
|
|
202
|
+
limit=limit
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
"success": True,
|
|
207
|
+
"project": project,
|
|
208
|
+
"decisions": decisions,
|
|
209
|
+
"code_patterns": patterns,
|
|
210
|
+
"relevant_to_query": relevant if query else None,
|
|
211
|
+
"search_method": search_method,
|
|
212
|
+
"degraded_mode": embeddings.is_degraded()
|
|
213
|
+
}
|
package/skills/state.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""Session state management skills."""
|
|
2
|
+
from typing import Dict, Any, Optional, List
|
|
3
|
+
from services.database import DatabaseService
|
|
4
|
+
from services.timeline import TimelineService, SESSION_GAP_SECONDS
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def state_get(
|
|
8
|
+
db: DatabaseService,
|
|
9
|
+
session_id: Optional[str] = None,
|
|
10
|
+
project_path: Optional[str] = None
|
|
11
|
+
) -> Dict[str, Any]:
|
|
12
|
+
"""
|
|
13
|
+
Get current session state.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
db: Database service instance
|
|
17
|
+
session_id: Specific session ID (optional)
|
|
18
|
+
project_path: Get latest session for project (if no session_id)
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
Dict with session state
|
|
22
|
+
"""
|
|
23
|
+
if session_id:
|
|
24
|
+
state = await db.get_or_create_session_state(session_id, project_path)
|
|
25
|
+
elif project_path:
|
|
26
|
+
state = await db.get_latest_session_for_project(project_path)
|
|
27
|
+
if not state:
|
|
28
|
+
return {
|
|
29
|
+
"success": True,
|
|
30
|
+
"state": None,
|
|
31
|
+
"message": "No session found for this project"
|
|
32
|
+
}
|
|
33
|
+
else:
|
|
34
|
+
return {
|
|
35
|
+
"success": False,
|
|
36
|
+
"error": "Must provide either session_id or project_path"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
"success": True,
|
|
41
|
+
"state": state,
|
|
42
|
+
"session_id": state.get("session_id"),
|
|
43
|
+
"current_goal": state.get("current_goal"),
|
|
44
|
+
"entity_registry": state.get("entity_registry", {}),
|
|
45
|
+
"pending_questions": state.get("pending_questions", []),
|
|
46
|
+
"events_since_checkpoint": state.get("events_since_checkpoint", 0)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def state_update(
|
|
51
|
+
db: DatabaseService,
|
|
52
|
+
session_id: str,
|
|
53
|
+
current_goal: Optional[str] = None,
|
|
54
|
+
pending_questions: Optional[List[str]] = None,
|
|
55
|
+
add_question: Optional[str] = None,
|
|
56
|
+
remove_question: Optional[str] = None,
|
|
57
|
+
register_entity: Optional[Dict[str, str]] = None,
|
|
58
|
+
entity_registry: Optional[Dict[str, str]] = None,
|
|
59
|
+
add_decision: Optional[str] = None,
|
|
60
|
+
decisions_summary: Optional[str] = None
|
|
61
|
+
) -> Dict[str, Any]:
|
|
62
|
+
"""
|
|
63
|
+
Update session state.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
db: Database service instance
|
|
67
|
+
session_id: The session ID
|
|
68
|
+
current_goal: Set current goal
|
|
69
|
+
pending_questions: Replace pending questions list
|
|
70
|
+
add_question: Add a single question to pending
|
|
71
|
+
remove_question: Remove a question from pending
|
|
72
|
+
register_entity: Add entity to registry {"key": "value"}
|
|
73
|
+
entity_registry: Replace entire entity registry
|
|
74
|
+
add_decision: Add a decision to the summary
|
|
75
|
+
decisions_summary: Replace entire decisions summary
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
Dict with updated state
|
|
79
|
+
"""
|
|
80
|
+
# Get current state first
|
|
81
|
+
state = await db.get_or_create_session_state(session_id)
|
|
82
|
+
|
|
83
|
+
# Handle question modifications
|
|
84
|
+
final_questions = pending_questions
|
|
85
|
+
if final_questions is None:
|
|
86
|
+
final_questions = state.get("pending_questions", [])
|
|
87
|
+
|
|
88
|
+
if add_question and add_question not in final_questions:
|
|
89
|
+
final_questions = list(final_questions) + [add_question]
|
|
90
|
+
|
|
91
|
+
if remove_question and remove_question in final_questions:
|
|
92
|
+
final_questions = [q for q in final_questions if q != remove_question]
|
|
93
|
+
|
|
94
|
+
# Handle entity registry modifications
|
|
95
|
+
final_registry = entity_registry
|
|
96
|
+
if final_registry is None:
|
|
97
|
+
final_registry = state.get("entity_registry", {})
|
|
98
|
+
|
|
99
|
+
if register_entity:
|
|
100
|
+
final_registry = {**final_registry, **register_entity}
|
|
101
|
+
|
|
102
|
+
# Handle decisions summary
|
|
103
|
+
final_decisions = decisions_summary
|
|
104
|
+
if final_decisions is None:
|
|
105
|
+
final_decisions = state.get("decisions_summary", "")
|
|
106
|
+
|
|
107
|
+
if add_decision:
|
|
108
|
+
if final_decisions:
|
|
109
|
+
final_decisions = f"{final_decisions}\n- {add_decision}"
|
|
110
|
+
else:
|
|
111
|
+
final_decisions = f"- {add_decision}"
|
|
112
|
+
|
|
113
|
+
# Perform update
|
|
114
|
+
success = await db.update_session_state(
|
|
115
|
+
session_id=session_id,
|
|
116
|
+
current_goal=current_goal,
|
|
117
|
+
pending_questions=final_questions,
|
|
118
|
+
entity_registry=final_registry,
|
|
119
|
+
decisions_summary=final_decisions
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Get updated state
|
|
123
|
+
updated_state = await db.get_or_create_session_state(session_id)
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
"success": success,
|
|
127
|
+
"session_id": session_id,
|
|
128
|
+
"state": updated_state,
|
|
129
|
+
"message": "Session state updated"
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
async def state_init_session(
|
|
134
|
+
db: DatabaseService,
|
|
135
|
+
embeddings,
|
|
136
|
+
project_path: str
|
|
137
|
+
) -> Dict[str, Any]:
|
|
138
|
+
"""
|
|
139
|
+
Initialize or resume a session for a project.
|
|
140
|
+
|
|
141
|
+
Handles the 4-hour gap logic for session boundaries.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
db: Database service instance
|
|
145
|
+
embeddings: Embedding service instance
|
|
146
|
+
project_path: Project path
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
Dict with session info and context
|
|
150
|
+
"""
|
|
151
|
+
timeline = TimelineService(db, embeddings)
|
|
152
|
+
|
|
153
|
+
session_id, is_new, previous_state = await timeline.get_or_create_session(project_path)
|
|
154
|
+
|
|
155
|
+
result = {
|
|
156
|
+
"success": True,
|
|
157
|
+
"session_id": session_id,
|
|
158
|
+
"is_new_session": is_new,
|
|
159
|
+
"project_path": project_path
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if is_new and previous_state:
|
|
163
|
+
# Load context from previous session
|
|
164
|
+
prev_checkpoint = await db.get_latest_checkpoint(previous_state["session_id"])
|
|
165
|
+
result["previous_session"] = {
|
|
166
|
+
"session_id": previous_state["session_id"],
|
|
167
|
+
"last_goal": previous_state.get("current_goal"),
|
|
168
|
+
"last_activity": previous_state.get("last_activity_at"),
|
|
169
|
+
"checkpoint": prev_checkpoint
|
|
170
|
+
}
|
|
171
|
+
result["message"] = f"New session created (previous session timed out after {SESSION_GAP_SECONDS // 3600}h gap)"
|
|
172
|
+
elif not is_new:
|
|
173
|
+
# Load current session context
|
|
174
|
+
context = await timeline.load_session_context(session_id)
|
|
175
|
+
result["state"] = context["state"]
|
|
176
|
+
result["recent_events"] = context["recent_events"][:5] # Last 5 events
|
|
177
|
+
result["checkpoint"] = context["checkpoint"]
|
|
178
|
+
result["message"] = "Continuing existing session"
|
|
179
|
+
else:
|
|
180
|
+
result["message"] = "New session created (no previous session)"
|
|
181
|
+
|
|
182
|
+
return result
|
package/skills/store.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""Store memory skill with rich context support."""
|
|
2
|
+
from typing import Dict, Any, Optional, List
|
|
3
|
+
from services.database import DatabaseService
|
|
4
|
+
from services.embeddings import EmbeddingService
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def store_memory(
|
|
8
|
+
db: DatabaseService,
|
|
9
|
+
embeddings: EmbeddingService,
|
|
10
|
+
content: str,
|
|
11
|
+
memory_type: str = "chunk",
|
|
12
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
13
|
+
session_id: Optional[str] = None,
|
|
14
|
+
# Project context
|
|
15
|
+
project_path: Optional[str] = None,
|
|
16
|
+
project_name: Optional[str] = None,
|
|
17
|
+
project_type: Optional[str] = None,
|
|
18
|
+
tech_stack: Optional[List[str]] = None,
|
|
19
|
+
# Session context
|
|
20
|
+
chat_id: Optional[str] = None,
|
|
21
|
+
# Agent context
|
|
22
|
+
agent_type: Optional[str] = None,
|
|
23
|
+
skill_used: Optional[str] = None,
|
|
24
|
+
tools_used: Optional[List[str]] = None,
|
|
25
|
+
# Outcome
|
|
26
|
+
outcome: Optional[str] = None,
|
|
27
|
+
success: Optional[bool] = None,
|
|
28
|
+
# Classification
|
|
29
|
+
tags: Optional[List[str]] = None,
|
|
30
|
+
importance: int = 5
|
|
31
|
+
) -> Dict[str, Any]:
|
|
32
|
+
"""
|
|
33
|
+
Store a memory with semantic embedding and rich context.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
db: Database service instance
|
|
37
|
+
embeddings: Embedding service instance
|
|
38
|
+
content: The text content to store
|
|
39
|
+
memory_type: Type of memory:
|
|
40
|
+
- 'session': Session summaries
|
|
41
|
+
- 'decision': Architectural/design decisions
|
|
42
|
+
- 'code': Code patterns and snippets
|
|
43
|
+
- 'chunk': General conversation chunks
|
|
44
|
+
- 'error': Error patterns and solutions
|
|
45
|
+
- 'preference': User preferences
|
|
46
|
+
metadata: Optional additional metadata
|
|
47
|
+
session_id: Session identifier
|
|
48
|
+
project_path: Full path to the project
|
|
49
|
+
project_name: Human-readable project name
|
|
50
|
+
project_type: Type (wordpress, react, python, etc.)
|
|
51
|
+
tech_stack: List of technologies used
|
|
52
|
+
chat_id: Specific chat/conversation ID
|
|
53
|
+
agent_type: Agent that processed this (Explore, Plan, etc.)
|
|
54
|
+
skill_used: Skill that was invoked
|
|
55
|
+
tools_used: List of tools that were called
|
|
56
|
+
outcome: Description of what happened
|
|
57
|
+
success: Whether the operation succeeded
|
|
58
|
+
tags: Classification tags
|
|
59
|
+
importance: 1-10 scale of importance (default 5)
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Dict with stored memory ID and status
|
|
63
|
+
"""
|
|
64
|
+
# Generate embedding for the content
|
|
65
|
+
embedding = await embeddings.generate_embedding(content)
|
|
66
|
+
|
|
67
|
+
# Store in database with full context
|
|
68
|
+
memory_id = await db.store_memory(
|
|
69
|
+
memory_type=memory_type,
|
|
70
|
+
content=content,
|
|
71
|
+
embedding=embedding,
|
|
72
|
+
metadata=metadata,
|
|
73
|
+
session_id=session_id,
|
|
74
|
+
project_path=project_path,
|
|
75
|
+
project_name=project_name,
|
|
76
|
+
project_type=project_type,
|
|
77
|
+
tech_stack=tech_stack,
|
|
78
|
+
chat_id=chat_id,
|
|
79
|
+
agent_type=agent_type,
|
|
80
|
+
skill_used=skill_used,
|
|
81
|
+
tools_used=tools_used,
|
|
82
|
+
outcome=outcome,
|
|
83
|
+
success=success,
|
|
84
|
+
tags=tags,
|
|
85
|
+
importance=importance
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
"success": True,
|
|
90
|
+
"memory_id": memory_id,
|
|
91
|
+
"type": memory_type,
|
|
92
|
+
"importance": importance,
|
|
93
|
+
"project": project_path,
|
|
94
|
+
"message": f"Memory stored successfully with ID {memory_id}"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
async def store_project(
|
|
99
|
+
db: DatabaseService,
|
|
100
|
+
path: str,
|
|
101
|
+
name: Optional[str] = None,
|
|
102
|
+
project_type: Optional[str] = None,
|
|
103
|
+
tech_stack: Optional[List[str]] = None,
|
|
104
|
+
conventions: Optional[Dict[str, Any]] = None,
|
|
105
|
+
preferences: Optional[Dict[str, Any]] = None
|
|
106
|
+
) -> Dict[str, Any]:
|
|
107
|
+
"""
|
|
108
|
+
Store or update project-level information.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
db: Database service instance
|
|
112
|
+
path: Full path to the project
|
|
113
|
+
name: Human-readable project name
|
|
114
|
+
project_type: Type (wordpress, react, python, etc.)
|
|
115
|
+
tech_stack: List of technologies
|
|
116
|
+
conventions: Coding conventions (naming, structure, etc.)
|
|
117
|
+
preferences: User preferences for this project
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Dict with project info
|
|
121
|
+
"""
|
|
122
|
+
project_id = await db.store_project(
|
|
123
|
+
path=path,
|
|
124
|
+
name=name,
|
|
125
|
+
project_type=project_type,
|
|
126
|
+
tech_stack=tech_stack,
|
|
127
|
+
conventions=conventions,
|
|
128
|
+
preferences=preferences
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
"success": True,
|
|
133
|
+
"project_id": project_id,
|
|
134
|
+
"path": path,
|
|
135
|
+
"message": f"Project info stored/updated for {path}"
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
async def store_pattern(
|
|
140
|
+
db: DatabaseService,
|
|
141
|
+
embeddings: EmbeddingService,
|
|
142
|
+
name: str,
|
|
143
|
+
solution: str,
|
|
144
|
+
problem_type: Optional[str] = None,
|
|
145
|
+
tech_context: Optional[List[str]] = None,
|
|
146
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
147
|
+
) -> Dict[str, Any]:
|
|
148
|
+
"""
|
|
149
|
+
Store a reusable solution pattern.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
db: Database service instance
|
|
153
|
+
embeddings: Embedding service instance
|
|
154
|
+
name: Pattern name
|
|
155
|
+
solution: The solution/approach
|
|
156
|
+
problem_type: Category (bug_fix, feature, refactor, config, etc.)
|
|
157
|
+
tech_context: Technologies this applies to
|
|
158
|
+
metadata: Additional info
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
Dict with pattern info
|
|
162
|
+
"""
|
|
163
|
+
embedding = await embeddings.generate_embedding(f"{name}: {solution}")
|
|
164
|
+
|
|
165
|
+
pattern_id = await db.store_pattern(
|
|
166
|
+
name=name,
|
|
167
|
+
solution=solution,
|
|
168
|
+
embedding=embedding,
|
|
169
|
+
problem_type=problem_type,
|
|
170
|
+
tech_context=tech_context,
|
|
171
|
+
metadata=metadata
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
"success": True,
|
|
176
|
+
"pattern_id": pattern_id,
|
|
177
|
+
"name": name,
|
|
178
|
+
"message": f"Pattern '{name}' stored successfully"
|
|
179
|
+
}
|