From 2db2b4a3d4821918974eef316bef382e2bf16dda Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Tue, 20 Jan 2026 20:47:43 +0200 Subject: [PATCH 01/14] add new models enums --- statgpt/common/config/llm_models.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/statgpt/common/config/llm_models.py b/statgpt/common/config/llm_models.py index 56769f82..4972cd44 100644 --- a/statgpt/common/config/llm_models.py +++ b/statgpt/common/config/llm_models.py @@ -30,6 +30,10 @@ class LLMModelsEnum(StrEnum): GPT_4_1_MINI_2025_04_14 = "gpt-4.1-mini-2025-04-14" GPT_4_1_NANO_2025_04_14 = "gpt-4.1-nano-2025-04-14" + # GPT-5 models + GPT_5_1_2025_11_13 = "gpt-5.1-2025-11-13" + GPT_5_2_2025_12_11 = "gpt-5.2-2025-12-11" + @property def deployment_id(self) -> str: return os.getenv(f"LLM_MODELS_{self.name}", self.value) @@ -42,3 +46,11 @@ def is_gpt_41_family(self) -> bool: LLMModelsEnum.GPT_4_1_MINI_2025_04_14, LLMModelsEnum.GPT_4_1_NANO_2025_04_14, } + + @property + def is_gpt_5_family(self) -> bool: + """Check if the model belongs to the GPT-5 family.""" + return self in { + LLMModelsEnum.GPT_5_1_2025_11_13, + LLMModelsEnum.GPT_5_2_2025_12_11, + } From f8463f230fab7eb425b3161d884605468c049861 Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Mon, 2 Feb 2026 19:27:08 +0200 Subject: [PATCH 02/14] add gpt 5 family support --- statgpt/common/config/__init__.py | 2 +- statgpt/common/config/llm_models.py | 22 ++++++++++++++++++++++ statgpt/common/schemas/model_config.py | 26 ++++++++++++++++++++++---- statgpt/common/settings/langchain.py | 25 +++++++++++++++++++------ statgpt/common/utils/models.py | 18 +++++++++++++++--- 5 files changed, 79 insertions(+), 14 deletions(-) diff --git a/statgpt/common/config/__init__.py b/statgpt/common/config/__init__.py index d39b9f99..06a5c5a2 100644 --- a/statgpt/common/config/__init__.py +++ b/statgpt/common/config/__init__.py @@ -1,4 +1,4 @@ -from .llm_models import EmbeddingModelsEnum, LLMModelsEnum +from .llm_models import EmbeddingModelsEnum, LLMModelsEnum, ReasoningEffortEnum, VerbosityEnum from .logging import LoggingConfig, logger, multiline_logger from .versions import Versions diff --git a/statgpt/common/config/llm_models.py b/statgpt/common/config/llm_models.py index 4972cd44..5c2523bf 100644 --- a/statgpt/common/config/llm_models.py +++ b/statgpt/common/config/llm_models.py @@ -6,6 +6,26 @@ class EmbeddingModelsEnum(StrEnum): TEXT_EMBEDDING_3_LARGE = "text-embedding-3-large" +class ReasoningEffortEnum(StrEnum): + """Reasoning effort levels for GPT-5 models.""" + + NONE = "none" # No reasoning mode - standard inference + MINIMAL = "minimal" + LOW = "low" + MEDIUM = "medium" + HIGH = "high" + XHIGH = "xhigh" + + +# NOTE: currently not used and not supported by LangChain, kept for future compatibility +class VerbosityEnum(StrEnum): + """Output verbosity levels for GPT-5 models.""" + + LOW = "low" + MEDIUM = "medium" + HIGH = "high" + + class LLMModelsEnum(StrEnum): # Gemini models GEMINI_2_0_FLASH_LITE_001 = "gemini-2.0-flash-lite-001" @@ -31,6 +51,7 @@ class LLMModelsEnum(StrEnum): GPT_4_1_NANO_2025_04_14 = "gpt-4.1-nano-2025-04-14" # GPT-5 models + GPT_5_MINI_2025_08_07 = "gpt-5-mini-2025-08-07" GPT_5_1_2025_11_13 = "gpt-5.1-2025-11-13" GPT_5_2_2025_12_11 = "gpt-5.2-2025-12-11" @@ -51,6 +72,7 @@ def is_gpt_41_family(self) -> bool: def is_gpt_5_family(self) -> bool: """Check if the model belongs to the GPT-5 family.""" return self in { + LLMModelsEnum.GPT_5_MINI_2025_08_07, LLMModelsEnum.GPT_5_1_2025_11_13, LLMModelsEnum.GPT_5_2_2025_12_11, } diff --git a/statgpt/common/schemas/model_config.py b/statgpt/common/schemas/model_config.py index 20c14078..ad8125db 100644 --- a/statgpt/common/schemas/model_config.py +++ b/statgpt/common/schemas/model_config.py @@ -1,6 +1,11 @@ from pydantic import Field -from statgpt.common.config import EmbeddingModelsEnum, LLMModelsEnum +from statgpt.common.config import ( + EmbeddingModelsEnum, + LLMModelsEnum, + ReasoningEffortEnum, + VerbosityEnum, +) from statgpt.common.settings.langchain import langchain_settings from .base import BaseYamlModel @@ -10,7 +15,8 @@ class BaseModelConfig(BaseYamlModel): """Base config for LLM and embeddings models configs.""" api_version: str = Field( - default=langchain_settings.default_api_version, description="API version for the model" + default=langchain_settings.default_api_version, + description="API version for the model", ) @@ -34,12 +40,24 @@ class LLMModelConfig(BaseModelConfig): default=langchain_settings.default_temperature, description=( "The temperature of the model. 0.0 means deterministic output, higher values mean more" - " randomness." + " randomness. Note: Not supported by GPT-5 models." ), ) seed: int | None = Field( default=langchain_settings.default_seed, description=( - "The seed of the model. If set, the model will produce the same output for the same input." + "The seed of the model. If set, the model will produce the same output for the same input. " + "Note: Not supported by GPT-5 models." ), ) + reasoning_effort: ReasoningEffortEnum | None = Field( + default=langchain_settings.default_reasoning_effort, + description=( + "Reasoning effort level for GPT-5 models. Ignored for non-reasoning models. " + "Supports: none, minimal, low, medium, high, xhigh." + ), + ) + verbosity: VerbosityEnum | None = Field( + default=langchain_settings.default_verbosity, + description=("Output verbosity for GPT-5 models (low/medium/high). "), + ) diff --git a/statgpt/common/settings/langchain.py b/statgpt/common/settings/langchain.py index 52f2f8fe..491f1e6d 100644 --- a/statgpt/common/settings/langchain.py +++ b/statgpt/common/settings/langchain.py @@ -1,10 +1,13 @@ -from typing import Optional - -from langchain import globals as lc_globals +from langchain_core import globals as lc_globals from pydantic import Field from pydantic_settings import BaseSettings, SettingsConfigDict -from statgpt.common.config.llm_models import EmbeddingModelsEnum, LLMModelsEnum +from statgpt.common.config.llm_models import ( + EmbeddingModelsEnum, + LLMModelsEnum, + ReasoningEffortEnum, + VerbosityEnum, +) class LangChainSettings(BaseSettings): @@ -21,7 +24,7 @@ class LangChainSettings(BaseSettings): ) default_model: LLMModelsEnum = Field( - default=LLMModelsEnum.GPT_4_1_2025_04_14, + default=LLMModelsEnum.GPT_5_2_2025_12_11, description="Default LLM model for LangChain", ) @@ -35,11 +38,21 @@ class LangChainSettings(BaseSettings): description="Default API version for Azure OpenAI", ) - default_seed: Optional[int] = Field( + default_seed: int | None = Field( default=None, description="Default seed for reproducible outputs", ) + default_reasoning_effort: ReasoningEffortEnum | None = Field( + default=ReasoningEffortEnum.NONE, + description="Default reasoning effort for GPT-5 models (none/minimal/low/medium/high/xhigh)", + ) + + default_verbosity: VerbosityEnum | None = Field( + default=VerbosityEnum.LOW, + description="Default verbosity for GPT-5 models (low/medium/high). None means use model default.", + ) + # Debugging settings verbose: bool = Field(default=False, description="Enable verbose mode for LangChain") diff --git a/statgpt/common/utils/models.py b/statgpt/common/utils/models.py index fc113b4c..e4bbd62c 100644 --- a/statgpt/common/utils/models.py +++ b/statgpt/common/utils/models.py @@ -4,6 +4,7 @@ from langchain_openai import AzureChatOpenAI, AzureOpenAIEmbeddings from pydantic import SecretStr +from statgpt.common.config import ReasoningEffortEnum from statgpt.common.config.logging import multiline_logger as logger from statgpt.common.schemas import EmbeddingsModelConfig, LLMModelConfig from statgpt.common.settings.dial import dial_settings @@ -26,13 +27,24 @@ def get_chat_model( azure_endpoint=azure_endpoint, api_version=model_config.api_version, azure_deployment=model_config.deployment.deployment_id, - temperature=model_config.temperature, - seed=model_config.seed, max_retries=10, api_key=api_key, # since we use SecretStr, it won't be logged timeout=timeout, # timeouts are crucial! ) - params.update(kwargs) # update default params + + if model_config.deployment.is_gpt_5_family: + # GPT-5: use reasoning_effort, temperature only allowed with reasoning_effort=none + if model_config.reasoning_effort is not None: + params["reasoning_effort"] = model_config.reasoning_effort + if model_config.reasoning_effort == ReasoningEffortEnum.NONE: + params["temperature"] = 0 + params.update({k: v for k, v in kwargs.items() if k not in ("temperature", "seed")}) + else: + # Legacy models: use temperature and seed + params["temperature"] = model_config.temperature + if model_config.seed is not None: + params["seed"] = model_config.seed + params.update(kwargs) if model_config.deployment.is_gpt_41_family: callback = BrokenResponseInterceptor(regex_pattern=r'\s{5,}') From 7dd7e5e6eb5ce503910ffef3a5a66576d96fc2e5 Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Fri, 13 Feb 2026 14:11:43 +0200 Subject: [PATCH 03/14] change default model back to 4.1 --- statgpt/common/settings/langchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/statgpt/common/settings/langchain.py b/statgpt/common/settings/langchain.py index 491f1e6d..bd355979 100644 --- a/statgpt/common/settings/langchain.py +++ b/statgpt/common/settings/langchain.py @@ -24,7 +24,7 @@ class LangChainSettings(BaseSettings): ) default_model: LLMModelsEnum = Field( - default=LLMModelsEnum.GPT_5_2_2025_12_11, + default=LLMModelsEnum.GPT_4_1_2025_04_14, description="Default LLM model for LangChain", ) From 486fa87c734ba34d5dca13ef8478665cb4cbc00b Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Mon, 16 Feb 2026 15:52:08 +0200 Subject: [PATCH 04/14] refactor --- statgpt/common/schemas/model_config.py | 18 ++++++++++++++++-- statgpt/common/utils/models.py | 19 +------------------ 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/statgpt/common/schemas/model_config.py b/statgpt/common/schemas/model_config.py index ad8125db..4e30a38b 100644 --- a/statgpt/common/schemas/model_config.py +++ b/statgpt/common/schemas/model_config.py @@ -1,4 +1,4 @@ -from pydantic import Field +from pydantic import Field, model_validator from statgpt.common.config import ( EmbeddingModelsEnum, @@ -36,7 +36,7 @@ class LLMModelConfig(BaseModelConfig): default=langchain_settings.default_model, description="The deployment of the model in DIAL", ) - temperature: float = Field( + temperature: float | None = Field( default=langchain_settings.default_temperature, description=( "The temperature of the model. 0.0 means deterministic output, higher values mean more" @@ -61,3 +61,17 @@ class LLMModelConfig(BaseModelConfig): default=langchain_settings.default_verbosity, description=("Output verbosity for GPT-5 models (low/medium/high). "), ) + + @model_validator(mode="after") + def _normalize_model_family_params(self) -> "LLMModelConfig": + if self.deployment.is_gpt_5_family: + self.seed = None + if self.reasoning_effort == ReasoningEffortEnum.NONE: + self.temperature = 0 + else: + # For reasoning levels only 1 is accepted + self.temperature = 1 + else: + self.reasoning_effort = None + self.verbosity = None + return self diff --git a/statgpt/common/utils/models.py b/statgpt/common/utils/models.py index e4bbd62c..89a8d0d1 100644 --- a/statgpt/common/utils/models.py +++ b/statgpt/common/utils/models.py @@ -4,7 +4,6 @@ from langchain_openai import AzureChatOpenAI, AzureOpenAIEmbeddings from pydantic import SecretStr -from statgpt.common.config import ReasoningEffortEnum from statgpt.common.config.logging import multiline_logger as logger from statgpt.common.schemas import EmbeddingsModelConfig, LLMModelConfig from statgpt.common.settings.dial import dial_settings @@ -16,9 +15,7 @@ def get_chat_model( model_config: LLMModelConfig, azure_endpoint: str = dial_settings.url, timeout: httpx.Timeout | None = None, - **kwargs, ) -> AzureChatOpenAI: - # default params if not isinstance(api_key, SecretStr): api_key = SecretStr(api_key) if not timeout: @@ -32,19 +29,7 @@ def get_chat_model( timeout=timeout, # timeouts are crucial! ) - if model_config.deployment.is_gpt_5_family: - # GPT-5: use reasoning_effort, temperature only allowed with reasoning_effort=none - if model_config.reasoning_effort is not None: - params["reasoning_effort"] = model_config.reasoning_effort - if model_config.reasoning_effort == ReasoningEffortEnum.NONE: - params["temperature"] = 0 - params.update({k: v for k, v in kwargs.items() if k not in ("temperature", "seed")}) - else: - # Legacy models: use temperature and seed - params["temperature"] = model_config.temperature - if model_config.seed is not None: - params["seed"] = model_config.seed - params.update(kwargs) + params.update(model_config.model_dump(exclude_none=True)) if model_config.deployment.is_gpt_41_family: callback = BrokenResponseInterceptor(regex_pattern=r'\s{5,}') @@ -61,7 +46,6 @@ def get_embeddings_model( api_key: str | SecretStr, model_config: EmbeddingsModelConfig, azure_endpoint: str = dial_settings.url, - **kwargs, ) -> AzureOpenAIEmbeddings: if not isinstance(api_key, SecretStr): api_key = SecretStr(api_key) @@ -72,7 +56,6 @@ def get_embeddings_model( max_retries=10, api_key=api_key, # since we use SecretStr, it won't be logged ) - params.update(kwargs) # update default params api_key_log = f'{api_key.get_secret_value()[:3]}*****{api_key.get_secret_value()[-2:]}' logger.info( f'creating langchain embeddings with the following params: {params}, Api key: {api_key_log}' From 26e9e656262e85fec92bc9f177bea7efd77dc0ac Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Mon, 16 Feb 2026 16:27:56 +0200 Subject: [PATCH 05/14] remove note --- statgpt/common/config/llm_models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/statgpt/common/config/llm_models.py b/statgpt/common/config/llm_models.py index 5c2523bf..9b2dcb83 100644 --- a/statgpt/common/config/llm_models.py +++ b/statgpt/common/config/llm_models.py @@ -17,7 +17,6 @@ class ReasoningEffortEnum(StrEnum): XHIGH = "xhigh" -# NOTE: currently not used and not supported by LangChain, kept for future compatibility class VerbosityEnum(StrEnum): """Output verbosity levels for GPT-5 models.""" From 5a21b2f474a2a4479cea08948ed8ce552cc0630f Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Mon, 16 Feb 2026 16:28:22 +0200 Subject: [PATCH 06/14] fix bug --- statgpt/common/utils/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/statgpt/common/utils/models.py b/statgpt/common/utils/models.py index 89a8d0d1..9b3bb93e 100644 --- a/statgpt/common/utils/models.py +++ b/statgpt/common/utils/models.py @@ -29,7 +29,7 @@ def get_chat_model( timeout=timeout, # timeouts are crucial! ) - params.update(model_config.model_dump(exclude_none=True)) + params.update(model_config.model_dump(mode="json", exclude_none=True, exclude={"deployment", "api_version"})) if model_config.deployment.is_gpt_41_family: callback = BrokenResponseInterceptor(regex_pattern=r'\s{5,}') From e89aa8d0ece95e8d5eb4cc41edd1b9a213c370f0 Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Tue, 17 Feb 2026 17:24:04 +0200 Subject: [PATCH 07/14] remove api_version from model_dump --- statgpt/common/utils/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/statgpt/common/utils/models.py b/statgpt/common/utils/models.py index 9b3bb93e..59a85d0e 100644 --- a/statgpt/common/utils/models.py +++ b/statgpt/common/utils/models.py @@ -29,7 +29,7 @@ def get_chat_model( timeout=timeout, # timeouts are crucial! ) - params.update(model_config.model_dump(mode="json", exclude_none=True, exclude={"deployment", "api_version"})) + params.update(model_config.model_dump(mode="json", exclude_none=True, exclude={"deployment"})) if model_config.deployment.is_gpt_41_family: callback = BrokenResponseInterceptor(regex_pattern=r'\s{5,}') From fbb69362f096ceff250c4a183dafb34a53583cb8 Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Tue, 17 Feb 2026 17:30:06 +0200 Subject: [PATCH 08/14] add doctsring to none reasoning --- statgpt/common/config/llm_models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/statgpt/common/config/llm_models.py b/statgpt/common/config/llm_models.py index 9b2dcb83..76638aa3 100644 --- a/statgpt/common/config/llm_models.py +++ b/statgpt/common/config/llm_models.py @@ -9,7 +9,8 @@ class EmbeddingModelsEnum(StrEnum): class ReasoningEffortEnum(StrEnum): """Reasoning effort levels for GPT-5 models.""" - NONE = "none" # No reasoning mode - standard inference + NONE = "none" + """No reasoning mode - standard inference.""" MINIMAL = "minimal" LOW = "low" MEDIUM = "medium" From 777a3742cba517952169bf8ccba3b69fddbd77d0 Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Tue, 17 Feb 2026 17:52:52 +0200 Subject: [PATCH 09/14] remove new params from langchain settings and upd default reasoning --- statgpt/common/schemas/model_config.py | 5 +++-- statgpt/common/settings/langchain.py | 17 +---------------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/statgpt/common/schemas/model_config.py b/statgpt/common/schemas/model_config.py index 4e30a38b..e30afa9d 100644 --- a/statgpt/common/schemas/model_config.py +++ b/statgpt/common/schemas/model_config.py @@ -51,14 +51,15 @@ class LLMModelConfig(BaseModelConfig): ), ) reasoning_effort: ReasoningEffortEnum | None = Field( - default=langchain_settings.default_reasoning_effort, + default=ReasoningEffortEnum.LOW, description=( "Reasoning effort level for GPT-5 models. Ignored for non-reasoning models. " "Supports: none, minimal, low, medium, high, xhigh." + "All models before gpt-5.1 default to medium reasoning effort, and do not support none" ), ) verbosity: VerbosityEnum | None = Field( - default=langchain_settings.default_verbosity, + default=VerbosityEnum.LOW, description=("Output verbosity for GPT-5 models (low/medium/high). "), ) diff --git a/statgpt/common/settings/langchain.py b/statgpt/common/settings/langchain.py index bd355979..13e08ef4 100644 --- a/statgpt/common/settings/langchain.py +++ b/statgpt/common/settings/langchain.py @@ -2,12 +2,7 @@ from pydantic import Field from pydantic_settings import BaseSettings, SettingsConfigDict -from statgpt.common.config.llm_models import ( - EmbeddingModelsEnum, - LLMModelsEnum, - ReasoningEffortEnum, - VerbosityEnum, -) +from statgpt.common.config.llm_models import EmbeddingModelsEnum, LLMModelsEnum class LangChainSettings(BaseSettings): @@ -43,16 +38,6 @@ class LangChainSettings(BaseSettings): description="Default seed for reproducible outputs", ) - default_reasoning_effort: ReasoningEffortEnum | None = Field( - default=ReasoningEffortEnum.NONE, - description="Default reasoning effort for GPT-5 models (none/minimal/low/medium/high/xhigh)", - ) - - default_verbosity: VerbosityEnum | None = Field( - default=VerbosityEnum.LOW, - description="Default verbosity for GPT-5 models (low/medium/high). None means use model default.", - ) - # Debugging settings verbose: bool = Field(default=False, description="Enable verbose mode for LangChain") From 287a7ef6244868c1e256f519dbbca2f6d7860aa9 Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Tue, 17 Feb 2026 18:19:44 +0200 Subject: [PATCH 10/14] refactor model validation --- statgpt/common/schemas/model_config.py | 33 ++++++++++++++------------ 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/statgpt/common/schemas/model_config.py b/statgpt/common/schemas/model_config.py index e30afa9d..6fc4837f 100644 --- a/statgpt/common/schemas/model_config.py +++ b/statgpt/common/schemas/model_config.py @@ -51,28 +51,31 @@ class LLMModelConfig(BaseModelConfig): ), ) reasoning_effort: ReasoningEffortEnum | None = Field( - default=ReasoningEffortEnum.LOW, + default=None, description=( - "Reasoning effort level for GPT-5 models. Ignored for non-reasoning models. " - "Supports: none, minimal, low, medium, high, xhigh." - "All models before gpt-5.1 default to medium reasoning effort, and do not support none" + "Reasoning effort level for GPT-5 models. " + "Supports: none, minimal, low, medium, high, xhigh. " + "All models before gpt-5.1 default to medium reasoning effort, and do not support none." ), ) verbosity: VerbosityEnum | None = Field( - default=VerbosityEnum.LOW, - description=("Output verbosity for GPT-5 models (low/medium/high). "), + default=None, + description="Output verbosity for GPT-5 models (low/medium/high).", ) @model_validator(mode="after") - def _normalize_model_family_params(self) -> "LLMModelConfig": + def _validate_model_family_params(self) -> "LLMModelConfig": if self.deployment.is_gpt_5_family: - self.seed = None - if self.reasoning_effort == ReasoningEffortEnum.NONE: - self.temperature = 0 - else: - # For reasoning levels only 1 is accepted - self.temperature = 1 + if self.seed is not None: + raise ValueError("seed is not supported for GPT-5 models") + if self.reasoning_effort is not ReasoningEffortEnum.NONE and self.temperature != 1: + raise ValueError( + "reasoning_effort is only supported for GPT-5 models when temperature is set to 1" + ) + else: - self.reasoning_effort = None - self.verbosity = None + if self.reasoning_effort is not None: + raise ValueError("reasoning_effort is only supported for GPT-5 models") + if self.verbosity is not None: + raise ValueError("verbosity is only supported for GPT-5 models") return self From 082d4efc1ad0ed2c9f418a3c543300cdfc9330c7 Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Tue, 17 Feb 2026 18:39:15 +0200 Subject: [PATCH 11/14] fix validation --- statgpt/common/schemas/model_config.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/statgpt/common/schemas/model_config.py b/statgpt/common/schemas/model_config.py index 6fc4837f..ed0bfe9f 100644 --- a/statgpt/common/schemas/model_config.py +++ b/statgpt/common/schemas/model_config.py @@ -68,11 +68,12 @@ def _validate_model_family_params(self) -> "LLMModelConfig": if self.deployment.is_gpt_5_family: if self.seed is not None: raise ValueError("seed is not supported for GPT-5 models") + if self.reasoning_effort is None: + raise ValueError("reasoning_effort is required for GPT-5 models") if self.reasoning_effort is not ReasoningEffortEnum.NONE and self.temperature != 1: raise ValueError( - "reasoning_effort is only supported for GPT-5 models when temperature is set to 1" + "temperature must be set to 1 when reasoning_effort is enabled for GPT-5 models" ) - else: if self.reasoning_effort is not None: raise ValueError("reasoning_effort is only supported for GPT-5 models") From 57b19a43c36a7ffe68794e80272bf59fce0cef2c Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Wed, 18 Feb 2026 10:13:00 +0200 Subject: [PATCH 12/14] fix bug default embedding model --- statgpt/common/models/models.py | 46 +++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/statgpt/common/models/models.py b/statgpt/common/models/models.py index 11af2350..bc7690c8 100644 --- a/statgpt/common/models/models.py +++ b/statgpt/common/models/models.py @@ -25,7 +25,9 @@ class Channel(DefaultBase): title: Mapped[str] description: Mapped[str] deployment_id: Mapped[str] = mapped_column(unique=True) - llm_model: Mapped[str] = mapped_column(default=langchain_settings.default_model.value) + llm_model: Mapped[str] = mapped_column( + default=langchain_settings.embedding_default_model.value + ) details: Mapped[dict[str, Any]] = mapped_column(type_=postgresql.JSONB) # ~~~~~ Relationships ~~~~~ @@ -37,7 +39,9 @@ class Channel(DefaultBase): "GlossaryTerm", back_populates="channel", cascade="all, delete-orphan" ) # NOTE: Jobs can exist without a channel, so the option `delete-orphan` is not used here. - jobs: Mapped[list["Job"]] = relationship("Job", back_populates="channel", cascade="all") + jobs: Mapped[list["Job"]] = relationship( + "Job", back_populates="channel", cascade="all" + ) # ~~~~~ Properties ~~~~~ @@ -102,7 +106,9 @@ class DataSet(DefaultBase): __tablename__ = "datasets" # TODO: use id_ as primary_key - id_: Mapped[uuid.UUID] = mapped_column(type_=postgresql.UUID(as_uuid=True), unique=True) + id_: Mapped[uuid.UUID] = mapped_column( + type_=postgresql.UUID(as_uuid=True), unique=True + ) source_id: Mapped[int] = mapped_column(ForeignKey("data_sources.id")) title: Mapped[str] details: Mapped[dict[str, Any]] = mapped_column(type_=postgresql.JSONB) @@ -143,45 +149,59 @@ class ChannelDatasetVersion(DefaultBase): __tablename__ = "channel_dataset_versions" __table_args__ = ( UniqueConstraint( - 'channel_dataset_id', 'version', name='uix_unique_version_for_channel_dataset' + "channel_dataset_id", + "version", + name="uix_unique_version_for_channel_dataset", ), ) channel_dataset_id: Mapped[int] = mapped_column(ForeignKey("channel_datasets.id")) - version: Mapped[int] = mapped_column(default=0) # will be auto-incremented by trigger + version: Mapped[int] = mapped_column( + default=0 + ) # will be auto-incremented by trigger preprocessing_status: Mapped[PreprocessingStatusEnum] pointer_to: Mapped[int | None] = mapped_column( - ForeignKey("channel_dataset_versions.id", ondelete='SET NULL'), default=None + ForeignKey("channel_dataset_versions.id", ondelete="SET NULL"), default=None ) creation_reason: Mapped[str] reason_for_failure: Mapped[str | None] = mapped_column(default=None) - structure_metadata: Mapped[dict | None] = mapped_column(type_=postgresql.JSONB, default=None) + structure_metadata: Mapped[dict | None] = mapped_column( + type_=postgresql.JSONB, default=None + ) structure_hash: Mapped[str | None] = mapped_column(type_=String(10), default=None) # Data hashes: - indicator_dimensions_hash: Mapped[str | None] = mapped_column(type_=String(10), default=None) + indicator_dimensions_hash: Mapped[str | None] = mapped_column( + type_=String(10), default=None + ) non_indicator_dimensions_hash: Mapped[str | None] = mapped_column( type_=String(10), default=None ) - special_dimensions_hash: Mapped[str | None] = mapped_column(type_=String(10), default=None) + special_dimensions_hash: Mapped[str | None] = mapped_column( + type_=String(10), default=None + ) # Config hash: - indexing_config_hash: Mapped[str | None] = mapped_column(type_=String(10), default=None) + indexing_config_hash: Mapped[str | None] = mapped_column( + type_=String(10), default=None + ) # Resolved configuration at indexing time (e.g. dynamic URN version resolved to concrete version) - resolved_config: Mapped[dict | None] = mapped_column(type_=postgresql.JSONB, default=None) + resolved_config: Mapped[dict | None] = mapped_column( + type_=postgresql.JSONB, default=None + ) # relationships channel_dataset: Mapped[ChannelDataset] = relationship(back_populates="versions") pointer = relationship( "ChannelDatasetVersion", - remote_side='ChannelDatasetVersion.id', + remote_side="ChannelDatasetVersion.id", back_populates="pointing_versions", cascade="all", passive_deletes=True, ) pointing_versions = relationship( "ChannelDatasetVersion", - remote_side='ChannelDatasetVersion.pointer_to', + remote_side="ChannelDatasetVersion.pointer_to", back_populates="pointer", cascade="all, delete-orphan", passive_deletes=True, From 9633d1a58b1a59294770071b3ecf098cada67c91 Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Wed, 18 Feb 2026 10:13:19 +0200 Subject: [PATCH 13/14] refactor & change note --- statgpt/common/schemas/model_config.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/statgpt/common/schemas/model_config.py b/statgpt/common/schemas/model_config.py index ed0bfe9f..064022ff 100644 --- a/statgpt/common/schemas/model_config.py +++ b/statgpt/common/schemas/model_config.py @@ -40,7 +40,7 @@ class LLMModelConfig(BaseModelConfig): default=langchain_settings.default_temperature, description=( "The temperature of the model. 0.0 means deterministic output, higher values mean more" - " randomness. Note: Not supported by GPT-5 models." + " randomness. Note: For reasoning models (except reasoning_effort=none) should be set to 1" ), ) seed: int | None = Field( @@ -70,7 +70,10 @@ def _validate_model_family_params(self) -> "LLMModelConfig": raise ValueError("seed is not supported for GPT-5 models") if self.reasoning_effort is None: raise ValueError("reasoning_effort is required for GPT-5 models") - if self.reasoning_effort is not ReasoningEffortEnum.NONE and self.temperature != 1: + if ( + self.reasoning_effort is not ReasoningEffortEnum.NONE + and self.temperature != 1 + ): raise ValueError( "temperature must be set to 1 when reasoning_effort is enabled for GPT-5 models" ) From dc62e5d4ebf8c3879abf1eebc6de16095fde5af9 Mon Sep 17 00:00:00 2001 From: Bahdan Kapionkin Date: Wed, 18 Feb 2026 13:12:11 +0200 Subject: [PATCH 14/14] reformat --- statgpt/common/models/models.py | 36 +++++++------------------- statgpt/common/schemas/model_config.py | 5 +--- 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/statgpt/common/models/models.py b/statgpt/common/models/models.py index eabf801b..8f89ac00 100644 --- a/statgpt/common/models/models.py +++ b/statgpt/common/models/models.py @@ -32,9 +32,7 @@ class Channel(DefaultBase): title: Mapped[str] description: Mapped[str] deployment_id: Mapped[str] = mapped_column(unique=True) - llm_model: Mapped[str] = mapped_column( - default=langchain_settings.embedding_default_model.value - ) + llm_model: Mapped[str] = mapped_column(default=langchain_settings.embedding_default_model.value) details: Mapped[dict[str, Any]] = mapped_column(type_=postgresql.JSONB) # ~~~~~ Relationships ~~~~~ @@ -46,9 +44,7 @@ class Channel(DefaultBase): "GlossaryTerm", back_populates="channel", cascade="all, delete-orphan" ) # NOTE: Jobs can exist without a channel, so the option `delete-orphan` is not used here. - jobs: Mapped[list["Job"]] = relationship( - "Job", back_populates="channel", cascade="all" - ) + jobs: Mapped[list["Job"]] = relationship("Job", back_populates="channel", cascade="all") # ~~~~~ Properties ~~~~~ @@ -113,9 +109,7 @@ class DataSet(DefaultBase): __tablename__ = "datasets" # TODO: use id_ as primary_key - id_: Mapped[uuid.UUID] = mapped_column( - type_=postgresql.UUID(as_uuid=True), unique=True - ) + id_: Mapped[uuid.UUID] = mapped_column(type_=postgresql.UUID(as_uuid=True), unique=True) source_id: Mapped[int] = mapped_column(ForeignKey("data_sources.id")) title: Mapped[str] details: Mapped[dict[str, Any]] = mapped_column(type_=postgresql.JSONB) @@ -163,9 +157,7 @@ class ChannelDatasetVersion(DefaultBase): ) channel_dataset_id: Mapped[int] = mapped_column(ForeignKey("channel_datasets.id")) - version: Mapped[int] = mapped_column( - default=0 - ) # will be auto-incremented by trigger + version: Mapped[int] = mapped_column(default=0) # will be auto-incremented by trigger preprocessing_status: Mapped[PreprocessingStatusEnum] pointer_to: Mapped[int | None] = mapped_column( ForeignKey("channel_dataset_versions.id", ondelete="SET NULL"), default=None @@ -174,28 +166,18 @@ class ChannelDatasetVersion(DefaultBase): creation_reason: Mapped[str] reason_for_failure: Mapped[str | None] = mapped_column(default=None) - structure_metadata: Mapped[dict | None] = mapped_column( - type_=postgresql.JSONB, default=None - ) + structure_metadata: Mapped[dict | None] = mapped_column(type_=postgresql.JSONB, default=None) structure_hash: Mapped[str | None] = mapped_column(type_=String(10), default=None) # Data hashes: - indicator_dimensions_hash: Mapped[str | None] = mapped_column( - type_=String(10), default=None - ) + indicator_dimensions_hash: Mapped[str | None] = mapped_column(type_=String(10), default=None) non_indicator_dimensions_hash: Mapped[str | None] = mapped_column( type_=String(10), default=None ) - special_dimensions_hash: Mapped[str | None] = mapped_column( - type_=String(10), default=None - ) + special_dimensions_hash: Mapped[str | None] = mapped_column(type_=String(10), default=None) # Config hash: - indexing_config_hash: Mapped[str | None] = mapped_column( - type_=String(10), default=None - ) + indexing_config_hash: Mapped[str | None] = mapped_column(type_=String(10), default=None) # Resolved configuration at indexing time (e.g. dynamic URN version resolved to concrete version) - resolved_config: Mapped[dict | None] = mapped_column( - type_=postgresql.JSONB, default=None - ) + resolved_config: Mapped[dict | None] = mapped_column(type_=postgresql.JSONB, default=None) # relationships channel_dataset: Mapped[ChannelDataset] = relationship(back_populates="versions") diff --git a/statgpt/common/schemas/model_config.py b/statgpt/common/schemas/model_config.py index 064022ff..a6505a87 100644 --- a/statgpt/common/schemas/model_config.py +++ b/statgpt/common/schemas/model_config.py @@ -70,10 +70,7 @@ def _validate_model_family_params(self) -> "LLMModelConfig": raise ValueError("seed is not supported for GPT-5 models") if self.reasoning_effort is None: raise ValueError("reasoning_effort is required for GPT-5 models") - if ( - self.reasoning_effort is not ReasoningEffortEnum.NONE - and self.temperature != 1 - ): + if self.reasoning_effort is not ReasoningEffortEnum.NONE and self.temperature != 1: raise ValueError( "temperature must be set to 1 when reasoning_effort is enabled for GPT-5 models" )