From 54f0e53d5b463991445b8f8edf4b0f19e915e309 Mon Sep 17 00:00:00 2001 From: AaryanCode69 Date: Sun, 1 Mar 2026 11:17:29 +0530 Subject: [PATCH 1/2] feat: make LLM and embedding model configurable via YAML config Previously, the model provider and model name were hard-coded in AgentGraph.__init__() as get_llm("openai", "gpt-4o-mini") and get_embedding("openai", "text-embedding-3-large"). This made it impossible to switch models without modifying source code. - Add llm and embedding configuration fields to the YAML config schema - Update Pydantic config models to validate new model settings - Update AgentGraph to read provider/model from YAML config instead of hard-coded values - Retain existing defaults for backward compatibility Resolves #108 --- bin/chat-chainlit.py | 3 ++- config_default.yml | 8 ++++++++ src/agent/graph.py | 18 +++++++++++++++--- src/util/config_yml/__init__.py | 2 ++ src/util/config_yml/models.py | 20 ++++++++++++++++++++ 5 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 src/util/config_yml/models.py diff --git a/bin/chat-chainlit.py b/bin/chat-chainlit.py index fa4faf6..60e0f95 100644 --- a/bin/chat-chainlit.py +++ b/bin/chat-chainlit.py @@ -20,7 +20,8 @@ config: Config | None = Config.from_yaml() profiles: list[ProfileName] = config.profiles if config else [ProfileName.React_to_Me] -llm_graph = AgentGraph(profiles) +models_config = config.models if config else None +llm_graph = AgentGraph(profiles, models_config=models_config) POSTGRES_CHAINLIT_DB = os.getenv("POSTGRES_CHAINLIT_DB") POSTGRES_USER = os.getenv("POSTGRES_USER") diff --git a/config_default.yml b/config_default.yml index e53055a..e2b8eda 100644 --- a/config_default.yml +++ b/config_default.yml @@ -1,5 +1,13 @@ # yaml-language-server: $schema=./.config.schema.yaml +models: + llm: + provider: openai + model: gpt-4o-mini + embedding: + provider: openai + model: text-embedding-3-large + profiles: - React-to-Me diff --git a/src/agent/graph.py b/src/agent/graph.py index 012df27..b972e4c 100644 --- a/src/agent/graph.py +++ b/src/agent/graph.py @@ -16,6 +16,7 @@ from agent.models import get_embedding, get_llm from agent.profiles import ProfileName, create_profile_graphs from agent.profiles.base import InputState, OutputState +from util.config_yml.models import EmbeddingConfig, LLMConfig, ModelsConfig from util.logging import logging LANGGRAPH_DB_URI = f"postgresql://{os.getenv('POSTGRES_USER')}:{os.getenv('POSTGRES_PASSWORD')}@postgres:5432/{os.getenv('POSTGRES_LANGGRAPH_DB')}?sslmode=disable" @@ -28,10 +29,21 @@ class AgentGraph: def __init__( self, profiles: list[ProfileName], + models_config: ModelsConfig | None = None, ) -> None: - # Get base models - llm: BaseChatModel = get_llm("openai", "gpt-4o-mini") - embedding: Embeddings = get_embedding("openai", "text-embedding-3-large") + # Get base models from config (with backward-compatible defaults) + if models_config is None: + models_config = ModelsConfig() + + llm_cfg: LLMConfig = models_config.llm + emb_cfg: EmbeddingConfig = models_config.embedding + + llm: BaseChatModel = get_llm( + llm_cfg.provider, llm_cfg.model, base_url=llm_cfg.base_url + ) + embedding: Embeddings = get_embedding( + emb_cfg.provider, emb_cfg.model, device=emb_cfg.device + ) self.uncompiled_graph: dict[str, StateGraph] = create_profile_graphs( profiles, llm, embedding diff --git a/src/util/config_yml/__init__.py b/src/util/config_yml/__init__.py index e6d57e9..c532c05 100644 --- a/src/util/config_yml/__init__.py +++ b/src/util/config_yml/__init__.py @@ -7,6 +7,7 @@ from agent.profiles import ProfileName from util.config_yml.features import Feature, Features from util.config_yml.messages import Message, TriggerEvent +from util.config_yml.models import EmbeddingConfig, LLMConfig, ModelsConfig from util.config_yml.usage_limits import MessageRate, UsageLimits from util.config_yml.user_matching import match_user from util.logging import logging @@ -18,6 +19,7 @@ class Config(BaseModel): features: Features messages: dict[str, Message] + models: ModelsConfig = ModelsConfig() profiles: list[ProfileName] usage_limits: UsageLimits diff --git a/src/util/config_yml/models.py b/src/util/config_yml/models.py new file mode 100644 index 0000000..8df314a --- /dev/null +++ b/src/util/config_yml/models.py @@ -0,0 +1,20 @@ +from typing import Literal + +from pydantic import BaseModel + + +class LLMConfig(BaseModel): + provider: Literal["openai", "ollama"] | str = "openai" + model: str = "gpt-4o-mini" + base_url: str | None = None + + +class EmbeddingConfig(BaseModel): + provider: Literal["openai", "huggingfacehub", "huggingfacelocal"] | str = "openai" + model: str = "text-embedding-3-large" + device: str | None = "cpu" + + +class ModelsConfig(BaseModel): + llm: LLMConfig = LLMConfig() + embedding: EmbeddingConfig = EmbeddingConfig() From 49a3bec4db9be066ca1a038b5a17bdbe4d2c726d Mon Sep 17 00:00:00 2001 From: AaryanCode69 Date: Sun, 1 Mar 2026 18:35:01 +0530 Subject: [PATCH 2/2] fix: allow extra fields in Config to prevent silent YAML rejection Pydantic v2 BaseModel rejects unknown fields by default. Adding a `models` key to config.yml caused the entire Config to fail validation, returning None and silently disabling messages, rate limits, and feature flags. Setting extra="ignore" lets the parser skip unrecognized keys while still loading all known configuration correctly. --- src/util/config_yml/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util/config_yml/__init__.py b/src/util/config_yml/__init__.py index c532c05..fa460c2 100644 --- a/src/util/config_yml/__init__.py +++ b/src/util/config_yml/__init__.py @@ -2,7 +2,7 @@ from typing import Self import yaml -from pydantic import BaseModel, ValidationError +from pydantic import BaseModel, ConfigDict, ValidationError from agent.profiles import ProfileName from util.config_yml.features import Feature, Features @@ -17,6 +17,8 @@ class Config(BaseModel): + model_config = ConfigDict(extra="ignore") + features: Features messages: dict[str, Message] models: ModelsConfig = ModelsConfig()