code-graph-builder 0.2.0__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.
Files changed (93) hide show
  1. code_graph_builder/__init__.py +82 -0
  2. code_graph_builder/builder.py +366 -0
  3. code_graph_builder/cgb_cli.py +32 -0
  4. code_graph_builder/cli.py +564 -0
  5. code_graph_builder/commands_cli.py +1288 -0
  6. code_graph_builder/config.py +340 -0
  7. code_graph_builder/constants.py +708 -0
  8. code_graph_builder/embeddings/__init__.py +40 -0
  9. code_graph_builder/embeddings/qwen3_embedder.py +573 -0
  10. code_graph_builder/embeddings/vector_store.py +584 -0
  11. code_graph_builder/examples/__init__.py +0 -0
  12. code_graph_builder/examples/example_configuration.py +276 -0
  13. code_graph_builder/examples/example_kuzu_usage.py +109 -0
  14. code_graph_builder/examples/example_semantic_search_full.py +347 -0
  15. code_graph_builder/examples/generate_wiki.py +915 -0
  16. code_graph_builder/examples/graph_export_example.py +100 -0
  17. code_graph_builder/examples/rag_example.py +206 -0
  18. code_graph_builder/examples/test_cli_demo.py +129 -0
  19. code_graph_builder/examples/test_embedding_api.py +153 -0
  20. code_graph_builder/examples/test_kuzu_local.py +190 -0
  21. code_graph_builder/examples/test_rag_redis.py +390 -0
  22. code_graph_builder/graph_updater.py +605 -0
  23. code_graph_builder/guidance/__init__.py +1 -0
  24. code_graph_builder/guidance/agent.py +123 -0
  25. code_graph_builder/guidance/prompts.py +74 -0
  26. code_graph_builder/guidance/toolset.py +264 -0
  27. code_graph_builder/language_spec.py +536 -0
  28. code_graph_builder/mcp/__init__.py +21 -0
  29. code_graph_builder/mcp/api_doc_generator.py +764 -0
  30. code_graph_builder/mcp/file_editor.py +207 -0
  31. code_graph_builder/mcp/pipeline.py +777 -0
  32. code_graph_builder/mcp/server.py +161 -0
  33. code_graph_builder/mcp/tools.py +1800 -0
  34. code_graph_builder/models.py +115 -0
  35. code_graph_builder/parser_loader.py +344 -0
  36. code_graph_builder/parsers/__init__.py +7 -0
  37. code_graph_builder/parsers/call_processor.py +306 -0
  38. code_graph_builder/parsers/call_resolver.py +139 -0
  39. code_graph_builder/parsers/definition_processor.py +796 -0
  40. code_graph_builder/parsers/factory.py +119 -0
  41. code_graph_builder/parsers/import_processor.py +293 -0
  42. code_graph_builder/parsers/structure_processor.py +145 -0
  43. code_graph_builder/parsers/type_inference.py +143 -0
  44. code_graph_builder/parsers/utils.py +134 -0
  45. code_graph_builder/rag/__init__.py +68 -0
  46. code_graph_builder/rag/camel_agent.py +429 -0
  47. code_graph_builder/rag/client.py +298 -0
  48. code_graph_builder/rag/config.py +239 -0
  49. code_graph_builder/rag/cypher_generator.py +67 -0
  50. code_graph_builder/rag/llm_backend.py +210 -0
  51. code_graph_builder/rag/markdown_generator.py +352 -0
  52. code_graph_builder/rag/prompt_templates.py +440 -0
  53. code_graph_builder/rag/rag_engine.py +640 -0
  54. code_graph_builder/rag/review_report.md +172 -0
  55. code_graph_builder/rag/tests/__init__.py +3 -0
  56. code_graph_builder/rag/tests/test_camel_agent.py +313 -0
  57. code_graph_builder/rag/tests/test_client.py +221 -0
  58. code_graph_builder/rag/tests/test_config.py +177 -0
  59. code_graph_builder/rag/tests/test_markdown_generator.py +240 -0
  60. code_graph_builder/rag/tests/test_prompt_templates.py +160 -0
  61. code_graph_builder/services/__init__.py +39 -0
  62. code_graph_builder/services/graph_service.py +465 -0
  63. code_graph_builder/services/kuzu_service.py +665 -0
  64. code_graph_builder/services/memory_service.py +171 -0
  65. code_graph_builder/settings.py +75 -0
  66. code_graph_builder/tests/ACCEPTANCE_CRITERIA_PHASE2.md +401 -0
  67. code_graph_builder/tests/__init__.py +1 -0
  68. code_graph_builder/tests/run_acceptance_check.py +378 -0
  69. code_graph_builder/tests/test_api_find.py +231 -0
  70. code_graph_builder/tests/test_api_find_integration.py +226 -0
  71. code_graph_builder/tests/test_basic.py +78 -0
  72. code_graph_builder/tests/test_c_api_extraction.py +388 -0
  73. code_graph_builder/tests/test_call_resolution_scenarios.py +504 -0
  74. code_graph_builder/tests/test_embedder.py +411 -0
  75. code_graph_builder/tests/test_integration_semantic.py +434 -0
  76. code_graph_builder/tests/test_mcp_protocol.py +298 -0
  77. code_graph_builder/tests/test_mcp_user_flow.py +190 -0
  78. code_graph_builder/tests/test_rag.py +404 -0
  79. code_graph_builder/tests/test_settings.py +135 -0
  80. code_graph_builder/tests/test_step1_graph_build.py +264 -0
  81. code_graph_builder/tests/test_step2_api_docs.py +323 -0
  82. code_graph_builder/tests/test_step3_embedding.py +278 -0
  83. code_graph_builder/tests/test_vector_store.py +552 -0
  84. code_graph_builder/tools/__init__.py +40 -0
  85. code_graph_builder/tools/graph_query.py +495 -0
  86. code_graph_builder/tools/semantic_search.py +387 -0
  87. code_graph_builder/types.py +333 -0
  88. code_graph_builder/utils/__init__.py +0 -0
  89. code_graph_builder/utils/path_utils.py +30 -0
  90. code_graph_builder-0.2.0.dist-info/METADATA +321 -0
  91. code_graph_builder-0.2.0.dist-info/RECORD +93 -0
  92. code_graph_builder-0.2.0.dist-info/WHEEL +4 -0
  93. code_graph_builder-0.2.0.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,134 @@
1
+ """Code Graph Builder - Parser Utilities."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable
6
+ from functools import lru_cache
7
+ from typing import TYPE_CHECKING, NamedTuple
8
+
9
+ from loguru import logger
10
+ from tree_sitter import Node, Query, QueryCursor
11
+
12
+ from .. import constants as cs
13
+ from ..types import ASTNode, LanguageQueries, NodeType, PropertyDict, SimpleNameLookup
14
+
15
+ if TYPE_CHECKING:
16
+ from ..language_spec import LanguageSpec
17
+ from ..services import IngestorProtocol
18
+ from ..types import FunctionRegistryTrieProtocol
19
+
20
+
21
+ class FunctionCapturesResult(NamedTuple):
22
+ """Result of capturing functions from AST."""
23
+
24
+ lang_config: LanguageSpec
25
+ captures: dict[str, list[ASTNode]]
26
+
27
+
28
+ def get_function_captures(
29
+ root_node: ASTNode,
30
+ language: cs.SupportedLanguage,
31
+ queries: dict[cs.SupportedLanguage, LanguageQueries],
32
+ ) -> FunctionCapturesResult | None:
33
+ """Get function captures from AST using Tree-sitter query."""
34
+ lang_queries = queries[language]
35
+ lang_config = lang_queries[cs.QUERY_CONFIG]
36
+
37
+ if not (query := lang_queries[cs.QUERY_FUNCTIONS]):
38
+ return None
39
+
40
+ cursor = QueryCursor(query)
41
+ captures = cursor.captures(root_node)
42
+ return FunctionCapturesResult(lang_config, captures)
43
+
44
+
45
+ @lru_cache(maxsize=10000)
46
+ def _cached_decode_bytes(text_bytes: bytes) -> str:
47
+ """Cached byte decoding for performance."""
48
+ return text_bytes.decode(cs.ENCODING_UTF8)
49
+
50
+
51
+ def safe_decode_text(node: ASTNode | None) -> str | None:
52
+ """Safely decode node text to string."""
53
+ if node is None or (text_bytes := node.text) is None:
54
+ return None
55
+ if isinstance(text_bytes, bytes):
56
+ return _cached_decode_bytes(text_bytes)
57
+ return str(text_bytes)
58
+
59
+
60
+ def safe_decode_with_fallback(node: ASTNode | None, fallback: str = "") -> str:
61
+ """Safely decode node text with fallback."""
62
+ return result if (result := safe_decode_text(node)) is not None else fallback
63
+
64
+
65
+ def contains_node(parent: ASTNode, target: ASTNode) -> bool:
66
+ """Check if parent contains target node."""
67
+ return parent == target or any(
68
+ contains_node(child, target) for child in parent.children
69
+ )
70
+
71
+
72
+ def ingest_method(
73
+ method_node: ASTNode,
74
+ container_qn: str,
75
+ container_type: cs.NodeLabel,
76
+ ingestor: IngestorProtocol,
77
+ function_registry: FunctionRegistryTrieProtocol,
78
+ simple_name_lookup: SimpleNameLookup,
79
+ get_docstring_func: Callable[[ASTNode], str | None],
80
+ language: cs.SupportedLanguage | None = None,
81
+ extract_decorators_func: Callable[[ASTNode], list[str]] | None = None,
82
+ method_qualified_name: str | None = None,
83
+ ) -> None:
84
+ """Ingest a method node into the graph."""
85
+ # Extract method name
86
+ if language == cs.SupportedLanguage.CPP:
87
+ from .cpp import utils as cpp_utils
88
+
89
+ method_name = cpp_utils.extract_function_name(method_node)
90
+ if not method_name:
91
+ return
92
+ elif not (method_name_node := method_node.child_by_field_name(cs.FIELD_NAME)):
93
+ return
94
+ elif (text := method_name_node.text) is None:
95
+ return
96
+ else:
97
+ method_name = text.decode(cs.ENCODING_UTF8)
98
+
99
+ method_qn = method_qualified_name or f"{container_qn}.{method_name}"
100
+
101
+ decorators = extract_decorators_func(method_node) if extract_decorators_func else []
102
+
103
+ method_props: PropertyDict = {
104
+ cs.KEY_QUALIFIED_NAME: method_qn,
105
+ cs.KEY_NAME: method_name,
106
+ cs.KEY_DECORATORS: decorators,
107
+ cs.KEY_START_LINE: method_node.start_point[0] + 1,
108
+ cs.KEY_END_LINE: method_node.end_point[0] + 1,
109
+ cs.KEY_DOCSTRING: get_docstring_func(method_node),
110
+ }
111
+
112
+ logger.info(f" Found Method: {method_name} (qn: {method_qn})")
113
+ ingestor.ensure_node_batch(cs.NodeLabel.METHOD, method_props)
114
+ function_registry[method_qn] = NodeType.METHOD
115
+ simple_name_lookup[method_name].add(method_qn)
116
+
117
+ ingestor.ensure_relationship_batch(
118
+ (container_type, cs.KEY_QUALIFIED_NAME, container_qn),
119
+ cs.RelationshipType.DEFINES_METHOD,
120
+ (cs.NodeLabel.METHOD, cs.KEY_QUALIFIED_NAME, method_qn),
121
+ )
122
+
123
+
124
+ def is_method_node(func_node: ASTNode, lang_config: LanguageSpec) -> bool:
125
+ """Check if a function node is actually a method."""
126
+ current = func_node.parent
127
+ if not isinstance(current, Node):
128
+ return False
129
+
130
+ while current and current.type not in lang_config.module_node_types:
131
+ if current.type in lang_config.class_node_types:
132
+ return True
133
+ current = current.parent
134
+ return False
@@ -0,0 +1,68 @@
1
+ """RAG module for code graph-based retrieval and generation.
2
+
3
+ This module provides RAG (Retrieval-Augmented Generation) capabilities
4
+ for code analysis using CAMEL framework and OpenAI-compatible LLM APIs.
5
+
6
+ Example:
7
+ >>> from code_graph_builder.rag import RAGConfig, create_rag_engine
8
+ >>> from code_graph_builder.rag.camel_agent import CamelAgent
9
+ >>>
10
+ >>> config = RAGConfig.from_env()
11
+ >>> engine = create_rag_engine(config)
12
+ >>> result = engine.query("Explain the authentication flow")
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from .config import (
18
+ MoonshotConfig,
19
+ OutputConfig,
20
+ RAGConfig,
21
+ RetrievalConfig,
22
+ )
23
+ from .client import (
24
+ ChatResponse,
25
+ LLMClient,
26
+ create_llm_client,
27
+ )
28
+ from .markdown_generator import (
29
+ AnalysisResult,
30
+ MarkdownGenerator,
31
+ SourceReference,
32
+ )
33
+ from .prompt_templates import (
34
+ CodeAnalysisPrompts,
35
+ CodeContext,
36
+ RAGPrompts,
37
+ create_code_context,
38
+ )
39
+ from .rag_engine import (
40
+ RAGEngine,
41
+ RAGResult,
42
+ create_rag_engine,
43
+ )
44
+
45
+ __all__ = [
46
+ # Config
47
+ "RAGConfig",
48
+ "MoonshotConfig",
49
+ "RetrievalConfig",
50
+ "OutputConfig",
51
+ # Engine
52
+ "RAGEngine",
53
+ "RAGResult",
54
+ "create_rag_engine",
55
+ # LLM Client
56
+ "LLMClient",
57
+ "ChatResponse",
58
+ "create_llm_client",
59
+ # Prompts
60
+ "CodeAnalysisPrompts",
61
+ "RAGPrompts",
62
+ "CodeContext",
63
+ "create_code_context",
64
+ # Markdown
65
+ "MarkdownGenerator",
66
+ "AnalysisResult",
67
+ "SourceReference",
68
+ ]
@@ -0,0 +1,429 @@
1
+ """CAMEL Agent wrapper for RAG integration.
2
+
3
+ This module provides integration with the CAMEL framework for multi-agent
4
+ code analysis workflows.
5
+
6
+ Note: This is a simplified implementation that provides CAMEL-like interfaces
7
+ without requiring the full CAMEL framework dependency. It can be extended
8
+ to use the actual CAMEL library if needed.
9
+
10
+ Examples:
11
+ >>> from code_graph_builder.rag.camel_agent import CamelAgent
12
+ >>> agent = CamelAgent(
13
+ ... role="Code Analyst",
14
+ ... goal="Analyze code and provide insights",
15
+ ... backstory="Expert in software architecture"
16
+ ... )
17
+ >>> result = agent.analyze("Explain this function", context="def foo(): pass")
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from dataclasses import dataclass, field
23
+ from typing import TYPE_CHECKING, Any, Protocol
24
+
25
+ from loguru import logger
26
+
27
+ from .client import LLMClient, create_llm_client
28
+ from .prompt_templates import CodeAnalysisPrompts, CodeContext
29
+
30
+ if TYPE_CHECKING:
31
+ from .rag_engine import RAGEngine, RAGResult
32
+
33
+
34
+ class AgentResponse(Protocol):
35
+ """Protocol for agent responses."""
36
+
37
+ content: str
38
+ metadata: dict[str, Any]
39
+
40
+
41
+ @dataclass
42
+ class CamelAgentResponse:
43
+ """Response from CAMEL agent.
44
+
45
+ Attributes:
46
+ content: Generated response content
47
+ metadata: Additional metadata
48
+ role: Agent role that generated the response
49
+ """
50
+
51
+ content: str
52
+ metadata: dict[str, Any] = field(default_factory=dict)
53
+ role: str = "agent"
54
+
55
+
56
+ class CamelAgent:
57
+ """CAMEL-style agent for code analysis.
58
+
59
+ Provides a CAMEL-like interface for single-agent code analysis tasks.
60
+ This implementation uses an OpenAI-compatible LLM as the underlying model.
61
+
62
+ Args:
63
+ role: Agent's role (e.g., "Code Analyst")
64
+ goal: Agent's goal/objective
65
+ backstory: Agent's background/context
66
+ llm_client: LLM API client
67
+ verbose: Enable verbose logging
68
+
69
+ Examples:
70
+ >>> agent = CamelAgent(
71
+ ... role="Senior Python Developer",
72
+ ... goal="Review code for best practices",
73
+ ... backstory="10+ years of Python experience"
74
+ ... )
75
+ >>> response = agent.analyze("Review this function", code="def foo(): pass")
76
+ >>> print(response.content)
77
+ """
78
+
79
+ def __init__(
80
+ self,
81
+ role: str,
82
+ goal: str,
83
+ backstory: str,
84
+ llm_client: LLMClient | None = None,
85
+ verbose: bool = False,
86
+ ):
87
+ self.role = role
88
+ self.goal = goal
89
+ self.backstory = backstory
90
+ self.llm_client = llm_client or create_llm_client()
91
+ self.verbose = verbose
92
+ self.prompts = CodeAnalysisPrompts()
93
+
94
+ # Build system prompt from role definition
95
+ self.system_prompt = self._build_system_prompt()
96
+
97
+ logger.info(f"Initialized CamelAgent: {role}")
98
+
99
+ def _build_system_prompt(self) -> str:
100
+ """Build system prompt from agent definition."""
101
+ return f"""You are a {self.role}.
102
+
103
+ Your Goal: {self.goal}
104
+
105
+ Your Backstory: {self.backstory}
106
+
107
+ Guidelines:
108
+ 1. Always stay in character as a {self.role}
109
+ 2. Focus on achieving your stated goal
110
+ 3. Use your expertise and background to provide insightful analysis
111
+ 4. Be thorough but concise in your responses
112
+ 5. When analyzing code, consider best practices, patterns, and potential issues
113
+
114
+ Respond in a professional, helpful manner."""
115
+
116
+ def analyze(
117
+ self,
118
+ task: str,
119
+ code: str | None = None,
120
+ context: str | None = None,
121
+ ) -> CamelAgentResponse:
122
+ """Analyze code or answer a question.
123
+
124
+ Args:
125
+ task: Task description or question
126
+ code: Code to analyze (optional)
127
+ context: Additional context (optional)
128
+
129
+ Returns:
130
+ CamelAgentResponse with analysis
131
+ """
132
+ # Build user message
133
+ user_content = task
134
+ if code:
135
+ user_content += f"\n\n```python\n{code}\n```"
136
+ if context:
137
+ user_content += f"\n\nContext: {context}"
138
+
139
+ messages = [
140
+ {"role": "system", "content": self.system_prompt},
141
+ {"role": "user", "content": user_content},
142
+ ]
143
+
144
+ try:
145
+ response = self.llm_client.chat_with_messages(messages)
146
+ return CamelAgentResponse(
147
+ content=response.content,
148
+ metadata={
149
+ "usage": response.usage,
150
+ "model": response.model,
151
+ },
152
+ role=self.role,
153
+ )
154
+ except Exception as e:
155
+ logger.error(f"Agent analysis failed: {e}")
156
+ return CamelAgentResponse(
157
+ content=f"Error during analysis: {e}",
158
+ metadata={"error": str(e)},
159
+ role=self.role,
160
+ )
161
+
162
+ def review_code(
163
+ self,
164
+ code: str,
165
+ review_type: str = "general",
166
+ ) -> CamelAgentResponse:
167
+ """Review code for specific aspects.
168
+
169
+ Args:
170
+ code: Code to review
171
+ review_type: Type of review (general, security, performance, style)
172
+
173
+ Returns:
174
+ Code review response
175
+ """
176
+ review_prompts = {
177
+ "general": "Please review this code for general quality, correctness, and best practices.",
178
+ "security": "Please review this code for security vulnerabilities and best practices.",
179
+ "performance": "Please review this code for performance issues and optimization opportunities.",
180
+ "style": "Please review this code for code style, readability, and maintainability.",
181
+ }
182
+
183
+ prompt = review_prompts.get(review_type, review_prompts["general"])
184
+
185
+ return self.analyze(
186
+ task=f"{prompt}\n\nProvide specific recommendations with examples.",
187
+ code=code,
188
+ )
189
+
190
+ def explain_code(
191
+ self,
192
+ code: str,
193
+ detail_level: str = "medium",
194
+ ) -> CamelAgentResponse:
195
+ """Explain code in detail.
196
+
197
+ Args:
198
+ code: Code to explain
199
+ detail_level: Level of detail (brief, medium, detailed)
200
+
201
+ Returns:
202
+ Code explanation
203
+ """
204
+ detail_instructions = {
205
+ "brief": "Provide a brief, high-level summary of what this code does.",
206
+ "medium": "Explain this code with a balance of high-level overview and key details.",
207
+ "detailed": "Provide a detailed explanation covering all logic, edge cases, and design decisions.",
208
+ }
209
+
210
+ instruction = detail_instructions.get(detail_level, detail_instructions["medium"])
211
+
212
+ return self.analyze(
213
+ task=f"{instruction}\n\nFormat your response in markdown.",
214
+ code=code,
215
+ )
216
+
217
+ def suggest_improvements(
218
+ self,
219
+ code: str,
220
+ focus_areas: list[str] | None = None,
221
+ ) -> CamelAgentResponse:
222
+ """Suggest improvements for code.
223
+
224
+ Args:
225
+ code: Code to improve
226
+ focus_areas: Specific areas to focus on (e.g., ["readability", "performance"])
227
+
228
+ Returns:
229
+ Improvement suggestions
230
+ """
231
+ task = "Suggest improvements for this code."
232
+
233
+ if focus_areas:
234
+ task += f"\n\nFocus on: {', '.join(focus_areas)}"
235
+
236
+ task += "\n\nFor each suggestion, provide:\n1. The issue\n2. Why it matters\n3. A concrete improved example"
237
+
238
+ return self.analyze(task=task, code=code)
239
+
240
+ def answer_question(
241
+ self,
242
+ question: str,
243
+ code_context: str | None = None,
244
+ ) -> CamelAgentResponse:
245
+ """Answer a question about code.
246
+
247
+ Args:
248
+ question: The question to answer
249
+ code_context: Relevant code context
250
+
251
+ Returns:
252
+ Answer response
253
+ """
254
+ return self.analyze(
255
+ task=question,
256
+ code=code_context,
257
+ )
258
+
259
+
260
+ class MultiAgentRAG:
261
+ """Multi-agent RAG system using CAMEL-style agents.
262
+
263
+ Coordinates multiple specialized agents for comprehensive code analysis.
264
+
265
+ Args:
266
+ rag_engine: RAG engine for retrieval
267
+ verbose: Enable verbose logging
268
+
269
+ Example:
270
+ >>> multi_agent = MultiAgentRAG(rag_engine)
271
+ >>> result = multi_agent.analyze(
272
+ ... query="Explain the authentication system",
273
+ ... analysis_types=["architecture", "security"]
274
+ ... )
275
+ """
276
+
277
+ def __init__(
278
+ self,
279
+ rag_engine: RAGEngine,
280
+ verbose: bool = False,
281
+ ):
282
+ self.rag_engine = rag_engine
283
+ self.verbose = verbose
284
+
285
+ # Initialize specialized agents
286
+ self._init_agents()
287
+
288
+ def _init_agents(self) -> None:
289
+ """Initialize specialized agents."""
290
+ self.architect = CamelAgent(
291
+ role="Software Architect",
292
+ goal="Analyze code architecture and design patterns",
293
+ backstory="Senior architect with 15+ years of experience in system design",
294
+ llm_client=self.rag_engine.llm_client,
295
+ verbose=self.verbose,
296
+ )
297
+
298
+ self.security_expert = CamelAgent(
299
+ role="Security Engineer",
300
+ goal="Identify security vulnerabilities and best practices",
301
+ backstory="Security specialist with expertise in secure coding practices",
302
+ llm_client=self.rag_engine.llm_client,
303
+ verbose=self.verbose,
304
+ )
305
+
306
+ self.performance_expert = CamelAgent(
307
+ role="Performance Engineer",
308
+ goal="Optimize code performance and resource usage",
309
+ backstory="Performance optimization specialist with deep knowledge of algorithms",
310
+ llm_client=self.rag_engine.llm_client,
311
+ verbose=self.verbose,
312
+ )
313
+
314
+ self.documentation_writer = CamelAgent(
315
+ role="Technical Writer",
316
+ goal="Create clear, comprehensive documentation",
317
+ backstory="Technical writer specializing in developer documentation",
318
+ llm_client=self.rag_engine.llm_client,
319
+ verbose=self.verbose,
320
+ )
321
+
322
+ def analyze(
323
+ self,
324
+ query: str,
325
+ analysis_types: list[str] | None = None,
326
+ ) -> dict[str, CamelAgentResponse]:
327
+ """Run multi-agent analysis on a query.
328
+
329
+ Args:
330
+ query: User query
331
+ analysis_types: Types of analysis to run (architecture, security, performance, docs)
332
+
333
+ Returns:
334
+ Dictionary of agent responses
335
+ """
336
+ if analysis_types is None:
337
+ analysis_types = ["architecture", "docs"]
338
+
339
+ # First, retrieve relevant code
340
+ rag_result = self.rag_engine.query(query)
341
+
342
+ # Build context from retrieved code
343
+ context_parts = []
344
+ for ctx in rag_result.contexts[:3]: # Limit to top 3 contexts
345
+ context_parts.append(ctx.format_context())
346
+ code_context = "\n\n---\n\n".join(context_parts)
347
+
348
+ # Run agent analyses
349
+ results: dict[str, CamelAgentResponse] = {}
350
+
351
+ if "architecture" in analysis_types:
352
+ results["architecture"] = self.architect.analyze(
353
+ task=f"Analyze the architecture and design patterns for: {query}",
354
+ context=code_context,
355
+ )
356
+
357
+ if "security" in analysis_types:
358
+ results["security"] = self.security_expert.analyze(
359
+ task=f"Review security aspects of: {query}",
360
+ context=code_context,
361
+ )
362
+
363
+ if "performance" in analysis_types:
364
+ results["performance"] = self.performance_expert.analyze(
365
+ task=f"Analyze performance characteristics of: {query}",
366
+ context=code_context,
367
+ )
368
+
369
+ if "docs" in analysis_types:
370
+ results["documentation"] = self.documentation_writer.analyze(
371
+ task=f"Create documentation for: {query}",
372
+ context=code_context,
373
+ )
374
+
375
+ return results
376
+
377
+ def comprehensive_review(
378
+ self,
379
+ qualified_name: str,
380
+ ) -> dict[str, CamelAgentResponse]:
381
+ """Run comprehensive review of a code entity.
382
+
383
+ Args:
384
+ qualified_name: Fully qualified name of the entity
385
+
386
+ Returns:
387
+ Dictionary of agent reviews
388
+ """
389
+ # Get code explanation first
390
+ rag_result = self.rag_engine.explain_code(qualified_name)
391
+
392
+ # Get source code
393
+ code = ""
394
+ if rag_result.contexts:
395
+ code = rag_result.contexts[0].source_code
396
+
397
+ # Run all agents
398
+ results: dict[str, CamelAgentResponse] = {
399
+ "explanation": rag_result,
400
+ "architecture": self.architect.analyze(
401
+ task="Analyze the architecture and design patterns in this code",
402
+ code=code,
403
+ ),
404
+ "security": self.security_expert.review_code(code, review_type="security"),
405
+ "performance": self.performance_expert.review_code(code, review_type="performance"),
406
+ "documentation": self.documentation_writer.explain_code(code, detail_level="detailed"),
407
+ }
408
+
409
+ return results
410
+
411
+
412
+ def create_camel_agent(
413
+ role: str,
414
+ goal: str,
415
+ backstory: str,
416
+ **kwargs: Any,
417
+ ) -> CamelAgent:
418
+ """Factory function to create a CAMEL agent.
419
+
420
+ Args:
421
+ role: Agent role
422
+ goal: Agent goal
423
+ backstory: Agent backstory
424
+ **kwargs: Additional arguments for CamelAgent
425
+
426
+ Returns:
427
+ Configured CamelAgent
428
+ """
429
+ return CamelAgent(role=role, goal=goal, backstory=backstory, **kwargs)