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.
- acra/__init__.py +7 -0
- acra/__main__.py +4 -0
- acra/agents/__init__.py +0 -0
- acra/agents/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/__pycache__/llm.cpython-312.pyc +0 -0
- acra/agents/__pycache__/llm_utils.cpython-312.pyc +0 -0
- acra/agents/coder/__init__.py +0 -0
- acra/agents/coder/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/coder/__pycache__/coder_agent.cpython-312.pyc +0 -0
- acra/agents/coder/__pycache__/coder_chain.cpython-312.pyc +0 -0
- acra/agents/coder/coder_agent.py +235 -0
- acra/agents/coder/coder_chain.py +204 -0
- acra/agents/critic/__init__.py +0 -0
- acra/agents/critic/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/critic/__pycache__/critic_agent.cpython-312.pyc +0 -0
- acra/agents/critic/__pycache__/critic_chain.cpython-312.pyc +0 -0
- acra/agents/critic/critic_agent.py +199 -0
- acra/agents/critic/critic_chain.py +268 -0
- acra/agents/executor/__init__.py +0 -0
- acra/agents/executor/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/executor/__pycache__/docker_runner.cpython-312.pyc +0 -0
- acra/agents/executor/__pycache__/executor_agent.cpython-312.pyc +0 -0
- acra/agents/executor/__pycache__/sandbox_runner.cpython-312.pyc +0 -0
- acra/agents/executor/docker_runner.py +114 -0
- acra/agents/executor/executor_agent.py +142 -0
- acra/agents/executor/sandbox_runner.py +144 -0
- acra/agents/human/__init__.py +0 -0
- acra/agents/human/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/human/__pycache__/human_node.cpython-312.pyc +0 -0
- acra/agents/human/human_node.py +37 -0
- acra/agents/llm.py +263 -0
- acra/agents/llm_utils.py +161 -0
- acra/agents/memory/__init__.py +0 -0
- acra/agents/memory/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/memory/__pycache__/memory_agent.cpython-312.pyc +0 -0
- acra/agents/memory/__pycache__/memory_manager.cpython-312.pyc +0 -0
- acra/agents/memory/__pycache__/retrieval.cpython-312.pyc +0 -0
- acra/agents/memory/memory_agent.py +239 -0
- acra/agents/memory/memory_manager.py +273 -0
- acra/agents/memory/retrieval.py +355 -0
- acra/agents/planner/__init__.py +0 -0
- acra/agents/planner/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/planner/__pycache__/planner_agent.cpython-312.pyc +0 -0
- acra/agents/planner/__pycache__/planner_chain.cpython-312.pyc +0 -0
- acra/agents/planner/planner_agent.py +97 -0
- acra/agents/planner/planner_chain.py +160 -0
- acra/agents/researcher/__init__.py +1 -0
- acra/agents/researcher/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/researcher/__pycache__/researcher_agent.cpython-312.pyc +0 -0
- acra/agents/researcher/__pycache__/researcher_chain.cpython-312.pyc +0 -0
- acra/agents/researcher/researcher_agent.py +231 -0
- acra/agents/researcher/researcher_chain.py +193 -0
- acra/brain/__init__.py +6 -0
- acra/brain/model_registry.py +19 -0
- acra/brain/provider_manager.py +21 -0
- acra/cli.py +52 -0
- acra/commands/__init__.py +29 -0
- acra/commands/ask.py +49 -0
- acra/commands/brain.py +58 -0
- acra/commands/config.py +25 -0
- acra/commands/context.py +30 -0
- acra/commands/graph.py +18 -0
- acra/commands/keys.py +40 -0
- acra/commands/logs.py +13 -0
- acra/commands/memory.py +27 -0
- acra/commands/plugin.py +18 -0
- acra/commands/research.py +65 -0
- acra/commands/serve.py +13 -0
- acra/commands/session.py +20 -0
- acra/commands/utils.py +12 -0
- acra/config/__init__.py +36 -0
- acra/config/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/config/__pycache__/defaults.cpython-312.pyc +0 -0
- acra/config/__pycache__/profile_manager.cpython-312.pyc +0 -0
- acra/config/defaults.py +88 -0
- acra/config/profile_manager.py +87 -0
- acra/execution/__init__.py +1 -0
- acra/execution/logs/__init__.py +1 -0
- acra/execution/logs/error_logs/__init__.py +1 -0
- acra/execution/logs/execution_logs/__init__.py +1 -0
- acra/execution/sandbox/__init__.py +1 -0
- acra/execution/sandbox/docker_executor.py +209 -0
- acra/execution/sandbox/isolated_runner.py +148 -0
- acra/execution/sandbox/sandbox_manager.py +178 -0
- acra/graph/__init__.py +0 -0
- acra/graph/checkpoint.py +85 -0
- acra/graph/conditional_edges.py +103 -0
- acra/graph/edges.py +85 -0
- acra/graph/graph_visualizer.py +175 -0
- acra/graph/nodes.py +68 -0
- acra/graph/router.py +69 -0
- acra/graph/state.py +93 -0
- acra/graph/workflow.py +117 -0
- acra/memory/__init__.py +1 -0
- acra/memory/checkpoints/__init__.py +1 -0
- acra/memory/checkpoints/data/__init__.py +1 -0
- acra/memory/checkpoints/postgres_checkpoint.py +247 -0
- acra/memory/checkpoints/sqlite_checkpoint.py +309 -0
- acra/memory/chroma_db/__init__.py +1 -0
- acra/memory/conversation_memory/__init__.py +1 -0
- acra/memory/conversation_memory/long_term.py +229 -0
- acra/memory/conversation_memory/short_term.py +158 -0
- acra/memory/storage/__init__.py +1 -0
- acra/memory/vector_store/__init__.py +0 -0
- acra/memory/vector_store/chroma_store.py +260 -0
- acra/memory/vector_store/embeddings.py +43 -0
- acra/observability/__init__.py +1 -0
- acra/observability/langsmith_tracing.py +91 -0
- acra/observability/metrics.py +189 -0
- acra/observability/monitoring.py +162 -0
- acra/observability/token_tracking.py +131 -0
- acra/prompts/__init__.py +1 -0
- acra/schemas/__init__.py +0 -0
- acra/schemas/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/schemas/__pycache__/coder_schema.cpython-312.pyc +0 -0
- acra/schemas/__pycache__/critic_schema.cpython-312.pyc +0 -0
- acra/schemas/__pycache__/execution_schema.cpython-312.pyc +0 -0
- acra/schemas/__pycache__/planner_schema.cpython-312.pyc +0 -0
- acra/schemas/__pycache__/researcher_schema.cpython-312.pyc +0 -0
- acra/schemas/__pycache__/shared_schema.cpython-312.pyc +0 -0
- acra/schemas/coder_schema.py +257 -0
- acra/schemas/critic_schema.py +177 -0
- acra/schemas/execution_schema.py +74 -0
- acra/schemas/planner_schema.py +129 -0
- acra/schemas/researcher_schema.py +220 -0
- acra/schemas/shared_schema.py +329 -0
- acra/tools/__init__.py +1 -0
- acra/tools/code_tools/__init__.py +1 -0
- acra/tools/code_tools/file_reader.py +156 -0
- acra/tools/code_tools/file_writer.py +108 -0
- acra/tools/code_tools/python_repl.py +72 -0
- acra/tools/code_tools/terminal_runner.py +98 -0
- acra/tools/github_tools/__init__.py +1 -0
- acra/tools/github_tools/commit_generator.py +91 -0
- acra/tools/github_tools/github_search.py +113 -0
- acra/tools/github_tools/repo_analyzer.py +138 -0
- acra/tools/integration_test_helper.py +370 -0
- acra/tools/validation_tools/__init__.py +1 -0
- acra/tools/validation_tools/dependency_checker.py +101 -0
- acra/tools/validation_tools/environment_config_validator.py +353 -0
- acra/tools/validation_tools/http_validator.py +336 -0
- acra/tools/validation_tools/response_validator.py +407 -0
- acra/tools/validation_tools/security_checker.py +93 -0
- acra/tools/validation_tools/syntax_checker.py +75 -0
- acra/tools/validation_tools/web_framework_validator.py +382 -0
- acra/tools/web_tools/__init__.py +1 -0
- acra/tools/web_tools/arxiv_search.py +110 -0
- acra/tools/web_tools/serpapi_search.py +106 -0
- acra/tools/web_tools/tavily_search.py +96 -0
- acra/ui/__init__.py +8 -0
- acra/ui/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/ui/__pycache__/banner.cpython-312.pyc +0 -0
- acra/ui/__pycache__/components.cpython-312.pyc +0 -0
- acra/ui/__pycache__/shell.cpython-312.pyc +0 -0
- acra/ui/__pycache__/theme.cpython-312.pyc +0 -0
- acra/ui/banner.py +40 -0
- acra/ui/components.py +32 -0
- acra/ui/shell.py +91 -0
- acra/ui/theme.py +28 -0
- acra/utils/__init__.py +21 -0
- acra/utils/context_manager.py +20 -0
- acra/utils/keyring_manager.py +83 -0
- acra/utils/output_formatter.py +18 -0
- acra/utils/session_manager.py +59 -0
- acra_cli-0.1.1.dist-info/METADATA +616 -0
- acra_cli-0.1.1.dist-info/RECORD +169 -0
- acra_cli-0.1.1.dist-info/WHEEL +5 -0
- acra_cli-0.1.1.dist-info/licenses/LICENSE +661 -0
- 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
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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,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]
|