claude-memory-agent 2.1.0 → 2.2.1

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 (91) hide show
  1. package/bin/cli.js +11 -1
  2. package/bin/lib/banner.js +39 -0
  3. package/bin/lib/environment.js +166 -0
  4. package/bin/lib/installer.js +291 -0
  5. package/bin/lib/models.js +95 -0
  6. package/bin/lib/steps/advanced.js +101 -0
  7. package/bin/lib/steps/confirm.js +87 -0
  8. package/bin/lib/steps/model.js +57 -0
  9. package/bin/lib/steps/provider.js +65 -0
  10. package/bin/lib/steps/scope.js +59 -0
  11. package/bin/lib/steps/server.js +74 -0
  12. package/bin/lib/ui.js +75 -0
  13. package/bin/onboarding.js +164 -0
  14. package/bin/postinstall.js +22 -257
  15. package/config.py +103 -4
  16. package/dashboard.html +697 -27
  17. package/hooks/extract_memories.py +439 -0
  18. package/hooks/pre_compact_hook.py +76 -0
  19. package/hooks/session_end_hook.py +149 -0
  20. package/hooks/stop_hook.py +372 -0
  21. package/install.py +91 -37
  22. package/main.py +1636 -892
  23. package/mcp_server.py +451 -0
  24. package/package.json +14 -3
  25. package/requirements.txt +12 -8
  26. package/services/adaptive_ranker.py +272 -0
  27. package/services/agent_catalog.json +153 -0
  28. package/services/agent_registry.py +245 -730
  29. package/services/claude_md_sync.py +320 -4
  30. package/services/consolidation.py +417 -0
  31. package/services/database.py +586 -105
  32. package/services/embedding_pipeline.py +262 -0
  33. package/services/embeddings.py +493 -85
  34. package/services/memory_decay.py +408 -0
  35. package/services/native_memory_paths.py +86 -0
  36. package/services/native_memory_sync.py +496 -0
  37. package/services/response_manager.py +183 -0
  38. package/services/terminal_ui.py +199 -0
  39. package/services/tier_manager.py +235 -0
  40. package/services/websocket.py +26 -6
  41. package/skills/search.py +136 -61
  42. package/skills/session_review.py +210 -23
  43. package/skills/store.py +125 -18
  44. package/terminal_dashboard.py +474 -0
  45. package/hooks/__pycache__/auto-detect-response.cpython-312.pyc +0 -0
  46. package/hooks/__pycache__/auto_capture.cpython-312.pyc +0 -0
  47. package/hooks/__pycache__/grounding-hook.cpython-312.pyc +0 -0
  48. package/hooks/__pycache__/session_end.cpython-312.pyc +0 -0
  49. package/hooks/__pycache__/session_start.cpython-312.pyc +0 -0
  50. package/services/__pycache__/__init__.cpython-312.pyc +0 -0
  51. package/services/__pycache__/agent_registry.cpython-312.pyc +0 -0
  52. package/services/__pycache__/auth.cpython-312.pyc +0 -0
  53. package/services/__pycache__/auto_inject.cpython-312.pyc +0 -0
  54. package/services/__pycache__/claude_md_sync.cpython-312.pyc +0 -0
  55. package/services/__pycache__/cleanup.cpython-312.pyc +0 -0
  56. package/services/__pycache__/compaction_flush.cpython-312.pyc +0 -0
  57. package/services/__pycache__/confidence.cpython-312.pyc +0 -0
  58. package/services/__pycache__/curator.cpython-312.pyc +0 -0
  59. package/services/__pycache__/daily_log.cpython-312.pyc +0 -0
  60. package/services/__pycache__/database.cpython-312.pyc +0 -0
  61. package/services/__pycache__/embeddings.cpython-312.pyc +0 -0
  62. package/services/__pycache__/insights.cpython-312.pyc +0 -0
  63. package/services/__pycache__/llm_analyzer.cpython-312.pyc +0 -0
  64. package/services/__pycache__/memory_md_sync.cpython-312.pyc +0 -0
  65. package/services/__pycache__/retry_queue.cpython-312.pyc +0 -0
  66. package/services/__pycache__/timeline.cpython-312.pyc +0 -0
  67. package/services/__pycache__/vector_index.cpython-312.pyc +0 -0
  68. package/services/__pycache__/websocket.cpython-312.pyc +0 -0
  69. package/skills/__pycache__/__init__.cpython-312.pyc +0 -0
  70. package/skills/__pycache__/admin.cpython-312.pyc +0 -0
  71. package/skills/__pycache__/checkpoint.cpython-312.pyc +0 -0
  72. package/skills/__pycache__/claude_md.cpython-312.pyc +0 -0
  73. package/skills/__pycache__/cleanup.cpython-312.pyc +0 -0
  74. package/skills/__pycache__/confidence_tracker.cpython-312.pyc +0 -0
  75. package/skills/__pycache__/context.cpython-312.pyc +0 -0
  76. package/skills/__pycache__/curator.cpython-312.pyc +0 -0
  77. package/skills/__pycache__/grounding.cpython-312.pyc +0 -0
  78. package/skills/__pycache__/insights.cpython-312.pyc +0 -0
  79. package/skills/__pycache__/natural_language.cpython-312.pyc +0 -0
  80. package/skills/__pycache__/retrieve.cpython-312.pyc +0 -0
  81. package/skills/__pycache__/search.cpython-312.pyc +0 -0
  82. package/skills/__pycache__/session_review.cpython-312.pyc +0 -0
  83. package/skills/__pycache__/state.cpython-312.pyc +0 -0
  84. package/skills/__pycache__/store.cpython-312.pyc +0 -0
  85. package/skills/__pycache__/summarize.cpython-312.pyc +0 -0
  86. package/skills/__pycache__/timeline.cpython-312.pyc +0 -0
  87. package/skills/__pycache__/verification.cpython-312.pyc +0 -0
  88. package/test_automation.py +0 -221
  89. package/test_complete.py +0 -338
  90. package/test_full.py +0 -322
  91. package/verify_db.py +0 -134
@@ -1,270 +1,35 @@
1
1
  #!/usr/bin/env node
2
+ 'use strict';
2
3
 
3
4
  /**
4
5
  * Post-installation script for Claude Memory Agent
5
- *
6
- * This runs automatically after npm install to:
7
- * 1. Check Python availability
8
- * 2. Install Python dependencies
9
- * 3. Run the configuration wizard (if interactive)
6
+ * Dispatches to the onboarding wizard (interactive) or installs with defaults (CI/piped).
10
7
  */
11
8
 
12
- const { execSync, spawn } = require('child_process');
13
9
  const path = require('path');
14
- const fs = require('fs');
15
- const readline = require('readline');
16
10
 
17
- const AGENT_DIR = path.dirname(__dirname);
18
-
19
- // Colors for terminal output
20
- const colors = {
21
- reset: '\x1b[0m',
22
- green: '\x1b[32m',
23
- yellow: '\x1b[33m',
24
- red: '\x1b[31m',
25
- cyan: '\x1b[36m',
26
- bold: '\x1b[1m'
27
- };
28
-
29
- function log(msg) {
30
- console.log(msg);
31
- }
32
-
33
- function success(msg) {
34
- console.log(`${colors.green}✓${colors.reset} ${msg}`);
35
- }
36
-
37
- function warn(msg) {
38
- console.log(`${colors.yellow}!${colors.reset} ${msg}`);
39
- }
40
-
41
- function error(msg) {
42
- console.log(`${colors.red}✗${colors.reset} ${msg}`);
43
- }
44
-
45
- function header(msg) {
46
- console.log(`\n${colors.bold}${colors.cyan}${msg}${colors.reset}\n`);
47
- }
48
-
49
- // Check Python availability
50
- function getPython() {
51
- const pythonCommands = ['python3', 'python', 'py'];
52
-
53
- for (const cmd of pythonCommands) {
54
- try {
55
- const result = execSync(`${cmd} --version`, {
56
- encoding: 'utf8',
57
- stdio: ['pipe', 'pipe', 'pipe']
58
- });
59
- const match = result.match(/Python (\d+)\.(\d+)/);
60
- if (match) {
61
- const major = parseInt(match[1]);
62
- const minor = parseInt(match[2]);
63
- if (major >= 3 && minor >= 9) {
64
- return { cmd, version: result.trim() };
65
- }
66
- }
67
- } catch (e) {
68
- continue;
69
- }
70
- }
71
- return null;
72
- }
73
-
74
- // Check if Ollama is running
75
- function checkOllama() {
76
- try {
77
- const http = require('http');
78
- return new Promise((resolve) => {
79
- const req = http.get('http://localhost:11434/api/tags', { timeout: 2000 }, (res) => {
80
- resolve(res.statusCode === 200);
81
- });
82
- req.on('error', () => resolve(false));
83
- req.on('timeout', () => {
84
- req.destroy();
85
- resolve(false);
86
- });
87
- });
88
- } catch (e) {
89
- return Promise.resolve(false);
90
- }
91
- }
92
-
93
- // Install Python dependencies
94
- function installPythonDeps(python) {
95
- const requirementsPath = path.join(AGENT_DIR, 'requirements.txt');
96
-
97
- if (!fs.existsSync(requirementsPath)) {
98
- warn('requirements.txt not found, skipping Python dependencies');
99
- return true;
100
- }
101
-
102
- log('Installing Python dependencies...');
103
- try {
104
- execSync(`${python} -m pip install -r requirements.txt -q --disable-pip-version-check`, {
105
- cwd: AGENT_DIR,
106
- stdio: ['pipe', 'pipe', 'pipe']
107
- });
108
- success('Python dependencies installed');
109
- return true;
110
- } catch (e) {
111
- error('Failed to install Python dependencies');
112
- console.log(' Run manually: pip install -r requirements.txt');
113
- return false;
114
- }
115
- }
116
-
117
- // Create .env file if it doesn't exist
118
- function createEnvFile() {
119
- const envPath = path.join(AGENT_DIR, '.env');
120
- const examplePath = path.join(AGENT_DIR, '.env.example');
121
-
122
- if (fs.existsSync(envPath)) {
123
- success('.env file already exists');
124
- return true;
125
- }
126
-
127
- // Create basic .env
128
- const envContent = `# Claude Memory Agent Configuration
129
- # Generated during npm install
130
-
131
- # Server
132
- PORT=8102
133
- HOST=0.0.0.0
134
- MEMORY_AGENT_URL=http://localhost:8102
135
-
136
- # Ollama
137
- OLLAMA_HOST=http://localhost:11434
138
- EMBEDDING_MODEL=nomic-embed-text
139
-
140
- # Database (relative to agent directory)
141
- DATABASE_PATH=${path.join(AGENT_DIR, 'memories.db').replace(/\\/g, '/')}
142
-
143
- # Logging
144
- LOG_LEVEL=INFO
145
- `;
146
-
147
- try {
148
- fs.writeFileSync(envPath, envContent);
149
- success('Created .env configuration file');
150
- return true;
151
- } catch (e) {
152
- warn('Could not create .env file');
153
- return false;
154
- }
155
- }
156
-
157
- // Main installation
158
11
  async function main() {
159
- header('Claude Memory Agent - Post-Installation Setup');
160
-
161
- // Check Python
162
- log('Checking Python...');
163
- const python = getPython();
164
- if (!python) {
165
- error('Python 3.9+ is required but not found');
166
- console.log('\n Please install Python from https://python.org/');
167
- console.log(' Then run: claude-memory-agent install\n');
168
- process.exit(1);
169
- }
170
- success(`Found ${python.version}`);
171
-
172
- // Install Python dependencies
173
- installPythonDeps(python.cmd);
174
-
175
- // Create .env file
176
- createEnvFile();
177
-
178
- // Check Ollama
179
- log('Checking Ollama...');
180
- const ollamaRunning = await checkOllama();
181
-
182
- if (ollamaRunning) {
183
- success('Ollama is running');
184
- // Check if model is installed
185
- const modelInstalled = await checkOllamaModel();
186
- if (modelInstalled) {
187
- success('Embedding model is ready');
188
- } else {
189
- warn('Embedding model not found');
190
- }
191
- }
192
-
193
- // Print next steps based on what's missing
194
- header('Installation Complete!');
195
-
196
- if (!ollamaRunning) {
197
- // Ollama not installed - show big warning
198
- console.log(`${colors.red}${colors.bold}╔════════════════════════════════════════════════════════════╗${colors.reset}`);
199
- console.log(`${colors.red}${colors.bold}║ REQUIRED: Install Ollama for semantic search to work ║${colors.reset}`);
200
- console.log(`${colors.red}${colors.bold}╚════════════════════════════════════════════════════════════╝${colors.reset}`);
201
- console.log('');
202
- console.log(' Ollama is required for the memory agent to work properly.');
203
- console.log(' Without it, semantic search will be disabled.');
204
- console.log('');
205
- console.log(` ${colors.cyan}Step 1:${colors.reset} Download and install Ollama:`);
206
- console.log(` ${colors.bold}https://ollama.ai/download${colors.reset}`);
207
- console.log('');
208
- console.log(` ${colors.cyan}Step 2:${colors.reset} After installing, open a terminal and run:`);
209
- console.log(` ${colors.bold}ollama pull nomic-embed-text${colors.reset}`);
210
- console.log('');
211
- console.log(` ${colors.cyan}Step 3:${colors.reset} Start Ollama (it runs in background):`);
212
- console.log(` ${colors.bold}ollama serve${colors.reset}`);
213
- console.log('');
214
- console.log(` ${colors.cyan}Step 4:${colors.reset} Then run the setup:`);
215
- console.log(` ${colors.bold}claude-memory-agent install${colors.reset}`);
216
- console.log('');
217
- } else {
218
- // Ollama running - show normal next steps
219
- console.log('Next steps:');
220
- console.log('');
221
- console.log(' 1. Run the setup wizard:');
222
- console.log(` ${colors.bold}claude-memory-agent install${colors.reset}`);
223
- console.log('');
224
- console.log(' 2. Start the agent:');
225
- console.log(` ${colors.bold}claude-memory-agent start${colors.reset}`);
226
- console.log('');
227
- console.log(' 3. Open the dashboard:');
228
- console.log(` ${colors.bold}claude-memory-agent dashboard${colors.reset}`);
229
- console.log('');
230
- }
231
- }
232
-
233
- // Check if embedding model is installed in Ollama
234
- async function checkOllamaModel() {
12
+ // Skip in CI
13
+ if (process.env.CI) {
14
+ console.log('Skipping post-install in CI environment');
15
+ return;
16
+ }
17
+
18
+ try {
19
+ const { main: runOnboarding } = require('./onboarding');
20
+ await runOnboarding();
21
+ } catch (err) {
22
+ // Fallback: if onboarding deps missing, do basic setup
23
+ console.log('Running basic setup (onboarding dependencies not available)...');
235
24
  try {
236
- const http = require('http');
237
- return new Promise((resolve) => {
238
- const req = http.get('http://localhost:11434/api/tags', { timeout: 2000 }, (res) => {
239
- let data = '';
240
- res.on('data', chunk => data += chunk);
241
- res.on('end', () => {
242
- try {
243
- const json = JSON.parse(data);
244
- const models = json.models || [];
245
- const hasModel = models.some(m =>
246
- m.name && m.name.includes('nomic-embed-text')
247
- );
248
- resolve(hasModel);
249
- } catch (e) {
250
- resolve(false);
251
- }
252
- });
253
- });
254
- req.on('error', () => resolve(false));
255
- req.on('timeout', () => {
256
- req.destroy();
257
- resolve(false);
258
- });
259
- });
260
- } catch (e) {
261
- return false;
25
+ const { basicSetup } = require('./lib/installer');
26
+ await basicSetup(path.dirname(__dirname));
27
+ } catch (fallbackErr) {
28
+ console.log('Post-install: run "claude-memory-agent install" to complete setup.');
262
29
  }
30
+ }
263
31
  }
264
32
 
265
- // Run if not in CI/CD environment
266
- if (!process.env.CI && !process.env.npm_config_ignore_scripts) {
267
- main().catch(console.error);
268
- } else {
269
- console.log('Skipping post-install in CI environment');
270
- }
33
+ main().catch(() => {
34
+ console.log('Post-install: run "claude-memory-agent install" to complete setup.');
35
+ });
package/config.py CHANGED
@@ -10,10 +10,13 @@ Usage:
10
10
  print(config.MEMORY_AGENT_URL)
11
11
  """
12
12
  import os
13
+ import logging
13
14
  from pathlib import Path
14
15
  from typing import Optional
15
16
  from dotenv import load_dotenv
16
17
 
18
+ logger = logging.getLogger(__name__)
19
+
17
20
  # Load .env from agent directory
18
21
  AGENT_DIR = Path(__file__).parent.resolve()
19
22
  load_dotenv(AGENT_DIR / ".env")
@@ -38,17 +41,18 @@ class Config:
38
41
  self.PID_FILE = AGENT_DIR / "memory-agent.pid"
39
42
 
40
43
  # Server configuration
41
- self.HOST = os.getenv("HOST", "0.0.0.0")
44
+ self.HOST = os.getenv("HOST", "127.0.0.1")
42
45
  self.PORT = int(os.getenv("PORT", "8102"))
43
46
  self.MEMORY_AGENT_URL = os.getenv(
44
47
  "MEMORY_AGENT_URL",
45
48
  f"http://localhost:{self.PORT}"
46
49
  )
47
50
 
48
- # Ollama / Embeddings
51
+ # Embeddings
52
+ self.EMBEDDING_PROVIDER = os.getenv("EMBEDDING_PROVIDER", "sentence-transformers")
49
53
  self.OLLAMA_HOST = os.getenv("OLLAMA_HOST", "http://localhost:11434")
50
- self.EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "nomic-embed-text")
51
- self.EMBEDDING_DIM = int(os.getenv("EMBEDDING_DIM", "768"))
54
+ self.EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "Alibaba-NLP/gte-large-en-v1.5")
55
+ self.EMBEDDING_DIM = int(os.getenv("EMBEDDING_DIM", "1024"))
52
56
  self.OLLAMA_HEALTH_TIMEOUT = float(os.getenv("OLLAMA_HEALTH_TIMEOUT", "2.0"))
53
57
  self.OLLAMA_HEALTH_CACHE_TTL = float(os.getenv("OLLAMA_HEALTH_CACHE_TTL", "30.0"))
54
58
 
@@ -68,12 +72,106 @@ class Config:
68
72
  self.AUTH_RATE_LIMIT = int(os.getenv("AUTH_RATE_LIMIT", "100"))
69
73
  self.AUTH_RATE_WINDOW = int(os.getenv("AUTH_RATE_WINDOW", "60"))
70
74
 
75
+ # Response size limits
76
+ self.MAX_RESPONSE_CHARS = int(os.getenv("MAX_RESPONSE_CHARS", "80000"))
77
+ self.CONTENT_TRUNCATE_LENGTH = int(os.getenv("CONTENT_TRUNCATE_LENGTH", "300"))
78
+ self.MIN_RESULT_COUNT = int(os.getenv("MIN_RESULT_COUNT", "3"))
79
+
71
80
  # Logging
72
81
  self.LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
73
82
 
83
+ # Memory decay
84
+ self.DECAY_ARCHIVE_THRESHOLD = float(os.getenv("DECAY_ARCHIVE_THRESHOLD", "0.1"))
85
+ self.DECAY_CHECK_INTERVAL_HOURS = int(os.getenv("DECAY_CHECK_INTERVAL_HOURS", "24"))
86
+
74
87
  # Hook timeouts
75
88
  self.API_TIMEOUT = int(os.getenv("API_TIMEOUT", "30"))
76
89
 
90
+ # CLaRa-inspired memory tiers
91
+ self.TIER_HOT_MAX_AGE_DAYS = int(os.getenv("TIER_HOT_MAX_AGE_DAYS", "14"))
92
+ self.TIER_HOT_MIN_IMPORTANCE = int(os.getenv("TIER_HOT_MIN_IMPORTANCE", "7"))
93
+ self.TIER_WARM_MAX_AGE_DAYS = int(os.getenv("TIER_WARM_MAX_AGE_DAYS", "90"))
94
+
95
+ # Memory consolidation
96
+ self.CONSOLIDATION_THRESHOLD = float(os.getenv("CONSOLIDATION_THRESHOLD", "0.85"))
97
+ self.CONSOLIDATION_MIN_GROUP = int(os.getenv("CONSOLIDATION_MIN_GROUP", "3"))
98
+ self.CONSOLIDATION_MAX_GROUP = int(os.getenv("CONSOLIDATION_MAX_GROUP", "20"))
99
+ self.CONSOLIDATION_MAX_PER_RUN = int(os.getenv("CONSOLIDATION_MAX_PER_RUN", "5"))
100
+ self.CONSOLIDATION_INTERVAL_HOURS = int(os.getenv("CONSOLIDATION_INTERVAL_HOURS", "12"))
101
+
102
+ # Embedding pipeline
103
+ self.EMBEDDING_CACHE_SIZE = int(os.getenv("EMBEDDING_CACHE_SIZE", "500"))
104
+ self.EMBEDDING_BATCH_SIZE = int(os.getenv("EMBEDDING_BATCH_SIZE", "10"))
105
+ self.EMBEDDING_PRECOMPUTE_INTERVAL = int(os.getenv("EMBEDDING_PRECOMPUTE_INTERVAL", "60"))
106
+
107
+ # Adaptive search ranking
108
+ self.DEFAULT_SEARCH_TEMPERATURE = float(os.getenv("DEFAULT_SEARCH_TEMPERATURE", "1.0"))
109
+
110
+ # Validate configuration
111
+ self._validate()
112
+
113
+ def _validate(self):
114
+ """Validate configuration values and warn on invalid settings."""
115
+ warnings = []
116
+
117
+ # Critical: port must be valid
118
+ if not (1 <= self.PORT <= 65535):
119
+ raise ValueError(f"PORT must be 1-65535, got {self.PORT}")
120
+
121
+ # Critical: pool size must be positive
122
+ if self.DB_POOL_SIZE < 1:
123
+ raise ValueError(f"DB_POOL_SIZE must be >= 1, got {self.DB_POOL_SIZE}")
124
+
125
+ # Critical: embedding provider must be valid
126
+ valid_providers = ("sentence-transformers", "ollama")
127
+ if self.EMBEDDING_PROVIDER not in valid_providers:
128
+ raise ValueError(f"EMBEDDING_PROVIDER must be one of {valid_providers}, got '{self.EMBEDDING_PROVIDER}'")
129
+
130
+ # Warnings for non-critical misconfigurations
131
+ if self.DB_TIMEOUT < 1.0:
132
+ warnings.append(f"DB_TIMEOUT={self.DB_TIMEOUT}s is very low, may cause spurious timeouts")
133
+
134
+ if self.DB_MAX_RETRIES < 0:
135
+ warnings.append(f"DB_MAX_RETRIES={self.DB_MAX_RETRIES} is negative, setting to 0")
136
+ self.DB_MAX_RETRIES = 0
137
+
138
+ if self.EMBEDDING_DIM not in (384, 768, 1024):
139
+ warnings.append(f"EMBEDDING_DIM={self.EMBEDDING_DIM} is unusual (expected 384/768/1024)")
140
+
141
+ if not (0.0 <= self.CONSOLIDATION_THRESHOLD <= 1.0):
142
+ warnings.append(f"CONSOLIDATION_THRESHOLD={self.CONSOLIDATION_THRESHOLD} out of range [0,1], clamping")
143
+ self.CONSOLIDATION_THRESHOLD = max(0.0, min(1.0, self.CONSOLIDATION_THRESHOLD))
144
+
145
+ if not (0.0 <= self.DECAY_ARCHIVE_THRESHOLD <= 1.0):
146
+ warnings.append(f"DECAY_ARCHIVE_THRESHOLD={self.DECAY_ARCHIVE_THRESHOLD} out of range [0,1], clamping")
147
+ self.DECAY_ARCHIVE_THRESHOLD = max(0.0, min(1.0, self.DECAY_ARCHIVE_THRESHOLD))
148
+
149
+ if not (0.0 <= self.DEFAULT_SEARCH_TEMPERATURE <= 2.0):
150
+ warnings.append(f"DEFAULT_SEARCH_TEMPERATURE={self.DEFAULT_SEARCH_TEMPERATURE} out of range [0,2], clamping")
151
+ self.DEFAULT_SEARCH_TEMPERATURE = max(0.0, min(2.0, self.DEFAULT_SEARCH_TEMPERATURE))
152
+
153
+ if self.MAX_RESPONSE_CHARS < 1000:
154
+ warnings.append(f"MAX_RESPONSE_CHARS={self.MAX_RESPONSE_CHARS} is very low, responses may be cut off")
155
+
156
+ if self.EMBEDDING_CACHE_SIZE < 0:
157
+ warnings.append(f"EMBEDDING_CACHE_SIZE={self.EMBEDDING_CACHE_SIZE} is negative, setting to 0")
158
+ self.EMBEDDING_CACHE_SIZE = 0
159
+
160
+ valid_log_levels = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}
161
+ if self.LOG_LEVEL.upper() not in valid_log_levels:
162
+ warnings.append(f"LOG_LEVEL='{self.LOG_LEVEL}' is invalid, using INFO")
163
+ self.LOG_LEVEL = "INFO"
164
+
165
+ if self.TIER_HOT_MAX_AGE_DAYS >= self.TIER_WARM_MAX_AGE_DAYS:
166
+ warnings.append(
167
+ f"TIER_HOT_MAX_AGE_DAYS ({self.TIER_HOT_MAX_AGE_DAYS}) >= "
168
+ f"TIER_WARM_MAX_AGE_DAYS ({self.TIER_WARM_MAX_AGE_DAYS}), "
169
+ f"hot tier would overlap warm tier"
170
+ )
171
+
172
+ for w in warnings:
173
+ logger.warning(f"Config: {w}")
174
+
77
175
  def get_health_url(self) -> str:
78
176
  """Get the health check URL."""
79
177
  return f"{self.MEMORY_AGENT_URL}/health"
@@ -100,5 +198,6 @@ PORT = config.PORT
100
198
  HOST = config.HOST
101
199
  MEMORY_AGENT_URL = config.MEMORY_AGENT_URL
102
200
  OLLAMA_HOST = config.OLLAMA_HOST
201
+ EMBEDDING_PROVIDER = config.EMBEDDING_PROVIDER
103
202
  EMBEDDING_MODEL = config.EMBEDDING_MODEL
104
203
  DATABASE_PATH = config.DATABASE_PATH