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,97 @@
1
+ """Core planner logic."""
2
+
3
+ import logging
4
+ from typing import Dict
5
+
6
+ from langchain_core.messages import AIMessage
7
+
8
+ from acra.agents.planner.planner_chain import create_planner_chain
9
+ from acra.graph.state import AgentState
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ def planner_agent(state: AgentState) -> Dict:
15
+ """Plan the next workflow step and route to the appropriate agent."""
16
+
17
+ messages = state.get("messages", [])
18
+ user_request = state.get(
19
+ "user_request",
20
+ messages[-1].content if messages else "No request provided.",
21
+ )
22
+
23
+ plan = state.get("plan", [])
24
+ completed_steps = state.get("completed_steps", [])
25
+ retry_count = state.get("retry_count", 0)
26
+ execution_success = state.get("execution_success", False)
27
+ critic_feedback = state.get("critic_feedback", "")
28
+ error_message = state.get("error_message", "")
29
+
30
+ planner_chain = create_planner_chain()
31
+
32
+ response = planner_chain.invoke({
33
+ "user_request": user_request,
34
+ "existing_plan": plan,
35
+ "completed_steps": completed_steps,
36
+ "retry_count": retry_count,
37
+ "execution_success": execution_success,
38
+ "critic_feedback": critic_feedback,
39
+ "error_message": error_message,
40
+ })
41
+
42
+ plan = response.tasks
43
+ current_step = response.current_step
44
+ workflow_status = response.workflow_status
45
+ next_agent = response.next_agent
46
+
47
+ if getattr(response, "reasoning", None):
48
+ logger.info("Planner reasoning: %s", response.reasoning)
49
+
50
+ if getattr(response, "recovery_strategy", None):
51
+ logger.info("Planner recovery strategy: %s", response.recovery_strategy)
52
+
53
+ should_request_human = state.get("interactive", False) and bool(
54
+ getattr(response, "require_human_approval", False)
55
+ )
56
+
57
+ if workflow_status == "completed":
58
+ next_agent = "end"
59
+ planner_message = (
60
+ "Planner Agent: Workflow planning and execution completed successfully."
61
+ )
62
+ elif should_request_human:
63
+ next_agent = "human"
64
+ planner_message = (
65
+ "Planner Agent: Human approval requested before continuing the workflow."
66
+ )
67
+ elif workflow_status == "researching" or next_agent == "researcher":
68
+ next_agent = "researcher"
69
+ planner_message = (
70
+ "Planner Agent: Research phase required before implementation."
71
+ )
72
+ elif retry_count >= 3:
73
+ next_agent = "critic"
74
+ planner_message = (
75
+ "Planner Agent: Execution failed multiple times. Escalating workflow to Critic Agent for analysis."
76
+ )
77
+ elif not execution_success:
78
+ next_agent = "coder"
79
+ planner_message = (
80
+ f"Planner Agent: Current Task: {current_step} Routing to Coder Agent for implementation."
81
+ )
82
+ else:
83
+ next_agent = "critic"
84
+ planner_message = (
85
+ f"Planner Agent: Task '{current_step}' completed successfully. Sending generated solution to Critic Agent for evaluation."
86
+ )
87
+
88
+ return {
89
+ "messages": messages + [AIMessage(content=planner_message)],
90
+ "plan": plan,
91
+ "current_step": current_step,
92
+ "workflow_status": workflow_status,
93
+ "next_agent": next_agent,
94
+ "current_agent": "planner",
95
+ "user_request": user_request,
96
+ }
97
+
@@ -0,0 +1,160 @@
1
+
2
+ from langchain_core.prompts import ChatPromptTemplate
3
+ from acra.schemas.planner_schema import PlannerOutput
4
+ from acra.agents.llm import llm
5
+
6
+ # create planner chain
7
+ def create_planner_chain():
8
+ """
9
+ Creates the Planner Agent chain.
10
+
11
+ Responsibilities:
12
+ - Analyze user goals
13
+ - Break tasks into executable steps
14
+ - Track workflow progress
15
+ - Decide next workflow phase
16
+ - Route execution intelligently
17
+ """
18
+
19
+ model = llm()
20
+
21
+ planner_prompt = ChatPromptTemplate.from_messages([
22
+ (
23
+ "system",
24
+
25
+ """
26
+ You are the Planner Agent inside an autonomous AI system called AgentForge.
27
+
28
+ Your role is to act as the workflow planning and orchestration intelligence.
29
+
30
+ You DO NOT write code.
31
+ You DO NOT execute programs.
32
+ You DO NOT perform research directly.
33
+
34
+ Your responsibilities:
35
+ 1. Understand the user's goal
36
+ 2. Break the task into logical execution steps
37
+ 3. Track workflow progress
38
+ 4. Decide the current workflow phase
39
+ 5. Route the workflow to the correct next agent
40
+ 6. Handle retries and recovery logic
41
+ 7. Ensure execution flows correctly
42
+
43
+ ==================================================
44
+ AVAILABLE AGENTS
45
+ ==================================================
46
+
47
+ 1. researcher
48
+ - Performs web/document/GitHub research
49
+
50
+ 2. coder
51
+ - Generates and modifies code
52
+
53
+ 3. executor
54
+ - Executes generated code
55
+
56
+ 4. critic
57
+ - Reviews quality, correctness, and security
58
+
59
+ 5. human
60
+ - Human approval/intervention node
61
+
62
+ 6. end
63
+ - Workflow completed
64
+
65
+ ==================================================
66
+ WORKFLOW RULES
67
+ ==================================================
68
+
69
+ - ALWAYS create a step-by-step plan
70
+ - Tasks should be actionable and sequential
71
+ - Prefer coder after planning
72
+ - Use critic after successful execution
73
+ - Use critic if repeated failures occur
74
+ - Use human if retries exceed safe limits
75
+ - Use end ONLY when workflow is complete
76
+
77
+ ==================================================
78
+ CURRENT WORKFLOW STATE
79
+ ==================================================
80
+
81
+ User Request:
82
+ {user_request}
83
+
84
+ Existing Plan:
85
+ {existing_plan}
86
+
87
+ Completed Steps:
88
+ {completed_steps}
89
+
90
+ Retry Count:
91
+ {retry_count}
92
+
93
+ Execution Success:
94
+ {execution_success}
95
+
96
+ Critic Feedback:
97
+ {critic_feedback}
98
+
99
+ Execution Error:
100
+ {error_message}
101
+
102
+ ==================================================
103
+ YOUR TASK
104
+ ==================================================
105
+
106
+ Analyze the workflow state carefully.
107
+
108
+ Then:
109
+ 1. Create or update the execution plan
110
+ 2. Determine the current step
111
+ 3. Determine workflow status
112
+ 4. Decide the next agent
113
+
114
+ ==================================================
115
+ OUTPUT FORMAT
116
+ ==================================================
117
+
118
+ Return ONLY valid structured output.
119
+
120
+ Fields:
121
+ - tasks
122
+ - current_step
123
+ - workflow_status
124
+ - next_agent
125
+
126
+ ==================================================
127
+ WORKFLOW STATUS OPTIONS
128
+ ==================================================
129
+
130
+ - planning
131
+ - coding
132
+ - executing
133
+ - reviewing
134
+ - failed
135
+ - completed
136
+
137
+ ==================================================
138
+ NEXT AGENT OPTIONS
139
+ ==================================================
140
+
141
+ - researcher
142
+ - coder
143
+ - executor
144
+ - critic
145
+ - human
146
+ - end
147
+ """
148
+ ),
149
+ ("human", """
150
+ Analyze the current workflow state and determine the next execution step.
151
+ """ )
152
+
153
+ ])
154
+
155
+ #structured output chain
156
+ structured_llm = model.with_structured_output(PlannerOutput)
157
+
158
+
159
+ return planner_prompt | structured_llm
160
+
@@ -0,0 +1 @@
1
+ # Package acra/agents/researcher
@@ -0,0 +1,231 @@
1
+ from typing import Dict
2
+ from langchain_core.messages import AIMessage
3
+ from acra.graph.state import AgentState
4
+ from acra.agents.researcher.researcher_chain import (
5
+ create_researcher_chain
6
+ )
7
+
8
+
9
+ def researcher_agent(state: AgentState) -> Dict:
10
+ """
11
+ Research Agent
12
+
13
+ Responsibilities:
14
+ - Analyze technical requirements
15
+ - Gather implementation guidance
16
+ - Recommend frameworks/tools
17
+ - Provide architecture insights
18
+ - Support downstream coding workflow
19
+ """
20
+
21
+ # extract state
22
+
23
+ user_request = state.get(
24
+ "user_request",
25
+ ""
26
+ )
27
+
28
+ current_step = state.get(
29
+ "current_step",
30
+ ""
31
+ )
32
+
33
+ plan = state.get(
34
+ "plan",
35
+ []
36
+ )
37
+
38
+ previous_research = state.get(
39
+ "research_data",
40
+ []
41
+ )
42
+
43
+ error_message = state.get(
44
+ "error_message",
45
+ ""
46
+ )
47
+
48
+ critic_feedback = state.get(
49
+ "critic_feedback",
50
+ ""
51
+ )
52
+
53
+
54
+ # create researcher chain
55
+
56
+ researcher_chain = create_researcher_chain()
57
+
58
+
59
+ # invoke researcher chain
60
+
61
+ response = researcher_chain.invoke({
62
+
63
+ "user_request": user_request,
64
+
65
+ "current_step": current_step,
66
+
67
+ "plan": plan,
68
+
69
+ "research_data": previous_research,
70
+
71
+ "error_message": error_message,
72
+
73
+ "critic_feedback": critic_feedback,
74
+ })
75
+
76
+
77
+ # extract structured output
78
+
79
+ research_status = response.research_status
80
+
81
+ research_summary = response.research_summary
82
+
83
+ findings = response.findings
84
+
85
+ sources = response.sources
86
+
87
+ implementation_recommendations = (
88
+ response.implementation_recommendations
89
+ )
90
+
91
+ recommended_technologies = (
92
+ response.recommended_technologies or []
93
+ )
94
+
95
+ security_considerations = (
96
+ response.security_considerations or []
97
+ )
98
+
99
+ performance_considerations = (
100
+ response.performance_considerations or []
101
+ )
102
+
103
+ architecture_suggestions = (
104
+ response.architecture_suggestions or []
105
+ )
106
+
107
+ next_agent = response.next_agent
108
+
109
+
110
+ # research status message
111
+
112
+ if research_status == "searching":
113
+
114
+ researcher_message = (
115
+ "Research Agent: "
116
+ "Analyzing technical requirements "
117
+ "and gathering implementation insights..."
118
+ )
119
+
120
+ elif research_status == "analyzing":
121
+
122
+ researcher_message = (
123
+ "Research Agent: "
124
+ "Evaluating frameworks, architecture patterns, "
125
+ "and implementation strategies..."
126
+ )
127
+
128
+ elif research_status == "completed":
129
+
130
+ researcher_message = (
131
+ "Research Agent: "
132
+ "Research completed successfully.\n\n"
133
+ f"Summary:\n{research_summary}"
134
+ )
135
+
136
+ elif research_status == "failed":
137
+
138
+ researcher_message = (
139
+ "Research Agent: "
140
+ "Research workflow encountered issues."
141
+ )
142
+
143
+ else:
144
+
145
+ researcher_message = (
146
+ "Research Agent: "
147
+ "Unexpected research state detected."
148
+ )
149
+
150
+
151
+ # format research data
152
+
153
+ formatted_findings = []
154
+
155
+ for finding in findings:
156
+
157
+ formatted_findings.append({
158
+
159
+ "topic": finding.topic,
160
+
161
+ "finding": finding.finding,
162
+
163
+ "implementation_impact": (
164
+ finding.implementation_impact
165
+ )
166
+ })
167
+
168
+
169
+ formatted_sources = []
170
+
171
+ for source in sources:
172
+
173
+ formatted_sources.append({
174
+
175
+ "title": source.title,
176
+
177
+ "source_type": source.source_type,
178
+
179
+ "url": source.url,
180
+
181
+ "summary": source.summary,
182
+
183
+ "relevance_score": (
184
+ source.relevance_score
185
+ )
186
+ })
187
+
188
+
189
+ # return updated state
190
+
191
+ return {
192
+
193
+ "messages": [
194
+ AIMessage(content=researcher_message)
195
+ ],
196
+
197
+ # Research Status
198
+ "research_status": research_status,
199
+
200
+ "research_summary": research_summary,
201
+
202
+ # Structured Research Data
203
+ "research_data": formatted_findings,
204
+
205
+ "research_sources": formatted_sources,
206
+
207
+ # Recommendations
208
+ "implementation_recommendations": (
209
+ implementation_recommendations
210
+ ),
211
+
212
+ "recommended_technologies": (
213
+ recommended_technologies
214
+ ),
215
+
216
+ "security_considerations": (
217
+ security_considerations
218
+ ),
219
+
220
+ "performance_considerations": (
221
+ performance_considerations
222
+ ),
223
+
224
+ "architecture_suggestions": (
225
+ architecture_suggestions
226
+ ),
227
+
228
+ # Workflow
229
+ "next_agent": next_agent,
230
+ "current_agent": "researcher",
231
+ }
@@ -0,0 +1,193 @@
1
+ from langchain_core.prompts import ChatPromptTemplate
2
+ from acra.agents.llm import llm
3
+
4
+ from acra.schemas.researcher_schema import ResearchOutput
5
+
6
+
7
+ #create researcher chain
8
+
9
+ def create_researcher_chain():
10
+ """
11
+ Creates the Research Agent chain.
12
+
13
+ Responsibilities:
14
+ - analyze technical requirements
15
+ - gather implementation knowledge
16
+ - recommend technologies
17
+ - provide architecture guidance
18
+ - support downstream coding agent
19
+ """
20
+
21
+ model = llm()
22
+
23
+ # Try to bind Tavily tool for web search
24
+ try:
25
+ from acra.tools.web_tools.tavily_search import TavilySearchTool
26
+ from langchain_core.tools import tool
27
+
28
+ tavily = TavilySearchTool()
29
+
30
+ @tool
31
+ def web_search(query: str) -> str:
32
+ """Search the web for technical information."""
33
+ result = tavily.search(query)
34
+ if result["success"]:
35
+ snippets = [r.get("content", "") for r in result["results"][:3]]
36
+ return "\n\n".join(snippets)
37
+ return f"Search failed: {result.get('error', 'unknown error')}"
38
+
39
+ model = model.bind_tools([web_search])
40
+ except EnvironmentError:
41
+ pass # Tavily key not set — fall back to parametric knowledge
42
+
43
+ researcher_prompt = ChatPromptTemplate.from_messages([
44
+
45
+ (
46
+ "system",
47
+
48
+ """
49
+ You are the Research Agent inside an autonomous AI system called OMNIAGENT.
50
+
51
+ You are a senior AI technical researcher and software architect.
52
+
53
+ Your role is to gather:
54
+ - implementation knowledge
55
+ - framework recommendations
56
+ - architecture patterns
57
+ - security best practices
58
+ - performance optimization insights
59
+
60
+ You DO NOT generate production code.
61
+
62
+ You ONLY:
63
+ - research
64
+ - analyze
65
+ - summarize
66
+ - recommend
67
+ - guide implementation
68
+
69
+ ==================================================
70
+ YOUR RESPONSIBILITIES
71
+ ==================================================
72
+
73
+ You must:
74
+
75
+ 1. Analyze the user request carefully
76
+
77
+ 2. Identify:
78
+ - required technologies
79
+ - relevant frameworks
80
+ - implementation patterns
81
+ - architecture approaches
82
+
83
+ 3. Recommend:
84
+ - libraries
85
+ - APIs
86
+ - tools
87
+ - best practices
88
+
89
+ 4. Identify:
90
+ - security concerns
91
+ - scalability concerns
92
+ - performance considerations
93
+
94
+ 5. Support downstream coding agent with:
95
+ - implementation guidance
96
+ - architecture recommendations
97
+ - dependency recommendations
98
+
99
+ ==================================================
100
+ CURRENT WORKFLOW STATE
101
+ ==================================================
102
+
103
+ USER REQUEST:
104
+ {user_request}
105
+
106
+ CURRENT TASK:
107
+ {current_step}
108
+
109
+ FULL EXECUTION PLAN:
110
+ {plan}
111
+
112
+ PREVIOUS RESEARCH:
113
+ {research_data}
114
+
115
+ EXECUTION ERRORS:
116
+ {error_message}
117
+
118
+ CRITIC FEEDBACK:
119
+ {critic_feedback}
120
+
121
+ ==================================================
122
+ RESEARCH OBJECTIVES
123
+ ==================================================
124
+
125
+ You should focus on:
126
+
127
+ 1. IMPLEMENTATION STRATEGY
128
+ 2. ARCHITECTURE DESIGN
129
+ 3. FRAMEWORK SELECTION
130
+ 4. SECURITY BEST PRACTICES
131
+ 5. PERFORMANCE OPTIMIZATION
132
+ 6. DEPENDENCY RECOMMENDATIONS
133
+ 7. SCALABILITY CONSIDERATIONS
134
+
135
+ ==================================================
136
+ IMPORTANT RULES
137
+ ==================================================
138
+
139
+ - Recommend realistic technologies only
140
+ - Avoid hallucinated libraries
141
+ - Prefer production-grade solutions
142
+ - Focus on implementation practicality
143
+ - Keep recommendations concise but actionable
144
+ - Think like a senior software architect
145
+
146
+ ==================================================
147
+ NEXT AGENT RULES
148
+ ==================================================
149
+
150
+ - Usually route to "coder"
151
+ - Route to "planner" if task needs replanning
152
+ - Route to "human" if request is unsafe/unclear
153
+
154
+ ==================================================
155
+ OUTPUT REQUIREMENTS
156
+ ==================================================
157
+
158
+ Return ONLY structured output.
159
+
160
+ ==================================================
161
+ IMPORTANT
162
+ ==================================================
163
+
164
+ Your output will directly guide the Coding Agent.
165
+
166
+ Provide:
167
+ - implementation clarity
168
+ - architectural direction
169
+ - production-grade recommendations
170
+ """
171
+ ),
172
+
173
+ (
174
+ "human",
175
+
176
+ """
177
+ Research the technical requirements and provide implementation guidance.
178
+ """
179
+ )
180
+
181
+ ])
182
+
183
+
184
+ # structure output
185
+
186
+ structured_llm = model.with_structured_output(
187
+ ResearchOutput
188
+ )
189
+
190
+
191
+ #return chain
192
+
193
+ return researcher_prompt | structured_llm
acra/brain/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Package acra.brain."""
2
+
3
+ from .provider_manager import ProviderManager
4
+ from .model_registry import ModelRegistry
5
+
6
+ __all__ = ["ProviderManager", "ModelRegistry"]
@@ -0,0 +1,19 @@
1
+ """Brain model registry utilities for acra."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Dict, List, Optional
6
+
7
+
8
+ class ModelRegistry:
9
+ """Stub model registry for brain provider commands."""
10
+
11
+ DEFAULT_MODELS: Dict[str, List[str]] = {
12
+ "gemini": ["gemini-2.5-flash", "gemini-2.5-pro"],
13
+ "openai": ["gpt-4o", "gpt-4.1"],
14
+ }
15
+
16
+ def list_models(self, provider: Optional[str] = None) -> List[str]:
17
+ if provider:
18
+ return self.DEFAULT_MODELS.get(provider, [])
19
+ return [model for models in self.DEFAULT_MODELS.values() for model in models]