groknroll 2.0.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.
- groknroll/__init__.py +36 -0
- groknroll/__main__.py +9 -0
- groknroll/agents/__init__.py +18 -0
- groknroll/agents/agent_manager.py +187 -0
- groknroll/agents/base_agent.py +118 -0
- groknroll/agents/build_agent.py +231 -0
- groknroll/agents/plan_agent.py +215 -0
- groknroll/cli/__init__.py +7 -0
- groknroll/cli/enhanced_cli.py +372 -0
- groknroll/cli/large_codebase_cli.py +413 -0
- groknroll/cli/main.py +331 -0
- groknroll/cli/rlm_commands.py +258 -0
- groknroll/clients/__init__.py +63 -0
- groknroll/clients/anthropic.py +112 -0
- groknroll/clients/azure_openai.py +142 -0
- groknroll/clients/base_lm.py +33 -0
- groknroll/clients/gemini.py +162 -0
- groknroll/clients/litellm.py +105 -0
- groknroll/clients/openai.py +129 -0
- groknroll/clients/portkey.py +94 -0
- groknroll/core/__init__.py +9 -0
- groknroll/core/agent.py +339 -0
- groknroll/core/comms_utils.py +264 -0
- groknroll/core/context.py +251 -0
- groknroll/core/exceptions.py +181 -0
- groknroll/core/large_codebase.py +564 -0
- groknroll/core/lm_handler.py +206 -0
- groknroll/core/rlm.py +446 -0
- groknroll/core/rlm_codebase.py +448 -0
- groknroll/core/rlm_integration.py +256 -0
- groknroll/core/types.py +276 -0
- groknroll/environments/__init__.py +34 -0
- groknroll/environments/base_env.py +182 -0
- groknroll/environments/constants.py +32 -0
- groknroll/environments/docker_repl.py +336 -0
- groknroll/environments/local_repl.py +388 -0
- groknroll/environments/modal_repl.py +502 -0
- groknroll/environments/prime_repl.py +588 -0
- groknroll/logger/__init__.py +4 -0
- groknroll/logger/rlm_logger.py +63 -0
- groknroll/logger/verbose.py +393 -0
- groknroll/operations/__init__.py +15 -0
- groknroll/operations/bash_ops.py +447 -0
- groknroll/operations/file_ops.py +473 -0
- groknroll/operations/git_ops.py +620 -0
- groknroll/oracle/__init__.py +11 -0
- groknroll/oracle/codebase_indexer.py +238 -0
- groknroll/oracle/oracle_agent.py +278 -0
- groknroll/setup.py +34 -0
- groknroll/storage/__init__.py +14 -0
- groknroll/storage/database.py +272 -0
- groknroll/storage/models.py +128 -0
- groknroll/utils/__init__.py +0 -0
- groknroll/utils/parsing.py +168 -0
- groknroll/utils/prompts.py +146 -0
- groknroll/utils/rlm_utils.py +19 -0
- groknroll-2.0.0.dist-info/METADATA +246 -0
- groknroll-2.0.0.dist-info/RECORD +62 -0
- groknroll-2.0.0.dist-info/WHEEL +5 -0
- groknroll-2.0.0.dist-info/entry_points.txt +3 -0
- groknroll-2.0.0.dist-info/licenses/LICENSE +21 -0
- groknroll-2.0.0.dist-info/top_level.txt +1 -0
groknroll/__init__.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
groknroll - The Ultimate CLI Coding Agent with RLM Core
|
|
3
|
+
|
|
4
|
+
Better than Claude Code. Local, unlimited context, autonomous.
|
|
5
|
+
Includes Recursive Language Models (RLM) for infinite context handling.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "2.0.0"
|
|
9
|
+
__author__ = "Michael Thornton"
|
|
10
|
+
|
|
11
|
+
# RLM Core exports
|
|
12
|
+
from groknroll.core.rlm import RLM
|
|
13
|
+
from groknroll.core.types import RLMChatCompletion, REPLResult, RLMIteration
|
|
14
|
+
from groknroll.core.exceptions import RLMError, REPLExecutionError, CostLimitExceededError
|
|
15
|
+
|
|
16
|
+
# groknroll CLI exports
|
|
17
|
+
from groknroll.core.agent import GroknrollAgent
|
|
18
|
+
|
|
19
|
+
# Oracle Agent exports
|
|
20
|
+
from groknroll.oracle import OracleAgent, CodebaseIndexer
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
# RLM Core
|
|
24
|
+
"RLM",
|
|
25
|
+
"RLMChatCompletion",
|
|
26
|
+
"REPLResult",
|
|
27
|
+
"RLMIteration",
|
|
28
|
+
"RLMError",
|
|
29
|
+
"REPLExecutionError",
|
|
30
|
+
"CostLimitExceededError",
|
|
31
|
+
# groknroll Agent
|
|
32
|
+
"GroknrollAgent",
|
|
33
|
+
# Oracle Agent
|
|
34
|
+
"OracleAgent",
|
|
35
|
+
"CodebaseIndexer",
|
|
36
|
+
]
|
groknroll/__main__.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Multi-agent system for groknroll
|
|
3
|
+
|
|
4
|
+
Provides build and plan agents with different permission levels.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from groknroll.agents.base_agent import BaseAgent, AgentCapability
|
|
8
|
+
from groknroll.agents.build_agent import BuildAgent
|
|
9
|
+
from groknroll.agents.plan_agent import PlanAgent
|
|
10
|
+
from groknroll.agents.agent_manager import AgentManager
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"BaseAgent",
|
|
14
|
+
"AgentCapability",
|
|
15
|
+
"BuildAgent",
|
|
16
|
+
"PlanAgent",
|
|
17
|
+
"AgentManager",
|
|
18
|
+
]
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Manager
|
|
3
|
+
|
|
4
|
+
Manages multiple agents and handles agent switching.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Dict, Optional, Any
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
from groknroll.agents.base_agent import BaseAgent, AgentResponse
|
|
12
|
+
from groknroll.agents.build_agent import BuildAgent
|
|
13
|
+
from groknroll.agents.plan_agent import PlanAgent
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class AgentInfo:
|
|
18
|
+
"""Information about an agent"""
|
|
19
|
+
name: str
|
|
20
|
+
description: str
|
|
21
|
+
capabilities: list[str]
|
|
22
|
+
is_active: bool
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class AgentManager:
|
|
26
|
+
"""
|
|
27
|
+
Agent Manager
|
|
28
|
+
|
|
29
|
+
Manages multiple agents and provides agent switching functionality.
|
|
30
|
+
Similar to OpenCode's Tab key agent switching.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
project_path: Path,
|
|
36
|
+
model: str = "gpt-4o-mini",
|
|
37
|
+
max_cost: float = 5.0,
|
|
38
|
+
timeout: int = 300
|
|
39
|
+
):
|
|
40
|
+
"""
|
|
41
|
+
Initialize agent manager
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
project_path: Project root path
|
|
45
|
+
model: Default model for agents
|
|
46
|
+
max_cost: Default max cost
|
|
47
|
+
timeout: Default timeout
|
|
48
|
+
"""
|
|
49
|
+
self.project_path = project_path
|
|
50
|
+
self.model = model
|
|
51
|
+
self.max_cost = max_cost
|
|
52
|
+
self.timeout = timeout
|
|
53
|
+
|
|
54
|
+
# Initialize agents
|
|
55
|
+
self.agents: Dict[str, BaseAgent] = {
|
|
56
|
+
"build": BuildAgent(
|
|
57
|
+
project_path=project_path,
|
|
58
|
+
model=model,
|
|
59
|
+
max_cost=max_cost,
|
|
60
|
+
timeout=timeout
|
|
61
|
+
),
|
|
62
|
+
"plan": PlanAgent(
|
|
63
|
+
project_path=project_path,
|
|
64
|
+
model=model,
|
|
65
|
+
max_cost=max_cost,
|
|
66
|
+
timeout=timeout
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Current agent
|
|
71
|
+
self.current_agent_name = "build" # Default to build agent
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def current_agent(self) -> BaseAgent:
|
|
75
|
+
"""Get current active agent"""
|
|
76
|
+
return self.agents[self.current_agent_name]
|
|
77
|
+
|
|
78
|
+
def switch(self, agent_name: str) -> bool:
|
|
79
|
+
"""
|
|
80
|
+
Switch to different agent
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
agent_name: Agent name (build/plan)
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
True if switched successfully
|
|
87
|
+
"""
|
|
88
|
+
if agent_name not in self.agents:
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
self.current_agent_name = agent_name
|
|
92
|
+
return True
|
|
93
|
+
|
|
94
|
+
def execute(
|
|
95
|
+
self,
|
|
96
|
+
task: str,
|
|
97
|
+
agent: Optional[str] = None,
|
|
98
|
+
context: Optional[Dict[str, Any]] = None
|
|
99
|
+
) -> AgentResponse:
|
|
100
|
+
"""
|
|
101
|
+
Execute task with current or specified agent
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
task: Task description
|
|
105
|
+
agent: Agent name (uses current if None)
|
|
106
|
+
context: Additional context
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
AgentResponse
|
|
110
|
+
"""
|
|
111
|
+
# Use specified agent or current
|
|
112
|
+
agent_name = agent or self.current_agent_name
|
|
113
|
+
|
|
114
|
+
if agent_name not in self.agents:
|
|
115
|
+
return AgentResponse(
|
|
116
|
+
success=False,
|
|
117
|
+
message=f"Unknown agent: {agent_name}",
|
|
118
|
+
agent_name=agent_name,
|
|
119
|
+
task=task
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Execute with agent
|
|
123
|
+
return self.agents[agent_name].execute(task, context)
|
|
124
|
+
|
|
125
|
+
def get_agent(self, name: str) -> Optional[BaseAgent]:
|
|
126
|
+
"""Get agent by name"""
|
|
127
|
+
return self.agents.get(name)
|
|
128
|
+
|
|
129
|
+
def list_agents(self) -> list[AgentInfo]:
|
|
130
|
+
"""List all available agents"""
|
|
131
|
+
return [
|
|
132
|
+
AgentInfo(
|
|
133
|
+
name=name,
|
|
134
|
+
description=agent.config.description,
|
|
135
|
+
capabilities=agent.get_capabilities(),
|
|
136
|
+
is_active=(name == self.current_agent_name)
|
|
137
|
+
)
|
|
138
|
+
for name, agent in self.agents.items()
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
142
|
+
"""Get statistics for all agents"""
|
|
143
|
+
return {
|
|
144
|
+
"current_agent": self.current_agent_name,
|
|
145
|
+
"agents": {
|
|
146
|
+
name: agent.get_stats()
|
|
147
|
+
for name, agent in self.agents.items()
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
def register_agent(self, name: str, agent: BaseAgent) -> None:
|
|
152
|
+
"""
|
|
153
|
+
Register custom agent
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
name: Agent name
|
|
157
|
+
agent: Agent instance
|
|
158
|
+
"""
|
|
159
|
+
self.agents[name] = agent
|
|
160
|
+
|
|
161
|
+
def unregister_agent(self, name: str) -> bool:
|
|
162
|
+
"""
|
|
163
|
+
Unregister agent
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
name: Agent name
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
True if unregistered successfully
|
|
170
|
+
"""
|
|
171
|
+
if name in ["build", "plan"]:
|
|
172
|
+
# Cannot unregister core agents
|
|
173
|
+
return False
|
|
174
|
+
|
|
175
|
+
if name in self.agents:
|
|
176
|
+
del self.agents[name]
|
|
177
|
+
|
|
178
|
+
# Switch to build if current agent was removed
|
|
179
|
+
if self.current_agent_name == name:
|
|
180
|
+
self.current_agent_name = "build"
|
|
181
|
+
|
|
182
|
+
return True
|
|
183
|
+
|
|
184
|
+
return False
|
|
185
|
+
|
|
186
|
+
def __repr__(self) -> str:
|
|
187
|
+
return f"AgentManager(current={self.current_agent_name}, agents={list(self.agents.keys())})"
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base Agent Interface
|
|
3
|
+
|
|
4
|
+
Defines the common interface for all groknroll agents.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Dict, Any, Optional, List
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from enum import Enum
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AgentCapability(Enum):
|
|
15
|
+
"""Agent capabilities"""
|
|
16
|
+
READ_FILES = "read_files"
|
|
17
|
+
WRITE_FILES = "write_files"
|
|
18
|
+
EDIT_FILES = "edit_files"
|
|
19
|
+
DELETE_FILES = "delete_files"
|
|
20
|
+
EXECUTE_BASH = "execute_bash"
|
|
21
|
+
GIT_OPERATIONS = "git_operations"
|
|
22
|
+
ANALYZE_CODE = "analyze_code"
|
|
23
|
+
SEARCH_CODE = "search_code"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class AgentConfig:
|
|
28
|
+
"""Configuration for an agent"""
|
|
29
|
+
name: str
|
|
30
|
+
description: str
|
|
31
|
+
capabilities: List[AgentCapability]
|
|
32
|
+
model: str = "gpt-4o-mini"
|
|
33
|
+
max_cost: float = 5.0
|
|
34
|
+
timeout: int = 300
|
|
35
|
+
verbose: bool = False
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class AgentResponse:
|
|
40
|
+
"""Response from agent execution"""
|
|
41
|
+
success: bool
|
|
42
|
+
message: str
|
|
43
|
+
agent_name: str
|
|
44
|
+
task: str
|
|
45
|
+
cost: float = 0.0
|
|
46
|
+
time: float = 0.0
|
|
47
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class BaseAgent(ABC):
|
|
51
|
+
"""
|
|
52
|
+
Base class for all groknroll agents
|
|
53
|
+
|
|
54
|
+
Agents have different capabilities and permission levels.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def __init__(self, config: AgentConfig, project_path: Path):
|
|
58
|
+
"""
|
|
59
|
+
Initialize agent
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
config: Agent configuration
|
|
63
|
+
project_path: Project root path
|
|
64
|
+
"""
|
|
65
|
+
self.config = config
|
|
66
|
+
self.project_path = project_path
|
|
67
|
+
self.execution_history: List[AgentResponse] = []
|
|
68
|
+
|
|
69
|
+
@abstractmethod
|
|
70
|
+
def execute(self, task: str, context: Optional[Dict[str, Any]] = None) -> AgentResponse:
|
|
71
|
+
"""
|
|
72
|
+
Execute task
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
task: Task description
|
|
76
|
+
context: Additional context
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
AgentResponse
|
|
80
|
+
"""
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
def can(self, capability: AgentCapability) -> bool:
|
|
84
|
+
"""Check if agent has capability"""
|
|
85
|
+
return capability in self.config.capabilities
|
|
86
|
+
|
|
87
|
+
def require(self, capability: AgentCapability) -> None:
|
|
88
|
+
"""Require capability (raises error if not available)"""
|
|
89
|
+
if not self.can(capability):
|
|
90
|
+
raise PermissionError(
|
|
91
|
+
f"Agent '{self.config.name}' does not have capability: {capability.value}"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def get_capabilities(self) -> List[str]:
|
|
95
|
+
"""Get list of capability names"""
|
|
96
|
+
return [cap.value for cap in self.config.capabilities]
|
|
97
|
+
|
|
98
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
99
|
+
"""Get agent statistics"""
|
|
100
|
+
successful = [r for r in self.execution_history if r.success]
|
|
101
|
+
failed = [r for r in self.execution_history if not r.success]
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
"name": self.config.name,
|
|
105
|
+
"total_executions": len(self.execution_history),
|
|
106
|
+
"successful": len(successful),
|
|
107
|
+
"failed": len(failed),
|
|
108
|
+
"total_cost": sum(r.cost for r in self.execution_history),
|
|
109
|
+
"total_time": sum(r.time for r in self.execution_history),
|
|
110
|
+
"capabilities": self.get_capabilities()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
def _log_execution(self, response: AgentResponse) -> None:
|
|
114
|
+
"""Log execution to history"""
|
|
115
|
+
self.execution_history.append(response)
|
|
116
|
+
|
|
117
|
+
def __repr__(self) -> str:
|
|
118
|
+
return f"{self.__class__.__name__}(name={self.config.name})"
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Build Agent
|
|
3
|
+
|
|
4
|
+
Full-access agent that can read, write, execute bash, and use git.
|
|
5
|
+
This is the primary agent for implementing features and making changes.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Dict, Any, Optional
|
|
10
|
+
import time
|
|
11
|
+
|
|
12
|
+
from groknroll.agents.base_agent import (
|
|
13
|
+
BaseAgent, AgentConfig, AgentCapability, AgentResponse
|
|
14
|
+
)
|
|
15
|
+
from groknroll.core.rlm_integration import RLMIntegration, RLMConfig
|
|
16
|
+
from groknroll.operations.file_ops import FileOperations
|
|
17
|
+
from groknroll.operations.bash_ops import BashOperations
|
|
18
|
+
from groknroll.operations.git_ops import GitOperations
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class BuildAgent(BaseAgent):
|
|
22
|
+
"""
|
|
23
|
+
Build Agent - Full Access
|
|
24
|
+
|
|
25
|
+
Capabilities:
|
|
26
|
+
- Read/write/edit/delete files
|
|
27
|
+
- Execute bash commands
|
|
28
|
+
- Git operations
|
|
29
|
+
- Code analysis
|
|
30
|
+
- Code search
|
|
31
|
+
|
|
32
|
+
Use for:
|
|
33
|
+
- Implementing new features
|
|
34
|
+
- Fixing bugs
|
|
35
|
+
- Refactoring code
|
|
36
|
+
- Running tests
|
|
37
|
+
- Building projects
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
project_path: Path,
|
|
43
|
+
model: str = "gpt-4o-mini",
|
|
44
|
+
max_cost: float = 5.0,
|
|
45
|
+
timeout: int = 300
|
|
46
|
+
):
|
|
47
|
+
"""
|
|
48
|
+
Initialize build agent
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
project_path: Project root path
|
|
52
|
+
model: LLM model to use
|
|
53
|
+
max_cost: Maximum cost per execution
|
|
54
|
+
timeout: Timeout in seconds
|
|
55
|
+
"""
|
|
56
|
+
# Build agent has all capabilities
|
|
57
|
+
config = AgentConfig(
|
|
58
|
+
name="build",
|
|
59
|
+
description="Full-access agent for building and modifying code",
|
|
60
|
+
capabilities=[
|
|
61
|
+
AgentCapability.READ_FILES,
|
|
62
|
+
AgentCapability.WRITE_FILES,
|
|
63
|
+
AgentCapability.EDIT_FILES,
|
|
64
|
+
AgentCapability.DELETE_FILES,
|
|
65
|
+
AgentCapability.EXECUTE_BASH,
|
|
66
|
+
AgentCapability.GIT_OPERATIONS,
|
|
67
|
+
AgentCapability.ANALYZE_CODE,
|
|
68
|
+
AgentCapability.SEARCH_CODE,
|
|
69
|
+
],
|
|
70
|
+
model=model,
|
|
71
|
+
max_cost=max_cost,
|
|
72
|
+
timeout=timeout
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
super().__init__(config, project_path)
|
|
76
|
+
|
|
77
|
+
# Initialize operations
|
|
78
|
+
self.file_ops = FileOperations(project_path)
|
|
79
|
+
self.bash_ops = BashOperations(project_path)
|
|
80
|
+
|
|
81
|
+
# Initialize git ops (may fail if not a git repo)
|
|
82
|
+
try:
|
|
83
|
+
self.git_ops = GitOperations(project_path)
|
|
84
|
+
except RuntimeError:
|
|
85
|
+
self.git_ops = None
|
|
86
|
+
|
|
87
|
+
# Initialize RLM
|
|
88
|
+
rlm_config = RLMConfig(
|
|
89
|
+
model=model,
|
|
90
|
+
max_cost=max_cost,
|
|
91
|
+
timeout_seconds=timeout
|
|
92
|
+
)
|
|
93
|
+
self.rlm = RLMIntegration(rlm_config)
|
|
94
|
+
|
|
95
|
+
def execute(self, task: str, context: Optional[Dict[str, Any]] = None) -> AgentResponse:
|
|
96
|
+
"""
|
|
97
|
+
Execute build task
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
task: Task description
|
|
101
|
+
context: Additional context
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
AgentResponse
|
|
105
|
+
"""
|
|
106
|
+
start_time = time.time()
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
# Prepare context with available operations
|
|
110
|
+
exec_context = {
|
|
111
|
+
"agent": "build",
|
|
112
|
+
"capabilities": self.get_capabilities(),
|
|
113
|
+
"project_path": str(self.project_path),
|
|
114
|
+
"operations": {
|
|
115
|
+
"file": "Available: read, write, edit, delete",
|
|
116
|
+
"bash": "Available: execute commands",
|
|
117
|
+
"git": "Available: status, add, commit, push, etc." if self.git_ops else "Not available"
|
|
118
|
+
},
|
|
119
|
+
**(context or {})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# Add instructions for using operations
|
|
123
|
+
enhanced_task = f"""Task: {task}
|
|
124
|
+
|
|
125
|
+
You are the BUILD agent with full access to:
|
|
126
|
+
- File operations (read, write, edit, delete)
|
|
127
|
+
- Bash execution
|
|
128
|
+
- Git operations
|
|
129
|
+
|
|
130
|
+
You can use RLM to execute Python code that calls these operations.
|
|
131
|
+
|
|
132
|
+
Available in context:
|
|
133
|
+
- file_ops: FileOperations instance
|
|
134
|
+
- bash_ops: BashOperations instance
|
|
135
|
+
- git_ops: GitOperations instance (or None)
|
|
136
|
+
|
|
137
|
+
Example usage in RLM code:
|
|
138
|
+
```python
|
|
139
|
+
# Read file
|
|
140
|
+
result = file_ops.read_file(Path("example.py"))
|
|
141
|
+
if result.success:
|
|
142
|
+
content = result.message
|
|
143
|
+
|
|
144
|
+
# Write file
|
|
145
|
+
result = file_ops.write_file(Path("new.py"), "print('hello')")
|
|
146
|
+
|
|
147
|
+
# Execute bash
|
|
148
|
+
result = bash_ops.execute("ls -la")
|
|
149
|
+
print(result.stdout)
|
|
150
|
+
|
|
151
|
+
# Git operations
|
|
152
|
+
status = git_ops.status()
|
|
153
|
+
print(f"Branch: {{status.branch}}")
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Execute the task using these operations.
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
# Execute with RLM
|
|
160
|
+
result = self.rlm.complete(
|
|
161
|
+
task=enhanced_task,
|
|
162
|
+
context=exec_context
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
elapsed_time = time.time() - start_time
|
|
166
|
+
|
|
167
|
+
response = AgentResponse(
|
|
168
|
+
success=result.success,
|
|
169
|
+
message=result.response if result.success else result.error or "Unknown error",
|
|
170
|
+
agent_name=self.config.name,
|
|
171
|
+
task=task,
|
|
172
|
+
cost=result.total_cost,
|
|
173
|
+
time=elapsed_time,
|
|
174
|
+
metadata={
|
|
175
|
+
"iterations": result.iterations,
|
|
176
|
+
"rlm_success": result.success
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
self._log_execution(response)
|
|
181
|
+
return response
|
|
182
|
+
|
|
183
|
+
except Exception as e:
|
|
184
|
+
elapsed_time = time.time() - start_time
|
|
185
|
+
|
|
186
|
+
response = AgentResponse(
|
|
187
|
+
success=False,
|
|
188
|
+
message=f"Build agent error: {e}",
|
|
189
|
+
agent_name=self.config.name,
|
|
190
|
+
task=task,
|
|
191
|
+
time=elapsed_time
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
self._log_execution(response)
|
|
195
|
+
return response
|
|
196
|
+
|
|
197
|
+
# =========================================================================
|
|
198
|
+
# Convenience Methods (Direct Operations)
|
|
199
|
+
# =========================================================================
|
|
200
|
+
|
|
201
|
+
def read_file(self, path: Path) -> str:
|
|
202
|
+
"""Read file (convenience method)"""
|
|
203
|
+
self.require(AgentCapability.READ_FILES)
|
|
204
|
+
result = self.file_ops.read_file(path)
|
|
205
|
+
if not result.success:
|
|
206
|
+
raise RuntimeError(result.message)
|
|
207
|
+
return result.message
|
|
208
|
+
|
|
209
|
+
def write_file(self, path: Path, content: str) -> None:
|
|
210
|
+
"""Write file (convenience method)"""
|
|
211
|
+
self.require(AgentCapability.WRITE_FILES)
|
|
212
|
+
result = self.file_ops.write_file(path, content, overwrite=True)
|
|
213
|
+
if not result.success:
|
|
214
|
+
raise RuntimeError(result.message)
|
|
215
|
+
|
|
216
|
+
def run_command(self, command: str) -> str:
|
|
217
|
+
"""Run bash command (convenience method)"""
|
|
218
|
+
self.require(AgentCapability.EXECUTE_BASH)
|
|
219
|
+
result = self.bash_ops.execute(command)
|
|
220
|
+
if not result.success:
|
|
221
|
+
raise RuntimeError(result.stderr)
|
|
222
|
+
return result.stdout
|
|
223
|
+
|
|
224
|
+
def git_status(self) -> str:
|
|
225
|
+
"""Get git status (convenience method)"""
|
|
226
|
+
self.require(AgentCapability.GIT_OPERATIONS)
|
|
227
|
+
if not self.git_ops:
|
|
228
|
+
raise RuntimeError("Git not available")
|
|
229
|
+
|
|
230
|
+
status = self.git_ops.status()
|
|
231
|
+
return f"Branch: {status.branch}, Staged: {len(status.staged)}, Unstaged: {len(status.unstaged)}"
|