forked from MervinPraison/PraisonAI
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontext_agent.py
More file actions
2499 lines (2004 loc) Β· 111 KB
/
context_agent.py
File metadata and controls
2499 lines (2004 loc) Β· 111 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""
ContextAgent - Advanced Context Engineering for AI Coding Assistants
This class implements proper Context Engineering principles following the PRD template:
- 10x better than prompt engineering
- 100x better than vibe coding
- Comprehensive context generation for first-try implementation success
- Systematic codebase analysis with modern tools
- PRP (Product Requirements Prompt) generation
- Validation loops and quality gates
- SAVES EVERY AGENT RESPONSE ALONG THE WAY for complete traceability
"""
import os
import json
import logging
from praisonaiagents._logging import get_logger
from datetime import datetime
from pathlib import Path
from typing import Optional, Any, Dict, Union, List, TYPE_CHECKING
# Lazy imports for performance - these are only loaded when needed
_subprocess = None
_glob = None
_ast = None
_asyncio = None
def _get_subprocess():
"""Lazy import subprocess to avoid import-time overhead."""
global _subprocess
if _subprocess is None:
import subprocess
_subprocess = subprocess
return _subprocess
def _get_glob():
"""Lazy import glob to avoid import-time overhead."""
global _glob
if _glob is None:
import glob
_glob = glob
return _glob
def _get_ast():
"""Lazy import ast to avoid import-time overhead."""
global _ast
if _ast is None:
import ast
_ast = ast
return _ast
def _get_asyncio():
"""Lazy import asyncio to avoid import-time overhead."""
global _asyncio
if _asyncio is None:
import asyncio
_asyncio = asyncio
return _asyncio
async def _async_subprocess_run(cmd: list, timeout: int = 60) -> tuple:
"""
Run subprocess asynchronously (non-blocking).
Args:
cmd: Command list to execute
timeout: Timeout in seconds
Returns:
Tuple of (stdout, stderr, returncode)
"""
asyncio = _get_asyncio()
try:
process = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await asyncio.wait_for(
process.communicate(),
timeout=timeout
)
return (
stdout.decode() if stdout else "",
stderr.decode() if stderr else "",
process.returncode
)
except asyncio.TimeoutError:
if process:
process.kill()
await process.wait()
raise
except FileNotFoundError:
raise
from ..agent.agent import Agent
from ..task import Task
class ContextAgent(Agent):
"""
Advanced Context Engineering Agent - Comprehensive context generation for AI coding assistants.
Implements the Context Engineering methodology from the PRD template:
Phase 1: Deep Codebase Analysis (using gitingest, AST analysis, etc.)
Phase 2: Pattern Extraction and Documentation
Phase 3: Comprehensive PRP Generation
Phase 4: Validation Framework Creation
Phase 5: Implementation Blueprint Generation
This follows the exact principles from the PRD template but adapted for PraisonAI architecture.
NEW: Saves every single agent response along the way for complete traceability!
"""
def __init__(
self,
name: Optional[str] = None,
role: Optional[str] = None,
goal: Optional[str] = None,
backstory: Optional[str] = None,
instructions: Optional[str] = None,
llm: Optional[Union[str, Any]] = None,
tools: Optional[List[Any]] = None,
project_path: Optional[str] = None,
auto_analyze: bool = True,
**kwargs
):
# Context Engineering specific defaults following PRD template
default_name = name or "Context Engineering Specialist"
default_role = role or "Expert Context Engineer and Product Requirements Analyst"
default_goal = goal or "Perform comprehensive codebase analysis and generate detailed PRPs for feature implementation"
default_backstory = backstory or """You are a world-class Context Engineering specialist with deep expertise in:
- Product Requirements Document (PRD) methodology
- Comprehensive codebase analysis and reverse engineering
- Feature implementation planning and architecture design
- Git repository ingestion and structured analysis
- Multi-agent orchestration for complex analysis tasks
Your approach follows systematic context engineering principles to understand codebases
deeply and generate actionable implementation guidance."""
# Initialize parent Agent
# Note: self.verbose is set by parent Agent based on output= parameter
super().__init__(
name=default_name,
role=default_role,
goal=default_goal,
backstory=default_backstory,
instructions=instructions,
llm=llm,
tools=tools or self._get_context_engineering_tools(),
**kwargs
)
# Context Engineering specific attributes
self.project_path = project_path
self.auto_analyze = auto_analyze
self.analysis_results = {}
self.prp_results = {}
self.context_documentation = {}
self.implementation_blueprint = {}
# Enhanced logging and output management
self.debug_mode = os.getenv('LOGLEVEL', '').lower() == 'debug'
from ..paths import get_project_prp_dir
self.output_dir = get_project_prp_dir() # Save in .praisonai/prp folder
self.setup_output_directories() # Create directories first
self.setup_logging() # Then setup logging
# Agent interaction tracking for comprehensive output
self.agent_interactions = []
self.interaction_counter = 0
# Auto-analyze if requested and project_path provided
if self.auto_analyze and self.project_path:
self._perform_context_engineering_analysis()
def _log(self, message: str, level: str = "info"):
"""
Configurable logging that respects verbose flag.
Args:
message: Message to log
level: Log level (info, debug, warning, error)
"""
if level == "debug":
if hasattr(self, 'logger'):
self.logger.debug(message)
if self.debug_mode:
print(f"π {message}")
elif level == "warning":
if hasattr(self, 'logger'):
self.logger.warning(message)
if self.verbose:
print(f"β οΈ {message}")
elif level == "error":
if hasattr(self, 'logger'):
self.logger.error(message)
print(f"β {message}") # Always show errors
else: # info
if hasattr(self, 'logger'):
self.logger.info(message)
if self.verbose:
print(message)
def setup_logging(self):
"""Setup comprehensive logging based on debug mode."""
try:
# Create logger
self.logger = get_logger(f"ContextAgent_{id(self)}")
self.logger.setLevel(logging.DEBUG if self.debug_mode else logging.INFO)
# Clear existing handlers
self.logger.handlers.clear()
# Console handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG if self.debug_mode else logging.INFO)
# File handler for debug mode
if self.debug_mode:
try:
log_file = self.output_dir / "debug_logs" / f"context_agent_debug_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
# Ensure the debug_logs directory exists
log_file.parent.mkdir(parents=True, exist_ok=True)
file_handler = logging.FileHandler(log_file)
file_handler.setLevel(logging.DEBUG)
# Detailed formatter for debug
debug_formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s'
)
file_handler.setFormatter(debug_formatter)
self.logger.addHandler(file_handler)
print(f"π Debug logging enabled: {log_file}")
except Exception as e:
print(f"β οΈ Warning: Could not setup debug file logging: {e}")
# Continue without file logging if it fails
# Console formatter
console_formatter = logging.Formatter('%(levelname)s - %(message)s')
console_handler.setFormatter(console_formatter)
self.logger.addHandler(console_handler)
except Exception as e:
print(f"β οΈ Warning: Could not setup logging: {e}")
# Create a minimal logger as fallback
self.logger = get_logger(f"ContextAgent_{id(self)}")
self.logger.setLevel(logging.INFO)
def setup_output_directories(self):
"""Setup all output directories for comprehensive saving."""
directories = [
self.output_dir,
self.output_dir / "agent_responses",
self.output_dir / "markdown_outputs",
self.output_dir / "debug_logs",
self.output_dir / "final_results"
]
for directory in directories:
directory.mkdir(parents=True, exist_ok=True)
if self.debug_mode:
print(f"π Debug: Output directories created: {[str(d) for d in directories]}")
def log_debug(self, message: str, **kwargs):
"""Enhanced debug logging with optional data."""
if self.debug_mode and hasattr(self, 'logger') and self.logger:
self.logger.debug(f"{message} {kwargs if kwargs else ''}")
elif self.debug_mode:
# Fallback to print if logger not ready
print(f"π DEBUG: {message} {kwargs if kwargs else ''}")
def save_markdown_output(self, content: str, filename: str, section_title: str = "Output"):
"""Save content as markdown file with proper formatting."""
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
markdown_content = f"""# {section_title}
**Generated:** {timestamp}
**ContextAgent Session:** {id(self)}
---
{content}
---
*Generated by ContextAgent - Context Engineering Specialist*
"""
# Save to markdown outputs directory
md_file = self.output_dir / "markdown_outputs" / f"{filename}.md"
with open(md_file, "w", encoding="utf-8") as f:
f.write(markdown_content)
print(f"π Markdown saved: {md_file}")
self.log_debug(f"Markdown output saved", file=str(md_file), length=len(content))
return str(md_file)
def save_comprehensive_session_report(self):
"""Save a comprehensive markdown report of the entire session (debug mode only)."""
if not self.debug_mode:
self.log_debug("Skipping comprehensive session report - not in debug mode")
return
if not self.agent_interactions:
self.log_debug("No agent interactions to save in comprehensive report")
return
timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
# Generate comprehensive markdown report
report = f"""# ContextAgent Session Report
**Session ID:** {id(self)}
**Generated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
**Total Agent Interactions:** {len(self.agent_interactions)}
**Debug Mode:** {'β
Enabled' if self.debug_mode else 'β Disabled'}
---
## π Session Summary
This report contains all agent interactions and outputs from a complete ContextAgent session.
### π― Agent Interactions Overview
"""
# Add interaction summary table
report += "| # | Agent | Phase | Response Length | Timestamp |\n"
report += "|---|-------|-------|-----------------|----------|\n"
for interaction in self.agent_interactions:
report += f"| {interaction['interaction_id']} | {interaction['agent_name']} | {interaction['phase']} | {len(interaction['response'])} chars | {interaction['timestamp']} |\n"
report += "\n---\n\n"
# Add detailed interactions
for i, interaction in enumerate(self.agent_interactions, 1):
report += f"""## π€ Agent {i}: {interaction['agent_name']}
**Phase:** {interaction['phase']}
**Timestamp:** {interaction['timestamp']}
**Response Length:** {len(interaction['response'])} characters
### π Prompt
```
{interaction['prompt'][:1000]}{'... [truncated]' if len(interaction['prompt']) > 1000 else ''}
```
### π― Response
{interaction['response']}
---
"""
# Save comprehensive report
report_file = self.save_markdown_output(
report,
f"comprehensive_session_report_{timestamp}",
"ContextAgent Comprehensive Session Report"
)
# Also save to final results
final_report_file = self.output_dir / "final_results" / f"session_report_{timestamp}.md"
with open(final_report_file, "w", encoding="utf-8") as f:
f.write(report)
print(f"π Comprehensive session report saved: {final_report_file}")
self.log_debug("Comprehensive session report generated", file=str(final_report_file))
return str(final_report_file)
def _save_agent_response(self, agent_name: str, prompt: str, response: str, phase: str = "", metadata: Dict[str, Any] = None) -> str:
"""Save individual agent response with mode-aware saving strategy."""
self.interaction_counter += 1
timestamp = datetime.now().isoformat()
# Enhanced debug logging
self.log_debug(f"Saving agent response",
agent=agent_name,
phase=phase,
response_length=len(response),
prompt_length=len(prompt))
interaction_data = {
"interaction_id": self.interaction_counter,
"timestamp": timestamp,
"phase": phase,
"agent_name": agent_name,
"prompt": prompt if self.debug_mode else prompt[:2000], # Full prompt in debug mode
"response": response,
"metadata": metadata or {}
}
# ALWAYS add to interactions list for final PRP
self.agent_interactions.append(interaction_data)
# ONLY save individual files in DEBUG MODE
if self.debug_mode:
# Save individual response file (JSON) - debug only
safe_agent_name = agent_name.lower().replace(' ', '_').replace('-', '_')
response_filename = f"{self.interaction_counter:03d}_{safe_agent_name}_{timestamp.replace(':', '_')}.json"
response_path = os.path.join(self.output_dir, "agent_responses", response_filename)
with open(response_path, "w") as f:
json.dump(interaction_data, f, indent=2)
# Save individual markdown files - debug only
md_filename = f"{self.interaction_counter:03d}_{safe_agent_name}_{timestamp.replace(':', '_')}"
self.save_markdown_output(
content=f"""## Agent: {agent_name}
**Phase:** {phase}
**Timestamp:** {timestamp}
**Response Length:** {len(response)} characters
### Prompt
```
{prompt[:1000]}{'... [truncated]' if len(prompt) > 1000 else ''}
```
### Response
{response}
""",
filename=md_filename,
section_title=f"{agent_name} - {phase}"
)
print(f"πΎ Agent response saved: {response_filename}")
self.log_debug(f"Agent response and markdown saved", json_file=response_filename, interaction_id=self.interaction_counter)
return response_path
else:
# In non-debug mode, just collect for final PRP
print(f"π Agent response collected for final PRP: {agent_name}")
return "collected_for_final_prp"
def _chat_with_agent_and_save(self, agent: Agent, prompt: str, phase: str = "") -> str:
"""Chat with agent and automatically save the response."""
print(f" π¬ Chatting with {agent.name}...")
response = agent.chat(prompt)
# Save the interaction
self._save_agent_response(
agent_name=agent.name,
prompt=prompt,
response=response,
phase=phase,
metadata={
"agent_role": agent.role,
"agent_goal": agent.goal,
"response_length": len(response)
}
)
return response
def _get_context_engineering_tools(self) -> List[Any]:
"""Get Context Engineering specific tools following PRD methodology."""
return [
self.analyze_codebase_with_gitingest,
self.perform_ast_analysis,
self.extract_implementation_patterns,
self.analyze_test_patterns,
self.generate_comprehensive_prp,
self.create_validation_framework,
self.build_implementation_blueprint,
self.compile_context_documentation,
self.analyze_integration_points,
self.create_quality_gates
]
def _perform_context_engineering_analysis(self):
"""Perform comprehensive Context Engineering analysis following PRD template phases."""
try:
print("π PHASE 1: Deep Codebase Analysis with Modern Tools...")
self.codebase_analysis = self.analyze_codebase_with_gitingest(self.project_path)
print("ποΈ PHASE 2: AST Analysis and Pattern Extraction...")
ast_analysis = self.perform_ast_analysis(self.project_path)
self.pattern_library = self.extract_implementation_patterns(self.project_path, ast_analysis)
print("π PHASE 3: Integration Point Analysis...")
self.integration_points = self.analyze_integration_points(self.project_path)
print("π PHASE 4: Context Documentation Compilation...")
self.context_documentation = self.compile_context_documentation(self.project_path)
print("β
PHASE 5: Validation Framework Creation...")
self.validation_framework = self.create_validation_framework(self.project_path)
print("π― Context Engineering analysis complete following PRD methodology!")
self._save_context_engineering_results()
# Generate summary report following PRD template
self._generate_analysis_summary()
except Exception as e:
print(f"β Context Engineering analysis failed: {e}")
# Fallback to basic analysis if advanced tools fail
self._perform_fallback_analysis()
def analyze_codebase_with_gitingest(self, project_path: str) -> Dict[str, Any]:
"""Analyze codebase using gitingest for comprehensive understanding."""
print(" π€ Creating Gitingest-Powered Codebase Analyst...")
try:
# Try to use gitingest for comprehensive analysis
digest_content = self._run_gitingest_analysis(project_path)
if digest_content:
# Create specialized analyst to process gitingest output
gitingest_analyst = Agent(
name="Gitingest Codebase Analyst",
role="Expert Codebase Analysis Specialist using Gitingest",
goal="Perform comprehensive codebase analysis using gitingest output following PRD methodology",
instructions="""You are an expert at analyzing gitingest codebase digests following the PRD template methodology.
Analyze the gitingest output to extract:
1. PROJECT STRUCTURE: Complete directory organization and file hierarchies
2. CODE PATTERNS: All classes, functions, decorators, inheritance patterns
3. ARCHITECTURAL INSIGHTS: Design patterns, architectural styles, layer organization
4. NAMING CONVENTIONS: Consistent naming styles and patterns across the codebase
5. IMPORT PATTERNS: Module dependencies, relative vs absolute imports
6. TESTING PATTERNS: Test organization, frameworks, coverage approaches
7. DOCUMENTATION PATTERNS: Docstring styles, README structure, API documentation
8. CONFIGURATION PATTERNS: Environment handling, settings management
9. ERROR HANDLING: Exception patterns, logging approaches, error management
10. INTEGRATION PATTERNS: API integrations, database patterns, external services
Provide comprehensive analysis that follows the PRD template principles and enables
AI assistants to implement features that perfectly match existing codebase patterns.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
prompt = f"""Analyze this gitingest codebase digest following PRD template methodology:
PROJECT PATH: {project_path}
GITINGEST COMPREHENSIVE ANALYSIS:
{digest_content[:8000]} # Limit for context window
Perform deep analysis following the 10 categories above. Focus on patterns that would
enable an AI assistant to implement new features that perfectly match the existing
codebase style and architecture following PRD template principles."""
print(" π Gitingest Analyst analyzing comprehensive codebase digest...")
# Use the new save method
response = self._chat_with_agent_and_save(gitingest_analyst, prompt, "PHASE_1_GITINGEST_ANALYSIS")
analysis = {
"analysis_method": "gitingest",
"project_structure": {"analysis": response[:1000]},
"code_patterns": {"analysis": response},
"architectural_insights": {"analysis": response},
"gitingest_digest": digest_content[:2000],
"full_analysis": response
}
print(f" β
Gitingest comprehensive analysis complete")
return analysis
except Exception as e:
print(f" β οΈ Gitingest analysis failed: {e}, falling back to manual analysis")
# Fallback to manual analysis if gitingest fails
return self._perform_manual_codebase_analysis(project_path)
def _run_gitingest_analysis(self, project_path: str) -> str:
"""Run gitingest analysis on the codebase."""
try:
# Try to run gitingest command
result = _get_subprocess().run(
["gitingest", project_path, "--output", "-"],
capture_output=True,
text=True,
timeout=60
)
if result.returncode == 0:
return result.stdout
else:
print(f" β οΈ Gitingest command failed: {result.stderr}")
return None
except _get_subprocess().TimeoutExpired:
print(" β οΈ Gitingest analysis timed out")
return None
except FileNotFoundError:
print(" β οΈ Gitingest not found, trying alternative analysis")
return None
except Exception as e:
print(f" β οΈ Gitingest error: {e}")
return None
def _perform_manual_codebase_analysis(self, project_path: str) -> Dict[str, Any]:
"""Fallback manual codebase analysis when gitingest is not available."""
print(" π§ Performing manual codebase analysis...")
# Get comprehensive file samples using manual methods
python_files = self._get_filtered_files(project_path, "*.py", 20)
config_files = self._get_filtered_files(project_path, "*.json", 5)
config_files.extend(self._get_filtered_files(project_path, "*.toml", 5))
config_files.extend(self._get_filtered_files(project_path, "*.yaml", 5))
doc_files = self._get_filtered_files(project_path, "*.md", 10)
# Create comprehensive manual analyst
manual_analyst = Agent(
name="Manual Codebase Analyst",
role="Expert Manual Codebase Analysis Specialist",
goal="Perform comprehensive manual codebase analysis following PRD methodology",
instructions="""Analyze the codebase samples following PRD template methodology for complete understanding.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Format comprehensive sample
comprehensive_content = self._format_comprehensive_samples(
python_files, config_files, doc_files, project_path
)
prompt = f"""Perform comprehensive manual codebase analysis following PRD template methodology:
PROJECT PATH: {project_path}
COMPREHENSIVE CODEBASE SAMPLES:
{comprehensive_content}
Analyze following PRD principles to extract patterns, conventions, and architectural insights."""
print(" π Manual Analyst analyzing codebase samples...")
# Use the new save method
response = self._chat_with_agent_and_save(manual_analyst, prompt, "PHASE_1_MANUAL_ANALYSIS")
analysis = {
"analysis_method": "manual",
"project_structure": {"analysis": response[:1000]},
"code_patterns": {"analysis": response},
"architectural_insights": {"analysis": response},
"full_analysis": response
}
print(f" β
Manual codebase analysis complete")
return analysis
def perform_ast_analysis(self, project_path: str) -> Dict[str, Any]:
"""Perform AST (Abstract Syntax Tree) analysis for code patterns."""
print(" π€ Creating AST Pattern Analyzer...")
ast_analyzer = Agent(
name="AST Pattern Analyzer",
role="Abstract Syntax Tree Analysis Expert",
goal="Extract code patterns and structures using AST analysis following PRD methodology",
instructions="""You are an expert at AST analysis for pattern extraction following PRD principles.
Analyze the AST information to identify:
1. Class hierarchies and inheritance patterns
2. Function signatures and patterns
3. Import dependencies and module structure
4. Decorator usage patterns
5. Exception handling patterns
6. Design pattern implementations
7. Code complexity metrics
8. API and interface patterns""",
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Perform AST analysis on Python files
python_files = self._get_filtered_files(project_path, "*.py", 15)
ast_data = self._extract_ast_patterns(python_files)
prompt = f"""Analyze AST patterns from this codebase following PRD methodology:
PROJECT PATH: {project_path}
AST ANALYSIS DATA:
{json.dumps(ast_data, indent=2)[:4000]}
Extract comprehensive patterns that follow PRD template principles for implementation guidance."""
print(" π AST Analyzer processing code patterns...")
# Use the new save method
response = self._chat_with_agent_and_save(ast_analyzer, prompt, "PHASE_2_AST_ANALYSIS")
patterns = {
"ast_method": True,
"class_patterns": ast_data.get("classes", []),
"function_patterns": ast_data.get("functions", []),
"import_patterns": ast_data.get("imports", []),
"decorator_patterns": ast_data.get("decorators", []),
"full_analysis": response
}
print(f" β
AST analysis complete: {len(patterns.get('class_patterns', []))} classes, {len(patterns.get('function_patterns', []))} functions analyzed")
return patterns
def extract_implementation_patterns(self, project_path: str, ast_analysis: Dict[str, Any] = None) -> Dict[str, Any]:
"""Extract reusable implementation patterns following PRD methodology."""
print(" π€ Creating Implementation Pattern Extractor...")
pattern_extractor = Agent(
name="Implementation Pattern Extractor",
role="Code Pattern Recognition Expert following PRD methodology",
goal="Extract reusable implementation patterns and best practices following PRD template principles",
instructions="""You are an expert at identifying and extracting reusable implementation
patterns from codebases following PRD template methodology. Focus on patterns that enable
first-try implementation success. Analyze to find:
1. DESIGN PATTERNS: Factory, Observer, Strategy, Singleton, etc.
2. ARCHITECTURAL PATTERNS: MVC, Repository, Service Layer, etc.
3. CODE ORGANIZATION: Module structure, class hierarchies, function patterns
4. ERROR HANDLING: Try-catch patterns, custom exceptions, logging
5. DATA HANDLING: Validation patterns, serialization, database interactions
6. TESTING PATTERNS: Test structure, mocking approaches, fixture patterns
7. ASYNC PATTERNS: Async/await usage, concurrency patterns
8. INTEGRATION PATTERNS: API clients, external service patterns
9. CONFIGURATION PATTERNS: Settings management, environment variables
10. UTILITY PATTERNS: Common helper functions, decorators, context managers
For each pattern, provide the pattern name, where it's used, and how to replicate it
following PRD template principles.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Get representative code samples
samples = self._get_pattern_samples(project_path)
# Include AST analysis if available
ast_info = ""
if ast_analysis:
ast_info = f"\nAST ANALYSIS:\n{json.dumps(ast_analysis, indent=2)[:2000]}"
prompt = f"""Extract implementation patterns following PRD methodology:
PROJECT PATH: {project_path}
CODE SAMPLES:
{samples}
{ast_info}
Identify and document all reusable implementation patterns that follow PRD template
principles and would help an AI assistant implement new features using the same
patterns and best practices for first-try success."""
print(" π Pattern Extractor analyzing implementation patterns...")
# Use the new save method
response = self._chat_with_agent_and_save(pattern_extractor, prompt, "PHASE_2_PATTERN_EXTRACTION")
patterns = {
"patterns_identified": response.count("PATTERN"),
"design_patterns": [],
"architectural_patterns": [],
"testing_patterns": [],
"integration_patterns": [],
"full_analysis": response
}
print(f" β
Extracted implementation patterns following PRD methodology")
return patterns
def analyze_test_patterns(self, project_path: str) -> Dict[str, Any]:
"""Analyze testing patterns for validation framework creation."""
print(" π€ Creating Test Pattern Analyzer...")
test_analyzer = Agent(
name="Test Pattern Analyzer",
role="Testing Pattern Recognition Expert",
goal="Analyze testing patterns for comprehensive validation framework design",
instructions="""Analyze testing patterns to understand validation approaches and create
comprehensive test frameworks following PRD methodology.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Get test files
test_files = self._get_filtered_files(project_path, "*test*.py", 10)
test_files.extend(self._get_filtered_files(project_path, "test_*.py", 10))
test_files.extend(self._get_filtered_files(project_path, "conftest.py", 5))
test_content = self._format_sample_files(test_files, project_path)
prompt = f"""Analyze testing patterns following PRD methodology:
PROJECT PATH: {project_path}
TEST PATTERNS:
{test_content}
Extract testing patterns for validation framework creation following PRD principles."""
print(" π Test Analyzer processing testing patterns...")
# Use the new save method
response = self._chat_with_agent_and_save(test_analyzer, prompt, "PHASE_2_TEST_ANALYSIS")
patterns = {
"test_files_analyzed": len(test_files),
"testing_frameworks": [],
"test_patterns": [],
"validation_approaches": [],
"full_analysis": response
}
print(f" β
Test pattern analysis complete: {len(test_files)} test files analyzed")
return patterns
def generate_comprehensive_prp(self, feature_request: str, context_analysis: Dict[str, Any] = None) -> str:
"""Generate comprehensive Product Requirements Prompt following PRD template exactly."""
print(" π€ Creating PRP Generation Specialist following PRD template...")
if context_analysis is None:
context_analysis = {
"codebase_analysis": self.codebase_analysis,
"pattern_library": self.pattern_library,
"integration_points": getattr(self, 'integration_points', {}),
"validation_framework": self.validation_framework,
"context_documentation": self.context_documentation
}
prp_generator = Agent(
name="PRP Generation Specialist",
role="Product Requirements Prompt Expert following PRD Template",
goal="Generate comprehensive PRPs following the exact PRD template methodology for first-try implementation success",
instructions="""You are an expert at generating comprehensive Product Requirements Prompts (PRPs)
following the exact PRD template methodology. Your PRPs must follow the PRD template structure exactly:
## Purpose
Clear statement of what needs to be built
## Core Principles
1. Context is King: Include ALL necessary documentation, examples, and caveats
2. Validation Loops: Provide executable tests/lints the AI can run and fix
3. Information Dense: Use keywords and patterns from the codebase
4. Progressive Success: Start simple, validate, then enhance
## Goal
What needs to be built - specific about end state
## Why
- Business value and user impact
- Integration with existing features
- Problems this solves
## What
User-visible behavior and technical requirements
### Success Criteria
- [ ] Specific measurable outcomes
## All Needed Context
### Documentation & References
Complete list of all context needed
### Current Codebase tree
Run tree command output
### Desired Codebase tree
Files to be added with responsibilities
### Known Gotchas & Library Quirks
Critical implementation details
## Implementation Blueprint
### Data models and structure
Core data models for type safety
### List of tasks to be completed
Ordered task list for implementation
### Per task pseudocode
Detailed pseudocode with critical details
### Integration Points
Database, config, route changes needed
## Validation Loop
### Level 1: Syntax & Style
Executable commands for validation
### Level 2: Unit Tests
Test cases with expected outcomes
### Level 3: Integration Test
End-to-end validation steps
## Final Validation Checklist
Complete checklist for verification
## Anti-Patterns to Avoid
Common mistakes to prevent
## Confidence Score: X/10
Confidence level for one-pass implementation
Generate PRPs following this EXACT structure for first-try implementation success.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
prompt = f"""Generate a comprehensive Product Requirements Prompt (PRP) following the EXACT PRD template structure:
FEATURE REQUEST: {feature_request}
COMPREHENSIVE CONTEXT ANALYSIS:
{json.dumps(context_analysis, indent=2)[:6000]}
PROJECT PATH: {self.project_path}
Create a PRP that follows the PRD template methodology EXACTLY with all sections:
- Purpose and Core Principles
- Goal, Why, What with Success Criteria
- All Needed Context with Documentation & References
- Implementation Blueprint with tasks and pseudocode
- Validation Loop with executable commands
- Final checklist and confidence score
Include ALL necessary context for an AI assistant to implement this feature correctly
on the first try following PRD template principles."""
print(" π PRP Generator creating comprehensive PRP following PRD template...")
# Use the new save method
prp = self._chat_with_agent_and_save(prp_generator, prompt, "PHASE_3_PRP_GENERATION")
print(f" β
Comprehensive PRP generated following PRD template ({len(prp)} characters)")
return prp
# Continue with remaining methods using the new save approach...
def create_validation_framework(self, project_path: str) -> Dict[str, Any]:
"""Create comprehensive validation framework following PRD methodology."""
print(" π€ Creating Validation Framework Architect...")
validation_architect = Agent(
name="Validation Framework Architect",
role="Quality Assurance Expert following PRD methodology",
goal="Design comprehensive validation frameworks following PRD template principles",
instructions="""Design validation frameworks following PRD methodology that include:
1. SYNTAX VALIDATION: Linting, formatting, type checking
2. UNIT TESTING: Comprehensive test coverage strategies
3. INTEGRATION TESTING: End-to-end testing approaches
4. PERFORMANCE VALIDATION: Performance benchmarks
5. SECURITY VALIDATION: Security best practices
6. CODE QUALITY: Complexity analysis, maintainability
7. DOCUMENTATION VALIDATION: Documentation completeness
8. DEPENDENCY VALIDATION: Dependency analysis and security""",
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Analyze existing validation patterns
test_files = self._get_filtered_files(project_path, "*test*.py", 10)
config_files = self._get_filtered_files(project_path, "*.toml", 3)
config_files.extend(self._get_filtered_files(project_path, "pyproject.toml", 1))
validation_content = self._format_sample_files(test_files + config_files, project_path)
prompt = f"""Design comprehensive validation framework following PRD methodology:
PROJECT PATH: {project_path}
EXISTING VALIDATION PATTERNS:
{validation_content}
Create validation framework with all 8 validation types and executable commands
following PRD template principles."""
print(" π Validation Architect designing framework...")
# Use the new save method
response = self._chat_with_agent_and_save(validation_architect, prompt, "PHASE_5_VALIDATION_FRAMEWORK")
framework = {
"syntax_validation": ["ruff check", "mypy"],
"testing_validation": ["pytest", "pytest --cov"],
"quality_gates": ["coverage report", "complexity analysis"],
"integration_tests": ["end-to-end test commands"],
"full_framework": response
}
print(f" β
Validation framework created following PRD methodology")
return framework
def compile_context_documentation(self, project_path: str) -> Dict[str, Any]:
"""Compile all context documentation following PRD methodology."""
print(" π€ Creating Context Documentation Compiler...")
doc_compiler = Agent(
name="Context Documentation Compiler",
role="Documentation Analysis Expert following PRD methodology",
goal="Compile comprehensive context documentation following PRD template principles",
instructions="""Compile all available documentation following PRD methodology including:
README files, API documentation, setup guides, architecture docs, and any other
relevant documentation that provides context for implementation.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Get documentation files
doc_files = self._get_filtered_files(project_path, "*.md", 10)
doc_files.extend(self._get_filtered_files(project_path, "*.rst", 5))
doc_files.extend(self._get_filtered_files(project_path, "*.txt", 5))