carolinacon commited on
Commit
43199e3
·
1 Parent(s): eb5efe8

created config and config loader

Browse files
.env.example ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Core API Keys
2
+ TAVILY_API_KEY=your-tavily-key
3
+ OPENAI_API_KEY=your-openai-key
4
+ GOOGLE_API_KEY=your-google-key
5
+
6
+ # Huggingface SpaceID - if you want run and submit the answers outside of the HF space
7
+ SPACE_ID=your-huggingface-space
8
+ HF_TOKEN=your-huggingface-token
9
+
10
+ # If running on Windows, configure the
11
+ CHESS_ENGINE_PATH=stock-fish-engine-location-here
12
+
13
+ # Configure this if you want to enable observability with LangSmith
14
+ LANGSMITH_API_KEY=your-langsmith-key
15
+ LANGSMITH_TRACING=true
16
+ LANGSMITH_PROJECT=gaia_agent
config/settings.py CHANGED
@@ -1,32 +1,161 @@
1
- # Configuration management
2
-
3
  import os
4
- from typing import Dict, Any
5
  from pathlib import Path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
 
 
 
 
7
 
8
- class AgentConfig:
9
- """Centralized configuration"""
10
 
11
- def __init__(self):
12
- # LLM Configuration
13
- self.MODEL_NAME = os.getenv("MODEL_NAME", "gpt-4.1")
 
 
14
 
15
- #Sizing limitations
16
- self.MAX_CONTEXT_TOKENS = 20000
 
17
 
 
 
 
 
 
18
 
19
- # File Paths
20
- self.PROJECT_ROOT = Path(__file__).parent.parent
21
- self.PROMPTS_PATH = self.PROJECT_ROOT / "config" / "prompts.yaml"
 
 
22
 
23
- def to_dict(self) -> Dict[str, Any]:
24
- """Convert config to dictionary"""
25
- return {
26
- key: value for key, value in self.__dict__.items()
27
- if not key.startswith('_')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  }
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
- # Global config instance
32
- config = AgentConfig()
 
 
 
 
 
1
  import os
 
2
  from pathlib import Path
3
+ from typing import Dict, List, Optional
4
+
5
+ from dotenv import load_dotenv, find_dotenv
6
+ from pydantic_settings import BaseSettings
7
+
8
+
9
+ class AgentConfig(BaseSettings):
10
+ """
11
+ Configuration class that works with environment variable manager.
12
+ """
13
+
14
+ # Core settings
15
+ environment: str = "development"
16
+ agent_name: str = "gaia_agent"
17
+ debug: bool = False
18
+
19
+ # Model configuration
20
+ model_name: str = "gpt-4.1"
21
+ response_processing_model_name: str = "gpt-4.1-mini"
22
+
23
+ max_tokens: int = 20000
24
+
25
+ project_root: Path = Path(__file__).parent.parent
26
+ prompts_location: Path = project_root / "config" / "prompts.yaml"
27
 
28
+ class Config:
29
+ env_file = ".env"
30
+ case_sensitive = False
31
+ extra = "allow"
32
 
 
 
33
 
34
+ class EnvironmentVariableManager:
35
+ """
36
+ Manages loading .env files and setting environment variables that
37
+ third-party libraries expect to find.
38
+ """
39
 
40
+ def __init__(self, env_file: Optional[str] = None):
41
+ """
42
+ Initialize the environment variable manager.
43
 
44
+ Args:
45
+ env_file: Path to .env file (if None, will search for it)
46
+ """
47
+ self.env_file = env_file or find_dotenv()
48
+ self.loaded_vars = {}
49
 
50
+ def load_env_file(self) -> Dict[str, str]:
51
+ """Load the .env file and return all variables."""
52
+ if not self.env_file or not Path(self.env_file).exists():
53
+ print(f"Warning: .env file not found at {self.env_file}")
54
+ return {}
55
 
56
+ # Load .env file
57
+ load_dotenv(self.env_file, override=True)
58
+
59
+ # Read the file manually to get all variables
60
+ env_vars = {}
61
+ with open(self.env_file, 'r') as f:
62
+ for line in f:
63
+ line = line.strip()
64
+ if line and not line.startswith('#') and '=' in line:
65
+ key, value = line.split('=', 1)
66
+ key = key.strip()
67
+ value = value.strip().strip('"\'') # Remove quotes
68
+ env_vars[key] = value
69
+
70
+ self.loaded_vars = env_vars
71
+ return env_vars
72
+
73
+ def get_required_env_vars(self, services: List[str]) -> List[str]:
74
+ """
75
+ Get list of required environment variables for specific services.
76
+
77
+ Args:
78
+ services: List of service names (e.g., ['openai', 'anthropic'])
79
+
80
+ Returns:
81
+ List of required environment variable names
82
+ """
83
+ service_requirements = {
84
+ 'openai': ['OPENAI_API_KEY'],
85
+ 'google': ['GOOGLE_API_KEY'],
86
+ 'tavily': ['TAVILY_API_KEY'],
87
  }
88
 
89
+ required = []
90
+ for service in services:
91
+ if service.lower() in service_requirements:
92
+ required.extend(service_requirements[service.lower()])
93
+
94
+ return required
95
+
96
+ def validate_required_env_vars(self, services: List[str]) -> List[str]:
97
+ """
98
+ Validate that required environment variables are set.
99
+
100
+ Returns:
101
+ List of missing environment variables
102
+ """
103
+ required = self.get_required_env_vars(services)
104
+ missing = []
105
+
106
+ for var in required:
107
+ if not os.environ.get(var):
108
+ missing.append(var)
109
+
110
+ return missing
111
+
112
+
113
+ class ConfigLoader:
114
+ """
115
+ Main configuration loader that handles both Pydantic config and environment variables.
116
+ """
117
+
118
+ def __init__(self, env_file: Optional[str] = None):
119
+ self.env_manager = EnvironmentVariableManager(env_file)
120
+ self.config = None
121
+
122
+ def load_config(self,
123
+ required_services: Optional[List[str]] = None,
124
+ validate: bool = True) -> AgentConfig:
125
+ """
126
+ Load configuration and set up environment variables.
127
+
128
+ Args:
129
+ required_services: List of services that must have API keys
130
+ validate: Whether to validate required environment variables
131
+
132
+ Returns:
133
+ Configured LangGraphConfigWithEnvVars instance
134
+ """
135
+
136
+ # Step 1: Load .env file
137
+ print("Loading .env file...")
138
+ loaded_vars = self.env_manager.load_env_file()
139
+ print(f"Loaded {len(loaded_vars)} variables from .env file")
140
+
141
+ # Step 2: Load Pydantic configuration
142
+ print("Loading Pydantic configuration...")
143
+ self.config = AgentConfig()
144
+
145
+ # Step 3: Validate required services
146
+ if validate and required_services:
147
+ print(f"Validating required services: {required_services}")
148
+ missing = self.env_manager.validate_required_env_vars(required_services)
149
+ if missing:
150
+ raise ValueError(f"Missing required environment variables: {missing}")
151
+ print("✓ All required environment variables are set")
152
+
153
+ return self.config
154
+
155
+
156
+ loader = ConfigLoader()
157
 
158
+ config = loader.load_config(
159
+ required_services=['openai', 'google', 'tavily'],
160
+ validate=True
161
+ )
nodes/chunking_node.py CHANGED
@@ -69,7 +69,7 @@ class OversizedContentHandler:
69
  raw_content = result['raw_content']
70
 
71
  content_size = self.count_tokens(raw_content)
72
- if content_size > config.MAX_CONTEXT_TOKENS:
73
  print(f"Proceed with chunking, evaluated no of tokens {content_size} for message {message.id}")
74
  chunked = True
75
  result['raw_content'] = self.extract_relevant_chunks(raw_content, query=query)
 
69
  raw_content = result['raw_content']
70
 
71
  content_size = self.count_tokens(raw_content)
72
+ if content_size > config.max_tokens:
73
  print(f"Proceed with chunking, evaluated no of tokens {content_size} for message {message.id}")
74
  chunked = True
75
  result['raw_content'] = self.extract_relevant_chunks(raw_content, query=query)
nodes/nodes.py CHANGED
@@ -5,6 +5,7 @@ import time
5
  from langchain_core.messages import SystemMessage, HumanMessage, AIMessage, RemoveMessage
6
  from langchain_openai import ChatOpenAI
7
 
 
8
  from core.messages import attachmentHandler
9
  from core.state import State
10
  from nodes.chunking_node import OversizedContentHandler
@@ -16,15 +17,17 @@ from tools.python_executor import execute_python_code
16
  from tools.tavily_tools import web_search_tools
17
  from utils.prompt_manager import prompt_mgmt
18
 
19
- model = ChatOpenAI(model="gpt-4.1")
20
- response_processing_model = ChatOpenAI(model="gpt-4.1-mini")
21
  web_search_tools.append(query_audio)
22
  web_search_tools.append(query_excel_file)
23
  web_search_tools.append(execute_python_code)
24
  web_search_tools.append(math_tool)
25
  web_search_tools.append(chess_analysis_tool)
 
 
26
  model = model.bind_tools(web_search_tools, parallel_tool_calls=False)
27
 
 
 
28
 
29
  # Node
30
  def pre_processor(state: State):
 
5
  from langchain_core.messages import SystemMessage, HumanMessage, AIMessage, RemoveMessage
6
  from langchain_openai import ChatOpenAI
7
 
8
+ from config.settings import config
9
  from core.messages import attachmentHandler
10
  from core.state import State
11
  from nodes.chunking_node import OversizedContentHandler
 
17
  from tools.tavily_tools import web_search_tools
18
  from utils.prompt_manager import prompt_mgmt
19
 
 
 
20
  web_search_tools.append(query_audio)
21
  web_search_tools.append(query_excel_file)
22
  web_search_tools.append(execute_python_code)
23
  web_search_tools.append(math_tool)
24
  web_search_tools.append(chess_analysis_tool)
25
+
26
+ model = ChatOpenAI(model=config.model_name)
27
  model = model.bind_tools(web_search_tools, parallel_tool_calls=False)
28
 
29
+ response_processing_model = ChatOpenAI(model=config.response_processing_model_name)
30
+
31
 
32
  # Node
33
  def pre_processor(state: State):
utils/dependencies_checker.py CHANGED
@@ -25,7 +25,7 @@ def find_stockfish_path():
25
 
26
 
27
  def check_dependencies():
28
- chess_engine_path =os.getenv("CHESS_ENGINE_PATH")
29
  if chess_engine_path is None:
30
  stockfish_path = find_stockfish_path()
31
  if stockfish_path:
 
25
 
26
 
27
  def check_dependencies():
28
+ chess_engine_path = os.getenv("CHESS_ENGINE_PATH")
29
  if chess_engine_path is None:
30
  stockfish_path = find_stockfish_path()
31
  if stockfish_path: