From 504a347eaa52ffad3f0050266617f638e4fa6bd1 Mon Sep 17 00:00:00 2001 From: Roxanne Farhad Date: Wed, 22 Oct 2025 17:12:20 -0400 Subject: [PATCH 1/5] pipeline to build tutorial agents --- .../build-and-push-tutorial-agent.yml | 86 +++++++++++++++++++ .../00_sync/000_hello_acp/Dockerfile | 4 +- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-push-tutorial-agent.yml b/.github/workflows/build-and-push-tutorial-agent.yml index 855950da..d0e59f65 100644 --- a/.github/workflows/build-and-push-tutorial-agent.yml +++ b/.github/workflows/build-and-push-tutorial-agent.yml @@ -24,3 +24,89 @@ on: required: true type: string default: "latest" + +permissions: + contents: read + packages: write + +jobs: + build-and-push-agent: + timeout-minutes: 10 + name: Build Tutorial Agent + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Validate agent path exists + run: | + if [ ! -d "${{ inputs.agent_path }}" ]; then + echo "❌ Error: Agent path '${{ inputs.agent_path }}' does not exist" + exit 1 + fi + echo "✅ Agent path verified: ${{ inputs.agent_path }}" + + - name: Validate manifest.yaml exists + run: | + if [ ! -f "${{ inputs.agent_path }}/manifest.yaml" ]; then + echo "❌ Error: manifest.yaml not found in '${{ inputs.agent_path }}'" + exit 1 + fi + echo "✅ manifest.yaml found" + echo "### Validation Summary" >> $GITHUB_STEP_SUMMARY + echo "- **Agent Path**: ${{ inputs.agent_path }}" >> $GITHUB_STEP_SUMMARY + echo "- **Version Tag**: ${{ inputs.version_tag }}" >> $GITHUB_STEP_SUMMARY + echo "- **Status**: ✅ Validation passed" >> $GITHUB_STEP_SUMMARY + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.12" + + - name: Get latest agentex-sdk version from PyPI + id: get-version + run: | + LATEST_VERSION=$(curl -s https://pypi.org/pypi/agentex-sdk/json | jq -r '.info.version') + echo "Latest agentex-sdk version: $LATEST_VERSION" + echo "AGENTEX_SDK_VERSION=$LATEST_VERSION" >> $GITHUB_ENV + pip install agentex-sdk==$LATEST_VERSION + echo "Installed agentex-sdk version $LATEST_VERSION" + + - name: Generate Image name + id: image-name + run: | + # Remove examples/tutorials/ prefix and replace / with - + AGENT_NAME=$(echo "${{ inputs.agent_path }}" | sed 's|^examples/tutorials/||' | sed 's|/|-|g') + IMAGE_NAME="${AGENT_NAME}-${{ inputs.version_tag }}" + echo "IMAGE_NAME=$IMAGE_NAME" >> $GITHUB_ENV + echo "image_name=$IMAGE_NAME" >> $GITHUB_OUTPUT + echo "Image name set to $IMAGE_NAME" + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and Push Agent Image + env: + REGISTRY: ghcr.io + REPOSITORY: agentex-agents + run: | + IMAGE_NAME="${{ steps.image-name.outputs.image_name }}" + + agentex agents build \ + --manifest "${{ inputs.agent_path }}/manifest.yaml" \ + --registry "${REGISTRY}" \ + --tag "${IMAGE_NAME}" \ + --platforms "linux/amd64" \ + --repository-name "${REPOSITORY}" \ + --push + + echo "Successfully built and pushed: ${REGISTRY}/${REPOSITORY}:$IMAGE_NAME" + echo "### Build Complete" >> $GITHUB_STEP_SUMMARY diff --git a/examples/tutorials/00_sync/000_hello_acp/Dockerfile b/examples/tutorials/00_sync/000_hello_acp/Dockerfile index 2c42e6ff..1efdf263 100644 --- a/examples/tutorials/00_sync/000_hello_acp/Dockerfile +++ b/examples/tutorials/00_sync/000_hello_acp/Dockerfile @@ -23,7 +23,7 @@ RUN uv pip install --system --upgrade pip setuptools wheel ENV UV_HTTP_TIMEOUT=1000 # Copy just the requirements file to optimize caching -COPY 000_hello_acp/requirements.txt /app/requirements.txt +COPY 000_hello_acp/pyproject.toml /app/requirements.txt WORKDIR /app/ @@ -37,4 +37,4 @@ COPY 000_hello_acp/project /app/project ENV PYTHONPATH=/app # Run the agent using uvicorn -CMD ["uvicorn", "project.acp:acp", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file +CMD ["uvicorn", "project.acp:acp", "--host", "0.0.0.0", "--port", "8000"] From 0f38f51f733aa6040ba035e42a968de06f136f75 Mon Sep 17 00:00:00 2001 From: Roxanne Farhad Date: Wed, 22 Oct 2025 17:57:29 -0400 Subject: [PATCH 2/5] add gh repo in name --- .github/workflows/build-and-push-tutorial-agent.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-and-push-tutorial-agent.yml b/.github/workflows/build-and-push-tutorial-agent.yml index ea95c7bd..d2c1d85d 100644 --- a/.github/workflows/build-and-push-tutorial-agent.yml +++ b/.github/workflows/build-and-push-tutorial-agent.yml @@ -95,11 +95,10 @@ jobs: - name: Build and Push Agent Image env: REGISTRY: ghcr.io - REPOSITORY_PREFIX: agentex-agents run: | AGENT_NAME="${{ steps.image-name.outputs.agent_name }}" VERSION_TAG="${{ inputs.version_tag }}" - REPOSITORY_NAME="${REPOSITORY_PREFIX}/${AGENT_NAME}" + REPOSITORY_NAME="${{ github.repository }}/tutorial-agents/${AGENT_NAME}" FULL_IMAGE="${REGISTRY}/${REPOSITORY_NAME}:${VERSION_TAG}" agentex agents build \ From b0eb0680b5fc48abc4ea951f74629d12b18f63cd Mon Sep 17 00:00:00 2001 From: Roxanne Farhad Date: Mon, 3 Nov 2025 18:31:43 -0500 Subject: [PATCH 3/5] adding this --- .../build-and-push-tutorial-agent.yml | 185 ++++++++++++------ 1 file changed, 129 insertions(+), 56 deletions(-) diff --git a/.github/workflows/build-and-push-tutorial-agent.yml b/.github/workflows/build-and-push-tutorial-agent.yml index d2c1d85d..fd782036 100644 --- a/.github/workflows/build-and-push-tutorial-agent.yml +++ b/.github/workflows/build-and-push-tutorial-agent.yml @@ -3,61 +3,124 @@ name: Build and Push Tutorial Agent on: workflow_dispatch: inputs: - agent_path: - description: "Path to the agent directory (e.g., examples/tutorials/10_agentic/00_base/000_hello_acp)" - required: true - type: string - version_tag: - description: "Version tag for the agent build (e.g., v1.0.0, latest)" - required: true - type: string - default: "latest" - - workflow_call: - inputs: - agent_path: - description: "Path to the agent directory" - required: true - type: string - version_tag: - description: "Version tag for the agent build" - required: true - type: string - default: "latest" + rebuild_all: + description: "Rebuild all agents regardless of changes" + required: false + type: boolean + default: false + + pull_request: + paths: + - "examples/tutorials/**" + + push: + branches: + - main + paths: + - "examples/tutorials/**" permissions: contents: read packages: write jobs: - build-and-push-agent: - timeout-minutes: 10 - name: Build Tutorial Agent + find-agents: runs-on: ubuntu-latest - + outputs: + agents: ${{ steps.get-agents.outputs.agents }} + has_agents: ${{ steps.get-agents.outputs.has_agents }} steps: - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch full history for git diff - - name: Validate agent path exists + - name: Find tutorial agents to build + id: get-agents + env: + REBUILD_ALL: ${{ inputs.rebuild_all }} run: | - if [ ! -d "${{ inputs.agent_path }}" ]; then - echo "❌ Error: Agent path '${{ inputs.agent_path }}' does not exist" - exit 1 + # Find all tutorial directories with manifest.yaml + all_agents=$(find examples/tutorials -name "manifest.yaml" -exec dirname {} \; | sort) + agents_to_build=() + + echo "DEBUG: REBUILD_ALL environment variable: '$REBUILD_ALL'" + + if [ "$REBUILD_ALL" = "true" ]; then + echo "Rebuild all agents requested" + echo "DEBUG: All agents found: $all_agents" + agents_to_build=($(echo "$all_agents")) + echo "DEBUG: Agents to build array has ${#agents_to_build[@]} items" + + echo "### 🔄 Rebuilding All Tutorial Agents" >> $GITHUB_STEP_SUMMARY + else + # Determine the base branch for comparison + if [ "${{ github.event_name }}" = "pull_request" ]; then + BASE_BRANCH="origin/${{ github.base_ref }}" + echo "Comparing against PR base branch: $BASE_BRANCH" + else + BASE_BRANCH="HEAD~1" + echo "Comparing against previous commit: $BASE_BRANCH" + fi + + # Check each agent directory for changes + for agent_dir in $all_agents; do + echo "Checking $agent_dir for changes..." + + # Check if any files in this agent directory have changed + if git diff --name-only $BASE_BRANCH HEAD | grep -q "^$agent_dir/"; then + echo " ✅ Changes detected in $agent_dir" + agents_to_build+=("$agent_dir") + else + echo " ⏭️ No changes in $agent_dir" + fi + done + + echo "### 🔄 Changed Tutorial Agents" >> $GITHUB_STEP_SUMMARY fi - echo "✅ Agent path verified: ${{ inputs.agent_path }}" - - name: Validate manifest.yaml exists - run: | - if [ ! -f "${{ inputs.agent_path }}/manifest.yaml" ]; then - echo "❌ Error: manifest.yaml not found in '${{ inputs.agent_path }}'" - exit 1 + # Convert array to JSON format and output summary + if [ ${#agents_to_build[@]} -eq 0 ]; then + echo "No agents to build" + echo "agents=[]" >> $GITHUB_OUTPUT + echo "has_agents=false" >> $GITHUB_OUTPUT + else + echo "Agents to build: ${#agents_to_build[@]}" + + # Debug the array contents + echo "DEBUG: Array contents:" + for agent in "${agents_to_build[@]}"; do + echo " - $agent" + done + + # Generate JSON properly + agents_json=$(printf '%s\n' "${agents_to_build[@]}" | jq -R -s -c 'split("\n") | map(select(length > 0))') + echo "agents=$agents_json" >> $GITHUB_OUTPUT + echo "has_agents=true" >> $GITHUB_OUTPUT + + echo "DEBUG: Generated JSON: $agents_json" + + echo "" >> $GITHUB_STEP_SUMMARY + for agent in "${agents_to_build[@]}"; do + echo "- \`$agent\`" >> $GITHUB_STEP_SUMMARY + done + echo "" >> $GITHUB_STEP_SUMMARY fi - echo "✅ manifest.yaml found" - echo "### Validation Summary" >> $GITHUB_STEP_SUMMARY - echo "- **Agent Path**: ${{ inputs.agent_path }}" >> $GITHUB_STEP_SUMMARY - echo "- **Version Tag**: ${{ inputs.version_tag }}" >> $GITHUB_STEP_SUMMARY - echo "- **Status**: ✅ Validation passed" >> $GITHUB_STEP_SUMMARY + + build-agents: + needs: find-agents + if: ${{ needs.find-agents.outputs.has_agents == 'true' }} + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + matrix: + agent_path: ${{ fromJson(needs.find-agents.outputs.agents) }} + fail-fast: false + name: build-${{ matrix.agent_path }} + + steps: + - name: Checkout repository + uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -80,35 +143,45 @@ jobs: id: image-name run: | # Remove examples/tutorials/ prefix and replace / with - - AGENT_NAME=$(echo "${{ inputs.agent_path }}" | sed 's|^examples/tutorials/||' | sed 's|/|-|g') + AGENT_NAME=$(echo "${{ matrix.agent_path }}" | sed 's|^examples/tutorials/||' | sed 's|/|-|g') echo "AGENT_NAME=$AGENT_NAME" >> $GITHUB_ENV echo "agent_name=$AGENT_NAME" >> $GITHUB_OUTPUT echo "Agent name set to $AGENT_NAME" - name: Login to GitHub Container Registry + # Only login if we're going to push (main branch or rebuild_all) + if: ${{ github.event_name == 'push' || inputs.rebuild_all }} uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and Push Agent Image + - name: Build and Conditionally Push Agent Image env: REGISTRY: ghcr.io run: | AGENT_NAME="${{ steps.image-name.outputs.agent_name }}" - VERSION_TAG="${{ inputs.version_tag }}" REPOSITORY_NAME="${{ github.repository }}/tutorial-agents/${AGENT_NAME}" - FULL_IMAGE="${REGISTRY}/${REPOSITORY_NAME}:${VERSION_TAG}" - - agentex agents build \ - --manifest "${{ inputs.agent_path }}/manifest.yaml" \ - --registry "${REGISTRY}" \ - --tag "${VERSION_TAG}" \ - --platforms "linux/amd64" \ - --repository-name "${REPOSITORY_NAME}" \ - --push - - echo "Successfully built and pushed: ${FULL_IMAGE}" - echo "### Build Complete" >> $GITHUB_STEP_SUMMARY - echo "- **Image**: \`${FULL_IMAGE}\`" >> $GITHUB_STEP_SUMMARY + + # Determine if we should push based on event type + if [ "${{ github.event_name }}" = "push" ] || [ "${{ inputs.rebuild_all }}" = "true" ]; then + SHOULD_PUSH=true + VERSION_TAG="latest" + echo "🚀 Building and pushing agent: ${{ matrix.agent_path }}" + else + SHOULD_PUSH=false + VERSION_TAG="pr-${{ github.event.number }}" + echo "🔍 Validating build for agent: ${{ matrix.agent_path }}" + fi + + # Build command - add --push only if we should push + BUILD_ARGS="--manifest ${{ matrix.agent_path }}/manifest.yaml --registry ${REGISTRY} --tag ${VERSION_TAG} --platforms linux/amd64 --repository-name ${REPOSITORY_NAME}" + + if [ "$SHOULD_PUSH" = "true" ]; then + agentex agents build $BUILD_ARGS --push + echo "✅ Successfully built and pushed: ${REGISTRY}/${REPOSITORY_NAME}:${VERSION_TAG}" + else + agentex agents build $BUILD_ARGS + echo "✅ Build validation successful for: ${{ matrix.agent_path }}" + fi From d44c2f20beab6441e78787ba65ce74371c548921 Mon Sep 17 00:00:00 2001 From: Roxanne Farhad Date: Tue, 4 Nov 2025 09:54:09 -0500 Subject: [PATCH 4/5] validating the diff checker works --- .../build-and-push-tutorial-agent.yml | 18 ++---------------- .../00_sync/000_hello_acp/project/acp.py | 8 +++----- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build-and-push-tutorial-agent.yml b/.github/workflows/build-and-push-tutorial-agent.yml index fd782036..fe972286 100644 --- a/.github/workflows/build-and-push-tutorial-agent.yml +++ b/.github/workflows/build-and-push-tutorial-agent.yml @@ -44,13 +44,9 @@ jobs: all_agents=$(find examples/tutorials -name "manifest.yaml" -exec dirname {} \; | sort) agents_to_build=() - echo "DEBUG: REBUILD_ALL environment variable: '$REBUILD_ALL'" - if [ "$REBUILD_ALL" = "true" ]; then echo "Rebuild all agents requested" - echo "DEBUG: All agents found: $all_agents" agents_to_build=($(echo "$all_agents")) - echo "DEBUG: Agents to build array has ${#agents_to_build[@]} items" echo "### 🔄 Rebuilding All Tutorial Agents" >> $GITHUB_STEP_SUMMARY else @@ -72,7 +68,7 @@ jobs: echo " ✅ Changes detected in $agent_dir" agents_to_build+=("$agent_dir") else - echo " ⏭️ No changes in $agent_dir" + echo " ⏭️ No changes in $agent_dir - skipping build" fi done @@ -86,20 +82,10 @@ jobs: echo "has_agents=false" >> $GITHUB_OUTPUT else echo "Agents to build: ${#agents_to_build[@]}" - - # Debug the array contents - echo "DEBUG: Array contents:" - for agent in "${agents_to_build[@]}"; do - echo " - $agent" - done - - # Generate JSON properly agents_json=$(printf '%s\n' "${agents_to_build[@]}" | jq -R -s -c 'split("\n") | map(select(length > 0))') echo "agents=$agents_json" >> $GITHUB_OUTPUT echo "has_agents=true" >> $GITHUB_OUTPUT - echo "DEBUG: Generated JSON: $agents_json" - echo "" >> $GITHUB_STEP_SUMMARY for agent in "${agents_to_build[@]}"; do echo "- \`$agent\`" >> $GITHUB_STEP_SUMMARY @@ -116,8 +102,8 @@ jobs: matrix: agent_path: ${{ fromJson(needs.find-agents.outputs.agents) }} fail-fast: false - name: build-${{ matrix.agent_path }} + name: build-${{ matrix.agent_path }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/examples/tutorials/00_sync/000_hello_acp/project/acp.py b/examples/tutorials/00_sync/000_hello_acp/project/acp.py index 6e2b1a2a..ee268a70 100644 --- a/examples/tutorials/00_sync/000_hello_acp/project/acp.py +++ b/examples/tutorials/00_sync/000_hello_acp/project/acp.py @@ -9,7 +9,6 @@ logger = make_logger(__name__) - # Create an ACP server acp = FastACP.create( acp_type="sync", @@ -18,13 +17,13 @@ @acp.on_message_send async def handle_message_send( - params: SendMessageParams + params: SendMessageParams, ) -> Union[TaskMessageContent, AsyncGenerator[TaskMessageUpdate, None]]: """Default message handler with streaming support""" # Extract content safely from the message message_text = "" - if hasattr(params.content, 'content'): - content_val = getattr(params.content, 'content', '') + if hasattr(params.content, "content"): + content_val = getattr(params.content, "content", "") if isinstance(content_val, str): message_text = content_val @@ -32,4 +31,3 @@ async def handle_message_send( author="agent", content=f"Hello! I've received your message. Here's a generic response, but in future tutorials we'll see how you can get me to intelligently respond to your message. This is what I heard you say: {message_text}", ) - From 152c53f3129d3a7d89b706591fbc171e0fad048e Mon Sep 17 00:00:00 2001 From: Roxanne Farhad Date: Tue, 4 Nov 2025 09:57:39 -0500 Subject: [PATCH 5/5] build and push agents workflow --- .../build-and-push-tutorial-agent.yml | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-push-tutorial-agent.yml b/.github/workflows/build-and-push-tutorial-agent.yml index fe972286..4b38c767 100644 --- a/.github/workflows/build-and-push-tutorial-agent.yml +++ b/.github/workflows/build-and-push-tutorial-agent.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: inputs: rebuild_all: - description: "Rebuild all agents regardless of changes" + description: "Rebuild all tutorial agents regardless of changes, this is reserved for maintainers only." required: false type: boolean default: false @@ -24,8 +24,29 @@ permissions: packages: write jobs: + check-permissions: + if: ${{ github.event_name == 'workflow_dispatch' }} + runs-on: ubuntu-latest + steps: + - name: Check if user is maintainer + uses: actions/github-script@v7 + with: + script: | + const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: context.actor + }); + + const allowedRoles = ['admin', 'maintain']; + if (!allowedRoles.includes(permission.permission)) { + throw new Error(`❌ User ${context.actor} does not have sufficient permissions. Required: ${allowedRoles.join(', ')}. Current: ${permission.permission}`); + } + find-agents: runs-on: ubuntu-latest + needs: [check-permissions] + if: ${{ !cancelled() && !failure() }} outputs: agents: ${{ steps.get-agents.outputs.agents }} has_agents: ${{ steps.get-agents.outputs.has_agents }} @@ -157,7 +178,7 @@ jobs: echo "🚀 Building and pushing agent: ${{ matrix.agent_path }}" else SHOULD_PUSH=false - VERSION_TAG="pr-${{ github.event.number }}" + VERSION_TAG="${{ github.commit.sha }}" echo "🔍 Validating build for agent: ${{ matrix.agent_path }}" fi