From c069dd276e419caa5b662390cdf3c3192f278af5 Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Fri, 7 Nov 2025 16:51:11 +0000 Subject: [PATCH 1/3] feat: add model validator to strip quotes from string fields in LLMConfig --- cognee/infrastructure/llm/config.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/cognee/infrastructure/llm/config.py b/cognee/infrastructure/llm/config.py index 8fd196eaf..dab2fa6c0 100644 --- a/cognee/infrastructure/llm/config.py +++ b/cognee/infrastructure/llm/config.py @@ -73,6 +73,26 @@ class LLMConfig(BaseSettings): model_config = SettingsConfigDict(env_file=".env", extra="allow") + @model_validator(mode="after") + def strip_quotes_from_strings(self) -> "LLMConfig": + """ + Strip surrounding quotes from all string fields in the model. + + This handles cases where Docker's --env-file or shell quoting + accidentally includes quotes in the value (e.g., LLM_API_KEY="value"). + + Returns: + LLMConfig: The instance with quotes stripped from all string fields. + """ + for field_name, _ in self.__class__.model_fields.items(): + value = getattr(self, field_name, None) + if isinstance(value, str) and len(value) >= 2: + if (value.startswith('"') and value.endswith('"')) or ( + value.startswith("'") and value.endswith("'") + ): + setattr(self, field_name, value[1:-1]) + return self + def model_post_init(self, __context) -> None: """Initialize the BAML registry after the model is created.""" # Check if BAML is selected as structured output framework but not available From 05c984f98f490e3a8c2ec2a2b643293f724eaf0f Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Fri, 7 Nov 2025 16:55:49 +0000 Subject: [PATCH 2/3] feat: enhance LLMConfig to selectively strip quotes from specific string fields --- cognee/infrastructure/llm/config.py | 35 ++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/cognee/infrastructure/llm/config.py b/cognee/infrastructure/llm/config.py index dab2fa6c0..b72c557c9 100644 --- a/cognee/infrastructure/llm/config.py +++ b/cognee/infrastructure/llm/config.py @@ -76,21 +76,36 @@ class LLMConfig(BaseSettings): @model_validator(mode="after") def strip_quotes_from_strings(self) -> "LLMConfig": """ - Strip surrounding quotes from all string fields in the model. + Strip surrounding quotes from specific string fields that often come from + environment variables with extra quotes (e.g., via Docker's --env-file). - This handles cases where Docker's --env-file or shell quoting - accidentally includes quotes in the value (e.g., LLM_API_KEY="value"). - - Returns: - LLMConfig: The instance with quotes stripped from all string fields. + Only applies to known config keys where quotes are invalid or cause issues. """ - for field_name, _ in self.__class__.model_fields.items(): + string_fields_to_strip = [ + "llm_api_key", + "llm_endpoint", + "llm_api_version", + "baml_llm_api_key", + "baml_llm_endpoint", + "baml_llm_api_version", + "fallback_api_key", + "fallback_endpoint", + "fallback_model", + "llm_provider", + "llm_model", + "baml_llm_provider", + "baml_llm_model", + ] + + cls = self.__class__ + for field_name in string_fields_to_strip: + if field_name not in cls.model_fields: + continue value = getattr(self, field_name, None) if isinstance(value, str) and len(value) >= 2: - if (value.startswith('"') and value.endswith('"')) or ( - value.startswith("'") and value.endswith("'") - ): + if value[0] == value[-1] and value[0] in ("'", '"'): setattr(self, field_name, value[1:-1]) + return self def model_post_init(self, __context) -> None: From 0d2e84f58e2ed79d3534add4adf9dafd70d571aa Mon Sep 17 00:00:00 2001 From: Boris Arzentar Date: Wed, 3 Dec 2025 10:59:17 +0100 Subject: [PATCH 3/3] test: test_strip_quotes_from_strings --- .../infrastructure/llm/test_llm_config.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 cognee/tests/unit/infrastructure/llm/test_llm_config.py diff --git a/cognee/tests/unit/infrastructure/llm/test_llm_config.py b/cognee/tests/unit/infrastructure/llm/test_llm_config.py new file mode 100644 index 000000000..0c024db2c --- /dev/null +++ b/cognee/tests/unit/infrastructure/llm/test_llm_config.py @@ -0,0 +1,46 @@ +import pytest + +from cognee.infrastructure.llm.config import LLMConfig + + +def test_strip_quotes_from_strings(): + """ + Test if the LLMConfig.strip_quotes_from_strings model validator behaves as expected. + """ + config = LLMConfig( + # Strings with surrounding double quotes ("value" → value) + llm_api_key='"double_value"', + # Strings with surrounding single quotes ('value' → value) + llm_endpoint="'single_value'", + # Strings without quotes (value → value) + llm_api_version="no_quotes_value", + # Empty quoted strings ("" → empty string) + fallback_model='""', + # None values (should remain None) + baml_llm_api_key=None, + # Mixed quotes ("value' → unchanged) + fallback_endpoint="\"mixed_quote'", + # Strings with internal quotes ("internal\"quotes" → internal"quotes") + baml_llm_model='"internal"quotes"', + ) + + # Strings with surrounding double quotes ("value" → value) + assert config.llm_api_key == "double_value" + + # Strings with surrounding single quotes ('value' → value) + assert config.llm_endpoint == "single_value" + + # Strings without quotes (value → value) + assert config.llm_api_version == "no_quotes_value" + + # Empty quoted strings ("" → empty string) + assert config.fallback_model == "" + + # None values (should remain None) + assert config.baml_llm_api_key is None + + # Mixed quotes ("value' → unchanged) + assert config.fallback_endpoint == "\"mixed_quote'" + + # Strings with internal quotes ("internal\"quotes" → internal"quotes") + assert config.baml_llm_model == 'internal"quotes'