mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
4b533608b6
* Update sample validation scripts * Adjust prompt * Update autogen-migration samples * Add fix suggestion * Split jobs * Add .env * Create trend report * Add timestamp * Add more env vars * Comments * force node24 * force node24 * force node22
137 lines
4.2 KiB
Python
137 lines
4.2 KiB
Python
# Copyright (c) Microsoft. All rights reserved.
|
|
|
|
"""Sample discovery module."""
|
|
|
|
import ast
|
|
import os
|
|
from pathlib import Path
|
|
|
|
from agent_framework import Executor, WorkflowContext, handler
|
|
|
|
from sample_validation.models import DiscoveryResult, SampleInfo, ValidationConfig
|
|
|
|
|
|
def _is_main_entrypoint_guard(test: ast.expr) -> bool:
|
|
"""Check whether an expression is ``__name__ == '__main__'``."""
|
|
if not isinstance(test, ast.Compare):
|
|
return False
|
|
|
|
if len(test.ops) != 1 or not isinstance(test.ops[0], ast.Eq):
|
|
return False
|
|
|
|
if len(test.comparators) != 1:
|
|
return False
|
|
|
|
left = test.left
|
|
right = test.comparators[0]
|
|
|
|
return (
|
|
isinstance(left, ast.Name)
|
|
and left.id == "__name__"
|
|
and isinstance(right, ast.Constant)
|
|
and right.value == "__main__"
|
|
) or (
|
|
isinstance(right, ast.Name)
|
|
and right.id == "__name__"
|
|
and isinstance(left, ast.Constant)
|
|
and left.value == "__main__"
|
|
)
|
|
|
|
|
|
def _has_main_entrypoint_guard(path: Path) -> bool:
|
|
"""Check whether a Python file defines a top-level main entrypoint guard."""
|
|
try:
|
|
source = path.read_text(encoding="utf-8")
|
|
tree = ast.parse(source)
|
|
except Exception:
|
|
return False
|
|
|
|
return any(
|
|
isinstance(node, ast.If) and _is_main_entrypoint_guard(node.test)
|
|
for node in tree.body
|
|
)
|
|
|
|
|
|
def discover_samples(
|
|
samples_dir: Path,
|
|
subdir: str | None = None,
|
|
exclude: list[str] | None = None,
|
|
) -> list[SampleInfo]:
|
|
"""
|
|
Find all Python sample files in the samples directory.
|
|
|
|
Args:
|
|
samples_dir: Root samples directory
|
|
subdir: Optional subdirectory to filter to
|
|
exclude: Optional list of subdirectory paths (relative to the search directory) to exclude
|
|
|
|
Returns:
|
|
List of SampleInfo objects for each discovered sample
|
|
"""
|
|
# Determine the search directory
|
|
if subdir:
|
|
search_dir = samples_dir / subdir
|
|
if not search_dir.exists():
|
|
print(f"Warning: Subdirectory '{subdir}' does not exist in {samples_dir}")
|
|
return []
|
|
else:
|
|
search_dir = samples_dir
|
|
|
|
# Resolve excluded paths to absolute for reliable comparison
|
|
exclude_paths = {(search_dir / exc).resolve() for exc in (exclude or [])}
|
|
|
|
python_files: list[Path] = []
|
|
|
|
# Walk through all subdirectories and find .py files
|
|
for root, dirs, files in os.walk(search_dir):
|
|
# Skip directories that start with _, __pycache__, or excluded paths
|
|
dirs[:] = [
|
|
d
|
|
for d in dirs
|
|
if not d.startswith("_")
|
|
and d != "__pycache__"
|
|
and (Path(root) / d).resolve() not in exclude_paths
|
|
]
|
|
|
|
for file in files:
|
|
# Skip files that start with _ and include only scripts with a main entrypoint guard
|
|
if file.endswith(".py") and not file.startswith("_"):
|
|
file_path = Path(root) / file
|
|
if _has_main_entrypoint_guard(file_path):
|
|
python_files.append(file_path)
|
|
|
|
# Sort files for consistent execution order
|
|
python_files = sorted(python_files)
|
|
|
|
# Convert to SampleInfo objects
|
|
samples: list[SampleInfo] = []
|
|
for path in python_files:
|
|
try:
|
|
samples.append(SampleInfo.from_path(path, samples_dir))
|
|
except Exception as e:
|
|
print(f"Warning: Could not read {path}: {e}")
|
|
|
|
return samples
|
|
|
|
|
|
class DiscoverSamplesExecutor(Executor):
|
|
"""Executor that discovers all samples in the samples directory."""
|
|
|
|
def __init__(self, config: ValidationConfig):
|
|
super().__init__(id="discover_samples")
|
|
self.config = config
|
|
|
|
@handler
|
|
async def discover(self, _: str, ctx: WorkflowContext[DiscoveryResult]) -> None:
|
|
"""Discover all Python samples."""
|
|
print(f"🔍 Discovering samples in {self.config.samples_dir}")
|
|
if self.config.subdir:
|
|
print(f" Filtering to subdirectory: {self.config.subdir}")
|
|
if self.config.exclude:
|
|
print(f" Excluding: {', '.join(self.config.exclude)}")
|
|
|
|
samples = discover_samples(self.config.samples_dir, self.config.subdir, self.config.exclude)
|
|
print(f" Found {len(samples)} samples")
|
|
|
|
await ctx.send_message(DiscoveryResult(samples=samples))
|