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.
Files changed (100) hide show
  1. package/.env.example +107 -0
  2. package/README.md +200 -0
  3. package/agent_card.py +512 -0
  4. package/bin/cli.js +181 -0
  5. package/bin/postinstall.js +216 -0
  6. package/config.py +104 -0
  7. package/dashboard.html +2689 -0
  8. package/hooks/README.md +196 -0
  9. package/hooks/__pycache__/auto-detect-response.cpython-312.pyc +0 -0
  10. package/hooks/__pycache__/auto_capture.cpython-312.pyc +0 -0
  11. package/hooks/__pycache__/session_end.cpython-312.pyc +0 -0
  12. package/hooks/__pycache__/session_start.cpython-312.pyc +0 -0
  13. package/hooks/auto-detect-response.py +348 -0
  14. package/hooks/auto_capture.py +255 -0
  15. package/hooks/detect-correction.py +173 -0
  16. package/hooks/grounding-hook.py +348 -0
  17. package/hooks/log-tool-use.py +234 -0
  18. package/hooks/log-user-request.py +208 -0
  19. package/hooks/pre-tool-decision.py +218 -0
  20. package/hooks/problem-detector.py +343 -0
  21. package/hooks/session_end.py +192 -0
  22. package/hooks/session_start.py +227 -0
  23. package/install.py +887 -0
  24. package/main.py +2859 -0
  25. package/manager.py +997 -0
  26. package/package.json +55 -0
  27. package/requirements.txt +8 -0
  28. package/run_server.py +136 -0
  29. package/services/__init__.py +50 -0
  30. package/services/__pycache__/__init__.cpython-312.pyc +0 -0
  31. package/services/__pycache__/agent_registry.cpython-312.pyc +0 -0
  32. package/services/__pycache__/auth.cpython-312.pyc +0 -0
  33. package/services/__pycache__/auto_inject.cpython-312.pyc +0 -0
  34. package/services/__pycache__/claude_md_sync.cpython-312.pyc +0 -0
  35. package/services/__pycache__/cleanup.cpython-312.pyc +0 -0
  36. package/services/__pycache__/compaction_flush.cpython-312.pyc +0 -0
  37. package/services/__pycache__/confidence.cpython-312.pyc +0 -0
  38. package/services/__pycache__/daily_log.cpython-312.pyc +0 -0
  39. package/services/__pycache__/database.cpython-312.pyc +0 -0
  40. package/services/__pycache__/embeddings.cpython-312.pyc +0 -0
  41. package/services/__pycache__/insights.cpython-312.pyc +0 -0
  42. package/services/__pycache__/llm_analyzer.cpython-312.pyc +0 -0
  43. package/services/__pycache__/memory_md_sync.cpython-312.pyc +0 -0
  44. package/services/__pycache__/retry_queue.cpython-312.pyc +0 -0
  45. package/services/__pycache__/timeline.cpython-312.pyc +0 -0
  46. package/services/__pycache__/vector_index.cpython-312.pyc +0 -0
  47. package/services/__pycache__/websocket.cpython-312.pyc +0 -0
  48. package/services/agent_registry.py +753 -0
  49. package/services/auth.py +331 -0
  50. package/services/auto_inject.py +250 -0
  51. package/services/claude_md_sync.py +275 -0
  52. package/services/cleanup.py +667 -0
  53. package/services/compaction_flush.py +447 -0
  54. package/services/confidence.py +301 -0
  55. package/services/daily_log.py +333 -0
  56. package/services/database.py +2485 -0
  57. package/services/embeddings.py +358 -0
  58. package/services/insights.py +632 -0
  59. package/services/llm_analyzer.py +595 -0
  60. package/services/memory_md_sync.py +409 -0
  61. package/services/retry_queue.py +453 -0
  62. package/services/timeline.py +579 -0
  63. package/services/vector_index.py +398 -0
  64. package/services/websocket.py +257 -0
  65. package/skills/__init__.py +6 -0
  66. package/skills/__pycache__/__init__.cpython-312.pyc +0 -0
  67. package/skills/__pycache__/admin.cpython-312.pyc +0 -0
  68. package/skills/__pycache__/checkpoint.cpython-312.pyc +0 -0
  69. package/skills/__pycache__/claude_md.cpython-312.pyc +0 -0
  70. package/skills/__pycache__/cleanup.cpython-312.pyc +0 -0
  71. package/skills/__pycache__/grounding.cpython-312.pyc +0 -0
  72. package/skills/__pycache__/insights.cpython-312.pyc +0 -0
  73. package/skills/__pycache__/natural_language.cpython-312.pyc +0 -0
  74. package/skills/__pycache__/retrieve.cpython-312.pyc +0 -0
  75. package/skills/__pycache__/search.cpython-312.pyc +0 -0
  76. package/skills/__pycache__/state.cpython-312.pyc +0 -0
  77. package/skills/__pycache__/store.cpython-312.pyc +0 -0
  78. package/skills/__pycache__/summarize.cpython-312.pyc +0 -0
  79. package/skills/__pycache__/timeline.cpython-312.pyc +0 -0
  80. package/skills/__pycache__/verification.cpython-312.pyc +0 -0
  81. package/skills/admin.py +469 -0
  82. package/skills/checkpoint.py +198 -0
  83. package/skills/claude_md.py +363 -0
  84. package/skills/cleanup.py +241 -0
  85. package/skills/grounding.py +801 -0
  86. package/skills/insights.py +231 -0
  87. package/skills/natural_language.py +277 -0
  88. package/skills/retrieve.py +67 -0
  89. package/skills/search.py +213 -0
  90. package/skills/state.py +182 -0
  91. package/skills/store.py +179 -0
  92. package/skills/summarize.py +588 -0
  93. package/skills/timeline.py +387 -0
  94. package/skills/verification.py +391 -0
  95. package/start_daemon.py +155 -0
  96. package/test_automation.py +221 -0
  97. package/test_complete.py +338 -0
  98. package/test_full.py +322 -0
  99. package/update_system.py +817 -0
  100. package/verify_db.py +134 -0
@@ -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
+ }
@@ -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
@@ -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
+ }