praisonaiagents 0.0.144__py3-none-any.whl → 0.0.146__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2315 @@
1
+ """
2
+ ContextAgent - Advanced Context Engineering for AI Coding Assistants
3
+
4
+ This class implements proper Context Engineering principles following the PRD template:
5
+ - 10x better than prompt engineering
6
+ - 100x better than vibe coding
7
+ - Comprehensive context generation for first-try implementation success
8
+ - Systematic codebase analysis with modern tools
9
+ - PRP (Product Requirements Prompt) generation
10
+ - Validation loops and quality gates
11
+ - SAVES EVERY AGENT RESPONSE ALONG THE WAY for complete traceability
12
+ """
13
+
14
+ import os
15
+ import json
16
+ import asyncio
17
+ import glob
18
+ import subprocess
19
+ import ast
20
+ import logging
21
+ from datetime import datetime
22
+ from pathlib import Path
23
+ from typing import Optional, Any, Dict, Union, List
24
+ from ..agent.agent import Agent
25
+ from ..task import Task
26
+
27
+ class ContextAgent(Agent):
28
+ """
29
+ Advanced Context Engineering Agent - Comprehensive context generation for AI coding assistants.
30
+
31
+ Implements the Context Engineering methodology from the PRD template:
32
+
33
+ Phase 1: Deep Codebase Analysis (using gitingest, AST analysis, etc.)
34
+ Phase 2: Pattern Extraction and Documentation
35
+ Phase 3: Comprehensive PRP Generation
36
+ Phase 4: Validation Framework Creation
37
+ Phase 5: Implementation Blueprint Generation
38
+
39
+ This follows the exact principles from the PRD template but adapted for PraisonAI architecture.
40
+
41
+ NEW: Saves every single agent response along the way for complete traceability!
42
+ """
43
+
44
+ def __init__(
45
+ self,
46
+ name: Optional[str] = None,
47
+ role: Optional[str] = None,
48
+ goal: Optional[str] = None,
49
+ backstory: Optional[str] = None,
50
+ instructions: Optional[str] = None,
51
+ llm: Optional[Union[str, Any]] = None,
52
+ tools: Optional[List[Any]] = None,
53
+ project_path: Optional[str] = None,
54
+ auto_analyze: bool = True,
55
+ **kwargs
56
+ ):
57
+ # Context Engineering specific defaults following PRD template
58
+ default_name = name or "Context Engineering Specialist"
59
+ default_role = role or "Expert Context Engineer and Product Requirements Analyst"
60
+ default_goal = goal or "Perform comprehensive codebase analysis and generate detailed PRPs for feature implementation"
61
+ default_backstory = backstory or """You are a world-class Context Engineering specialist with deep expertise in:
62
+ - Product Requirements Document (PRD) methodology
63
+ - Comprehensive codebase analysis and reverse engineering
64
+ - Feature implementation planning and architecture design
65
+ - Git repository ingestion and structured analysis
66
+ - Multi-agent orchestration for complex analysis tasks
67
+
68
+ Your approach follows systematic context engineering principles to understand codebases
69
+ deeply and generate actionable implementation guidance."""
70
+
71
+ # Initialize parent Agent
72
+ super().__init__(
73
+ name=default_name,
74
+ role=default_role,
75
+ goal=default_goal,
76
+ backstory=default_backstory,
77
+ instructions=instructions,
78
+ llm=llm,
79
+ tools=tools or self._get_context_engineering_tools(),
80
+ **kwargs
81
+ )
82
+
83
+ # Context Engineering specific attributes
84
+ self.project_path = project_path
85
+ self.auto_analyze = auto_analyze
86
+ self.analysis_results = {}
87
+ self.prp_results = {}
88
+ self.context_documentation = {}
89
+ self.implementation_blueprint = {}
90
+
91
+ # Enhanced logging and output management
92
+ self.debug_mode = os.getenv('LOGLEVEL', '').lower() == 'debug'
93
+ self.output_dir = Path(".praison/prp") # Save in .praison/prp folder
94
+ self.setup_output_directories() # Create directories first
95
+ self.setup_logging() # Then setup logging
96
+
97
+ # Agent interaction tracking for comprehensive output
98
+ self.agent_interactions = []
99
+ self.interaction_counter = 0
100
+
101
+ # Auto-analyze if requested and project_path provided
102
+ if self.auto_analyze and self.project_path:
103
+ self._perform_context_engineering_analysis()
104
+
105
+ def setup_logging(self):
106
+ """Setup comprehensive logging based on debug mode."""
107
+ try:
108
+ # Create logger
109
+ self.logger = logging.getLogger(f"ContextAgent_{id(self)}")
110
+ self.logger.setLevel(logging.DEBUG if self.debug_mode else logging.INFO)
111
+
112
+ # Clear existing handlers
113
+ self.logger.handlers.clear()
114
+
115
+ # Console handler
116
+ console_handler = logging.StreamHandler()
117
+ console_handler.setLevel(logging.DEBUG if self.debug_mode else logging.INFO)
118
+
119
+ # File handler for debug mode
120
+ if self.debug_mode:
121
+ try:
122
+ log_file = self.output_dir / "debug_logs" / f"context_agent_debug_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
123
+ # Ensure the debug_logs directory exists
124
+ log_file.parent.mkdir(parents=True, exist_ok=True)
125
+
126
+ file_handler = logging.FileHandler(log_file)
127
+ file_handler.setLevel(logging.DEBUG)
128
+
129
+ # Detailed formatter for debug
130
+ debug_formatter = logging.Formatter(
131
+ '%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s'
132
+ )
133
+ file_handler.setFormatter(debug_formatter)
134
+ self.logger.addHandler(file_handler)
135
+
136
+ print(f"🐛 Debug logging enabled: {log_file}")
137
+ except Exception as e:
138
+ print(f"⚠️ Warning: Could not setup debug file logging: {e}")
139
+ # Continue without file logging if it fails
140
+
141
+ # Console formatter
142
+ console_formatter = logging.Formatter('%(levelname)s - %(message)s')
143
+ console_handler.setFormatter(console_formatter)
144
+ self.logger.addHandler(console_handler)
145
+
146
+ except Exception as e:
147
+ print(f"⚠️ Warning: Could not setup logging: {e}")
148
+ # Create a minimal logger as fallback
149
+ self.logger = logging.getLogger(f"ContextAgent_{id(self)}")
150
+ self.logger.setLevel(logging.INFO)
151
+
152
+ def setup_output_directories(self):
153
+ """Setup all output directories for comprehensive saving."""
154
+ directories = [
155
+ self.output_dir,
156
+ self.output_dir / "agent_responses",
157
+ self.output_dir / "markdown_outputs",
158
+ self.output_dir / "debug_logs",
159
+ self.output_dir / "final_results"
160
+ ]
161
+
162
+ for directory in directories:
163
+ directory.mkdir(parents=True, exist_ok=True)
164
+
165
+ if self.debug_mode:
166
+ print(f"🐛 Debug: Output directories created: {[str(d) for d in directories]}")
167
+
168
+ def log_debug(self, message: str, **kwargs):
169
+ """Enhanced debug logging with optional data."""
170
+ if self.debug_mode and hasattr(self, 'logger') and self.logger:
171
+ self.logger.debug(f"{message} {kwargs if kwargs else ''}")
172
+ elif self.debug_mode:
173
+ # Fallback to print if logger not ready
174
+ print(f"🐛 DEBUG: {message} {kwargs if kwargs else ''}")
175
+
176
+ def save_markdown_output(self, content: str, filename: str, section_title: str = "Output"):
177
+ """Save content as markdown file with proper formatting."""
178
+ timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
179
+
180
+ markdown_content = f"""# {section_title}
181
+
182
+ **Generated:** {timestamp}
183
+ **ContextAgent Session:** {id(self)}
184
+
185
+ ---
186
+
187
+ {content}
188
+
189
+ ---
190
+ *Generated by ContextAgent - Context Engineering Specialist*
191
+ """
192
+
193
+ # Save to markdown outputs directory
194
+ md_file = self.output_dir / "markdown_outputs" / f"{filename}.md"
195
+ with open(md_file, "w", encoding="utf-8") as f:
196
+ f.write(markdown_content)
197
+
198
+ print(f"📝 Markdown saved: {md_file}")
199
+ self.log_debug(f"Markdown output saved", file=str(md_file), length=len(content))
200
+
201
+ return str(md_file)
202
+
203
+ def save_comprehensive_session_report(self):
204
+ """Save a comprehensive markdown report of the entire session (debug mode only)."""
205
+ if not self.debug_mode:
206
+ self.log_debug("Skipping comprehensive session report - not in debug mode")
207
+ return
208
+
209
+ if not self.agent_interactions:
210
+ self.log_debug("No agent interactions to save in comprehensive report")
211
+ return
212
+
213
+ timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
214
+
215
+ # Generate comprehensive markdown report
216
+ report = f"""# ContextAgent Session Report
217
+
218
+ **Session ID:** {id(self)}
219
+ **Generated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
220
+ **Total Agent Interactions:** {len(self.agent_interactions)}
221
+ **Debug Mode:** {'✅ Enabled' if self.debug_mode else '❌ Disabled'}
222
+
223
+ ---
224
+
225
+ ## 📋 Session Summary
226
+
227
+ This report contains all agent interactions and outputs from a complete ContextAgent session.
228
+
229
+ ### 🎯 Agent Interactions Overview
230
+
231
+ """
232
+
233
+ # Add interaction summary table
234
+ report += "| # | Agent | Phase | Response Length | Timestamp |\n"
235
+ report += "|---|-------|-------|-----------------|----------|\n"
236
+
237
+ for interaction in self.agent_interactions:
238
+ report += f"| {interaction['interaction_id']} | {interaction['agent_name']} | {interaction['phase']} | {len(interaction['response'])} chars | {interaction['timestamp']} |\n"
239
+
240
+ report += "\n---\n\n"
241
+
242
+ # Add detailed interactions
243
+ for i, interaction in enumerate(self.agent_interactions, 1):
244
+ report += f"""## 🤖 Agent {i}: {interaction['agent_name']}
245
+
246
+ **Phase:** {interaction['phase']}
247
+ **Timestamp:** {interaction['timestamp']}
248
+ **Response Length:** {len(interaction['response'])} characters
249
+
250
+ ### 📝 Prompt
251
+ ```
252
+ {interaction['prompt'][:1000]}{'... [truncated]' if len(interaction['prompt']) > 1000 else ''}
253
+ ```
254
+
255
+ ### 🎯 Response
256
+ {interaction['response']}
257
+
258
+ ---
259
+
260
+ """
261
+
262
+ # Save comprehensive report
263
+ report_file = self.save_markdown_output(
264
+ report,
265
+ f"comprehensive_session_report_{timestamp}",
266
+ "ContextAgent Comprehensive Session Report"
267
+ )
268
+
269
+ # Also save to final results
270
+ final_report_file = self.output_dir / "final_results" / f"session_report_{timestamp}.md"
271
+ with open(final_report_file, "w", encoding="utf-8") as f:
272
+ f.write(report)
273
+
274
+ print(f"📊 Comprehensive session report saved: {final_report_file}")
275
+ self.log_debug("Comprehensive session report generated", file=str(final_report_file))
276
+
277
+ return str(final_report_file)
278
+
279
+ def _save_agent_response(self, agent_name: str, prompt: str, response: str, phase: str = "", metadata: Dict[str, Any] = None) -> str:
280
+ """Save individual agent response with mode-aware saving strategy."""
281
+ self.interaction_counter += 1
282
+ timestamp = datetime.now().isoformat()
283
+
284
+ # Enhanced debug logging
285
+ self.log_debug(f"Saving agent response",
286
+ agent=agent_name,
287
+ phase=phase,
288
+ response_length=len(response),
289
+ prompt_length=len(prompt))
290
+
291
+ interaction_data = {
292
+ "interaction_id": self.interaction_counter,
293
+ "timestamp": timestamp,
294
+ "phase": phase,
295
+ "agent_name": agent_name,
296
+ "prompt": prompt if self.debug_mode else prompt[:2000], # Full prompt in debug mode
297
+ "response": response,
298
+ "metadata": metadata or {}
299
+ }
300
+
301
+ # ALWAYS add to interactions list for final PRP
302
+ self.agent_interactions.append(interaction_data)
303
+
304
+ # ONLY save individual files in DEBUG MODE
305
+ if self.debug_mode:
306
+ # Save individual response file (JSON) - debug only
307
+ safe_agent_name = agent_name.lower().replace(' ', '_').replace('-', '_')
308
+ response_filename = f"{self.interaction_counter:03d}_{safe_agent_name}_{timestamp.replace(':', '_')}.json"
309
+ response_path = os.path.join(self.output_dir, "agent_responses", response_filename)
310
+
311
+ with open(response_path, "w") as f:
312
+ json.dump(interaction_data, f, indent=2)
313
+
314
+ # Save individual markdown files - debug only
315
+ md_filename = f"{self.interaction_counter:03d}_{safe_agent_name}_{timestamp.replace(':', '_')}"
316
+ self.save_markdown_output(
317
+ content=f"""## Agent: {agent_name}
318
+ **Phase:** {phase}
319
+ **Timestamp:** {timestamp}
320
+ **Response Length:** {len(response)} characters
321
+
322
+ ### Prompt
323
+ ```
324
+ {prompt[:1000]}{'... [truncated]' if len(prompt) > 1000 else ''}
325
+ ```
326
+
327
+ ### Response
328
+ {response}
329
+ """,
330
+ filename=md_filename,
331
+ section_title=f"{agent_name} - {phase}"
332
+ )
333
+
334
+ print(f"💾 Agent response saved: {response_filename}")
335
+ self.log_debug(f"Agent response and markdown saved", json_file=response_filename, interaction_id=self.interaction_counter)
336
+ return response_path
337
+ else:
338
+ # In non-debug mode, just collect for final PRP
339
+ print(f"📝 Agent response collected for final PRP: {agent_name}")
340
+ return "collected_for_final_prp"
341
+
342
+ def _chat_with_agent_and_save(self, agent: Agent, prompt: str, phase: str = "") -> str:
343
+ """Chat with agent and automatically save the response."""
344
+ print(f" 💬 Chatting with {agent.name}...")
345
+ response = agent.chat(prompt)
346
+
347
+ # Save the interaction
348
+ self._save_agent_response(
349
+ agent_name=agent.name,
350
+ prompt=prompt,
351
+ response=response,
352
+ phase=phase,
353
+ metadata={
354
+ "agent_role": agent.role,
355
+ "agent_goal": agent.goal,
356
+ "response_length": len(response)
357
+ }
358
+ )
359
+
360
+ return response
361
+
362
+ def _get_context_engineering_tools(self) -> List[Any]:
363
+ """Get Context Engineering specific tools following PRD methodology."""
364
+ return [
365
+ self.analyze_codebase_with_gitingest,
366
+ self.perform_ast_analysis,
367
+ self.extract_implementation_patterns,
368
+ self.analyze_test_patterns,
369
+ self.generate_comprehensive_prp,
370
+ self.create_validation_framework,
371
+ self.build_implementation_blueprint,
372
+ self.compile_context_documentation,
373
+ self.analyze_integration_points,
374
+ self.create_quality_gates
375
+ ]
376
+
377
+ def _perform_context_engineering_analysis(self):
378
+ """Perform comprehensive Context Engineering analysis following PRD template phases."""
379
+ try:
380
+ print("📊 PHASE 1: Deep Codebase Analysis with Modern Tools...")
381
+ self.codebase_analysis = self.analyze_codebase_with_gitingest(self.project_path)
382
+
383
+ print("🏗️ PHASE 2: AST Analysis and Pattern Extraction...")
384
+ ast_analysis = self.perform_ast_analysis(self.project_path)
385
+ self.pattern_library = self.extract_implementation_patterns(self.project_path, ast_analysis)
386
+
387
+ print("🔗 PHASE 3: Integration Point Analysis...")
388
+ self.integration_points = self.analyze_integration_points(self.project_path)
389
+
390
+ print("📚 PHASE 4: Context Documentation Compilation...")
391
+ self.context_documentation = self.compile_context_documentation(self.project_path)
392
+
393
+ print("✅ PHASE 5: Validation Framework Creation...")
394
+ self.validation_framework = self.create_validation_framework(self.project_path)
395
+
396
+ print("🎯 Context Engineering analysis complete following PRD methodology!")
397
+ self._save_context_engineering_results()
398
+
399
+ # Generate summary report following PRD template
400
+ self._generate_analysis_summary()
401
+
402
+ except Exception as e:
403
+ print(f"❌ Context Engineering analysis failed: {e}")
404
+ # Fallback to basic analysis if advanced tools fail
405
+ self._perform_fallback_analysis()
406
+
407
+ def analyze_codebase_with_gitingest(self, project_path: str) -> Dict[str, Any]:
408
+ """Analyze codebase using gitingest for comprehensive understanding."""
409
+ print(" 🤖 Creating Gitingest-Powered Codebase Analyst...")
410
+
411
+ try:
412
+ # Try to use gitingest for comprehensive analysis
413
+ digest_content = self._run_gitingest_analysis(project_path)
414
+
415
+ if digest_content:
416
+ # Create specialized analyst to process gitingest output
417
+ gitingest_analyst = Agent(
418
+ name="Gitingest Codebase Analyst",
419
+ role="Expert Codebase Analysis Specialist using Gitingest",
420
+ goal="Perform comprehensive codebase analysis using gitingest output following PRD methodology",
421
+ instructions="""You are an expert at analyzing gitingest codebase digests following the PRD template methodology.
422
+
423
+ Analyze the gitingest output to extract:
424
+ 1. PROJECT STRUCTURE: Complete directory organization and file hierarchies
425
+ 2. CODE PATTERNS: All classes, functions, decorators, inheritance patterns
426
+ 3. ARCHITECTURAL INSIGHTS: Design patterns, architectural styles, layer organization
427
+ 4. NAMING CONVENTIONS: Consistent naming styles and patterns across the codebase
428
+ 5. IMPORT PATTERNS: Module dependencies, relative vs absolute imports
429
+ 6. TESTING PATTERNS: Test organization, frameworks, coverage approaches
430
+ 7. DOCUMENTATION PATTERNS: Docstring styles, README structure, API documentation
431
+ 8. CONFIGURATION PATTERNS: Environment handling, settings management
432
+ 9. ERROR HANDLING: Exception patterns, logging approaches, error management
433
+ 10. INTEGRATION PATTERNS: API integrations, database patterns, external services
434
+
435
+ Provide comprehensive analysis that follows the PRD template principles and enables
436
+ AI assistants to implement features that perfectly match existing codebase patterns.""",
437
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
438
+ verbose=getattr(self, 'verbose', True)
439
+ )
440
+
441
+ prompt = f"""Analyze this gitingest codebase digest following PRD template methodology:
442
+
443
+ PROJECT PATH: {project_path}
444
+
445
+ GITINGEST COMPREHENSIVE ANALYSIS:
446
+ {digest_content[:8000]} # Limit for context window
447
+
448
+ Perform deep analysis following the 10 categories above. Focus on patterns that would
449
+ enable an AI assistant to implement new features that perfectly match the existing
450
+ codebase style and architecture following PRD template principles."""
451
+
452
+ print(" 🔍 Gitingest Analyst analyzing comprehensive codebase digest...")
453
+ # Use the new save method
454
+ response = self._chat_with_agent_and_save(gitingest_analyst, prompt, "PHASE_1_GITINGEST_ANALYSIS")
455
+
456
+ analysis = {
457
+ "analysis_method": "gitingest",
458
+ "project_structure": {"analysis": response[:1000]},
459
+ "code_patterns": {"analysis": response},
460
+ "architectural_insights": {"analysis": response},
461
+ "gitingest_digest": digest_content[:2000],
462
+ "full_analysis": response
463
+ }
464
+
465
+ print(f" ✅ Gitingest comprehensive analysis complete")
466
+ return analysis
467
+
468
+ except Exception as e:
469
+ print(f" ⚠️ Gitingest analysis failed: {e}, falling back to manual analysis")
470
+
471
+ # Fallback to manual analysis if gitingest fails
472
+ return self._perform_manual_codebase_analysis(project_path)
473
+
474
+ def _run_gitingest_analysis(self, project_path: str) -> str:
475
+ """Run gitingest analysis on the codebase."""
476
+ try:
477
+ # Try to run gitingest command
478
+ result = subprocess.run(
479
+ ["gitingest", project_path, "--output", "-"],
480
+ capture_output=True,
481
+ text=True,
482
+ timeout=60
483
+ )
484
+
485
+ if result.returncode == 0:
486
+ return result.stdout
487
+ else:
488
+ print(f" ⚠️ Gitingest command failed: {result.stderr}")
489
+ return None
490
+
491
+ except subprocess.TimeoutExpired:
492
+ print(" ⚠️ Gitingest analysis timed out")
493
+ return None
494
+ except FileNotFoundError:
495
+ print(" ⚠️ Gitingest not found, trying alternative analysis")
496
+ return None
497
+ except Exception as e:
498
+ print(f" ⚠️ Gitingest error: {e}")
499
+ return None
500
+
501
+ def _perform_manual_codebase_analysis(self, project_path: str) -> Dict[str, Any]:
502
+ """Fallback manual codebase analysis when gitingest is not available."""
503
+ print(" 🔧 Performing manual codebase analysis...")
504
+
505
+ # Get comprehensive file samples using manual methods
506
+ python_files = self._get_filtered_files(project_path, "*.py", 20)
507
+ config_files = self._get_filtered_files(project_path, "*.json", 5)
508
+ config_files.extend(self._get_filtered_files(project_path, "*.toml", 5))
509
+ config_files.extend(self._get_filtered_files(project_path, "*.yaml", 5))
510
+ doc_files = self._get_filtered_files(project_path, "*.md", 10)
511
+
512
+ # Create comprehensive manual analyst
513
+ manual_analyst = Agent(
514
+ name="Manual Codebase Analyst",
515
+ role="Expert Manual Codebase Analysis Specialist",
516
+ goal="Perform comprehensive manual codebase analysis following PRD methodology",
517
+ instructions="""Analyze the codebase samples following PRD template methodology for complete understanding.""",
518
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
519
+ verbose=getattr(self, 'verbose', True)
520
+ )
521
+
522
+ # Format comprehensive sample
523
+ comprehensive_content = self._format_comprehensive_samples(
524
+ python_files, config_files, doc_files, project_path
525
+ )
526
+
527
+ prompt = f"""Perform comprehensive manual codebase analysis following PRD template methodology:
528
+
529
+ PROJECT PATH: {project_path}
530
+
531
+ COMPREHENSIVE CODEBASE SAMPLES:
532
+ {comprehensive_content}
533
+
534
+ Analyze following PRD principles to extract patterns, conventions, and architectural insights."""
535
+
536
+ print(" 🔍 Manual Analyst analyzing codebase samples...")
537
+ # Use the new save method
538
+ response = self._chat_with_agent_and_save(manual_analyst, prompt, "PHASE_1_MANUAL_ANALYSIS")
539
+
540
+ analysis = {
541
+ "analysis_method": "manual",
542
+ "project_structure": {"analysis": response[:1000]},
543
+ "code_patterns": {"analysis": response},
544
+ "architectural_insights": {"analysis": response},
545
+ "full_analysis": response
546
+ }
547
+
548
+ print(f" ✅ Manual codebase analysis complete")
549
+ return analysis
550
+
551
+ def perform_ast_analysis(self, project_path: str) -> Dict[str, Any]:
552
+ """Perform AST (Abstract Syntax Tree) analysis for code patterns."""
553
+ print(" 🤖 Creating AST Pattern Analyzer...")
554
+
555
+ ast_analyzer = Agent(
556
+ name="AST Pattern Analyzer",
557
+ role="Abstract Syntax Tree Analysis Expert",
558
+ goal="Extract code patterns and structures using AST analysis following PRD methodology",
559
+ instructions="""You are an expert at AST analysis for pattern extraction following PRD principles.
560
+ Analyze the AST information to identify:
561
+ 1. Class hierarchies and inheritance patterns
562
+ 2. Function signatures and patterns
563
+ 3. Import dependencies and module structure
564
+ 4. Decorator usage patterns
565
+ 5. Exception handling patterns
566
+ 6. Design pattern implementations
567
+ 7. Code complexity metrics
568
+ 8. API and interface patterns""",
569
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
570
+ verbose=getattr(self, 'verbose', True)
571
+ )
572
+
573
+ # Perform AST analysis on Python files
574
+ python_files = self._get_filtered_files(project_path, "*.py", 15)
575
+ ast_data = self._extract_ast_patterns(python_files)
576
+
577
+ prompt = f"""Analyze AST patterns from this codebase following PRD methodology:
578
+
579
+ PROJECT PATH: {project_path}
580
+
581
+ AST ANALYSIS DATA:
582
+ {json.dumps(ast_data, indent=2)[:4000]}
583
+
584
+ Extract comprehensive patterns that follow PRD template principles for implementation guidance."""
585
+
586
+ print(" 🔍 AST Analyzer processing code patterns...")
587
+ # Use the new save method
588
+ response = self._chat_with_agent_and_save(ast_analyzer, prompt, "PHASE_2_AST_ANALYSIS")
589
+
590
+ patterns = {
591
+ "ast_method": True,
592
+ "class_patterns": ast_data.get("classes", []),
593
+ "function_patterns": ast_data.get("functions", []),
594
+ "import_patterns": ast_data.get("imports", []),
595
+ "decorator_patterns": ast_data.get("decorators", []),
596
+ "full_analysis": response
597
+ }
598
+
599
+ print(f" ✅ AST analysis complete: {len(patterns.get('class_patterns', []))} classes, {len(patterns.get('function_patterns', []))} functions analyzed")
600
+ return patterns
601
+
602
+ def extract_implementation_patterns(self, project_path: str, ast_analysis: Dict[str, Any] = None) -> Dict[str, Any]:
603
+ """Extract reusable implementation patterns following PRD methodology."""
604
+ print(" 🤖 Creating Implementation Pattern Extractor...")
605
+
606
+ pattern_extractor = Agent(
607
+ name="Implementation Pattern Extractor",
608
+ role="Code Pattern Recognition Expert following PRD methodology",
609
+ goal="Extract reusable implementation patterns and best practices following PRD template principles",
610
+ instructions="""You are an expert at identifying and extracting reusable implementation
611
+ patterns from codebases following PRD template methodology. Focus on patterns that enable
612
+ first-try implementation success. Analyze to find:
613
+
614
+ 1. DESIGN PATTERNS: Factory, Observer, Strategy, Singleton, etc.
615
+ 2. ARCHITECTURAL PATTERNS: MVC, Repository, Service Layer, etc.
616
+ 3. CODE ORGANIZATION: Module structure, class hierarchies, function patterns
617
+ 4. ERROR HANDLING: Try-catch patterns, custom exceptions, logging
618
+ 5. DATA HANDLING: Validation patterns, serialization, database interactions
619
+ 6. TESTING PATTERNS: Test structure, mocking approaches, fixture patterns
620
+ 7. ASYNC PATTERNS: Async/await usage, concurrency patterns
621
+ 8. INTEGRATION PATTERNS: API clients, external service patterns
622
+ 9. CONFIGURATION PATTERNS: Settings management, environment variables
623
+ 10. UTILITY PATTERNS: Common helper functions, decorators, context managers
624
+
625
+ For each pattern, provide the pattern name, where it's used, and how to replicate it
626
+ following PRD template principles.""",
627
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
628
+ verbose=getattr(self, 'verbose', True)
629
+ )
630
+
631
+ # Get representative code samples
632
+ samples = self._get_pattern_samples(project_path)
633
+
634
+ # Include AST analysis if available
635
+ ast_info = ""
636
+ if ast_analysis:
637
+ ast_info = f"\nAST ANALYSIS:\n{json.dumps(ast_analysis, indent=2)[:2000]}"
638
+
639
+ prompt = f"""Extract implementation patterns following PRD methodology:
640
+
641
+ PROJECT PATH: {project_path}
642
+
643
+ CODE SAMPLES:
644
+ {samples}
645
+ {ast_info}
646
+
647
+ Identify and document all reusable implementation patterns that follow PRD template
648
+ principles and would help an AI assistant implement new features using the same
649
+ patterns and best practices for first-try success."""
650
+
651
+ print(" 🔍 Pattern Extractor analyzing implementation patterns...")
652
+ # Use the new save method
653
+ response = self._chat_with_agent_and_save(pattern_extractor, prompt, "PHASE_2_PATTERN_EXTRACTION")
654
+
655
+ patterns = {
656
+ "patterns_identified": response.count("PATTERN"),
657
+ "design_patterns": [],
658
+ "architectural_patterns": [],
659
+ "testing_patterns": [],
660
+ "integration_patterns": [],
661
+ "full_analysis": response
662
+ }
663
+
664
+ print(f" ✅ Extracted implementation patterns following PRD methodology")
665
+ return patterns
666
+
667
+ def analyze_test_patterns(self, project_path: str) -> Dict[str, Any]:
668
+ """Analyze testing patterns for validation framework creation."""
669
+ print(" 🤖 Creating Test Pattern Analyzer...")
670
+
671
+ test_analyzer = Agent(
672
+ name="Test Pattern Analyzer",
673
+ role="Testing Pattern Recognition Expert",
674
+ goal="Analyze testing patterns for comprehensive validation framework design",
675
+ instructions="""Analyze testing patterns to understand validation approaches and create
676
+ comprehensive test frameworks following PRD methodology.""",
677
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
678
+ verbose=getattr(self, 'verbose', True)
679
+ )
680
+
681
+ # Get test files
682
+ test_files = self._get_filtered_files(project_path, "*test*.py", 10)
683
+ test_files.extend(self._get_filtered_files(project_path, "test_*.py", 10))
684
+ test_files.extend(self._get_filtered_files(project_path, "conftest.py", 5))
685
+
686
+ test_content = self._format_sample_files(test_files, project_path)
687
+
688
+ prompt = f"""Analyze testing patterns following PRD methodology:
689
+
690
+ PROJECT PATH: {project_path}
691
+
692
+ TEST PATTERNS:
693
+ {test_content}
694
+
695
+ Extract testing patterns for validation framework creation following PRD principles."""
696
+
697
+ print(" 🔍 Test Analyzer processing testing patterns...")
698
+ # Use the new save method
699
+ response = self._chat_with_agent_and_save(test_analyzer, prompt, "PHASE_2_TEST_ANALYSIS")
700
+
701
+ patterns = {
702
+ "test_files_analyzed": len(test_files),
703
+ "testing_frameworks": [],
704
+ "test_patterns": [],
705
+ "validation_approaches": [],
706
+ "full_analysis": response
707
+ }
708
+
709
+ print(f" ✅ Test pattern analysis complete: {len(test_files)} test files analyzed")
710
+ return patterns
711
+
712
+ def generate_comprehensive_prp(self, feature_request: str, context_analysis: Dict[str, Any] = None) -> str:
713
+ """Generate comprehensive Product Requirements Prompt following PRD template exactly."""
714
+ print(" 🤖 Creating PRP Generation Specialist following PRD template...")
715
+
716
+ if context_analysis is None:
717
+ context_analysis = {
718
+ "codebase_analysis": self.codebase_analysis,
719
+ "pattern_library": self.pattern_library,
720
+ "integration_points": getattr(self, 'integration_points', {}),
721
+ "validation_framework": self.validation_framework,
722
+ "context_documentation": self.context_documentation
723
+ }
724
+
725
+ prp_generator = Agent(
726
+ name="PRP Generation Specialist",
727
+ role="Product Requirements Prompt Expert following PRD Template",
728
+ goal="Generate comprehensive PRPs following the exact PRD template methodology for first-try implementation success",
729
+ instructions="""You are an expert at generating comprehensive Product Requirements Prompts (PRPs)
730
+ following the exact PRD template methodology. Your PRPs must follow the PRD template structure exactly:
731
+
732
+ ## Purpose
733
+ Clear statement of what needs to be built
734
+
735
+ ## Core Principles
736
+ 1. Context is King: Include ALL necessary documentation, examples, and caveats
737
+ 2. Validation Loops: Provide executable tests/lints the AI can run and fix
738
+ 3. Information Dense: Use keywords and patterns from the codebase
739
+ 4. Progressive Success: Start simple, validate, then enhance
740
+
741
+ ## Goal
742
+ What needs to be built - specific about end state
743
+
744
+ ## Why
745
+ - Business value and user impact
746
+ - Integration with existing features
747
+ - Problems this solves
748
+
749
+ ## What
750
+ User-visible behavior and technical requirements
751
+
752
+ ### Success Criteria
753
+ - [ ] Specific measurable outcomes
754
+
755
+ ## All Needed Context
756
+
757
+ ### Documentation & References
758
+ Complete list of all context needed
759
+
760
+ ### Current Codebase tree
761
+ Run tree command output
762
+
763
+ ### Desired Codebase tree
764
+ Files to be added with responsibilities
765
+
766
+ ### Known Gotchas & Library Quirks
767
+ Critical implementation details
768
+
769
+ ## Implementation Blueprint
770
+
771
+ ### Data models and structure
772
+ Core data models for type safety
773
+
774
+ ### List of tasks to be completed
775
+ Ordered task list for implementation
776
+
777
+ ### Per task pseudocode
778
+ Detailed pseudocode with critical details
779
+
780
+ ### Integration Points
781
+ Database, config, route changes needed
782
+
783
+ ## Validation Loop
784
+
785
+ ### Level 1: Syntax & Style
786
+ Executable commands for validation
787
+
788
+ ### Level 2: Unit Tests
789
+ Test cases with expected outcomes
790
+
791
+ ### Level 3: Integration Test
792
+ End-to-end validation steps
793
+
794
+ ## Final Validation Checklist
795
+ Complete checklist for verification
796
+
797
+ ## Anti-Patterns to Avoid
798
+ Common mistakes to prevent
799
+
800
+ ## Confidence Score: X/10
801
+ Confidence level for one-pass implementation
802
+
803
+ Generate PRPs following this EXACT structure for first-try implementation success.""",
804
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
805
+ verbose=getattr(self, 'verbose', True)
806
+ )
807
+
808
+ prompt = f"""Generate a comprehensive Product Requirements Prompt (PRP) following the EXACT PRD template structure:
809
+
810
+ FEATURE REQUEST: {feature_request}
811
+
812
+ COMPREHENSIVE CONTEXT ANALYSIS:
813
+ {json.dumps(context_analysis, indent=2)[:6000]}
814
+
815
+ PROJECT PATH: {self.project_path}
816
+
817
+ Create a PRP that follows the PRD template methodology EXACTLY with all sections:
818
+ - Purpose and Core Principles
819
+ - Goal, Why, What with Success Criteria
820
+ - All Needed Context with Documentation & References
821
+ - Implementation Blueprint with tasks and pseudocode
822
+ - Validation Loop with executable commands
823
+ - Final checklist and confidence score
824
+
825
+ Include ALL necessary context for an AI assistant to implement this feature correctly
826
+ on the first try following PRD template principles."""
827
+
828
+ print(" 🔍 PRP Generator creating comprehensive PRP following PRD template...")
829
+ # Use the new save method
830
+ prp = self._chat_with_agent_and_save(prp_generator, prompt, "PHASE_3_PRP_GENERATION")
831
+
832
+ print(f" ✅ Comprehensive PRP generated following PRD template ({len(prp)} characters)")
833
+ return prp
834
+
835
+ # Continue with remaining methods using the new save approach...
836
+ def create_validation_framework(self, project_path: str) -> Dict[str, Any]:
837
+ """Create comprehensive validation framework following PRD methodology."""
838
+ print(" 🤖 Creating Validation Framework Architect...")
839
+
840
+ validation_architect = Agent(
841
+ name="Validation Framework Architect",
842
+ role="Quality Assurance Expert following PRD methodology",
843
+ goal="Design comprehensive validation frameworks following PRD template principles",
844
+ instructions="""Design validation frameworks following PRD methodology that include:
845
+ 1. SYNTAX VALIDATION: Linting, formatting, type checking
846
+ 2. UNIT TESTING: Comprehensive test coverage strategies
847
+ 3. INTEGRATION TESTING: End-to-end testing approaches
848
+ 4. PERFORMANCE VALIDATION: Performance benchmarks
849
+ 5. SECURITY VALIDATION: Security best practices
850
+ 6. CODE QUALITY: Complexity analysis, maintainability
851
+ 7. DOCUMENTATION VALIDATION: Documentation completeness
852
+ 8. DEPENDENCY VALIDATION: Dependency analysis and security""",
853
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
854
+ verbose=getattr(self, 'verbose', True)
855
+ )
856
+
857
+ # Analyze existing validation patterns
858
+ test_files = self._get_filtered_files(project_path, "*test*.py", 10)
859
+ config_files = self._get_filtered_files(project_path, "*.toml", 3)
860
+ config_files.extend(self._get_filtered_files(project_path, "pyproject.toml", 1))
861
+
862
+ validation_content = self._format_sample_files(test_files + config_files, project_path)
863
+
864
+ prompt = f"""Design comprehensive validation framework following PRD methodology:
865
+
866
+ PROJECT PATH: {project_path}
867
+
868
+ EXISTING VALIDATION PATTERNS:
869
+ {validation_content}
870
+
871
+ Create validation framework with all 8 validation types and executable commands
872
+ following PRD template principles."""
873
+
874
+ print(" 🔍 Validation Architect designing framework...")
875
+ # Use the new save method
876
+ response = self._chat_with_agent_and_save(validation_architect, prompt, "PHASE_5_VALIDATION_FRAMEWORK")
877
+
878
+ framework = {
879
+ "syntax_validation": ["ruff check", "mypy"],
880
+ "testing_validation": ["pytest", "pytest --cov"],
881
+ "quality_gates": ["coverage report", "complexity analysis"],
882
+ "integration_tests": ["end-to-end test commands"],
883
+ "full_framework": response
884
+ }
885
+
886
+ print(f" ✅ Validation framework created following PRD methodology")
887
+ return framework
888
+
889
+ def compile_context_documentation(self, project_path: str) -> Dict[str, Any]:
890
+ """Compile all context documentation following PRD methodology."""
891
+ print(" 🤖 Creating Context Documentation Compiler...")
892
+
893
+ doc_compiler = Agent(
894
+ name="Context Documentation Compiler",
895
+ role="Documentation Analysis Expert following PRD methodology",
896
+ goal="Compile comprehensive context documentation following PRD template principles",
897
+ instructions="""Compile all available documentation following PRD methodology including:
898
+ README files, API documentation, setup guides, architecture docs, and any other
899
+ relevant documentation that provides context for implementation.""",
900
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
901
+ verbose=getattr(self, 'verbose', True)
902
+ )
903
+
904
+ # Get documentation files
905
+ doc_files = self._get_filtered_files(project_path, "*.md", 10)
906
+ doc_files.extend(self._get_filtered_files(project_path, "*.rst", 5))
907
+ doc_files.extend(self._get_filtered_files(project_path, "*.txt", 5))
908
+
909
+ doc_content = self._format_sample_files(doc_files, project_path)
910
+
911
+ prompt = f"""Compile context documentation following PRD methodology:
912
+
913
+ PROJECT PATH: {project_path}
914
+
915
+ DOCUMENTATION FILES:
916
+ {doc_content}
917
+
918
+ Extract and organize all documentation that provides context for implementation
919
+ following PRD template principles."""
920
+
921
+ print(" 🔍 Documentation Compiler processing context docs...")
922
+ # Use the new save method
923
+ response = self._chat_with_agent_and_save(doc_compiler, prompt, "PHASE_4_DOCUMENTATION_COMPILATION")
924
+
925
+ docs = {
926
+ "readme_files": [f for f in doc_files if "readme" in f.lower()],
927
+ "api_docs": [f for f in doc_files if "api" in f.lower()],
928
+ "setup_docs": [f for f in doc_files if any(term in f.lower() for term in ["setup", "install", "config"])],
929
+ "full_documentation": response
930
+ }
931
+
932
+ print(f" ✅ Context documentation compiled: {len(doc_files)} files analyzed")
933
+ return docs
934
+
935
+ def analyze_integration_points(self, project_path: str) -> Dict[str, Any]:
936
+ """Analyze integration points and external dependencies following PRD methodology."""
937
+ print(" 🤖 Creating Integration Point Analyzer...")
938
+
939
+ integration_analyzer = Agent(
940
+ name="Integration Point Analyzer",
941
+ role="Integration Analysis Expert following PRD methodology",
942
+ goal="Analyze all integration points and dependencies following PRD template principles",
943
+ instructions="""Analyze integration points following PRD methodology including:
944
+ APIs, databases, external services, configuration points, and any other
945
+ integration requirements that affect implementation.""",
946
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
947
+ verbose=getattr(self, 'verbose', True)
948
+ )
949
+
950
+ # Get configuration and dependency files
951
+ config_files = self._get_filtered_files(project_path, "*.toml", 5)
952
+ config_files.extend(self._get_filtered_files(project_path, "requirements*.txt", 5))
953
+ config_files.extend(self._get_filtered_files(project_path, "*.yaml", 5))
954
+ config_files.extend(self._get_filtered_files(project_path, "*.yml", 5))
955
+ config_files.extend(self._get_filtered_files(project_path, "*.json", 5))
956
+
957
+ integration_content = self._format_sample_files(config_files, project_path)
958
+
959
+ prompt = f"""Analyze integration points following PRD methodology:
960
+
961
+ PROJECT PATH: {project_path}
962
+
963
+ CONFIGURATION AND DEPENDENCY FILES:
964
+ {integration_content}
965
+
966
+ Identify all integration points, APIs, databases, and external dependencies
967
+ following PRD template principles."""
968
+
969
+ print(" 🔍 Integration Analyzer processing integration points...")
970
+ # Use the new save method
971
+ response = self._chat_with_agent_and_save(integration_analyzer, prompt, "PHASE_3_INTEGRATION_ANALYSIS")
972
+
973
+ integration_points = {
974
+ "apis": [],
975
+ "databases": [],
976
+ "external_services": [],
977
+ "configuration_points": [],
978
+ "dependencies": config_files,
979
+ "full_analysis": response
980
+ }
981
+
982
+ print(f" ✅ Integration point analysis complete: {len(config_files)} config files analyzed")
983
+ return integration_points
984
+
985
+ def build_implementation_blueprint(self, feature_request: str, context_analysis: Dict[str, Any] = None) -> Dict[str, Any]:
986
+ """Build detailed implementation blueprint following PRD template."""
987
+ print(" 🤖 Creating Implementation Blueprint Architect...")
988
+
989
+ if context_analysis is None:
990
+ context_analysis = self.codebase_analysis
991
+
992
+ blueprint_architect = Agent(
993
+ name="Implementation Blueprint Architect",
994
+ role="Software Implementation Planning Expert following PRD methodology",
995
+ goal="Create detailed implementation blueprints following PRD template principles",
996
+ instructions="""Create implementation blueprints following PRD methodology that include:
997
+ 1. TASK BREAKDOWN: Detailed task list in implementation order
998
+ 2. FILE MODIFICATIONS: Specific files to modify and how
999
+ 3. NEW FILE CREATION: New files needed and their purpose
1000
+ 4. DEPENDENCY MANAGEMENT: Dependencies to add/update
1001
+ 5. DATABASE CHANGES: Schema modifications if needed
1002
+ 6. CONFIGURATION UPDATES: Config changes required
1003
+ 7. TESTING REQUIREMENTS: Tests to create/update
1004
+ 8. DOCUMENTATION UPDATES: Documentation to create/update
1005
+ 9. INTEGRATION STEPS: How to integrate with existing systems
1006
+ 10. VALIDATION CHECKPOINTS: Validation steps at each phase""",
1007
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
1008
+ verbose=getattr(self, 'verbose', True)
1009
+ )
1010
+
1011
+ prompt = f"""Create detailed implementation blueprint following PRD methodology:
1012
+
1013
+ FEATURE REQUEST: {feature_request}
1014
+
1015
+ CONTEXT ANALYSIS:
1016
+ {json.dumps(context_analysis, indent=2)[:3000]}
1017
+
1018
+ PROJECT PATH: {self.project_path}
1019
+
1020
+ Create comprehensive blueprint following PRD template with all 10 components for
1021
+ detailed, actionable implementation steps."""
1022
+
1023
+ print(" 🔍 Blueprint Architect creating detailed implementation plan...")
1024
+ # Use the new save method
1025
+ response = self._chat_with_agent_and_save(blueprint_architect, prompt, "PHASE_5_IMPLEMENTATION_BLUEPRINT")
1026
+
1027
+ blueprint = {
1028
+ "task_breakdown": [],
1029
+ "file_modifications": [],
1030
+ "new_files": [],
1031
+ "dependencies": [],
1032
+ "validation_checkpoints": [],
1033
+ "full_blueprint": response
1034
+ }
1035
+
1036
+ print(f" ✅ Implementation blueprint created following PRD methodology")
1037
+ return blueprint
1038
+
1039
+ # Helper methods and remaining functionality...
1040
+ def _get_filtered_files(self, project_path: str, pattern: str, max_files: int) -> List[str]:
1041
+ """Get filtered files excluding unwanted directories following PRD principles."""
1042
+ try:
1043
+ files = glob.glob(os.path.join(project_path, "**", pattern), recursive=True)
1044
+
1045
+ # Filter out unwanted files following PRD methodology
1046
+ filtered = []
1047
+ exclude_patterns = [
1048
+ '__pycache__', '.pytest_cache', '.git', 'node_modules',
1049
+ '.venv', 'venv', 'dist', 'build', '.praison', '.chroma_db',
1050
+ '.ruff_cache', '.mypy_cache', 'context_engineering_output'
1051
+ ]
1052
+
1053
+ for file_path in files:
1054
+ if not any(exclude in file_path for exclude in exclude_patterns):
1055
+ filtered.append(file_path)
1056
+
1057
+ return filtered[:max_files]
1058
+ except Exception:
1059
+ return []
1060
+
1061
+ def _format_comprehensive_samples(self, python_files: List[str], config_files: List[str],
1062
+ doc_files: List[str], project_path: str) -> str:
1063
+ """Format comprehensive samples following PRD methodology."""
1064
+ content = []
1065
+
1066
+ # Python files
1067
+ if python_files:
1068
+ content.append("=== PYTHON CODE SAMPLES ===")
1069
+ content.append(self._format_sample_files(python_files, project_path))
1070
+
1071
+ # Config files
1072
+ if config_files:
1073
+ content.append("\n=== CONFIGURATION SAMPLES ===")
1074
+ content.append(self._format_sample_files(config_files, project_path))
1075
+
1076
+ # Documentation files
1077
+ if doc_files:
1078
+ content.append("\n=== DOCUMENTATION SAMPLES ===")
1079
+ content.append(self._format_sample_files(doc_files, project_path))
1080
+
1081
+ return "\n".join(content)
1082
+
1083
+ def _format_sample_files(self, files: List[str], project_path: str) -> str:
1084
+ """Format sample files for analysis following PRD principles."""
1085
+ formatted = []
1086
+ for file_path in files:
1087
+ try:
1088
+ rel_path = os.path.relpath(file_path, project_path)
1089
+ with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
1090
+ content = f.read()[:3000]
1091
+ formatted.append(f"File: {rel_path}\n{content}\n{'='*80}")
1092
+ except Exception:
1093
+ continue
1094
+ return "\n\n".join(formatted)
1095
+
1096
+ def _get_pattern_samples(self, project_path: str) -> str:
1097
+ """Get representative samples for pattern extraction following PRD methodology."""
1098
+ samples = []
1099
+
1100
+ # Get diverse file types following PRD principles
1101
+ patterns = ["*.py", "test_*.py", "*_test.py", "conftest.py", "setup.py", "__init__.py", "pyproject.toml"]
1102
+ for pattern in patterns:
1103
+ files = self._get_filtered_files(project_path, pattern, 3)
1104
+ if files:
1105
+ samples.extend(files)
1106
+
1107
+ return self._format_sample_files(samples, project_path)
1108
+
1109
+ def create_quality_gates(self, requirements: List[str]) -> Dict[str, Any]:
1110
+ """Create quality gates for validation following PRD methodology."""
1111
+ return {
1112
+ "syntax_gates": ["ruff check", "mypy"],
1113
+ "test_gates": ["pytest --cov=80"],
1114
+ "quality_gates": ["complexity check", "security scan"],
1115
+ "integration_gates": ["integration tests"],
1116
+ "requirements": requirements
1117
+ }
1118
+
1119
+ def _save_context_engineering_results(self):
1120
+ """Save all Context Engineering results following PRD methodology."""
1121
+ # Save comprehensive analysis
1122
+ with open(os.path.join(self.output_dir, "comprehensive_analysis.json"), "w") as f:
1123
+ json.dump(self.codebase_analysis, f, indent=2)
1124
+
1125
+ # Save pattern library
1126
+ with open(os.path.join(self.output_dir, "pattern_library.json"), "w") as f:
1127
+ json.dump(self.pattern_library, f, indent=2)
1128
+
1129
+ # Save validation framework
1130
+ with open(os.path.join(self.output_dir, "validation_framework.json"), "w") as f:
1131
+ json.dump(self.validation_framework, f, indent=2)
1132
+
1133
+ # Save all agent interactions summary
1134
+ with open(os.path.join(self.output_dir, "all_agent_interactions.json"), "w") as f:
1135
+ json.dump(self.agent_interactions, f, indent=2)
1136
+
1137
+ print(f"💾 Context Engineering results saved to: {self.output_dir}/")
1138
+ print(f"💾 Agent interactions ({len(self.agent_interactions)} total) saved to: agent_responses/")
1139
+
1140
+ def _generate_analysis_summary(self):
1141
+ """Generate analysis summary following PRD methodology."""
1142
+ summary = f"""
1143
+ # Context Engineering Analysis Summary
1144
+
1145
+ ## Analysis Method: {self.codebase_analysis.get('analysis_method', 'manual')}
1146
+ ## Project Path: {self.project_path}
1147
+ ## Analysis Completion: ✅
1148
+ ## Total Agent Interactions: {len(self.agent_interactions)}
1149
+
1150
+ ### Agent Interaction Tracking
1151
+ All {len(self.agent_interactions)} agent responses have been saved with complete traceability:
1152
+ - Individual response files in agent_responses/ directory
1153
+ - Complete interaction log in all_agent_interactions.json
1154
+ - Timestamps, prompts, responses, and metadata preserved
1155
+
1156
+ ### Codebase Analysis
1157
+ - Method: {self.codebase_analysis.get('analysis_method', 'manual')}
1158
+ - Categories Analyzed: {len(self.codebase_analysis)}
1159
+
1160
+ ### Pattern Library
1161
+ - Patterns Identified: {self.pattern_library.get('patterns_identified', 0)}
1162
+ - Implementation Patterns: Available
1163
+ - Testing Patterns: Available
1164
+
1165
+ ### Validation Framework
1166
+ - Validation Types: {len(self.validation_framework)}
1167
+ - Quality Gates: Configured
1168
+ - Test Frameworks: Identified
1169
+
1170
+ ### Context Documentation
1171
+ - Documentation Files: {len(self.context_documentation.get('readme_files', []))} README files
1172
+ - API Documentation: {len(self.context_documentation.get('api_docs', []))} API docs
1173
+ - Setup Documentation: Available
1174
+
1175
+ ### Integration Points
1176
+ - Dependencies Analyzed: {len(getattr(self, 'integration_points', {}).get('dependencies', []))}
1177
+ - Configuration Points: Identified
1178
+ - External Services: Catalogued
1179
+
1180
+ ## Ready for PRP Generation ✅
1181
+ The Context Engineering analysis is complete and ready to generate comprehensive
1182
+ Product Requirements Prompts following PRD template methodology.
1183
+
1184
+ ## Complete Traceability ✅
1185
+ Every agent interaction has been saved for full audit trail and reproducibility.
1186
+ """
1187
+
1188
+ with open(os.path.join(self.output_dir, "analysis_summary.md"), "w") as f:
1189
+ f.write(summary)
1190
+
1191
+ print(f"📋 Analysis summary saved following PRD methodology")
1192
+ print(f"📋 Complete agent interaction audit trail available")
1193
+
1194
+ def _perform_fallback_analysis(self):
1195
+ """Perform fallback analysis if main analysis fails."""
1196
+ print("🔄 Performing fallback Context Engineering analysis...")
1197
+
1198
+ # Basic fallback analysis
1199
+ self.codebase_analysis = {"analysis_method": "fallback", "basic_structure": "analyzed"}
1200
+ self.pattern_library = {"patterns_identified": 0, "fallback_mode": True}
1201
+ self.validation_framework = {"basic_validation": ["pytest", "ruff check"]}
1202
+
1203
+ print("✅ Fallback analysis complete")
1204
+
1205
+ def generate_feature_prp(self, feature_request: str) -> str:
1206
+ """Generate a comprehensive PRP for a specific feature request following PRD methodology."""
1207
+ print(f"🎯 Generating comprehensive PRP following PRD template for: {feature_request}")
1208
+
1209
+ # Use all available context following PRD methodology
1210
+ full_context = {
1211
+ "codebase_analysis": self.codebase_analysis,
1212
+ "pattern_library": self.pattern_library,
1213
+ "integration_points": getattr(self, 'integration_points', {}),
1214
+ "validation_framework": self.validation_framework,
1215
+ "context_documentation": self.context_documentation
1216
+ }
1217
+
1218
+ prp = self.generate_comprehensive_prp(feature_request, full_context)
1219
+
1220
+ # If auto_analyze was True and we have agent interactions, create combined response
1221
+ if hasattr(self, 'agent_interactions') and self.agent_interactions and len(self.agent_interactions) > 0:
1222
+ print(f"📊 Creating combined response with {len(self.agent_interactions)} agent interactions...")
1223
+ return self._generate_combined_analysis(feature_request)
1224
+
1225
+ # Otherwise just save and return the PRP
1226
+ safe_filename = feature_request.lower().replace(' ', '_').replace('-', '_')[:50]
1227
+ prp_path = os.path.join(self.output_dir, "PRPs", f"{safe_filename}.md")
1228
+
1229
+ with open(prp_path, "w") as f:
1230
+ f.write(prp)
1231
+
1232
+ print(f"📄 Comprehensive PRP following PRD template saved to: {prp_path}")
1233
+ return prp
1234
+
1235
+ def execute_prp(self, prp_file_path: str) -> Dict[str, Any]:
1236
+ """Execute a PRP following PRD methodology (placeholder for future implementation)."""
1237
+ print(f"🚀 PRP execution capability - ready for implementation following PRD methodology")
1238
+ return {"status": "ready", "prp_file": prp_file_path}
1239
+
1240
+ def start(self, input_text: str) -> str:
1241
+ """Start Context Engineering analysis with structured input parsing."""
1242
+ print(f"🚀 Starting Context Engineering analysis with structured input parsing...")
1243
+
1244
+ # First, parse the input to extract codebase and goal
1245
+ parsed_input = self._parse_structured_input(input_text)
1246
+
1247
+ codebase = parsed_input.get('codebase', '')
1248
+ goal = parsed_input.get('goal', '')
1249
+
1250
+ print(f"📊 Parsed Input:")
1251
+ print(f" 🔗 Codebase: {codebase}")
1252
+ print(f" 🎯 Goal: {goal}")
1253
+
1254
+ if codebase:
1255
+ if codebase.startswith(('http://', 'https://')):
1256
+ # Handle GitHub URL analysis with specific goal
1257
+ if 'github.com' in codebase:
1258
+ print(f"🌐 GitHub repository analysis focused on goal: {goal}")
1259
+ return self._analyze_github_with_goal(codebase, goal)
1260
+ else:
1261
+ print(f"🌐 General URL analysis focused on goal: {goal}")
1262
+ return self._analyze_url_with_goal(codebase, goal)
1263
+ else:
1264
+ # Handle local path analysis with specific goal
1265
+ if os.path.exists(codebase):
1266
+ print(f"📁 Local codebase analysis focused on goal: {goal}")
1267
+ self.project_path = codebase
1268
+ self._perform_context_engineering_analysis()
1269
+ return self._generate_goal_focused_analysis(codebase, goal)
1270
+ else:
1271
+ print(f"⚠️ Codebase path not found: {codebase}, using current project path")
1272
+ return self._generate_goal_focused_analysis(self.project_path, goal)
1273
+ else:
1274
+ # No specific codebase provided, use current directory
1275
+ print(f"📁 Using current directory with goal: {goal}")
1276
+ return self._generate_goal_focused_analysis(self.project_path, goal)
1277
+
1278
+ def _parse_structured_input(self, input_text: str) -> Dict[str, str]:
1279
+ """Parse structured input to extract codebase and goal using a specialized agent."""
1280
+ print(" 🤖 Creating Structured Input Parser Agent...")
1281
+
1282
+ parser_agent = Agent(
1283
+ name="Structured Input Parser",
1284
+ role="Expert Input Analysis and Extraction Specialist",
1285
+ goal="Extract codebase URLs/paths and implementation goals from user input",
1286
+ instructions="""You are an expert at parsing user input to extract structured information.
1287
+
1288
+ From the provided input, extract:
1289
+ 1. CODEBASE: Any GitHub URLs, repository paths, or local directory paths mentioned
1290
+ 2. GOAL: The specific task, feature, or implementation goal the user wants to achieve
1291
+
1292
+ Rules for extraction:
1293
+ - Look for GitHub URLs (https://github.com/owner/repo)
1294
+ - Look for local paths (/path/to/directory)
1295
+ - Look for implementation goals (add authentication, implement feature X, etc.)
1296
+ - If multiple goals are mentioned, combine them into a coherent objective
1297
+ - If no explicit codebase is mentioned, return empty string for codebase
1298
+ - Always extract a meaningful goal even if it's implied
1299
+
1300
+ Return your analysis in this exact format:
1301
+ CODEBASE: [extracted codebase URL or path]
1302
+ GOAL: [extracted implementation goal]
1303
+
1304
+ Be precise and extract only what is explicitly mentioned or clearly implied.""",
1305
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
1306
+ verbose=getattr(self, 'verbose', True)
1307
+ )
1308
+
1309
+ prompt = f"""Parse this user input to extract codebase and goal:
1310
+
1311
+ USER INPUT: {input_text}
1312
+
1313
+ Extract the codebase (GitHub URL, repository path, or local directory) and the implementation goal.
1314
+ Return in the exact format specified in your instructions."""
1315
+
1316
+ print(" 🔍 Parsing structured input...")
1317
+ response = self._chat_with_agent_and_save(parser_agent, prompt, "INPUT_PARSING")
1318
+
1319
+ # Parse the response to extract codebase and goal
1320
+ parsed = self._extract_codebase_and_goal(response)
1321
+
1322
+ print(f" ✅ Input parsing complete: Codebase='{parsed.get('codebase', '')}', Goal='{parsed.get('goal', '')}'")
1323
+ return parsed
1324
+
1325
+ def _extract_codebase_and_goal(self, parser_response: str) -> Dict[str, str]:
1326
+ """Extract codebase and goal from parser agent response."""
1327
+ codebase = ""
1328
+ goal = ""
1329
+
1330
+ lines = parser_response.strip().split('\n')
1331
+ for line in lines:
1332
+ line = line.strip()
1333
+ if line.startswith('CODEBASE:'):
1334
+ codebase = line.replace('CODEBASE:', '').strip()
1335
+ elif line.startswith('GOAL:'):
1336
+ goal = line.replace('GOAL:', '').strip()
1337
+
1338
+ # Fallback parsing if format wasn't followed exactly
1339
+ if not codebase or not goal:
1340
+ # Look for GitHub URLs
1341
+ import re
1342
+ github_pattern = r'https://github\.com/[^\s]+'
1343
+ github_matches = re.findall(github_pattern, parser_response)
1344
+ if github_matches and not codebase:
1345
+ codebase = github_matches[0]
1346
+
1347
+ # Look for common goal keywords
1348
+ goal_keywords = ['add', 'implement', 'create', 'build', 'develop', 'need to', 'authentication', 'feature']
1349
+ if not goal:
1350
+ for keyword in goal_keywords:
1351
+ if keyword.lower() in parser_response.lower():
1352
+ # Extract sentence containing the keyword
1353
+ sentences = parser_response.split('.')
1354
+ for sentence in sentences:
1355
+ if keyword.lower() in sentence.lower():
1356
+ goal = sentence.strip()
1357
+ break
1358
+ if goal:
1359
+ break
1360
+
1361
+ return {
1362
+ 'codebase': codebase,
1363
+ 'goal': goal or "Comprehensive codebase analysis and context generation"
1364
+ }
1365
+
1366
+ def _analyze_github_with_goal(self, github_url: str, goal: str) -> str:
1367
+ """Analyze GitHub repository with gitingest, focusing on specific goal."""
1368
+ print(f" 🌐 Analyzing GitHub repository with goal focus...")
1369
+
1370
+ # Step 1: Get complete repository structure and file listing
1371
+ print(" 📊 Step 1: Getting complete repository structure...")
1372
+ repo_structure = self._get_repository_structure(github_url)
1373
+
1374
+ # Step 2: Have agent select relevant files based on goal
1375
+ print(" 🎯 Step 2: Agent selecting relevant files for goal...")
1376
+ selected_files = self._select_relevant_files_for_goal(repo_structure, goal, github_url)
1377
+
1378
+ # Step 3: Analyze only selected files with gitingest
1379
+ print(" 📋 Step 3: Analyzing selected files with gitingest...")
1380
+ return self._analyze_selected_files(github_url, goal, selected_files)
1381
+
1382
+ def _get_repository_structure(self, github_url: str) -> Dict[str, Any]:
1383
+ """Get complete repository structure with detailed file metadata."""
1384
+ self.log_debug("Starting repository structure analysis", github_url=github_url)
1385
+
1386
+ try:
1387
+ # Step 1: Get basic file structure
1388
+ print(" 📋 Getting basic repository structure...")
1389
+ self.log_debug("Getting basic repository structure")
1390
+ basic_structure = self._get_basic_structure(github_url)
1391
+ self.log_debug("Basic structure obtained", file_count=basic_structure.get('file_count', 0))
1392
+
1393
+ # Step 2: Get enhanced metadata for key files
1394
+ print(" 🔍 Extracting detailed file metadata...")
1395
+ self.log_debug("Starting enhanced metadata extraction")
1396
+ enhanced_structure = self._get_enhanced_file_metadata(github_url, basic_structure)
1397
+ self.log_debug("Enhanced metadata extraction complete",
1398
+ enhanced=enhanced_structure.get('enhanced', False),
1399
+ metadata_length=len(enhanced_structure.get('file_metadata', '')))
1400
+
1401
+ return enhanced_structure
1402
+
1403
+ except Exception as e:
1404
+ print(f" ⚠️ Repository structure analysis failed: {e}")
1405
+ self.log_debug("Repository structure analysis failed", error=str(e))
1406
+ return {
1407
+ "method": "failed",
1408
+ "structure": "Unable to retrieve repository structure",
1409
+ "file_count": 0,
1410
+ "success": False
1411
+ }
1412
+
1413
+ def _get_basic_structure(self, github_url: str) -> Dict[str, Any]:
1414
+ """Get basic repository file structure."""
1415
+ try:
1416
+ # Try using gitingest with structure-only flag first
1417
+ result = subprocess.run(
1418
+ ["gitingest", github_url, "--tree-only", "--output", "-"],
1419
+ capture_output=True,
1420
+ text=True,
1421
+ timeout=60
1422
+ )
1423
+
1424
+ if result.returncode == 0:
1425
+ return {
1426
+ "method": "gitingest_tree",
1427
+ "structure": result.stdout,
1428
+ "file_count": result.stdout.count('\n'),
1429
+ "success": True
1430
+ }
1431
+ else:
1432
+ print(f" ⚠️ Gitingest tree failed, using GitHub API...")
1433
+ return self._get_structure_fallback(github_url)
1434
+
1435
+ except (subprocess.TimeoutExpired, FileNotFoundError) as e:
1436
+ print(f" ⚠️ Gitingest not available: {e}, using GitHub API...")
1437
+ return self._get_structure_fallback(github_url)
1438
+
1439
+ def _get_enhanced_file_metadata(self, github_url: str, basic_structure: Dict[str, Any]) -> Dict[str, Any]:
1440
+ """Extract enhanced metadata including functions, classes, and docstrings."""
1441
+ print(" 🔍 Extracting detailed file metadata...")
1442
+
1443
+ # Step 1: Get raw content from repository
1444
+ sample_content = self._get_repository_sample_content(github_url, basic_structure.get('structure', ''))
1445
+
1446
+ # Step 2: Parse the content to extract structured metadata
1447
+ parsed_metadata = self._parse_code_metadata(sample_content, basic_structure)
1448
+
1449
+ # DEBUG: Check what metadata was actually parsed
1450
+ print(f" 🔍 DEBUG: Parsed metadata length: {len(parsed_metadata)} chars")
1451
+ print(f" 🔍 DEBUG: Metadata preview: {parsed_metadata[:200]}...")
1452
+
1453
+ # Step 3: Create enhanced structure with parsed metadata
1454
+ enhanced_structure = {
1455
+ "method": "enhanced_metadata",
1456
+ "basic_structure": basic_structure,
1457
+ "file_metadata": parsed_metadata,
1458
+ "file_count": basic_structure.get('file_count', 0),
1459
+ "success": True,
1460
+ "enhanced": True
1461
+ }
1462
+
1463
+ print(f" ✅ Enhanced structure created with metadata length: {len(enhanced_structure.get('file_metadata', ''))}")
1464
+ return enhanced_structure
1465
+
1466
+ def _parse_code_metadata(self, sample_content: str, basic_structure: Dict[str, Any]) -> str:
1467
+ """Parse code content to extract functions, classes, docstrings, and other metadata."""
1468
+ print(" 🤖 Creating Code Metadata Parser Agent...")
1469
+
1470
+ # Check if we have actual content to parse
1471
+ if not sample_content or len(sample_content.strip()) < 100:
1472
+ print(" ⚠️ No substantial content available for metadata parsing")
1473
+ return """
1474
+ METADATA EXTRACTION STATUS: Limited content available
1475
+
1476
+ BASIC FILE STRUCTURE ANALYSIS:
1477
+ - Repository appears to contain Python, JavaScript, and configuration files
1478
+ - Authentication-related files likely in: auth/, user/, login/, security/ directories
1479
+ - Configuration files: settings.py, config.py, .env files
1480
+ - API files: api/, routes/, endpoints/ directories
1481
+
1482
+ RECOMMENDED FILE SELECTION APPROACH:
1483
+ - Look for files with 'auth', 'login', 'user', 'security' in names
1484
+ - Include main application files (app.py, main.py, server.py)
1485
+ - Include configuration files (settings.py, config.py)
1486
+ - Include API route files
1487
+ - Include requirements.txt, package.json for dependencies
1488
+
1489
+ Note: Detailed function/class metadata not available due to content access limitations.
1490
+ """
1491
+
1492
+ # Truncate sample content if too large to prevent context overflow
1493
+ max_content_length = 60000 # Increased from 50K to 60K for better metadata
1494
+ if len(sample_content) > max_content_length:
1495
+ sample_content = sample_content[:max_content_length] + "\n\n... [Content truncated for analysis] ..."
1496
+ print(f" 📏 Sample content truncated to {max_content_length} chars for metadata parsing")
1497
+
1498
+ metadata_parser = Agent(
1499
+ name="Code Metadata Parser",
1500
+ role="Expert Code Analysis and Metadata Extraction Specialist",
1501
+ goal="Parse code content to extract detailed metadata including functions, classes, and docstrings",
1502
+ instructions="""You are an expert at parsing code content and extracting structured metadata.
1503
+
1504
+ From the provided code content, extract detailed metadata for each file:
1505
+
1506
+ FOR PYTHON FILES (.py):
1507
+ - FUNCTIONS: Extract function names with their docstrings and parameters
1508
+ Format: "function_name(params): docstring_summary"
1509
+ - CLASSES: Extract class names with their docstrings and key methods
1510
+ Format: "ClassName: docstring_summary, methods: [method1, method2]"
1511
+ - MODULE_DOCSTRING: Top-level file description
1512
+ - KEY_IMPORTS: Important imports and dependencies
1513
+ - DECORATORS: Common decorators used (@app.route, @property, etc.)
1514
+
1515
+ FOR JAVASCRIPT/TYPESCRIPT FILES (.js, .ts, .jsx, .tsx):
1516
+ - FUNCTIONS: Function names and purposes
1517
+ - CLASSES/COMPONENTS: React components or ES6 classes
1518
+ - EXPORTS: What the file exports
1519
+ - IMPORTS: Key dependencies
1520
+
1521
+ FOR CONFIGURATION FILES (.json, .toml, .yaml, .env):
1522
+ - PURPOSE: What this configuration controls
1523
+ - KEY_SECTIONS: Main configuration categories
1524
+ - DEPENDENCIES: Packages or services configured
1525
+
1526
+ FOR DOCUMENTATION FILES (.md, .rst, .txt):
1527
+ - TITLE: Document title/purpose
1528
+ - SECTIONS: Main topics covered
1529
+ - API_DOCS: If it documents APIs or functions
1530
+
1531
+ **CRITICAL**: Return structured data that clearly shows:
1532
+ 1. File name and type
1533
+ 2. Functions/classes with their purposes
1534
+ 3. Key imports and dependencies
1535
+ 4. Configuration purposes
1536
+ 5. Documentation topics
1537
+
1538
+ Make the output easy for a file selection agent to understand which files contain what functionality.""",
1539
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
1540
+ verbose=getattr(self, 'verbose', True)
1541
+ )
1542
+
1543
+ structure_text = basic_structure.get('structure', '')
1544
+
1545
+ prompt = f"""Parse this repository content to extract detailed metadata:
1546
+
1547
+ REPOSITORY STRUCTURE:
1548
+ {structure_text}
1549
+
1550
+ REPOSITORY CONTENT TO PARSE:
1551
+ {sample_content}
1552
+
1553
+ Extract structured metadata for each file showing:
1554
+ - Functions and their purposes
1555
+ - Classes and their purposes
1556
+ - Key imports and dependencies
1557
+ - Configuration sections
1558
+ - Documentation topics
1559
+
1560
+ Focus on creating clear, structured metadata that will help with intelligent file selection."""
1561
+
1562
+ print(" 🔍 Code Parser extracting functions, classes, and docstrings...")
1563
+ response = self._chat_with_agent_and_save(metadata_parser, prompt, "CODE_METADATA_PARSING")
1564
+
1565
+ # Ensure we return the actual parsed metadata response
1566
+ print(f" ✅ Extracted metadata length: {len(response)} characters")
1567
+ if len(response) < 100:
1568
+ print(" ⚠️ Warning: Very short metadata response - may indicate parsing issues")
1569
+
1570
+ return response
1571
+
1572
+ def _get_repository_sample_content(self, github_url: str, structure_text: str) -> str:
1573
+ """Get actual code content from key repository files for metadata extraction."""
1574
+ try:
1575
+ print(" 📋 Getting actual code content from repository files...")
1576
+
1577
+ # Validate GitHub token first
1578
+ github_token = os.getenv('GITHUB_TOKEN')
1579
+ if github_token:
1580
+ print(f" 🔑 GitHub token found: {github_token[:8]}...{github_token[-4:]} (length: {len(github_token)})")
1581
+
1582
+ # Validate token format
1583
+ import re
1584
+ github_pat_pattern = r"^(?:gh[pousr]_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9]{22}_[A-Za-z0-9]{59})$"
1585
+ if not re.match(github_pat_pattern, github_token):
1586
+ print(" ⚠️ Token format looks invalid - may cause authentication issues")
1587
+ print(" 📝 Valid formats: ghp_xxxx or github_pat_xxxx")
1588
+ else:
1589
+ print(" ✅ Token format is valid")
1590
+
1591
+ # Quick test of token validity
1592
+ try:
1593
+ import requests
1594
+ test_headers = {'Authorization': f'Bearer {github_token}'}
1595
+ test_response = requests.get('https://api.github.com/user', headers=test_headers, timeout=5)
1596
+ if test_response.status_code == 200:
1597
+ user_data = test_response.json()
1598
+ print(f" ✅ Token is valid for user: {user_data.get('login')}")
1599
+ elif test_response.status_code == 401:
1600
+ print(" ❌ Token is invalid or expired!")
1601
+ print(" 📝 Generate new token at: https://github.com/settings/tokens")
1602
+ elif test_response.status_code == 403:
1603
+ print(" ❌ Token lacks required permissions!")
1604
+ print(" 📝 Required scopes: 'repo' or 'public_repo'")
1605
+ else:
1606
+ print(f" ⚠️ Unexpected token test result: {test_response.status_code}")
1607
+ except Exception as e:
1608
+ print(f" ⚠️ Could not validate token: {e}")
1609
+ else:
1610
+ print(" ⚠️ No GitHub token found - may hit rate limits")
1611
+
1612
+ # Try gitingest Python package first for actual content
1613
+ try:
1614
+ from gitingest import ingest
1615
+ print(" 🔧 Using gitingest Python package to fetch actual code content...")
1616
+
1617
+ # Get comprehensive content including actual code
1618
+ # Use better limits for codebase overview while avoiding context overflow
1619
+ summary, tree, content = ingest(
1620
+ github_url,
1621
+ max_file_size=10000, # 10KB per file for better overview (was 5KB)
1622
+ include_patterns={'*.py', '*.js', '*.ts', '*.json', '*.md', '*.yaml', '*.toml'}, # Include more file types for overview
1623
+ exclude_patterns={'*test*', '*__pycache__*', '*.pyc', '*migrations*', '*node_modules*', '*.min.js', '*.bundle.js'}, # Exclude generated/test files
1624
+ token=github_token
1625
+ )
1626
+
1627
+ # More conservative truncation to ensure we keep actual code content
1628
+ max_content_for_metadata = 80000 # 80K chars for metadata extraction
1629
+ if len(content) > max_content_for_metadata:
1630
+ # Keep the beginning (which has most file headers) and truncate the rest
1631
+ content = content[:max_content_for_metadata] + "\n\n... [Content truncated but metadata extracted from available content] ..."
1632
+ print(f" 📏 Content size: {len(content)}, keeping first {max_content_for_metadata} chars for metadata")
1633
+
1634
+ # Return actual code content for parsing - this is crucial for metadata extraction
1635
+ return f"REPOSITORY SUMMARY:\n{summary}\n\nFILE TREE:\n{tree}\n\nACTUAL CODE CONTENT:\n{content}"
1636
+
1637
+ except ImportError:
1638
+ print(" ⚠️ gitingest Python package not available, using command line...")
1639
+
1640
+ # Fallback to command line gitingest for actual content
1641
+ result = subprocess.run(
1642
+ ["gitingest", github_url, "--output", "-"],
1643
+ capture_output=True,
1644
+ text=True,
1645
+ timeout=120
1646
+ )
1647
+
1648
+ if result.returncode == 0:
1649
+ # This should contain actual file contents, not just structure
1650
+ return result.stdout
1651
+ else:
1652
+ print(f" ⚠️ Gitingest command failed: {result.stderr}")
1653
+ return self._get_github_sample_files(github_url, structure_text)
1654
+
1655
+ except Exception as e:
1656
+ print(f" ⚠️ Sample content extraction failed: {e}")
1657
+ return self._get_github_sample_files(github_url, structure_text)
1658
+
1659
+ def _get_github_sample_files(self, github_url: str, structure_text: str) -> str:
1660
+ """Fallback to get sample file contents directly from GitHub."""
1661
+ try:
1662
+ print(" 🔄 Attempting to fetch sample file contents from GitHub...")
1663
+
1664
+ # Extract repo info
1665
+ repo_parts = github_url.replace('https://github.com/', '').strip('/')
1666
+
1667
+ # Check for GitHub token for better rate limits
1668
+ github_token = os.getenv('GITHUB_TOKEN')
1669
+ headers = {}
1670
+ if github_token:
1671
+ headers['Authorization'] = f'Bearer {github_token}' # Use Bearer instead of token
1672
+ print(" 🔑 Using GitHub token for enhanced rate limits")
1673
+
1674
+ # Select important files to fetch content from
1675
+ important_files = []
1676
+ for line in structure_text.split('\n'):
1677
+ line = line.strip()
1678
+ if line and any(ext in line for ext in ['.py', '.js', '.ts', '.json', '.md']):
1679
+ # Prioritize likely important files
1680
+ if any(keyword in line.lower() for keyword in [
1681
+ 'main', 'app', 'server', 'index', 'config', 'setup',
1682
+ 'auth', 'user', 'login', 'api', 'route', 'model'
1683
+ ]):
1684
+ important_files.append(line)
1685
+ if len(important_files) >= 10: # Limit to avoid too many API calls
1686
+ break
1687
+
1688
+ # Fetch content from important files
1689
+ file_contents = []
1690
+ for file_path in important_files[:5]: # Limit to 5 files to avoid rate limits
1691
+ try:
1692
+ api_url = f"https://api.github.com/repos/{repo_parts}/contents/{file_path}"
1693
+
1694
+ import urllib.request
1695
+ import json
1696
+ import base64
1697
+
1698
+ request = urllib.request.Request(api_url, headers=headers)
1699
+
1700
+ with urllib.request.urlopen(request) as response:
1701
+ file_data = json.loads(response.read())
1702
+
1703
+ if file_data.get('content') and file_data.get('encoding') == 'base64':
1704
+ content = base64.b64decode(file_data['content']).decode('utf-8')
1705
+ file_contents.append(f"\n--- FILE: {file_path} ---\n{content[:2000]}") # First 2000 chars
1706
+
1707
+ except Exception as e:
1708
+ print(f" ⚠️ Failed to fetch {file_path}: {e}")
1709
+ continue
1710
+
1711
+ if file_contents:
1712
+ return f"SAMPLE FILE CONTENTS:\n{''.join(file_contents)}"
1713
+ else:
1714
+ return "No sample content available - file fetching failed"
1715
+
1716
+ except Exception as e:
1717
+ print(f" ⚠️ GitHub sample file fetching failed: {e}")
1718
+ return "No sample content available - GitHub API failed"
1719
+
1720
+ def _select_relevant_files_for_goal(self, repo_structure: Dict[str, Any], goal: str, github_url: str) -> List[str]:
1721
+ """Have an agent intelligently select relevant files based on goal and enhanced metadata."""
1722
+ print(" 🤖 Creating Enhanced File Selection Agent...")
1723
+
1724
+ file_selector = Agent(
1725
+ name="Enhanced File Selection Agent",
1726
+ role="Expert File Selection Specialist with Metadata Analysis",
1727
+ goal=f"Select most relevant files for implementing: {goal}",
1728
+ instructions=f"""You are an expert at selecting the most relevant files from a repository for a specific goal: {goal}
1729
+
1730
+ You have access to enhanced metadata including:
1731
+ - File structure and organization
1732
+ - Functions and classes in each file
1733
+ - Docstrings and descriptions
1734
+ - Configuration purposes
1735
+ - Documentation coverage
1736
+ - Import dependencies
1737
+
1738
+ CORE FILES TO ALWAYS INCLUDE (if they exist):
1739
+ - README.md, setup.py, pyproject.toml, package.json, requirements.txt
1740
+ - Main entry points: main.py, app.py, index.js, server.py
1741
+ - Configuration files: config.py, settings.py, .env.example
1742
+ - Key documentation: CONTRIBUTING.md, API.md, docs/
1743
+
1744
+ GOAL-SPECIFIC SELECTION for "{goal}":
1745
+ - Files with functions/classes directly related to goal keywords
1746
+ - Files mentioned in docstrings related to the goal
1747
+ - Configuration files that would need updates for the goal
1748
+ - Test files that cover similar functionality
1749
+ - Documentation that explains related features
1750
+ - Dependencies and imports relevant to the goal
1751
+
1752
+ ENHANCED SELECTION CRITERIA:
1753
+ 1. Core project files (always include)
1754
+ 2. Files with functions/classes matching goal keywords
1755
+ 3. Files with docstrings mentioning goal-related concepts
1756
+ 4. Files in directories related to the goal
1757
+ 5. Configuration files that would be affected
1758
+ 6. Test files for related functionality
1759
+ 7. Documentation explaining similar features
1760
+ 8. Dependency files showing required packages
1761
+
1762
+ METADATA-BASED PRIORITIZATION:
1763
+ - High Priority: Files with functions/classes directly implementing goal features
1764
+ - Medium Priority: Files with related functionality or configuration
1765
+ - Low Priority: Files with tangential connections
1766
+
1767
+ Use the enhanced metadata to make intelligent decisions about file relevance.
1768
+
1769
+ Return ONLY a Python list of file paths, like:
1770
+ ["README.md", "src/auth/login.py", "config/settings.py", ...]
1771
+
1772
+ Maximum 50 files for efficient analysis.""",
1773
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
1774
+ verbose=getattr(self, 'verbose', True)
1775
+ )
1776
+
1777
+ # Prepare enhanced structure information
1778
+ basic_structure = repo_structure.get('basic_structure', {}).get('structure', '')
1779
+ file_metadata = repo_structure.get('file_metadata', '')
1780
+ file_count = repo_structure.get('file_count', 0)
1781
+
1782
+ # DEBUG: Check what metadata is actually available
1783
+ print(f" 🔍 DEBUG: Received metadata length: {len(file_metadata)} chars")
1784
+ print(f" 🔍 DEBUG: Enhanced flag: {repo_structure.get('enhanced', False)}")
1785
+ print(f" 🔍 DEBUG: Metadata preview: {file_metadata[:200] if file_metadata else 'NO METADATA'}...")
1786
+
1787
+ prompt = f"""Select the most relevant files for goal: {goal}
1788
+
1789
+ REPOSITORY: {github_url}
1790
+ GOAL: {goal}
1791
+ TOTAL FILES: {file_count}
1792
+ ENHANCED METADATA AVAILABLE: {repo_structure.get('enhanced', False)}
1793
+
1794
+ REPOSITORY STRUCTURE:
1795
+ {basic_structure}
1796
+
1797
+ PARSED CODE METADATA (Functions, Classes, Docstrings):
1798
+ {file_metadata}
1799
+
1800
+ Based on the goal "{goal}" and the parsed metadata showing actual functions/classes/docstrings:"""
1801
+
1802
+ # DEBUG: Verify f-string substitution worked
1803
+ print(f" 🔍 DEBUG: Variable values before f-string:")
1804
+ print(f" 🔍 DEBUG: goal = '{goal}'")
1805
+ print(f" 🔍 DEBUG: file_count = {file_count}")
1806
+ print(f" 🔍 DEBUG: enhanced = {repo_structure.get('enhanced', False)}")
1807
+ print(f" 🔍 DEBUG: file_metadata is None: {file_metadata is None}")
1808
+ print(f" 🔍 DEBUG: file_metadata is empty string: {repr(file_metadata == '')}")
1809
+ print(f" 🔍 DEBUG: type(file_metadata) = {type(file_metadata)}")
1810
+
1811
+ # Continue building the prompt
1812
+ prompt += """
1813
+
1814
+ INTELLIGENT SELECTION CRITERIA:
1815
+ 1. **FUNCTION-LEVEL MATCHING**: Select files that contain functions directly related to "{goal}"
1816
+ 2. **CLASS-LEVEL MATCHING**: Select files with classes that handle "{goal}" functionality
1817
+ 3. **DOCSTRING MATCHING**: Select files whose docstrings mention "{goal}" concepts
1818
+ 4. **DEPENDENCY MATCHING**: Select files that import libraries relevant to "{goal}"
1819
+ 5. **CONFIGURATION MATCHING**: Select config files that would need updates for "{goal}"
1820
+ 6. **TEST MATCHING**: Select test files that cover "{goal}" functionality
1821
+ 7. **DOCUMENTATION MATCHING**: Select docs that explain "{goal}" or similar features
1822
+
1823
+ EXAMPLES FOR AUTHENTICATION GOAL:
1824
+ - Files with functions like: login(), authenticate(), verify_token()
1825
+ - Files with classes like: User, AuthManager, SecurityHandler
1826
+ - Files with docstrings mentioning: "authentication", "login", "security", "user management"
1827
+ - Files importing: jwt, bcrypt, passport, oauth libraries
1828
+ - Config files with: security settings, database user models, API keys
1829
+ - Test files testing: login flows, authentication endpoints
1830
+ - Docs explaining: API authentication, user management
1831
+
1832
+ Use the detailed metadata to make precise selections based on actual code content, not just filenames.
1833
+
1834
+ Return as a Python list: ["file1.py", "file2.js", ...]
1835
+ Maximum 50 files.""".format(goal=goal)
1836
+
1837
+ print(" 🔍 Enhanced File Selector analyzing metadata...")
1838
+
1839
+ # DEBUG: Show the actual prompt being sent
1840
+ print(f" 🔍 DEBUG: Full prompt length: {len(prompt)} chars")
1841
+ print(f" 🔍 DEBUG: Prompt preview (first 500 chars):")
1842
+ print(f" {prompt[:500]}...")
1843
+
1844
+ # DEBUG: Check specifically for metadata in the prompt
1845
+ metadata_start = prompt.find("PARSED CODE METADATA")
1846
+ if metadata_start != -1:
1847
+ metadata_section = prompt[metadata_start:metadata_start+1000]
1848
+ print(f" 🔍 DEBUG: Found metadata section at position {metadata_start}:")
1849
+ print(f" {metadata_section}...")
1850
+ else:
1851
+ print(f" ❌ DEBUG: 'PARSED CODE METADATA' section NOT FOUND in prompt!")
1852
+
1853
+ # DEBUG: Check the actual file_metadata variable content
1854
+ print(f" 🔍 DEBUG: file_metadata variable length: {len(file_metadata)}")
1855
+ print(f" 🔍 DEBUG: file_metadata first 300 chars: {file_metadata[:300]}...")
1856
+
1857
+ response = self._chat_with_agent_and_save(file_selector, prompt, "ENHANCED_FILE_SELECTION")
1858
+
1859
+ # Parse the response to extract file list
1860
+ selected_files = self._parse_file_list_from_response(response)
1861
+
1862
+ print(f" ✅ Selected {len(selected_files)} relevant files from {file_count} total files using enhanced metadata")
1863
+ return selected_files
1864
+
1865
+ def _parse_file_list_from_response(self, response: str) -> List[str]:
1866
+ """Parse file list from agent response."""
1867
+ import re
1868
+
1869
+ # Look for Python list pattern
1870
+ list_pattern = r'\[(.*?)\]'
1871
+ matches = re.findall(list_pattern, response, re.DOTALL)
1872
+
1873
+ if matches:
1874
+ # Take the first list found
1875
+ list_content = matches[0]
1876
+ # Extract quoted strings
1877
+ file_pattern = r'["\']([^"\']+)["\']'
1878
+ files = re.findall(file_pattern, list_content)
1879
+ return files[:50] # Limit to 50 files
1880
+
1881
+ # Fallback: look for lines that look like file paths
1882
+ lines = response.split('\n')
1883
+ files = []
1884
+ for line in lines:
1885
+ line = line.strip()
1886
+ if line and ('.' in line or '/' in line) and not line.startswith('#'):
1887
+ # Remove quotes and clean up
1888
+ clean_line = line.strip('"\'`- ')
1889
+ if clean_line and not clean_line.startswith('//'):
1890
+ files.append(clean_line)
1891
+ if len(files) >= 50:
1892
+ break
1893
+
1894
+ return files
1895
+
1896
+ def _analyze_selected_files(self, github_url: str, goal: str, selected_files: List[str]) -> str:
1897
+ """Analyze only the selected relevant files with gitingest."""
1898
+ print(f" 🔍 Creating Focused Repository Analyzer for {len(selected_files)} files...")
1899
+
1900
+ # Try to get content for selected files only
1901
+ if selected_files:
1902
+ focused_content = self._get_focused_content(github_url, selected_files)
1903
+ else:
1904
+ print(" ⚠️ No files selected, falling back to full analysis...")
1905
+ focused_content = self._run_gitingest_for_github(github_url)
1906
+
1907
+ focused_analyzer = Agent(
1908
+ name="Focused Repository Analyst",
1909
+ role="Expert Repository Analysis Specialist with Focused File Selection",
1910
+ goal=f"Analyze selected repository files specifically for implementing: {goal}",
1911
+ instructions=f"""You are analyzing carefully selected files from a GitHub repository with this specific goal: {goal}
1912
+
1913
+ These files were intelligently selected to be most relevant for: {goal}
1914
+
1915
+ Focus your analysis on:
1916
+ 1. GOAL-RELEVANT COMPONENTS: How these files relate to {goal}
1917
+ 2. ARCHITECTURE: How {goal} should fit into the existing architecture
1918
+ 3. PATTERNS: Existing implementation patterns to follow for {goal}
1919
+ 4. DEPENDENCIES: What dependencies are needed for {goal}
1920
+ 5. TESTING: How to test the {goal} implementation
1921
+ 6. INTEGRATION: How {goal} integrates with existing features
1922
+ 7. CONFIGURATION: Setup and configuration needs for {goal}
1923
+ 8. EXAMPLES: Similar features that can guide {goal} implementation
1924
+
1925
+ Since these files were pre-selected for relevance, provide deep analysis of how each contributes to implementing: {goal}""",
1926
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
1927
+ verbose=getattr(self, 'verbose', True)
1928
+ )
1929
+
1930
+ prompt = f"""Analyze these carefully selected repository files for implementing: {goal}
1931
+
1932
+ REPOSITORY: {github_url}
1933
+ GOAL: {goal}
1934
+ SELECTED FILES: {len(selected_files)}
1935
+
1936
+ FILES ANALYZED:
1937
+ {', '.join(selected_files[:20])}{'...' if len(selected_files) > 20 else ''}
1938
+
1939
+ FOCUSED CONTENT:
1940
+ {focused_content[:30000] if focused_content else "No content available"}
1941
+
1942
+ Provide comprehensive analysis focused specifically on implementing the goal: {goal}
1943
+ Since these files were pre-selected for relevance, explain how each contributes to the goal."""
1944
+
1945
+ print(" 🔍 Focused Analyzer processing selected files...")
1946
+ analysis_response = self._chat_with_agent_and_save(focused_analyzer, prompt, "FOCUSED_FILE_ANALYSIS")
1947
+
1948
+ # Generate goal-focused PRP
1949
+ return self._generate_goal_focused_prp(github_url, goal, analysis_response, selected_files)
1950
+
1951
+ def _run_gitingest_for_github(self, github_url: str) -> str:
1952
+ """Run gitingest analysis specifically for GitHub repositories."""
1953
+ try:
1954
+ # Try using gitingest Python package first
1955
+ try:
1956
+ from gitingest import ingest
1957
+ print(f" 🔧 Using gitingest Python package for GitHub repository...")
1958
+ summary, tree, content = ingest(github_url)
1959
+ return f"SUMMARY:\n{summary}\n\nTREE:\n{tree}\n\nCONTENT:\n{content}"
1960
+ except ImportError:
1961
+ print(f" ⚠️ gitingest Python package not available, trying command line...")
1962
+ # Fallback to command line gitingest
1963
+ result = subprocess.run(
1964
+ ["gitingest", github_url, "--output", "-"],
1965
+ capture_output=True,
1966
+ text=True,
1967
+ timeout=120
1968
+ )
1969
+
1970
+ if result.returncode == 0:
1971
+ return result.stdout
1972
+ else:
1973
+ print(f" ⚠️ Gitingest command failed: {result.stderr}")
1974
+ return None
1975
+
1976
+ except subprocess.TimeoutExpired:
1977
+ print(" ⚠️ Gitingest analysis timed out")
1978
+ return None
1979
+ except FileNotFoundError:
1980
+ print(" ⚠️ Gitingest not found")
1981
+ return None
1982
+ except Exception as e:
1983
+ print(f" ⚠️ Gitingest error: {e}")
1984
+ return None
1985
+
1986
+ def _get_focused_content(self, github_url: str, selected_files: List[str]) -> str:
1987
+ """Get content for only the selected files."""
1988
+ try:
1989
+ # For now, fallback to full analysis since gitingest file filtering might not be available
1990
+ print(f" 📋 Getting focused content for {len(selected_files)} selected files...")
1991
+ return self._run_gitingest_for_github(github_url)
1992
+
1993
+ except Exception as e:
1994
+ print(f" ⚠️ Focused content extraction failed: {e}")
1995
+ return self._run_gitingest_for_github(github_url)
1996
+
1997
+ def _generate_goal_focused_prp(self, codebase: str, goal: str, analysis_response: str, selected_files: Union[List[str], List[Dict]] = None) -> str:
1998
+ """Generate a comprehensive PRP focused on the specific goal."""
1999
+ print(f" 📝 Creating Goal-Focused PRP Generator...")
2000
+
2001
+ prp_generator = Agent(
2002
+ name="Goal-Focused PRP Generator",
2003
+ role="Expert Goal-Focused Product Requirements Prompt Specialist",
2004
+ goal=f"Generate comprehensive PRP for implementing: {goal}",
2005
+ instructions=f"""You are generating a comprehensive PRP specifically for this goal: {goal}
2006
+
2007
+ Create a PRP following PRD template methodology that includes:
2008
+
2009
+ ## Purpose
2010
+ Clear statement for implementing: {goal}
2011
+
2012
+ ## Goal-Specific Context
2013
+ All context needed specifically for: {goal}
2014
+
2015
+ ## Implementation Blueprint for {goal}
2016
+ - Specific files to modify for {goal}
2017
+ - New files needed for {goal}
2018
+ - Dependencies required for {goal}
2019
+ - Configuration changes for {goal}
2020
+
2021
+ ## Goal-Focused Validation
2022
+ - Tests specific to {goal}
2023
+ - Quality gates for {goal}
2024
+ - Success criteria for {goal}
2025
+
2026
+ Focus everything on successfully implementing: {goal}""",
2027
+ llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
2028
+ verbose=getattr(self, 'verbose', True)
2029
+ )
2030
+
2031
+ chunk_info = ""
2032
+ if selected_files:
2033
+ chunk_info = f"\n\nSELECTED FILES ANALYZED:\n{len(selected_files)} files pre-selected for relevance"
2034
+
2035
+ prompt = f"""Generate a comprehensive Goal-Focused PRP:
2036
+
2037
+ CODEBASE: {codebase}
2038
+ GOAL: {goal}
2039
+
2040
+ REPOSITORY ANALYSIS:
2041
+ {analysis_response}
2042
+ {chunk_info}
2043
+
2044
+ Create a complete PRP following PRD template methodology, focused specifically on implementing: {goal}
2045
+ Include all necessary context, implementation guidance, and validation for this specific goal."""
2046
+
2047
+ print(" 📝 Generating goal-focused PRP...")
2048
+ prp_response = self._chat_with_agent_and_save(prp_generator, prompt, "GOAL_FOCUSED_PRP_GENERATION")
2049
+
2050
+ # Create final combined response
2051
+ all_responses = []
2052
+
2053
+ # Add parsing response
2054
+ all_responses.append({
2055
+ "agent": "Structured Input Parser",
2056
+ "phase": "Input Analysis",
2057
+ "response": f"Extracted Codebase: {codebase}\nExtracted Goal: {goal}"
2058
+ })
2059
+
2060
+ # Add repository analysis
2061
+ all_responses.append({
2062
+ "agent": "Goal-Focused Repository Analyst",
2063
+ "phase": "Repository Analysis",
2064
+ "response": analysis_response
2065
+ })
2066
+
2067
+ # Add chunk analyses if any
2068
+ if selected_files:
2069
+ for file_path in selected_files:
2070
+ all_responses.append({
2071
+ "agent": "Intelligent File Selector",
2072
+ "phase": "File Selection",
2073
+ "response": f"Selected file: {file_path}"
2074
+ })
2075
+
2076
+ # Add final PRP
2077
+ all_responses.append({
2078
+ "agent": "Goal-Focused PRP Generator",
2079
+ "phase": "Goal-Focused PRP Generation",
2080
+ "response": prp_response
2081
+ })
2082
+
2083
+ # Create combined response focused on the goal
2084
+ return self._create_goal_focused_combined_response(all_responses, codebase, goal)
2085
+
2086
+ def _generate_goal_focused_analysis(self, codebase: str, goal: str) -> str:
2087
+ """Generate goal-focused analysis for local codebase."""
2088
+ # If we have existing agent interactions from auto_analyze, incorporate them
2089
+ if hasattr(self, 'agent_interactions') and self.agent_interactions:
2090
+ return self._create_goal_focused_from_existing(codebase, goal)
2091
+ else:
2092
+ # Perform fresh analysis focused on the goal
2093
+ return self._perform_fresh_goal_analysis(codebase, goal)
2094
+
2095
+ def _create_goal_focused_combined_response(self, agent_responses: List[Dict], codebase: str, goal: str) -> str:
2096
+ """Create a comprehensive PRP focused on the specific goal."""
2097
+
2098
+ # Create comprehensive PRP content structured for LLM implementation
2099
+ prp_content = f"""# Product Requirements Prompt (PRP): {goal}
2100
+
2101
+ ## 📋 Implementation Overview
2102
+ **Target Codebase:** {codebase}
2103
+ **Implementation Goal:** {goal}
2104
+ **Analysis Date:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
2105
+
2106
+ ## 🎯 Executive Summary
2107
+ This comprehensive Product Requirements Prompt (PRP) provides all necessary context and implementation guidance for successfully implementing **{goal}** in the specified codebase. The analysis follows Context Engineering principles to ensure first-try implementation success.
2108
+
2109
+ ## 📊 Repository Analysis
2110
+ """
2111
+
2112
+ # Extract key information from agent responses
2113
+ repository_analysis = ""
2114
+ file_selections = ""
2115
+ implementation_guidance = ""
2116
+
2117
+ for response_data in agent_responses:
2118
+ agent_name = response_data.get("agent", "")
2119
+ phase = response_data.get("phase", "")
2120
+ response = response_data.get("response", "")
2121
+
2122
+ if "Repository" in phase or "Structure" in phase:
2123
+ repository_analysis += f"### {phase}\n{response}\n\n"
2124
+ elif "File Selection" in phase or "Enhanced File" in phase:
2125
+ file_selections += f"### {phase}\n{response}\n\n"
2126
+ elif "PRP Generation" in phase or "Analysis" in phase:
2127
+ implementation_guidance += f"### {phase}\n{response}\n\n"
2128
+ else:
2129
+ implementation_guidance += f"### {agent_name} - {phase}\n{response}\n\n"
2130
+
2131
+ # Build structured PRP
2132
+ prp_content += repository_analysis
2133
+
2134
+ if file_selections:
2135
+ prp_content += f"""## 📁 File Selection Strategy
2136
+ {file_selections}"""
2137
+
2138
+ prp_content += f"""## 🚀 Implementation Guidance
2139
+ {implementation_guidance}
2140
+
2141
+ ## ✅ Implementation Checklist
2142
+ Based on the analysis above, follow these steps to implement **{goal}**:
2143
+
2144
+ 1. **Review Selected Files**: Focus on the files identified in the analysis as most relevant to {goal}
2145
+ 2. **Follow Implementation Patterns**: Use the patterns and structures identified in the repository analysis
2146
+ 3. **Implement Core Functionality**: Based on the detailed guidance provided above
2147
+ 4. **Test Implementation**: Ensure the implementation works with existing codebase patterns
2148
+ 5. **Validate Goal Achievement**: Confirm that {goal} has been successfully implemented
2149
+
2150
+ ## 🎯 Success Criteria
2151
+ - [ ] {goal} functionality is fully implemented
2152
+ - [ ] Implementation follows existing codebase patterns and conventions
2153
+ - [ ] All identified files are properly updated
2154
+ - [ ] Implementation is tested and validated
2155
+ - [ ] Goal requirements are completely satisfied
2156
+
2157
+ ## 📚 Context Engineering Benefits
2158
+ This PRP provides:
2159
+ - 🎯 **Goal-Focused Analysis**: Every insight directed toward implementing {goal}
2160
+ - 🔧 **Repository Intelligence**: Deep understanding of codebase structure and patterns
2161
+ - 📋 **Actionable Guidance**: Step-by-step implementation instructions
2162
+ - ✅ **Quality Assurance**: Built-in validation and success criteria
2163
+
2164
+ **Result:** Complete implementation-ready PRP for {goal} in {codebase}
2165
+ """
2166
+
2167
+ # Save output based on debug mode
2168
+ timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
2169
+ safe_goal = goal.replace(' ', '_').replace('/', '_')[:50]
2170
+
2171
+ if self.debug_mode:
2172
+ # Debug mode: Save comprehensive report + individual files (already saved)
2173
+ self.save_comprehensive_session_report()
2174
+ final_output_file = self.save_markdown_output(
2175
+ content=prp_content,
2176
+ filename=f"comprehensive_prp_{safe_goal}_{timestamp}",
2177
+ section_title=f"Comprehensive PRP: {goal}"
2178
+ )
2179
+ print(f"🐛 Debug mode: Comprehensive session report + individual files + final PRP saved")
2180
+ else:
2181
+ # Non-debug mode: Save ONLY the final comprehensive PRP directly in .praison/prp
2182
+ # Use clean filename: goal name + timestamp
2183
+ final_output_file = self.output_dir / f"{safe_goal}_prp_{timestamp}.md"
2184
+ final_output_file.parent.mkdir(parents=True, exist_ok=True)
2185
+
2186
+ # Add markdown header for standalone file
2187
+ standalone_prp = f"""# Implementation PRP: {goal}
2188
+
2189
+ **Generated by ContextAgent**
2190
+ **Date:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
2191
+ **Codebase:** {codebase}
2192
+
2193
+ ---
2194
+
2195
+ {prp_content}
2196
+
2197
+ ---
2198
+ *This PRP contains all necessary context for implementing {goal}. Use this as your complete implementation guide.*
2199
+ """
2200
+
2201
+ with open(final_output_file, "w", encoding="utf-8") as f:
2202
+ f.write(standalone_prp)
2203
+
2204
+ print(f"✅ Implementation PRP complete with {len(self.agent_interactions)} agent interactions")
2205
+ print(f"📝 Final PRP saved: {final_output_file}")
2206
+ if not self.debug_mode:
2207
+ print(f"📋 Single file mode: Only comprehensive PRP saved (use LOGLEVEL=debug for detailed logs)")
2208
+
2209
+ # Enhanced debug summary
2210
+ self.log_debug("Session completed",
2211
+ total_interactions=len(self.agent_interactions),
2212
+ final_output=str(final_output_file),
2213
+ goal=goal,
2214
+ codebase=codebase,
2215
+ debug_mode=self.debug_mode)
2216
+
2217
+ return prp_content
2218
+
2219
+ def _analyze_url_with_goal(self, url: str, goal: str) -> str:
2220
+ """Analyze general URL with specific goal focus."""
2221
+ return self.generate_feature_prp(f"Analyze {url} and implement {goal}")
2222
+
2223
+ def _create_goal_focused_from_existing(self, codebase: str, goal: str) -> str:
2224
+ """Create goal-focused analysis from existing agent interactions."""
2225
+ # Filter and refocus existing interactions on the specific goal
2226
+ goal_focused_prp = self.generate_comprehensive_prp(
2227
+ f"Implement {goal} in {codebase}",
2228
+ {
2229
+ "codebase_analysis": self.codebase_analysis,
2230
+ "pattern_library": self.pattern_library,
2231
+ "integration_points": getattr(self, 'integration_points', {}),
2232
+ "validation_framework": self.validation_framework,
2233
+ "context_documentation": self.context_documentation,
2234
+ "specific_goal": goal
2235
+ }
2236
+ )
2237
+
2238
+ return self._create_goal_focused_combined_response([
2239
+ {
2240
+ "agent": "Goal-Focused Context Refiner",
2241
+ "phase": "Goal-Focused Analysis",
2242
+ "response": goal_focused_prp
2243
+ }
2244
+ ], codebase, goal)
2245
+
2246
+ def _perform_fresh_goal_analysis(self, codebase: str, goal: str) -> str:
2247
+ """Perform fresh analysis focused on the specific goal."""
2248
+ # Trigger analysis if not already done
2249
+ if not hasattr(self, 'codebase_analysis') or not self.codebase_analysis:
2250
+ self._perform_context_engineering_analysis()
2251
+
2252
+ return self._generate_goal_focused_analysis(codebase, goal)
2253
+
2254
+ def get_agent_interaction_summary(self) -> Dict[str, Any]:
2255
+ """Get summary of all agent interactions."""
2256
+ return {
2257
+ "total_interactions": len(self.agent_interactions),
2258
+ "phases_completed": list(set([interaction.get("phase", "") for interaction in self.agent_interactions])),
2259
+ "agents_used": list(set([interaction.get("agent_name", "") for interaction in self.agent_interactions])),
2260
+ "output_directory": self.output_dir,
2261
+ "interactions_saved": True
2262
+ }
2263
+
2264
+ def _get_structure_fallback(self, github_url: str) -> Dict[str, Any]:
2265
+ """Fallback method to get repository structure using GitHub API."""
2266
+ try:
2267
+ # Extract repo info from URL
2268
+ repo_parts = github_url.replace('https://github.com/', '').strip('/')
2269
+
2270
+ # Try using GitHub API for tree structure
2271
+ api_url = f"https://api.github.com/repos/{repo_parts}/git/trees/main?recursive=1"
2272
+
2273
+ import urllib.request
2274
+ import json
2275
+
2276
+ with urllib.request.urlopen(api_url) as response:
2277
+ data = json.loads(response.read())
2278
+
2279
+ file_structure = []
2280
+ for item in data.get('tree', []):
2281
+ if item['type'] == 'blob': # Files only
2282
+ file_structure.append(item['path'])
2283
+
2284
+ return {
2285
+ "method": "github_api",
2286
+ "structure": '\n'.join(file_structure),
2287
+ "file_count": len(file_structure),
2288
+ "success": True
2289
+ }
2290
+
2291
+ except Exception as e:
2292
+ print(f" ⚠️ GitHub API fallback failed: {e}")
2293
+ return {
2294
+ "method": "failed",
2295
+ "structure": "Unable to retrieve repository structure",
2296
+ "file_count": 0,
2297
+ "success": False
2298
+ }
2299
+
2300
+
2301
+ def create_context_agent(llm: Optional[Union[str, Any]] = None, **kwargs) -> ContextAgent:
2302
+ """
2303
+ Factory function to create a ContextAgent following Context Engineering and PRD methodology.
2304
+
2305
+ Args:
2306
+ llm: Language model to use (e.g., "gpt-4o-mini", "claude-3-haiku")
2307
+ **kwargs: Additional arguments to pass to ContextAgent constructor
2308
+
2309
+ Returns:
2310
+ ContextAgent: Configured ContextAgent for comprehensive context generation following PRD principles
2311
+ """
2312
+ if llm is None:
2313
+ llm = "gpt-4o-mini"
2314
+
2315
+ return ContextAgent(llm=llm, **kwargs)