Skip to content

Commit 5f7880d

Browse files
authored
Merge pull request #41 from nforro/tools
beeai: tools implementation
2 parents 2e5ebb5 + 08d64aa commit 5f7880d

File tree

17 files changed

+326
-27
lines changed

17 files changed

+326
-27
lines changed

beeai/Containerfile

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,22 @@ FROM fedora:42
22

33
# Install system dependencies
44
RUN dnf -y install \
5-
centpkg \
6-
curl \
7-
git \
8-
glab \
9-
python3 \
10-
python3-pip \
11-
python3-redis \
12-
rpmbuild \
13-
rpmdevtools \
14-
rpmlint \
15-
spectool \
5+
centpkg \
6+
curl \
7+
git \
8+
python3 \
9+
python3-pip \
10+
python3-redis \
11+
rpmbuild \
12+
rpmdevtools \
13+
rpmlint \
14+
spectool \
1615
&& dnf -y clean all
1716

1817
COPY beeai-gemini.patch /tmp
1918

2019
# Install BeeAI Framework and Phoenix
21-
RUN pip3 install \
20+
RUN pip3 install --no-cache-dir \
2221
beeai-framework[mcp,duckduckgo]==0.1.31 \
2322
openinference-instrumentation-beeai \
2423
arize-phoenix-otel \

beeai/Containerfile.mcp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
FROM fedora:42
2+
3+
# Install system dependencies
4+
RUN dnf -y install \
5+
python3 \
6+
python3-pip \
7+
python3-ogr \
8+
git \
9+
&& dnf clean all
10+
11+
# Install FastMCP
12+
RUN pip3 install --no-cache-dir fastmcp
13+
14+
# Create user
15+
RUN useradd -m -G wheel mcp
16+
17+
# Create directories
18+
# `/home/mcp/mcp_servers/` should be directly copied for Openshift deployment
19+
# although it is locally mounted through a volume
20+
COPY mcp_servers/ /home/mcp/mcp_servers/
21+
RUN chgrp -R root /home/mcp && chmod -R g+rwX /home/mcp
22+
23+
USER mcp
24+
WORKDIR /home/mcp
25+
26+
CMD ["/bin/bash"]

beeai/Containerfile.tests

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
FROM fedora:42
2+
3+
# Install system dependencies
4+
RUN dnf -y install \
5+
make \
6+
python3 \
7+
python3-ogr \
8+
python3-pip \
9+
python3-pytest \
10+
python3-pytest-asyncio \
11+
python3-flexmock \
12+
&& dnf clean all
13+
14+
# Install BeeAI Framework and FastMCP
15+
RUN pip3 install --no-cache-dir beeai-framework fastmcp
16+
17+
WORKDIR /src

beeai/Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,12 @@ redis-cli:
9999
.PHONY: clean
100100
clean:
101101
$(COMPOSE) -f $(COMPOSE_FILE) down --volumes
102+
103+
104+
.PHONY: build-test-image
105+
build-test-image:
106+
$(MAKE) -f Makefile.tests build-test-image
107+
108+
.PHONY: check-in-container
109+
check-in-container:
110+
$(MAKE) -f Makefile.tests check-in-container

beeai/Makefile.tests

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
TEST_IMAGE ?= beeai-tests
2+
TEST_TARGET ?= ./tests/unit
3+
4+
CONTAINER_ENGINE ?= $(shell command -v podman 2>/dev/null || echo "docker")
5+
6+
.PHONY: build-test-image
7+
build-test-image:
8+
$(CONTAINER_ENGINE) build --rm --tag $(TEST_IMAGE) -f Containerfile.tests
9+
10+
.PHONY: check
11+
check:
12+
cd ./agents && \
13+
PYTHONPATH=$(CURDIR) PYTHONDONTWRITEBYTECODE=1 python3 -m pytest --verbose --showlocals $(TEST_TARGET)
14+
cd ./mcp_servers && \
15+
PYTHONPATH=$(CURDIR) PYTHONDONTWRITEBYTECODE=1 python3 -m pytest --verbose --showlocals $(TEST_TARGET)
16+
17+
.PHONY: check-in-container
18+
check-in-container:
19+
$(CONTAINER_ENGINE) run --rm -it -v $(CURDIR):/src:z --env TEST_TARGET $(TEST_IMAGE) make -f Makefile.tests check

beeai/agents/backport_agent.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
from base_agent import BaseAgent, TInputSchema, TOutputSchema
2323
from constants import COMMIT_PREFIX, BRANCH_PREFIX
2424
from observability import setup_observability
25-
from tools import ShellCommandTool
25+
from tools.shell_command import ShellCommandTool
2626
from triage_agent import BackportData, ErrorData
27-
from utils import redis_client, get_git_finalization_steps
27+
from utils import mcp_tools, redis_client, get_git_finalization_steps
2828

2929
logger = logging.getLogger(__name__)
3030

@@ -46,6 +46,10 @@ class InputSchema(BaseModel):
4646
git_email: str = Field(
4747
description="E-mail address of the git user", default="[email protected]"
4848
)
49+
git_repo_basepath: str = Field(
50+
description="Base path for cloned git repos",
51+
default=os.getenv("GIT_REPO_BASEPATH"),
52+
)
4953

5054

5155
class OutputSchema(BaseModel):
@@ -114,9 +118,8 @@ def prompt(self) -> str:
114118
2. Check if the package {{ package }} already has the fix {{ jira_issue }} applied.
115119
116120
3. Create a local Git repository by following these steps:
117-
* Check if the fork already exists for {{ gitlab_user }} as {{ gitlab_user }}/{{ package }} and if not,
118-
create a fork of the {{ package }} package using the glab tool.
119-
* Clone the fork using git and HTTPS into the temp directory.
121+
* Create a fork of the {{ package }} package using the `fork_repository` tool.
122+
* Clone the fork using git and HTTPS into a temporary directory under {{ git_repo_basepath }}.
120123
* Run command `centpkg sources` in the cloned repository which downloads all sources defined in the RPM specfile.
121124
* Create a new Git branch named `automated-package-update-{{ jira_issue }}`.
122125
@@ -141,6 +144,19 @@ def prompt(self) -> str:
141144
6. {{ backport_git_steps }}
142145
"""
143146

147+
async def run_with_schema(self, input: TInputSchema) -> TOutputSchema:
148+
async with mcp_tools(os.getenv("MCP_GITLAB_URL")) as gitlab_tools:
149+
tools = self._tools.copy()
150+
try:
151+
self._tools.extend(gitlab_tools)
152+
return await self._run_with_schema(input)
153+
finally:
154+
self._tools = tools
155+
# disassociate removed tools from requirements
156+
for requirement in self._requirements:
157+
if requirement._source_tool in gitlab_tools:
158+
requirement._source_tool = None
159+
144160

145161
async def main() -> None:
146162
logging.basicConfig(level=logging.INFO)

beeai/agents/rebase_agent.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
from base_agent import BaseAgent, TInputSchema, TOutputSchema
2323
from constants import COMMIT_PREFIX, BRANCH_PREFIX
2424
from observability import setup_observability
25-
from tools import ShellCommandTool
25+
from tools.shell_command import ShellCommandTool
2626
from triage_agent import RebaseData, ErrorData
27-
from utils import redis_client, get_git_finalization_steps
27+
from utils import mcp_tools, redis_client, get_git_finalization_steps
2828

2929
logger = logging.getLogger(__name__)
3030

@@ -45,6 +45,10 @@ class InputSchema(BaseModel):
4545
git_email: str = Field(
4646
description="E-mail address of the git user", default="[email protected]"
4747
)
48+
git_repo_basepath: str = Field(
49+
description="Base path for cloned git repos",
50+
default=os.getenv("GIT_REPO_BASEPATH"),
51+
)
4852

4953

5054
class OutputSchema(BaseModel):
@@ -113,7 +117,6 @@ def prompt(self) -> str:
113117
* The Git user's email address is {{ git_email }}
114118
* Use {{ gitlab_user }} as the GitLab user.
115119
* Work only in a temporary directory that you can create with the mktemp tool.
116-
* To create forks and open merge requests, always use GitLab's `glab` CLI tool.
117120
* You can find packaging guidelines at https://docs.fedoraproject.org/en-US/packaging-guidelines/
118121
* You can find the RPM packaging guide at https://rpm-packaging-guide.github.io/.
119122
* Do not run the `centpkg new-sources` command for now (testing purposes), just write down the commands you would run.
@@ -137,9 +140,8 @@ def prompt(self) -> str:
137140
* Do not clone any repository for detecting the version in .spec file.
138141
139142
3. Create a local Git repository by following these steps:
140-
* Check if the fork already exists for {{ gitlab_user }} as {{ gitlab_user }}/{{ package }} and if not,
141-
create a fork of the {{ package }} package using the glab tool.
142-
* Clone the fork using git and HTTPS into the temp directory.
143+
* Create a fork of the {{ package }} package using the `fork_repository` tool.
144+
* Clone the fork using git and HTTPS into a temporary directory under {{ git_repo_basepath }}.
143145
144146
4. Update the {{ package }} to the newer version:
145147
* Create a new Git branch named `automated-package-update-{{ version }}`.
@@ -171,6 +173,19 @@ def prompt(self) -> str:
171173
- Any validation issues found with rpmlint
172174
"""
173175

176+
async def run_with_schema(self, input: TInputSchema) -> TOutputSchema:
177+
async with mcp_tools(os.getenv("MCP_GITLAB_URL")) as gitlab_tools:
178+
tools = self._tools.copy()
179+
try:
180+
self._tools.extend(gitlab_tools)
181+
return await self._run_with_schema(input)
182+
finally:
183+
self._tools = tools
184+
# disassociate removed tools from requirements
185+
for requirement in self._requirements:
186+
if requirement._source_tool in gitlab_tools:
187+
requirement._source_tool = None
188+
174189

175190
async def main() -> None:
176191
logging.basicConfig(level=logging.INFO)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import pytest
2+
3+
from beeai_framework.middleware.trajectory import GlobalTrajectoryMiddleware
4+
5+
from tools.shell_command import ShellCommandTool, ShellCommandToolInput
6+
7+
8+
@pytest.mark.parametrize(
9+
"command, exit_code, stdout, stderr",
10+
[
11+
(
12+
"exit 28",
13+
28,
14+
None,
15+
None,
16+
),
17+
(
18+
"echo -n test",
19+
0,
20+
"test",
21+
None,
22+
),
23+
(
24+
"echo -n error >&2 && false",
25+
1,
26+
None,
27+
"error",
28+
),
29+
],
30+
)
31+
@pytest.mark.asyncio
32+
async def test_shell_command(command, exit_code, stdout, stderr):
33+
tool = ShellCommandTool()
34+
output = await tool.run(input=ShellCommandToolInput(command=command)).middleware(
35+
GlobalTrajectoryMiddleware(pretty=True)
36+
)
37+
result = output.to_json_safe()
38+
assert result.exit_code == exit_code
39+
assert result.stdout == stdout
40+
assert result.stderr == stderr

beeai/agents/tools/__init__.py

Whitespace-only changes.
File renamed without changes.

0 commit comments

Comments
 (0)