99from typing import Any , Dict , Optional , Union
1010
1111from advanced_omi_backend .model_registry import get_models_registry
12+ from advanced_omi_backend .utils .config_utils import resolve_value
1213
1314memory_logger = logging .getLogger ("memory_service" )
1415
@@ -24,25 +25,32 @@ def _is_langfuse_enabled() -> bool:
2425
2526class LLMProvider (Enum ):
2627 """Supported LLM providers."""
28+
2729 OPENAI = "openai"
2830 OLLAMA = "ollama"
2931 CUSTOM = "custom"
3032
33+
3134class VectorStoreProvider (Enum ):
3235 """Supported vector store providers."""
36+
3337 QDRANT = "qdrant"
3438 WEAVIATE = "weaviate"
3539 CUSTOM = "custom"
3640
41+
3742class MemoryProvider (Enum ):
3843 """Supported memory service providers."""
39- CHRONICLE = "chronicle" # Default sophisticated implementation
44+
45+ CHRONICLE = "chronicle" # Default sophisticated implementation
4046 OPENMEMORY_MCP = "openmemory_mcp" # OpenMemory MCP backend
41- MYCELIA = "mycelia" # Mycelia memory backend
47+ MYCELIA = "mycelia" # Mycelia memory backend
48+
4249
4350@dataclass
4451class MemoryConfig :
4552 """Configuration for memory service."""
53+
4654 memory_provider : MemoryProvider = MemoryProvider .CHRONICLE
4755 llm_provider : LLMProvider = LLMProvider .OPENAI
4856 vector_store_provider : VectorStoreProvider = VectorStoreProvider .QDRANT
@@ -55,21 +63,6 @@ class MemoryConfig:
5563 extraction_enabled : bool = True
5664 timeout_seconds : int = 1200
5765
58- # Helper to resolve ${VAR:-default}
59- def resolve_value (value : Union [str , int , float ]) -> Union [str , int , float ]:
60- """Resolve environment variable references in configuration values.
61-
62- Supports ${VAR} and ${VAR:-default} syntax. Returns the original value
63- if it's not a string or doesn't match the pattern.
64- """
65- if isinstance (value , str ) and value .startswith ("${" ) and value .endswith ("}" ):
66- content = value [2 :- 1 ]
67- if ":-" in content :
68- var_name , default_val = content .split (":-" , 1 )
69- return os .getenv (var_name , default_val )
70- else :
71- return os .getenv (content , "" )
72- return value
7366
7467def load_config_yml () -> Dict [str , Any ]:
7568 """Load config.yml from standard locations."""
@@ -78,37 +71,35 @@ def load_config_yml() -> Dict[str, Any]:
7871 # Path inside Docker: /app/config.yml (if mounted) or ../../../config.yml relative to src
7972 paths = [
8073 Path ("/app/config.yml" ),
81- current_dir .parent .parent .parent .parent .parent / "config.yml" , # Relative to src/
74+ current_dir .parent .parent .parent .parent .parent / "config.yml" , # Relative to src/
8275 Path ("./config.yml" ),
8376 ]
84-
77+
8578 for path in paths :
8679 if path .exists ():
87- with open (path , 'r' ) as f :
80+ with open (path , "r" ) as f :
8881 return yaml .safe_load (f ) or {}
89-
82+
9083 raise FileNotFoundError (f"config.yml not found in any of: { [str (p ) for p in paths ]} " )
9184
85+
9286def create_openmemory_config (
9387 server_url : str = "http://localhost:8765" ,
9488 client_name : str = "chronicle" ,
9589 user_id : str = "default" ,
96- timeout : int = 30
90+ timeout : int = 30 ,
9791) -> Dict [str , Any ]:
9892 """Create OpenMemory MCP configuration."""
9993 return {
10094 "server_url" : server_url ,
10195 "client_name" : client_name ,
10296 "user_id" : user_id ,
103- "timeout" : timeout
97+ "timeout" : timeout ,
10498 }
10599
106100
107101def create_mycelia_config (
108- api_url : str = "http://localhost:8080" ,
109- api_key : str = None ,
110- timeout : int = 30 ,
111- ** kwargs
102+ api_url : str = "http://localhost:8080" , api_key : str = None , timeout : int = 30 , ** kwargs
112103) -> Dict [str , Any ]:
113104 """Create Mycelia configuration."""
114105 config = {
@@ -161,7 +152,7 @@ def build_memory_config_from_env() -> MemoryConfig:
161152 try :
162153 # Determine memory provider from registry
163154 reg = get_models_registry ()
164- mem_settings = ( reg .memory if reg else {})
155+ mem_settings = reg .memory if reg else {}
165156 memory_provider = (mem_settings .get ("provider" ) or "chronicle" ).lower ()
166157
167158 # Map legacy provider names to current names
@@ -173,18 +164,20 @@ def build_memory_config_from_env() -> MemoryConfig:
173164 raise ValueError (f"Unsupported memory provider: { memory_provider } " )
174165
175166 memory_provider_enum = MemoryProvider (memory_provider )
176-
167+
177168 # For OpenMemory MCP, configuration is much simpler
178169 if memory_provider_enum == MemoryProvider .OPENMEMORY_MCP :
179- mcp = ( mem_settings .get ("openmemory_mcp" ) or {})
170+ mcp = mem_settings .get ("openmemory_mcp" ) or {}
180171 openmemory_config = create_openmemory_config (
181172 server_url = mcp .get ("server_url" , "http://localhost:8765" ),
182173 client_name = mcp .get ("client_name" , "chronicle" ),
183174 user_id = mcp .get ("user_id" , "default" ),
184175 timeout = int (mcp .get ("timeout" , 30 )),
185176 )
186177
187- memory_logger .info (f"🔧 Memory config: Provider=OpenMemory MCP, URL={ openmemory_config ['server_url' ]} " )
178+ memory_logger .info (
179+ f"🔧 Memory config: Provider=OpenMemory MCP, URL={ openmemory_config ['server_url' ]} "
180+ )
188181
189182 return MemoryConfig (
190183 memory_provider = memory_provider_enum ,
@@ -195,7 +188,7 @@ def build_memory_config_from_env() -> MemoryConfig:
195188 # For Mycelia provider, build mycelia_config + llm_config (for temporal extraction)
196189 if memory_provider_enum == MemoryProvider .MYCELIA :
197190 # Registry-driven Mycelia configuration
198- mys = ( mem_settings .get ("mycelia" ) or {})
191+ mys = mem_settings .get ("mycelia" ) or {}
199192 api_url = mys .get ("api_url" , "http://localhost:5173" )
200193 timeout = int (mys .get ("timeout" , 30 ))
201194 mycelia_config = create_mycelia_config (api_url = api_url , timeout = timeout )
@@ -210,21 +203,27 @@ def build_memory_config_from_env() -> MemoryConfig:
210203 model = llm_def .model_name ,
211204 base_url = llm_def .model_url ,
212205 )
213- memory_logger .info (f"🔧 Mycelia temporal extraction (registry): LLM={ llm_def .model_name } " )
206+ memory_logger .info (
207+ f"🔧 Mycelia temporal extraction (registry): LLM={ llm_def .model_name } "
208+ )
214209 else :
215- memory_logger .warning ("Registry not available for Mycelia temporal extraction; disabled" )
210+ memory_logger .warning (
211+ "Registry not available for Mycelia temporal extraction; disabled"
212+ )
216213
217- memory_logger .info (f"🔧 Memory config: Provider=Mycelia, URL={ mycelia_config ['api_url' ]} " )
214+ memory_logger .info (
215+ f"🔧 Memory config: Provider=Mycelia, URL={ mycelia_config ['api_url' ]} "
216+ )
218217
219218 return MemoryConfig (
220219 memory_provider = memory_provider_enum ,
221220 mycelia_config = mycelia_config ,
222221 llm_config = llm_config ,
223222 timeout_seconds = int (mem_settings .get ("timeout_seconds" , timeout )),
224223 )
225-
224+
226225 # For Chronicle provider, use registry-driven configuration
227-
226+
228227 # Registry-driven configuration only (no env-based branching)
229228 llm_config = None
230229 llm_provider_enum = LLMProvider .OPENAI # OpenAI-compatible API family
@@ -236,7 +235,7 @@ def build_memory_config_from_env() -> MemoryConfig:
236235 if not llm_def :
237236 raise ValueError ("No default LLM defined in config.yml" )
238237 model = llm_def .model_name
239- embedding_model = ( embed_def .model_name if embed_def else "text-embedding-3-small" )
238+ embedding_model = embed_def .model_name if embed_def else "text-embedding-3-small"
240239 base_url = llm_def .model_url
241240 memory_logger .info (
242241 f"🔧 Memory config (registry): LLM={ model } , Embedding={ embedding_model } , Base URL={ base_url } "
@@ -267,9 +266,9 @@ def build_memory_config_from_env() -> MemoryConfig:
267266 embedding_dims = embedding_dims ,
268267 )
269268 vector_store_provider_enum = VectorStoreProvider .QDRANT
270-
269+
271270 # Get memory extraction settings from registry
272- extraction_cfg = ( mem_settings .get ("extraction" ) or {})
271+ extraction_cfg = mem_settings .get ("extraction" ) or {}
273272 extraction_enabled = bool (extraction_cfg .get ("enabled" , True ))
274273 extraction_prompt = extraction_cfg .get ("prompt" ) if extraction_enabled else None
275274
@@ -291,7 +290,7 @@ def build_memory_config_from_env() -> MemoryConfig:
291290 extraction_enabled = extraction_enabled ,
292291 timeout_seconds = timeout_seconds ,
293292 )
294-
293+
295294 except ImportError :
296295 memory_logger .warning ("Config loader not available, using environment variables only" )
297296 raise
@@ -302,7 +301,7 @@ def get_embedding_dims(llm_config: Dict[str, Any]) -> int:
302301 Query the embedding endpoint and return the embedding vector length.
303302 Works for OpenAI and OpenAI-compatible endpoints (e.g., Ollama).
304303 """
305- embedding_model = llm_config .get (' embedding_model' )
304+ embedding_model = llm_config .get (" embedding_model" )
306305 try :
307306 reg = get_models_registry ()
308307 if reg :
0 commit comments