Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Path-based label mappings for actions/labeler@v6
# Uses any-glob-to-any-file: a single file match triggers the label

area/langgraph:
- changed-files:
- any-glob-to-any-file: 'agents/langgraph/**'

area/crewai:
- changed-files:
- any-glob-to-any-file: 'agents/crewai/**'

area/autogen:
- changed-files:
- any-glob-to-any-file: 'agents/autogen/**'

area/llamaindex:
- changed-files:
- any-glob-to-any-file: 'agents/llamaindex/**'

area/langflow:
- changed-files:
- any-glob-to-any-file: 'agents/langflow/**'

area/google-adk:
- changed-files:
- any-glob-to-any-file: 'agents/google/**'

area/a2a:
- changed-files:
- any-glob-to-any-file: 'agents/a2a/**'

area/vanilla-python:
- changed-files:
- any-glob-to-any-file: 'agents/vanilla_python/**'

area/helm:
- changed-files:
- any-glob-to-any-file: 'charts/**'

area/docs:
- changed-files:
- any-glob-to-any-file:
- 'docs/**'
- '*.md'

area/ci:
- changed-files:
- any-glob-to-any-file: '.github/**'

area/tests:
- changed-files:
- any-glob-to-any-file:
- 'tests/**'
- 'eval/**'

area/tracing:
- changed-files:
- any-glob-to-any-file:
- '**/tracing.py'
- 'tracing.md'
145 changes: 145 additions & 0 deletions .github/scripts/pr_size.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#!/usr/bin/env python3
"""
PR Size Labeler — calculates PR size and applies size/* labels.

Triggered by the pr-labeler workflow. Uses the GitHub API via PyGitHub
to count lines changed (additions + deletions), excluding generated and
binary files. Posts an advisory comment on XL PRs.

Environment variables (set by the workflow):
GITHUB_TOKEN — GitHub token with pull-requests: write
GITHUB_REPOSITORY — owner/repo
PR_NUMBER — pull request number
"""

import fnmatch
import os
import sys

from github import Github
from github.GithubException import GithubException

# --- Configuration ---

SIZE_THRESHOLDS = [
("size/xs", 0, 10),
("size/s", 11, 100),
("size/m", 101, 500),
("size/l", 501, 1199),
("size/xl", 1200, float("inf")),
]

LABEL_COLORS = {
"size/xs": "0e8a16",
"size/s": "0e8a16",
"size/m": "0e8a16",
"size/l": "fbca04",
"size/xl": "d93f0b",
}

EXCLUDED_PATTERNS = [
"uv.lock",
"*.lock",
"*.generated.*",
"images/*",
]

XL_COMMENT_MARKER = "<!-- pr-size-labeler:xl-warning -->"

XL_COMMENT_TEMPLATE = """{marker}
**Large PR detected ({lines} lines changed)**

This PR exceeds 1200 lines of code changes (excluding lock files and \
generated content). Large PRs are harder to review thoroughly and are more \
likely to introduce bugs.

Consider splitting this PR into smaller, focused changes.
"""


def is_excluded(filename: str) -> bool:
"""Check if a file matches any exclusion pattern."""
for pattern in EXCLUDED_PATTERNS:
if fnmatch.fnmatch(filename, pattern):
return True
return False


def get_size_label(lines: int) -> str:
"""Return the size label for the given line count."""
for label, lower, upper in SIZE_THRESHOLDS:
if lower <= lines <= upper:
return label
return "size/xl"


def ensure_label_exists(repo, label_name: str) -> None:
"""Create the label in the repo if it doesn't exist."""
try:
repo.get_label(label_name)
except GithubException:
color = LABEL_COLORS.get(label_name, "ededed")
repo.create_label(name=label_name, color=color)
print(f"Created label: {label_name}")


def remove_old_size_labels(pr) -> None:
"""Remove any existing size/* labels from the PR."""
for label in pr.get_labels():
if label.name.startswith("size/"):
pr.remove_from_labels(label.name)
print(f"Removed label: {label.name}")


def calculate_size(pr) -> int:
"""Calculate total lines changed, excluding ignored files."""
total = 0
for f in pr.get_files():
if not is_excluded(f.filename):
total += f.additions + f.deletions
else:
print(f"Excluded: {f.filename}")
return total


def post_xl_comment(pr, lines: int) -> None:
"""Post an XL warning comment if one doesn't already exist."""
for comment in pr.get_issue_comments():
if XL_COMMENT_MARKER in comment.body:
print("XL comment already exists, skipping")
return
body = XL_COMMENT_TEMPLATE.format(marker=XL_COMMENT_MARKER, lines=lines)
pr.create_issue_comment(body)
print("Posted XL warning comment")


def main() -> None:
token = os.environ.get("GITHUB_TOKEN")
repo_name = os.environ.get("GITHUB_REPOSITORY")
pr_number_str = os.environ.get("PR_NUMBER")

if not all([token, repo_name, pr_number_str]):
print("Error: GITHUB_TOKEN, GITHUB_REPOSITORY, and PR_NUMBER must be set")
sys.exit(1)

pr_number = int(pr_number_str)

gh = Github(token, retry=3)
repo = gh.get_repo(repo_name)
pr = repo.get_pull(pr_number)

lines = calculate_size(pr)
label = get_size_label(lines)
print(f"PR #{pr_number}: {lines} lines changed -> {label}")

ensure_label_exists(repo, label)
remove_old_size_labels(pr)
pr.add_to_labels(label)
print(f"Applied label: {label}")

if label == "size/xl":
post_xl_comment(pr, lines)


if __name__ == "__main__":
main()
47 changes: 47 additions & 0 deletions .github/workflows/pr-labeler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Automated PR labeling: path-based area/* labels + size-based size/* labels.
# Uses pull_request_target to support fork PRs (write access to base repo).

name: PR Labeler

on:
pull_request_target:
types: [opened, synchronize]

permissions:
contents: read
pull-requests: write

jobs:
label-pr:
runs-on: ubuntu-latest
steps:
# Step 1: Path-based area/* labels
- name: Apply area labels
uses: actions/labeler@v6
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
configuration-path: .github/labeler.yml
sync-labels: true

# Step 2: Size-based size/* labels + XL comment
- name: Checkout scripts
uses: actions/checkout@v4
with:
sparse-checkout: .github/scripts
sparse-checkout-cone-mode: false

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install dependencies
run: pip install PyGithub

- name: Apply size labels
continue-on-error: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: python .github/scripts/pr_size.py
34 changes: 34 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,40 @@ chore: bump python-dotenv in requirements

This is optional but appreciated; maintainers may ask you to reword commits when preparing a release.

## Automated PR labels

Every pull request is automatically labeled when opened or updated:

**Area labels** (`area/*`) — applied based on which directories your PR touches. A PR can have multiple area labels if it spans several directories. These help reviewers quickly identify which parts of the codebase are affected.

| Label | Matches |
|-------|---------|
| `area/langgraph` | `agents/langgraph/**` |
| `area/crewai` | `agents/crewai/**` |
| `area/autogen` | `agents/autogen/**` |
| `area/llamaindex` | `agents/llamaindex/**` |
| `area/langflow` | `agents/langflow/**` |
| `area/google-adk` | `agents/google/**` |
| `area/a2a` | `agents/a2a/**` |
| `area/vanilla-python` | `agents/vanilla_python/**` |
| `area/helm` | `charts/**` |
| `area/docs` | `docs/**`, `*.md` (root) |
| `area/ci` | `.github/**` |
| `area/tests` | `tests/**`, `eval/**` |
| `area/tracing` | `**/tracing.py`, `tracing.md` |

**Size labels** (`size/*`) — applied based on total lines changed (additions + deletions), excluding lock files, generated files, and images.

| Label | Lines Changed |
|-------|--------------|
| `size/xs` | 0–10 |
| `size/s` | 11–100 |
| `size/m` | 101–500 |
| `size/l` | 501–1199 |
| `size/xl` | 1200+ |

PRs labeled `size/xl` will receive an advisory comment encouraging the author to consider splitting the PR. This is informational only — it does not block merges.

## Adding MLflow tracing to your agent template

All agent templates in this repo must include MLflow tracing integration. Tracing lets users optionally capture LLM calls, tool executions, and agent orchestration spans in MLflow — it's opt-in via the `MLFLOW_TRACKING_URI` environment variable. If `MLFLOW_TRACKING_URI` is set but the server is unreachable, the agent logs a warning and continues without tracing. Note: if `MLFLOW_TRACKING_URI` is set but the MLflow package is not installed, the agent will fail at startup with an `ImportError` — MLflow must be installed when the env var is set.
Expand Down