Python: replace pre-commit with prek, add PEP 723 script deps, clean up dev dependencies (#3748)

* python: replace pre-commit with prek, add PEP 723 script deps, clean up dev dependencies

- Replace pre-commit with prek (Rust-native, faster pre-commit alternative)
- Move supported hooks to repo: builtin for zero-clone speed
- Add new builtin hooks: trailing-whitespace, check-merge-conflict, detect-private-key, check-added-large-files
- Update all hook versions to latest (pre-commit-hooks v6, pyupgrade v3.21.2, bandit 1.9.3, uv-pre-commit 0.10.0)
- Add PEP 723 inline script metadata to 34 samples with external deps
- Remove autogen-agentchat/autogen-ext from dev deps (now declared per-sample)
- Remove unused dev deps: pytest-env, tomli-w
- Add agent-framework-core>=1.0.0b260130 lower bound to all 21 packages
- Update CI workflow to use j178/prek-action
- Update docs: DEV_SETUP.md, AGENTS.md, CODING_STANDARD.md, SAMPLE_GUIDELINES.md

* updated lock

* python: fix prek config paths for local execution and CI workflow

Remove global 'files: ^python/' filter and strip python/ prefix from all path patterns in .pre-commit-config.yaml so prek finds files when run from the python/ directory. Update CI workflow to use --cd python instead of --config path. Include trailing whitespace fixes and dev dependency cleanup.

* python: move helper scripts to scripts/ folder and exclude from checks

* python: exclude AGENTS.md from prek markdown code lint

* python: exclude AGENTS.md and azure_ai_search sample from markdown lint

* fix m365 sample

* python: ignore CPY rule for samples with PEP 723 headers

* fix in dev_setup

* python: replace aiofiles with regular open in samples

* python: suppress reportUnusedImport in markdown code block checker

* python: use samples pyright config for markdown code block checker

Write a temp pyrightconfig.json matching pyrightconfig.samples.json rules (typeCheckingMode=off, only reportMissingImports and reportAttributeAccessIssue). Filter output to only fail on these rules since syntax-level errors (top-level await, undefined vars) are expected in README documentation snippets.

* python: use markdown-code-lint with fixed globs instead of prek file list

The prek-markdown-code-lint task received all changed files including non-README markdown and files with pre-existing broken imports. Replace with the standard markdown-code-lint task which uses the correct glob patterns (README.md, packages/**/README.md, samples/**/*.md).

* python: exclude READMEs with pre-existing broken imports from markdown lint

* python: fix broken README code snippets instead of excluding them

- ag-ui: replace TextContent (removed) with content.type == 'text'
- durabletask: fix import path to durabletask.worker.TaskHubGrpcWorker
- orchestrations: use constructor params instead of .participants() method
- observability: mark deprecated code blocks as plain text, filter
  reportMissingImports to agent_framework modules only
- remove README excludes from markdown-code-lint task

* add revision to gaia download

* feat(python): parallelize checks across packages

Run (package × task) cross-product in parallel using ThreadPoolExecutor
and subprocesses. Key changes:

- Add scripts/task_runner.py with shared parallel execution engine
- Update run_tasks_in_packages_if_exists.py to accept multiple tasks
- Update run_tasks_in_changed_packages.py with --files flag and parallel support
- Add check-packages poe task (fmt+lint+pyright+mypy in parallel)
- Add prek-markdown-code-lint and prek-samples-check with change detection
- Split CI code quality workflow into parallel prek and mypy jobs
- Update DEV_SETUP.md to document new parallel behavior

Core package changes still trigger checks on all packages.

* feat(ci): split code quality into 4 parallel jobs

Split the single prek job into parallel jobs:
- pre-commit-hooks: lightweight hooks (SKIP=poe-check)
- package-checks: fmt/lint/pyright/mypy via check-packages
- samples-markdown: samples-lint, samples-syntax, markdown-code-lint
- mypy: change-detected mypy checks

All 4 jobs run concurrently (×2 Python versions = 8 runners).

* feat(ci): use only Python 3.10 for code quality checks

* refactor(python): add future annotations and remove quoted types

Add `from __future__ import annotations` to 93 package files that
used quoted string annotations, then run pyupgrade --py310-plus to
remove the now-unnecessary quotes.

Fixes https://github.com/microsoft/agent-framework/issues/3578
This commit is contained in:
Eduard van Valkenburg
2026-02-09 18:51:01 +01:00
committed by GitHub
Unverified
parent ad0dac3c86
commit 977c3adfb2
177 changed files with 1373 additions and 1010 deletions
+8 -16
View File
@@ -5,7 +5,7 @@ Orchestration patterns for Microsoft Agent Framework. This package provides high
## Installation
```bash
pip install agent-framework-orchestrations
pip install agent-framework-orchestrations --pre
```
## Orchestration Patterns
@@ -15,9 +15,9 @@ pip install agent-framework-orchestrations
Chain agents/executors in sequence, passing conversation context along:
```python
from agent_framework_orchestrations import SequentialBuilder
from agent_framework.orchestrations import SequentialBuilder
workflow = SequentialBuilder().participants([agent1, agent2, agent3]).build()
workflow = SequentialBuilder(participants=[agent1, agent2, agent3]).build()
```
### ConcurrentBuilder
@@ -25,9 +25,9 @@ workflow = SequentialBuilder().participants([agent1, agent2, agent3]).build()
Fan-out to multiple agents in parallel, then aggregate results:
```python
from agent_framework_orchestrations import ConcurrentBuilder
from agent_framework.orchestrations import ConcurrentBuilder
workflow = ConcurrentBuilder().participants([agent1, agent2, agent3]).build()
workflow = ConcurrentBuilder(participants=[agent1, agent2, agent3]).build()
```
### HandoffBuilder
@@ -35,7 +35,7 @@ workflow = ConcurrentBuilder().participants([agent1, agent2, agent3]).build()
Decentralized agent routing where agents decide handoff targets:
```python
from agent_framework_orchestrations import HandoffBuilder
from agent_framework.orchestrations import HandoffBuilder
workflow = (
HandoffBuilder()
@@ -50,7 +50,7 @@ workflow = (
Orchestrator-directed multi-agent conversations:
```python
from agent_framework_orchestrations import GroupChatBuilder
from agent_framework.orchestrations import GroupChatBuilder
workflow = GroupChatBuilder(
participants=[agent1, agent2],
@@ -63,7 +63,7 @@ workflow = GroupChatBuilder(
Sophisticated multi-agent orchestration using the Magentic One pattern:
```python
from agent_framework_orchestrations import MagenticBuilder
from agent_framework.orchestrations import MagenticBuilder
workflow = MagenticBuilder(
participants=[researcher, writer, reviewer],
@@ -71,14 +71,6 @@ workflow = MagenticBuilder(
).build()
```
## Usage with agent_framework
You can also import orchestrations through the main agent_framework package:
```python
from agent_framework.orchestrations import SequentialBuilder, ConcurrentBuilder
```
## Documentation
For more information, see the [Agent Framework documentation](https://aka.ms/agent-framework).
@@ -18,6 +18,8 @@ The default wiring uses AgentExecutor under the hood for agent participants so
existing observability and streaming semantics continue to apply.
"""
from __future__ import annotations
import inspect
import logging
import sys
@@ -691,7 +693,7 @@ class GroupChatBuilder:
self._participants = named
def with_termination_condition(self, termination_condition: TerminationCondition) -> "GroupChatBuilder":
def with_termination_condition(self, termination_condition: TerminationCondition) -> GroupChatBuilder:
"""Set a custom termination condition for the group chat workflow.
Args:
@@ -732,7 +734,7 @@ class GroupChatBuilder:
self._termination_condition = termination_condition
return self
def with_max_rounds(self, max_rounds: int | None) -> "GroupChatBuilder":
def with_max_rounds(self, max_rounds: int | None) -> GroupChatBuilder:
"""Set a maximum number of orchestrator rounds to prevent infinite conversations.
When the round limit is reached, the workflow automatically completes with
@@ -750,7 +752,7 @@ class GroupChatBuilder:
self._max_rounds = max_rounds
return self
def with_checkpointing(self, checkpoint_storage: CheckpointStorage) -> "GroupChatBuilder":
def with_checkpointing(self, checkpoint_storage: CheckpointStorage) -> GroupChatBuilder:
"""Enable checkpointing for the built workflow using the provided storage.
Checkpointing allows the workflow to persist state and resume from interruption
@@ -782,7 +784,7 @@ class GroupChatBuilder:
self._checkpoint_storage = checkpoint_storage
return self
def with_request_info(self, *, agents: Sequence[str | SupportsAgentRun] | None = None) -> "GroupChatBuilder":
def with_request_info(self, *, agents: Sequence[str | SupportsAgentRun] | None = None) -> GroupChatBuilder:
"""Enable request info after agent participant responses.
This enables human-in-the-loop (HIL) scenarios for the group chat orchestration.
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core",
"agent-framework-core>=1.0.0b260130",
]
[tool.uv]