1313from codeflow_engine .actions .ai_linting_fixer .ai_agent_manager import AIAgentManager
1414from codeflow_engine .actions .ai_linting_fixer .code_analyzer import CodeAnalyzer
1515from codeflow_engine .actions .ai_linting_fixer .detection import IssueDetector
16- from codeflow_engine .actions .ai_linting_fixer .display import (AILintingFixerDisplay ,
17- DisplayConfig )
16+ from codeflow_engine .actions .ai_linting_fixer .display import (
17+ AILintingFixerDisplay ,
18+ DisplayConfig ,
19+ )
1820from codeflow_engine .actions .ai_linting_fixer .error_handler import ErrorHandler
1921from codeflow_engine .actions .ai_linting_fixer .file_manager import FileManager
20- from codeflow_engine .actions .ai_linting_fixer .issue_converter import \
21- convert_detection_issue_to_model_issue
22+ from codeflow_engine .actions .ai_linting_fixer .issue_converter import (
23+ convert_detection_issue_to_model_issue ,
24+ )
2225from codeflow_engine .actions .ai_linting_fixer .issue_fixer import IssueFixer
23- from codeflow_engine .actions .ai_linting_fixer .models import (AILintingFixerInputs ,
24- AILintingFixerOutputs )
25- from codeflow_engine .actions .ai_linting_fixer .performance_tracker import \
26- PerformanceTracker
26+ from codeflow_engine .actions .ai_linting_fixer .models import (
27+ AILintingFixerInputs ,
28+ AILintingFixerOutputs ,
29+ )
30+ from codeflow_engine .actions .ai_linting_fixer .performance_tracker import (
31+ PerformanceTracker ,
32+ )
2733from codeflow_engine .actions .llm .manager import ActionLLMProviderManager
2834
2935logger = logging .getLogger (__name__ )
@@ -37,7 +43,9 @@ class AILintingFixer:
3743 def __init__ (self , display_config : DisplayConfig | None = None ):
3844 """Initialize the AI Linting Fixer with all components."""
3945 # Set logging levels to ERROR by default to prevent clutter
40- logging .getLogger ("codeflow_engine.actions.ai_linting_fixer" ).setLevel (logging .ERROR )
46+ logging .getLogger ("codeflow_engine.actions.ai_linting_fixer" ).setLevel (
47+ logging .ERROR
48+ )
4149 logging .getLogger ("codeflow_engine.actions.llm" ).setLevel (logging .ERROR )
4250 logging .getLogger ("httpx" ).setLevel (logging .ERROR )
4351
@@ -49,31 +57,36 @@ def __init__(self, display_config: DisplayConfig | None = None):
4957 self .error_handler = ErrorHandler ()
5058
5159 # Get Azure OpenAI configuration
52- azure_endpoint = os .getenv ("AZURE_OPENAI_ENDPOINT" , "https://<your-azure-openai-endpoint>/" )
60+ azure_endpoint = os .getenv (
61+ "AZURE_OPENAI_ENDPOINT" , "https://<your-azure-openai-endpoint>/"
62+ )
5363 azure_api_key = os .getenv ("AZURE_OPENAI_API_KEY" )
5464
5565 # Soft validation: check if Azure OpenAI is properly configured
5666 azure_configured = (
57- azure_api_key and
58- azure_endpoint and
59- "<" not in azure_endpoint and
60- "your-azure-openai-endpoint" not in azure_endpoint
67+ azure_api_key
68+ and azure_endpoint
69+ and "<" not in azure_endpoint
70+ and "your-azure-openai-endpoint" not in azure_endpoint
6171 )
6272
6373 # Build LLM configuration with fallback providers
64- llm_config = {
74+ providers_config : dict [str , dict [str , str | None ]] = {}
75+ llm_config : dict [str , Any ] = {
6576 "default_provider" : None , # Will be set based on available providers
6677 "fallback_order" : [], # Will be populated based on available providers
67- "providers" : {} ,
78+ "providers" : providers_config ,
6879 }
6980
7081 # Add Azure OpenAI provider only if properly configured
7182 if azure_configured :
72- llm_config [ "providers" ] ["azure_openai" ] = {
83+ providers_config ["azure_openai" ] = {
7384 "azure_endpoint" : azure_endpoint ,
7485 "api_key" : azure_api_key ,
7586 "api_version" : os .getenv ("AZURE_OPENAI_API_VERSION" , "2024-02-01" ),
76- "deployment_name" : os .getenv ("AZURE_OPENAI_DEPLOYMENT_NAME" , "gpt-35-turbo" ),
87+ "deployment_name" : os .getenv (
88+ "AZURE_OPENAI_DEPLOYMENT_NAME" , "gpt-35-turbo"
89+ ),
7790 }
7891 logger .info ("Azure OpenAI provider configured successfully" )
7992 else :
@@ -83,32 +96,36 @@ def __init__(self, display_config: DisplayConfig | None = None):
8396 "Azure OpenAI API key not configured. "
8497 "Set AZURE_OPENAI_API_KEY environment variable to enable Azure OpenAI provider."
8598 )
86- if (not azure_endpoint or "<" in azure_endpoint or
87- "your-azure-openai-endpoint" in azure_endpoint ):
99+ if (
100+ not azure_endpoint
101+ or "<" in azure_endpoint
102+ or "your-azure-openai-endpoint" in azure_endpoint
103+ ):
88104 logger .warning (
89105 "Azure OpenAI endpoint not properly configured. "
90106 "Set AZURE_OPENAI_ENDPOINT environment variable to enable "
91- "Azure OpenAI provider. Current value: %s" , azure_endpoint
107+ "Azure OpenAI provider. Current value: %s" ,
108+ azure_endpoint ,
92109 )
93110 logger .info ("Azure OpenAI provider skipped due to missing configuration" )
94111
95112 # Add other providers for fallback
96113 openai_api_key = os .getenv ("OPENAI_API_KEY" )
97114 if openai_api_key :
98- llm_config [ "providers" ] ["openai" ] = {
115+ providers_config ["openai" ] = {
99116 "api_key" : openai_api_key ,
100117 }
101118 logger .info ("OpenAI provider configured" )
102119
103120 anthropic_api_key = os .getenv ("ANTHROPIC_API_KEY" )
104121 if anthropic_api_key :
105- llm_config [ "providers" ] ["anthropic" ] = {
122+ providers_config ["anthropic" ] = {
106123 "api_key" : anthropic_api_key ,
107124 }
108125 logger .info ("Anthropic provider configured" )
109126
110127 # Determine default provider and fallback order based on available providers
111- available_providers = list (llm_config [ "providers" ] .keys ())
128+ available_providers = list (providers_config .keys ())
112129 if available_providers :
113130 # Set default provider to the first available one
114131 llm_config ["default_provider" ] = available_providers [0 ]
@@ -124,22 +141,24 @@ def __init__(self, display_config: DisplayConfig | None = None):
124141 logger .warning (" - ANTHROPIC_API_KEY" )
125142
126143 # Log final configuration
127- configured_providers = list (llm_config [ "providers" ] .keys ())
144+ configured_providers = list (providers_config .keys ())
128145 logger .info (
129146 "LLM configuration: default_provider=%s, fallback_order=%s, "
130147 "configured_providers=%s" ,
131- llm_config ['default_provider' ], llm_config ['fallback_order' ],
132- configured_providers
148+ llm_config ["default_provider" ],
149+ llm_config ["fallback_order" ],
150+ configured_providers ,
133151 )
134152
135153 # Initialize LLM manager with validation
154+ self .llm_manager : ActionLLMProviderManager | None
136155 if llm_config ["default_provider" ] is not None :
137156 self .llm_manager = ActionLLMProviderManager (
138157 llm_config , display = self .display
139158 )
140159 logger .info (
141160 "LLM manager initialized successfully with provider: %s" ,
142- llm_config ["default_provider" ]
161+ llm_config ["default_provider" ],
143162 )
144163 else :
145164 self .llm_manager = None
@@ -151,6 +170,7 @@ def __init__(self, display_config: DisplayConfig | None = None):
151170
152171 # Initialize AI agent manager only if LLM manager is available
153172 if self .llm_manager is not None :
173+ self .ai_agent_manager : AIAgentManager | None
154174 self .ai_agent_manager = AIAgentManager (
155175 self .llm_manager , self .performance_tracker
156176 )
@@ -164,20 +184,20 @@ def __init__(self, display_config: DisplayConfig | None = None):
164184
165185 # Initialize issue fixer only if AI agent manager is available
166186 if self .ai_agent_manager is not None :
187+ self .issue_fixer : IssueFixer | None
167188 self .issue_fixer = IssueFixer (
168189 self .ai_agent_manager , self .file_manager , self .error_handler
169190 )
170191 logger .info ("Issue fixer initialized successfully" )
171192 else :
172193 self .issue_fixer = None
173- logger .warning (
174- "Issue fixer not initialized - no AI capabilities available"
175- )
194+ logger .warning ("Issue fixer not initialized - no AI capabilities available" )
176195
177196 # Initialize database for logging interactions
178197 try :
179- from codeflow_engine .actions .ai_linting_fixer .database import \
180- AIInteractionDB
198+ from codeflow_engine .actions .ai_linting_fixer .database import (
199+ AIInteractionDB ,
200+ )
181201
182202 self .database = AIInteractionDB ()
183203 if self .issue_fixer is not None :
@@ -353,23 +373,31 @@ def _get_error_recovery_suggestions(
353373
354374 def is_ai_available (self ) -> bool :
355375 """Check if AI features are available (LLM provider configured)."""
356- return (self .llm_manager is not None and
357- self .ai_agent_manager is not None and
358- self .issue_fixer is not None )
376+ return (
377+ self .llm_manager is not None
378+ and self .ai_agent_manager is not None
379+ and self .issue_fixer is not None
380+ )
359381
360382 def get_ai_availability_message (self ) -> str :
361383 """Get a user-friendly message about AI availability and configuration instructions."""
362384 if self .is_ai_available ():
363385 return "AI features are available and ready to use."
364386
365- message = ("AI features are not available. To enable AI-powered linting fixes, "
366- "configure at least one LLM provider:\n \n " )
387+ message = (
388+ "AI features are not available. To enable AI-powered linting fixes, "
389+ "configure at least one LLM provider:\n \n "
390+ )
367391 message += "1. OpenAI: Set OPENAI_API_KEY environment variable\n "
368392 message += "2. Anthropic: Set ANTHROPIC_API_KEY environment variable\n "
369- message += ("3. Azure OpenAI: Set AZURE_OPENAI_API_KEY and "
370- "AZURE_OPENAI_ENDPOINT environment variables\n \n " )
371- message += ("Without AI providers, only issue detection will be available "
372- "(no automatic fixes)." )
393+ message += (
394+ "3. Azure OpenAI: Set AZURE_OPENAI_API_KEY and "
395+ "AZURE_OPENAI_ENDPOINT environment variables\n \n "
396+ )
397+ message += (
398+ "Without AI providers, only issue detection will be available "
399+ "(no automatic fixes)."
400+ )
373401 return message
374402
375403 def run (self , inputs : AILintingFixerInputs ) -> AILintingFixerOutputs :
@@ -424,7 +452,7 @@ def run(self, inputs: AILintingFixerInputs) -> AILintingFixerOutputs:
424452 self .display .operation .show_detection_results (
425453 filtered_count = len (filtered_issues ),
426454 total_count = len (issues ),
427- unique_files_count = unique_files_count
455+ unique_files_count = unique_files_count ,
428456 )
429457
430458 if not filtered_issues :
@@ -492,7 +520,9 @@ def run(self, inputs: AILintingFixerInputs) -> AILintingFixerOutputs:
492520
493521 for i , issue in enumerate (issues_to_process , 1 ):
494522 self .display .operation .show_processing_progress (
495- i , len (issues_to_process ), convert_detection_issue_to_model_issue (issue )
523+ i ,
524+ len (issues_to_process ),
525+ convert_detection_issue_to_model_issue (issue ),
496526 )
497527
498528 try :
@@ -567,7 +597,9 @@ def run(self, inputs: AILintingFixerInputs) -> AILintingFixerOutputs:
567597 processing_duration = time .time () - start_time
568598
569599 # Get performance metrics with defensive guard
570- get_perf = getattr (self .performance_tracker , "get_performance_summary" , None )
600+ get_perf = getattr (
601+ self .performance_tracker , "get_performance_summary" , None
602+ )
571603 if callable (get_perf ):
572604 performance_summary = get_perf ()
573605 else :
0 commit comments