acra-cli 0.1.1__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 (169) hide show
  1. acra/__init__.py +7 -0
  2. acra/__main__.py +4 -0
  3. acra/agents/__init__.py +0 -0
  4. acra/agents/__pycache__/__init__.cpython-312.pyc +0 -0
  5. acra/agents/__pycache__/llm.cpython-312.pyc +0 -0
  6. acra/agents/__pycache__/llm_utils.cpython-312.pyc +0 -0
  7. acra/agents/coder/__init__.py +0 -0
  8. acra/agents/coder/__pycache__/__init__.cpython-312.pyc +0 -0
  9. acra/agents/coder/__pycache__/coder_agent.cpython-312.pyc +0 -0
  10. acra/agents/coder/__pycache__/coder_chain.cpython-312.pyc +0 -0
  11. acra/agents/coder/coder_agent.py +235 -0
  12. acra/agents/coder/coder_chain.py +204 -0
  13. acra/agents/critic/__init__.py +0 -0
  14. acra/agents/critic/__pycache__/__init__.cpython-312.pyc +0 -0
  15. acra/agents/critic/__pycache__/critic_agent.cpython-312.pyc +0 -0
  16. acra/agents/critic/__pycache__/critic_chain.cpython-312.pyc +0 -0
  17. acra/agents/critic/critic_agent.py +199 -0
  18. acra/agents/critic/critic_chain.py +268 -0
  19. acra/agents/executor/__init__.py +0 -0
  20. acra/agents/executor/__pycache__/__init__.cpython-312.pyc +0 -0
  21. acra/agents/executor/__pycache__/docker_runner.cpython-312.pyc +0 -0
  22. acra/agents/executor/__pycache__/executor_agent.cpython-312.pyc +0 -0
  23. acra/agents/executor/__pycache__/sandbox_runner.cpython-312.pyc +0 -0
  24. acra/agents/executor/docker_runner.py +114 -0
  25. acra/agents/executor/executor_agent.py +142 -0
  26. acra/agents/executor/sandbox_runner.py +144 -0
  27. acra/agents/human/__init__.py +0 -0
  28. acra/agents/human/__pycache__/__init__.cpython-312.pyc +0 -0
  29. acra/agents/human/__pycache__/human_node.cpython-312.pyc +0 -0
  30. acra/agents/human/human_node.py +37 -0
  31. acra/agents/llm.py +263 -0
  32. acra/agents/llm_utils.py +161 -0
  33. acra/agents/memory/__init__.py +0 -0
  34. acra/agents/memory/__pycache__/__init__.cpython-312.pyc +0 -0
  35. acra/agents/memory/__pycache__/memory_agent.cpython-312.pyc +0 -0
  36. acra/agents/memory/__pycache__/memory_manager.cpython-312.pyc +0 -0
  37. acra/agents/memory/__pycache__/retrieval.cpython-312.pyc +0 -0
  38. acra/agents/memory/memory_agent.py +239 -0
  39. acra/agents/memory/memory_manager.py +273 -0
  40. acra/agents/memory/retrieval.py +355 -0
  41. acra/agents/planner/__init__.py +0 -0
  42. acra/agents/planner/__pycache__/__init__.cpython-312.pyc +0 -0
  43. acra/agents/planner/__pycache__/planner_agent.cpython-312.pyc +0 -0
  44. acra/agents/planner/__pycache__/planner_chain.cpython-312.pyc +0 -0
  45. acra/agents/planner/planner_agent.py +97 -0
  46. acra/agents/planner/planner_chain.py +160 -0
  47. acra/agents/researcher/__init__.py +1 -0
  48. acra/agents/researcher/__pycache__/__init__.cpython-312.pyc +0 -0
  49. acra/agents/researcher/__pycache__/researcher_agent.cpython-312.pyc +0 -0
  50. acra/agents/researcher/__pycache__/researcher_chain.cpython-312.pyc +0 -0
  51. acra/agents/researcher/researcher_agent.py +231 -0
  52. acra/agents/researcher/researcher_chain.py +193 -0
  53. acra/brain/__init__.py +6 -0
  54. acra/brain/model_registry.py +19 -0
  55. acra/brain/provider_manager.py +21 -0
  56. acra/cli.py +52 -0
  57. acra/commands/__init__.py +29 -0
  58. acra/commands/ask.py +49 -0
  59. acra/commands/brain.py +58 -0
  60. acra/commands/config.py +25 -0
  61. acra/commands/context.py +30 -0
  62. acra/commands/graph.py +18 -0
  63. acra/commands/keys.py +40 -0
  64. acra/commands/logs.py +13 -0
  65. acra/commands/memory.py +27 -0
  66. acra/commands/plugin.py +18 -0
  67. acra/commands/research.py +65 -0
  68. acra/commands/serve.py +13 -0
  69. acra/commands/session.py +20 -0
  70. acra/commands/utils.py +12 -0
  71. acra/config/__init__.py +36 -0
  72. acra/config/__pycache__/__init__.cpython-312.pyc +0 -0
  73. acra/config/__pycache__/defaults.cpython-312.pyc +0 -0
  74. acra/config/__pycache__/profile_manager.cpython-312.pyc +0 -0
  75. acra/config/defaults.py +88 -0
  76. acra/config/profile_manager.py +87 -0
  77. acra/execution/__init__.py +1 -0
  78. acra/execution/logs/__init__.py +1 -0
  79. acra/execution/logs/error_logs/__init__.py +1 -0
  80. acra/execution/logs/execution_logs/__init__.py +1 -0
  81. acra/execution/sandbox/__init__.py +1 -0
  82. acra/execution/sandbox/docker_executor.py +209 -0
  83. acra/execution/sandbox/isolated_runner.py +148 -0
  84. acra/execution/sandbox/sandbox_manager.py +178 -0
  85. acra/graph/__init__.py +0 -0
  86. acra/graph/checkpoint.py +85 -0
  87. acra/graph/conditional_edges.py +103 -0
  88. acra/graph/edges.py +85 -0
  89. acra/graph/graph_visualizer.py +175 -0
  90. acra/graph/nodes.py +68 -0
  91. acra/graph/router.py +69 -0
  92. acra/graph/state.py +93 -0
  93. acra/graph/workflow.py +117 -0
  94. acra/memory/__init__.py +1 -0
  95. acra/memory/checkpoints/__init__.py +1 -0
  96. acra/memory/checkpoints/data/__init__.py +1 -0
  97. acra/memory/checkpoints/postgres_checkpoint.py +247 -0
  98. acra/memory/checkpoints/sqlite_checkpoint.py +309 -0
  99. acra/memory/chroma_db/__init__.py +1 -0
  100. acra/memory/conversation_memory/__init__.py +1 -0
  101. acra/memory/conversation_memory/long_term.py +229 -0
  102. acra/memory/conversation_memory/short_term.py +158 -0
  103. acra/memory/storage/__init__.py +1 -0
  104. acra/memory/vector_store/__init__.py +0 -0
  105. acra/memory/vector_store/chroma_store.py +260 -0
  106. acra/memory/vector_store/embeddings.py +43 -0
  107. acra/observability/__init__.py +1 -0
  108. acra/observability/langsmith_tracing.py +91 -0
  109. acra/observability/metrics.py +189 -0
  110. acra/observability/monitoring.py +162 -0
  111. acra/observability/token_tracking.py +131 -0
  112. acra/prompts/__init__.py +1 -0
  113. acra/schemas/__init__.py +0 -0
  114. acra/schemas/__pycache__/__init__.cpython-312.pyc +0 -0
  115. acra/schemas/__pycache__/coder_schema.cpython-312.pyc +0 -0
  116. acra/schemas/__pycache__/critic_schema.cpython-312.pyc +0 -0
  117. acra/schemas/__pycache__/execution_schema.cpython-312.pyc +0 -0
  118. acra/schemas/__pycache__/planner_schema.cpython-312.pyc +0 -0
  119. acra/schemas/__pycache__/researcher_schema.cpython-312.pyc +0 -0
  120. acra/schemas/__pycache__/shared_schema.cpython-312.pyc +0 -0
  121. acra/schemas/coder_schema.py +257 -0
  122. acra/schemas/critic_schema.py +177 -0
  123. acra/schemas/execution_schema.py +74 -0
  124. acra/schemas/planner_schema.py +129 -0
  125. acra/schemas/researcher_schema.py +220 -0
  126. acra/schemas/shared_schema.py +329 -0
  127. acra/tools/__init__.py +1 -0
  128. acra/tools/code_tools/__init__.py +1 -0
  129. acra/tools/code_tools/file_reader.py +156 -0
  130. acra/tools/code_tools/file_writer.py +108 -0
  131. acra/tools/code_tools/python_repl.py +72 -0
  132. acra/tools/code_tools/terminal_runner.py +98 -0
  133. acra/tools/github_tools/__init__.py +1 -0
  134. acra/tools/github_tools/commit_generator.py +91 -0
  135. acra/tools/github_tools/github_search.py +113 -0
  136. acra/tools/github_tools/repo_analyzer.py +138 -0
  137. acra/tools/integration_test_helper.py +370 -0
  138. acra/tools/validation_tools/__init__.py +1 -0
  139. acra/tools/validation_tools/dependency_checker.py +101 -0
  140. acra/tools/validation_tools/environment_config_validator.py +353 -0
  141. acra/tools/validation_tools/http_validator.py +336 -0
  142. acra/tools/validation_tools/response_validator.py +407 -0
  143. acra/tools/validation_tools/security_checker.py +93 -0
  144. acra/tools/validation_tools/syntax_checker.py +75 -0
  145. acra/tools/validation_tools/web_framework_validator.py +382 -0
  146. acra/tools/web_tools/__init__.py +1 -0
  147. acra/tools/web_tools/arxiv_search.py +110 -0
  148. acra/tools/web_tools/serpapi_search.py +106 -0
  149. acra/tools/web_tools/tavily_search.py +96 -0
  150. acra/ui/__init__.py +8 -0
  151. acra/ui/__pycache__/__init__.cpython-312.pyc +0 -0
  152. acra/ui/__pycache__/banner.cpython-312.pyc +0 -0
  153. acra/ui/__pycache__/components.cpython-312.pyc +0 -0
  154. acra/ui/__pycache__/shell.cpython-312.pyc +0 -0
  155. acra/ui/__pycache__/theme.cpython-312.pyc +0 -0
  156. acra/ui/banner.py +40 -0
  157. acra/ui/components.py +32 -0
  158. acra/ui/shell.py +91 -0
  159. acra/ui/theme.py +28 -0
  160. acra/utils/__init__.py +21 -0
  161. acra/utils/context_manager.py +20 -0
  162. acra/utils/keyring_manager.py +83 -0
  163. acra/utils/output_formatter.py +18 -0
  164. acra/utils/session_manager.py +59 -0
  165. acra_cli-0.1.1.dist-info/METADATA +616 -0
  166. acra_cli-0.1.1.dist-info/RECORD +169 -0
  167. acra_cli-0.1.1.dist-info/WHEEL +5 -0
  168. acra_cli-0.1.1.dist-info/licenses/LICENSE +661 -0
  169. acra_cli-0.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,382 @@
1
+ import re
2
+ from typing import Dict, List, Optional, Tuple
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass
7
+ class FrameworkIssue:
8
+ """Framework validation issue"""
9
+ severity: str # "error", "warning", "info"
10
+ category: str # "configuration", "routing", "dependency", etc.
11
+ message: str
12
+ line_hint: Optional[str] = None
13
+
14
+
15
+ class WebFrameworkValidatorTool:
16
+ """
17
+ Web framework-specific validation tool.
18
+
19
+ Responsibilities:
20
+ - Validate Flask applications
21
+ - Validate FastAPI applications
22
+ - Check routing definitions
23
+ - Verify middleware configuration
24
+ - Check for common framework issues
25
+ """
26
+
27
+ # Framework patterns
28
+ FLASK_PATTERNS = {
29
+ "app_initialization": r"from\s+flask\s+import\s+Flask|Flask\s*\(",
30
+ "routes": r"@app\.route\(",
31
+ "blueprints": r"Blueprint\s*\(",
32
+ "error_handlers": r"@app\.errorhandler",
33
+ "before_request": r"@app\.before_request",
34
+ "after_request": r"@app\.after_request",
35
+ }
36
+
37
+ FASTAPI_PATTERNS = {
38
+ "app_initialization": r"from\s+fastapi\s+import\s+FastAPI|FastAPI\s*\(",
39
+ "routes": r"@app\.(get|post|put|delete|patch)",
40
+ "dependencies": r"from\s+fastapi\s+import\s+Depends",
41
+ "middleware": r"@app\.middleware",
42
+ "lifespan": r"lifespan\s*=",
43
+ }
44
+
45
+ DJANGO_PATTERNS = {
46
+ "models": r"from\s+django\.db\s+import\s+models|class\s+.*\(models\.Model\)",
47
+ "views": r"from\s+django\.views\s+import|def\s+\w+\(request\)",
48
+ "urls": r"from\s+django\.urls\s+import",
49
+ "settings": r"INSTALLED_APPS|DEBUG\s*=",
50
+ }
51
+
52
+ @staticmethod
53
+ def detect_framework(code: str) -> Optional[str]:
54
+ """
55
+ Detect which web framework is used.
56
+
57
+ Args:
58
+ code: Python source code
59
+
60
+ Returns:
61
+ Framework name or None
62
+ """
63
+ if re.search(WebFrameworkValidatorTool.FASTAPI_PATTERNS["app_initialization"], code):
64
+ return "fastapi"
65
+ elif re.search(WebFrameworkValidatorTool.FLASK_PATTERNS["app_initialization"], code):
66
+ return "flask"
67
+ elif re.search(WebFrameworkValidatorTool.DJANGO_PATTERNS["models"], code):
68
+ return "django"
69
+ return None
70
+
71
+ @staticmethod
72
+ def validate_flask_app(code: str) -> Dict:
73
+ """
74
+ Validate Flask application.
75
+
76
+ Args:
77
+ code: Flask application code
78
+
79
+ Returns:
80
+ Validation result with issues and recommendations
81
+ """
82
+ issues: List[FrameworkIssue] = []
83
+ features_found = {}
84
+
85
+ # Check for Flask initialization
86
+ if not re.search(WebFrameworkValidatorTool.FLASK_PATTERNS["app_initialization"], code):
87
+ issues.append(FrameworkIssue(
88
+ severity="error",
89
+ category="initialization",
90
+ message="Flask app not initialized with Flask() constructor"
91
+ ))
92
+
93
+ # Check for routes
94
+ routes = re.findall(r"@app\.route\(['\"]([^'\"]+)['\"]\)", code)
95
+ features_found["routes"] = len(routes)
96
+
97
+ if not routes:
98
+ issues.append(FrameworkIssue(
99
+ severity="warning",
100
+ category="routing",
101
+ message="No routes defined in Flask application"
102
+ ))
103
+
104
+ # Check for missing app.run()
105
+ if "app.run(" not in code:
106
+ issues.append(FrameworkIssue(
107
+ severity="warning",
108
+ category="execution",
109
+ message="No app.run() call found - application may not start"
110
+ ))
111
+
112
+ # Check for debug mode
113
+ if "debug=True" in code:
114
+ issues.append(FrameworkIssue(
115
+ severity="warning",
116
+ category="configuration",
117
+ message="Debug mode enabled - disable in production"
118
+ ))
119
+
120
+ # Check for CORS
121
+ has_cors = "CORS" in code or "cors" in code.lower()
122
+ features_found["cors"] = has_cors
123
+
124
+ # Check for error handlers
125
+ error_handlers = len(re.findall(r"@app\.errorhandler", code))
126
+ features_found["error_handlers"] = error_handlers
127
+
128
+ return {
129
+ "framework": "flask",
130
+ "valid": len([i for i in issues if i.severity == "error"]) == 0,
131
+ "issues": [
132
+ {
133
+ "severity": issue.severity,
134
+ "category": issue.category,
135
+ "message": issue.message
136
+ }
137
+ for issue in issues
138
+ ],
139
+ "features_found": features_found
140
+ }
141
+
142
+ @staticmethod
143
+ def validate_fastapi_app(code: str) -> Dict:
144
+ """
145
+ Validate FastAPI application.
146
+
147
+ Args:
148
+ code: FastAPI application code
149
+
150
+ Returns:
151
+ Validation result with issues and recommendations
152
+ """
153
+ issues: List[FrameworkIssue] = []
154
+ features_found = {}
155
+
156
+ # Check for FastAPI initialization
157
+ if not re.search(WebFrameworkValidatorTool.FASTAPI_PATTERNS["app_initialization"], code):
158
+ issues.append(FrameworkIssue(
159
+ severity="error",
160
+ category="initialization",
161
+ message="FastAPI app not initialized with FastAPI() constructor"
162
+ ))
163
+
164
+ # Check for routes
165
+ routes = re.findall(r"@app\.(get|post|put|delete|patch)\(", code)
166
+ features_found["routes"] = len(routes)
167
+
168
+ if not routes:
169
+ issues.append(FrameworkIssue(
170
+ severity="warning",
171
+ category="routing",
172
+ message="No routes defined in FastAPI application"
173
+ ))
174
+
175
+ # Check for uvicorn
176
+ has_uvicorn = "uvicorn" in code
177
+ features_found["uvicorn"] = has_uvicorn
178
+
179
+ # Check for type hints
180
+ type_hint_patterns = [
181
+ r"def\s+\w+\([^)]*:\s*\w+[^)]*\)", # Function parameters with type hints
182
+ r"->\s*[A-Z]\w+", # Return type hints
183
+ ]
184
+ has_type_hints = any(re.search(pattern, code) for pattern in type_hint_patterns)
185
+ features_found["type_hints"] = has_type_hints
186
+
187
+ # Check for response models
188
+ has_response_models = "response_model=" in code
189
+ features_found["response_models"] = has_response_models
190
+
191
+ if not has_response_models:
192
+ issues.append(FrameworkIssue(
193
+ severity="info",
194
+ category="best_practice",
195
+ message="Consider using response_model for better API documentation"
196
+ ))
197
+
198
+ # Check for CORS
199
+ has_cors = "CORSMiddleware" in code or "cors" in code.lower()
200
+ features_found["cors"] = has_cors
201
+
202
+ # Check for dependency injection
203
+ has_dependencies = "Depends(" in code
204
+ features_found["dependency_injection"] = has_dependencies
205
+
206
+ return {
207
+ "framework": "fastapi",
208
+ "valid": len([i for i in issues if i.severity == "error"]) == 0,
209
+ "issues": [
210
+ {
211
+ "severity": issue.severity,
212
+ "category": issue.category,
213
+ "message": issue.message
214
+ }
215
+ for issue in issues
216
+ ],
217
+ "features_found": features_found
218
+ }
219
+
220
+ @staticmethod
221
+ def validate_routing(code: str, framework: str) -> Dict:
222
+ """
223
+ Validate route definitions.
224
+
225
+ Args:
226
+ code: Application code
227
+ framework: Web framework name
228
+
229
+ Returns:
230
+ Routing validation result
231
+ """
232
+ issues = []
233
+ routes = []
234
+
235
+ if framework == "flask":
236
+ # Extract Flask routes
237
+ pattern = r"@app\.route\(['\"]([^'\"]+)['\"]\s*(?:,\s*methods=\[([^\]]+)\])?\)"
238
+ for match in re.finditer(pattern, code):
239
+ path = match.group(1)
240
+ methods = match.group(2)
241
+ if methods:
242
+ methods = [m.strip().strip("'\"") for m in methods.split(",")]
243
+ else:
244
+ methods = ["GET"]
245
+
246
+ # Check for common issues
247
+ if path.endswith("/"):
248
+ issues.append(f"Route '{path}' ends with trailing slash")
249
+
250
+ if "//" in path:
251
+ issues.append(f"Route '{path}' has double slashes")
252
+
253
+ routes.append({
254
+ "path": path,
255
+ "methods": methods
256
+ })
257
+
258
+ elif framework == "fastapi":
259
+ # Extract FastAPI routes
260
+ pattern = r"@app\.(get|post|put|delete|patch)\(['\"]([^'\"]+)['\"]\)"
261
+ for match in re.finditer(pattern, code):
262
+ method = match.group(1).upper()
263
+ path = match.group(2)
264
+
265
+ # Check for common issues
266
+ if not path.startswith("/"):
267
+ issues.append(f"Route '{path}' should start with /")
268
+
269
+ if path.endswith("/") and path != "/":
270
+ issues.append(f"Route '{path}' ends with trailing slash")
271
+
272
+ routes.append({
273
+ "path": path,
274
+ "method": method
275
+ })
276
+
277
+ return {
278
+ "framework": framework,
279
+ "routes_found": len(routes),
280
+ "routes": routes,
281
+ "issues": issues,
282
+ "valid": len(issues) == 0
283
+ }
284
+
285
+ @staticmethod
286
+ def validate_middleware(code: str, framework: str) -> Dict:
287
+ """
288
+ Validate middleware configuration.
289
+
290
+ Args:
291
+ code: Application code
292
+ framework: Web framework name
293
+
294
+ Returns:
295
+ Middleware validation result
296
+ """
297
+ middleware = []
298
+ issues = []
299
+
300
+ if framework == "flask":
301
+ # Check for common middleware patterns
302
+ middleware_patterns = {
303
+ "session": r"from\s+flask_session|Session\(",
304
+ "cors": r"from\s+flask_cors|CORS\(",
305
+ "caching": r"from\s+flask_caching|Cache\(",
306
+ "authentication": r"from\s+flask_login|LoginManager",
307
+ }
308
+
309
+ for name, pattern in middleware_patterns.items():
310
+ if re.search(pattern, code):
311
+ middleware.append(name)
312
+
313
+ elif framework == "fastapi":
314
+ # Check for FastAPI middleware
315
+ middleware_patterns = {
316
+ "cors": r"CORSMiddleware",
317
+ "gzip": r"GZipMiddleware",
318
+ "trusted_host": r"TrustedHostMiddleware",
319
+ "http_exception": r"HTTPException",
320
+ }
321
+
322
+ for name, pattern in middleware_patterns.items():
323
+ if re.search(pattern, code):
324
+ middleware.append(name)
325
+
326
+ return {
327
+ "framework": framework,
328
+ "middleware": middleware,
329
+ "middleware_count": len(middleware),
330
+ "issues": issues,
331
+ "valid": True
332
+ }
333
+
334
+ @staticmethod
335
+ def validate_full_app(code: str) -> Dict:
336
+ """
337
+ Perform full validation of a web application.
338
+
339
+ Args:
340
+ code: Application code
341
+
342
+ Returns:
343
+ Comprehensive validation result
344
+ """
345
+ framework = WebFrameworkValidatorTool.detect_framework(code)
346
+
347
+ if not framework:
348
+ return {
349
+ "valid": False,
350
+ "framework": None,
351
+ "error": "Could not detect web framework",
352
+ "sections": {}
353
+ }
354
+
355
+ result = {
356
+ "valid": True,
357
+ "framework": framework,
358
+ "sections": {}
359
+ }
360
+
361
+ # Run framework-specific validation
362
+ if framework == "flask":
363
+ result["sections"]["framework"] = WebFrameworkValidatorTool.validate_flask_app(code)
364
+ elif framework == "fastapi":
365
+ result["sections"]["framework"] = WebFrameworkValidatorTool.validate_fastapi_app(code)
366
+
367
+ # Validate routing
368
+ result["sections"]["routing"] = WebFrameworkValidatorTool.validate_routing(code, framework)
369
+
370
+ # Validate middleware
371
+ result["sections"]["middleware"] = WebFrameworkValidatorTool.validate_middleware(code, framework)
372
+
373
+ # Determine overall validity
374
+ errors = []
375
+ for section in result["sections"].values():
376
+ if isinstance(section, dict) and not section.get("valid", True):
377
+ errors.extend(section.get("issues", []))
378
+
379
+ result["valid"] = len(errors) == 0
380
+ result["total_issues"] = len(errors)
381
+
382
+ return result
@@ -0,0 +1 @@
1
+ # Package acra/tools/web_tools
@@ -0,0 +1,110 @@
1
+ import logging
2
+ from typing import Dict, List
3
+
4
+ import arxiv
5
+
6
+
7
+ # arxiv search tool
8
+
9
+ class ArxivSearchTool:
10
+ """
11
+ arXiv research paper retrieval tool.
12
+
13
+ Responsibilities:
14
+ - retrieve AI/ML papers
15
+ - gather academic references
16
+ - support advanced technical research
17
+ """
18
+
19
+ def __init__(
20
+ self,
21
+ max_results: int = 5
22
+ ):
23
+
24
+ self.max_results = max_results
25
+
26
+
27
+ # search papers
28
+
29
+ def search(
30
+ self,
31
+ query: str
32
+ ) -> Dict:
33
+ """
34
+ Search arXiv papers.
35
+ """
36
+
37
+ try:
38
+
39
+ search = arxiv.Search(
40
+
41
+ query=query,
42
+
43
+ max_results=self.max_results,
44
+
45
+ sort_by=arxiv.SortCriterion.Relevance
46
+ )
47
+
48
+ results = []
49
+
50
+ for paper in search.results():
51
+
52
+ results.append({
53
+
54
+ "title": paper.title,
55
+
56
+ "authors": [
57
+ author.name
58
+ for author in paper.authors
59
+ ],
60
+
61
+ "summary": paper.summary,
62
+
63
+ "published": str(
64
+ paper.published
65
+ ),
66
+
67
+ "pdf_url": paper.pdf_url,
68
+
69
+ "entry_id": paper.entry_id
70
+ })
71
+
72
+ return {
73
+
74
+ "success": True,
75
+
76
+ "query": query,
77
+
78
+ "papers": results
79
+ }
80
+
81
+ except Exception as e:
82
+ logging.getLogger(__name__).error("ArxivSearchTool.search failed: %s", e, exc_info=True)
83
+
84
+ return {
85
+
86
+ "success": False,
87
+
88
+ "query": query,
89
+
90
+ "error": str(e),
91
+
92
+ "papers": []
93
+ }
94
+
95
+
96
+ #global helper for simplified search usage
97
+
98
+ def arxiv_search(
99
+ query: str,
100
+ max_results: int = 5
101
+ ) -> Dict:
102
+ """
103
+ Simple arXiv helper.
104
+ """
105
+
106
+ tool = ArxivSearchTool(
107
+ max_results=max_results
108
+ )
109
+
110
+ return tool.search(query)
@@ -0,0 +1,106 @@
1
+ import os
2
+ import logging
3
+ from typing import Dict
4
+
5
+ from serpapi import GoogleSearch
6
+
7
+
8
+ # serpapi configuration
9
+
10
+ SERPAPI_API_KEY = os.getenv(
11
+ "SERPAPI_API_KEY"
12
+ )
13
+
14
+
15
+ # serpapi search tool
16
+
17
+ class SerpAPISearchTool:
18
+ """
19
+ Google Search tool using SerpAPI.
20
+
21
+ Responsibilities:
22
+ - retrieve Google search results
23
+ - fetch technical articles
24
+ - gather implementation references
25
+ - support researcher agent
26
+ """
27
+
28
+ def __init__(
29
+ self,
30
+ num_results: int = 5
31
+ ):
32
+
33
+ self.num_results = num_results
34
+
35
+
36
+ # search
37
+
38
+ def search(
39
+ self,
40
+ query: str
41
+ ) -> Dict:
42
+ """
43
+ Execute Google search.
44
+ """
45
+
46
+ try:
47
+
48
+ params = {
49
+
50
+ "engine": "google",
51
+
52
+ "q": query,
53
+
54
+ "api_key": SERPAPI_API_KEY,
55
+
56
+ "num": self.num_results
57
+ }
58
+
59
+ search = GoogleSearch(params)
60
+
61
+ results = search.get_dict()
62
+
63
+ organic_results = results.get(
64
+ "organic_results",
65
+ []
66
+ )
67
+
68
+ return {
69
+
70
+ "success": True,
71
+
72
+ "query": query,
73
+
74
+ "results": organic_results
75
+ }
76
+
77
+ except Exception as e:
78
+ logging.getLogger(__name__).error("SerpAPISearch.search failed: %s", e, exc_info=True)
79
+
80
+ return {
81
+
82
+ "success": False,
83
+
84
+ "query": query,
85
+
86
+ "error": str(e),
87
+
88
+ "results": []
89
+ }
90
+
91
+
92
+ #global helper for simplified search usage
93
+
94
+ def serpapi_search(
95
+ query: str,
96
+ num_results: int = 5
97
+ ) -> Dict:
98
+ """
99
+ Simple SerpAPI helper.
100
+ """
101
+
102
+ tool = SerpAPISearchTool(
103
+ num_results=num_results
104
+ )
105
+
106
+ return tool.search(query)
@@ -0,0 +1,96 @@
1
+ import os
2
+ import logging
3
+ from typing import Dict, List, Optional
4
+
5
+ from tavily import TavilyClient
6
+
7
+
8
+ #tavily search tool
9
+
10
+ class TavilySearchTool:
11
+ """
12
+ Tavily-powered web search tool.
13
+
14
+ Responsibilities:
15
+ - perform AI-optimized web search
16
+ - retrieve technical documentation
17
+ - gather implementation resources
18
+ - support research workflows
19
+ """
20
+
21
+ def __init__(
22
+ self,
23
+ max_results: int = 5
24
+ ):
25
+
26
+ self.max_results = max_results
27
+ api_key = os.getenv("TAVILY_API_KEY")
28
+ if not api_key:
29
+ raise EnvironmentError("TAVILY_API_KEY is not set.")
30
+ self.client = TavilyClient(api_key=api_key)
31
+
32
+
33
+ #search
34
+
35
+ def search(
36
+ self,
37
+ query: str,
38
+ search_depth: str = "advanced"
39
+ ) -> Dict:
40
+ """
41
+ Execute Tavily web search.
42
+ """
43
+
44
+ try:
45
+
46
+ response = self.client.search(
47
+
48
+ query=query,
49
+
50
+ search_depth=search_depth,
51
+
52
+ max_results=self.max_results
53
+ )
54
+
55
+ return {
56
+
57
+ "success": True,
58
+
59
+ "query": query,
60
+
61
+ "results": response.get(
62
+ "results",
63
+ []
64
+ )
65
+ }
66
+
67
+ except Exception as e:
68
+ logging.getLogger(__name__).error("TavilySearchTool.search failed: %s", e, exc_info=True)
69
+
70
+ return {
71
+
72
+ "success": False,
73
+
74
+ "query": query,
75
+
76
+ "error": str(e),
77
+
78
+ "results": []
79
+ }
80
+
81
+
82
+ # helper function for simplified search usage
83
+
84
+ def tavily_search(
85
+ query: str,
86
+ max_results: int = 5
87
+ ) -> Dict:
88
+ """
89
+ Simple Tavily search helper.
90
+ """
91
+
92
+ tool = TavilySearchTool(
93
+ max_results=max_results
94
+ )
95
+
96
+ return tool.search(query)
acra/ui/__init__.py ADDED
@@ -0,0 +1,8 @@
1
+ """UI components for acra."""
2
+
3
+ from .banner import welcome_banner
4
+ from .components import render_panel, render_message
5
+ from .shell import launch_shell
6
+ from .theme import get_theme
7
+
8
+ __all__ = ["welcome_banner", "render_panel", "render_message", "launch_shell", "get_theme"]