diff --git a/.github/workflows/build-agent.yaml b/.github/workflows/build-agent.yaml new file mode 100644 index 0000000..7a83aff --- /dev/null +++ b/.github/workflows/build-agent.yaml @@ -0,0 +1,51 @@ +name: Build and Push Agent Image + +on: + push: + tags: + - 'release-*' + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python environment + uses: actions/setup-python@v4 + with: + python-version: '3.13' + + - name: Install Agent Stack CLI + run: pip install agentstack-cli + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker + uses: docker/setup-docker-action@v4 + with: + daemon-config: '{"features": {"containerd-snapshotter": true}}' + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract version from tag + id: extract_version + run: | + # Extract version from tag (e.g., release-1.2.3 -> 1.2.3) + VERSION=${GITHUB_REF#refs/tags/release-} + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Build and Push + run: | + agentstack build ./ --tag ghcr.io/${{ github.repository }}/github-issue-creator:${{ steps.extract_version.outputs.version }} --no-import --multi-platform --push \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3cc086f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.13-slim-trixie +COPY --from=ghcr.io/astral-sh/uv:0.7.15 /uv /bin/ + +ENV UV_LINK_MODE=copy \ + PRODUCTION_MODE=true \ + IS_BUILD_PASS=true + +ADD . /app +WORKDIR /app + +RUN uv sync --no-cache --locked --link-mode copy + +ENV PRODUCTION_MODE=True \ + PATH="/app/.venv/bin:$PATH" \ + HOME=/tmp + +CMD ["uv", "run", "--no-sync", "server"] \ No newline at end of file diff --git a/README.md b/README.md index 762f83e..0602470 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,21 @@ uv run server The server will start on `http://127.0.0.1:8000` and register the GitHub Issue Creator agent that coordinates the complete workflow. +### Running in Agent Stack + +You can also easily start the agent in [Agent Stack](https://agentstack.beeai.dev/). + +```bash +# Install the GH issue creator +agentstack add ghcr.io/i-am-bee/github-issue-creator/github-issue-creator:0.2.0 + +# Setup the repo +agentstack env add "GitHub Issue Creator" GITHUB_REPOSITORY=username/reponame + +# Setup the PAT +agentstack env add "GitHub Issue Creator" GITHUB_PAT=github_pat_XXX +``` + ## Security Considerations > [!WARNING] diff --git a/pyproject.toml b/pyproject.toml index ee4efcd..1df824f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "github-issue-creator" -version = "0.1.0" +version = "0.2.0" readme = "README.md" authors = [ {name = "Matous Havlena", email = "matous.havlena@ibm.com"} diff --git a/src/github_issue_creator/agents/build_mock.py b/src/github_issue_creator/agents/build_mock.py new file mode 100644 index 0000000..9edaebb --- /dev/null +++ b/src/github_issue_creator/agents/build_mock.py @@ -0,0 +1,6 @@ +from beeai_framework.agents.requirement import RequirementAgent +from github_issue_creator.utils.config import llm + + +def get_build_mock(): + return RequirementAgent(llm=llm) \ No newline at end of file diff --git a/src/github_issue_creator/agents/manager.py b/src/github_issue_creator/agents/manager.py index 029a6d3..f23a3ff 100644 --- a/src/github_issue_creator/agents/manager.py +++ b/src/github_issue_creator/agents/manager.py @@ -25,6 +25,7 @@ async def get_agent_manager(): """Create and configure the issue workflow management agent.""" + tools = await session_manager.get_tools() try: diff --git a/src/github_issue_creator/server.py b/src/github_issue_creator/server.py index 7e1146b..4958cc0 100644 --- a/src/github_issue_creator/server.py +++ b/src/github_issue_creator/server.py @@ -1,21 +1,27 @@ +import os + import asyncio from textwrap import dedent from a2a.types import AgentSkill from beeai_framework.adapters.beeai_platform.serve.server import BeeAIPlatformServer -from agentstack_sdk.a2a.extensions.ui.agent_detail import AgentDetail +from agentstack_sdk.a2a.extensions.ui.agent_detail import AgentDetail, EnvVar from openinference.instrumentation.beeai import BeeAIInstrumentor from github_issue_creator.agents.manager import get_agent_manager +from github_issue_creator.agents.build_mock import get_build_mock BeeAIInstrumentor().instrument() +async def get_root_agent(): + return get_build_mock() if os.getenv("IS_BUILD_PASS") == "true" else await get_agent_manager() async def run(): - manager = await get_agent_manager() - server = BeeAIPlatformServer(config={"configure_telemetry": True}) + root_agent = await get_root_agent() + + server = BeeAIPlatformServer(config={"configure_telemetry": True, "port": 8000,"host": "0.0.0.0"}) server.register( - manager, + root_agent, name="GitHub Issue Creator", description=dedent( """\ @@ -28,6 +34,14 @@ async def run(): detail=AgentDetail( interaction_mode="multi-turn", framework="BeeAI", + variables=[ + EnvVar(name="GITHUB_REPOSITORY", description="The repository to create the issue in", required=True), + EnvVar(name="GITHUB_PAT", description="The GitHub Personal Access Token to use for the API", required=True), + + EnvVar(name="DOCS_URL", description="The URL of the documentation to use for the API", required=False), + EnvVar(name="TEMPLATE_BUG_URL", description="The URL of the bug template to use for the API", required=False), + EnvVar(name="TEMPLATE_FEATURE_URL", description="The URL of the feature template to use for the API", required=False), + ], ), skills=[ AgentSkill( diff --git a/src/github_issue_creator/utils/config.py b/src/github_issue_creator/utils/config.py index 51a90a3..efbd592 100644 --- a/src/github_issue_creator/utils/config.py +++ b/src/github_issue_creator/utils/config.py @@ -1,12 +1,18 @@ import os - from beeai_framework.backend import ChatModel from dotenv import load_dotenv +from beeai_framework.adapters.agentstack.backend.chat import AgentStackChatModel + load_dotenv() -model = os.getenv("MODEL", "openai:gpt-5-mini") -llm = ChatModel.from_name(model, {"api_key": os.getenv("API_KEY")}) +default_model = "openai:gpt-5-mini" + +if os.getenv("API_KEY") is not None: + model = os.getenv("MODEL", default_model) + llm = ChatModel.from_name(model, {"api_key": os.getenv("API_KEY")}) +else: + llm = AgentStackChatModel(preferred_models=[default_model]) # Import after load_dotenv to ensure env vars are loaded from github_issue_creator.tools.session_manager import SessionManager diff --git a/uv.lock b/uv.lock index a41a94d..d7fe3fa 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.11, <4.0" resolution-markers = [ "python_full_version >= '3.13'", @@ -733,7 +733,7 @@ wheels = [ [[package]] name = "github-issue-creator" -version = "0.1.0" +version = "0.2.0" source = { editable = "." } dependencies = [ { name = "agentstack-sdk" },