diff --git a/.github/workflows/python-lab-tests.yml b/.github/workflows/python-lab-tests.yml
new file mode 100644
index 0000000000..8d41cb6d81
--- /dev/null
+++ b/.github/workflows/python-lab-tests.yml
@@ -0,0 +1,71 @@
+name: Python - Lab Tests
+
+on:
+ pull_request:
+ branches: ["main", "feature*"]
+ paths:
+ - "python/packages/lab/**"
+ push:
+ branches: ["main"]
+ paths:
+ - "python/packages/lab/**"
+
+env:
+ # Configure a constant location for the uv cache
+ UV_CACHE_DIR: /tmp/.uv-cache
+
+jobs:
+ python-lab-tests:
+ name: Python Lab Tests
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: true
+ matrix:
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
+ os: [ubuntu-latest, windows-latest, macos-latest]
+ env:
+ UV_PYTHON: ${{ matrix.python-version }}
+ permissions:
+ contents: read
+ defaults:
+ run:
+ working-directory: python
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Set up python and install the project
+ id: python-setup
+ uses: ./.github/actions/python-setup
+ with:
+ python-version: ${{ matrix.python-version }}
+ os: ${{ runner.os }}
+ env:
+ # Configure a constant location for the uv cache
+ UV_CACHE_DIR: /tmp/.uv-cache
+
+ # Lab specific tests
+ - name: Run lab tests
+ run: cd packages/lab && uv run poe test
+
+ - name: Run lab lint
+ run: cd packages/lab && uv run poe lint
+
+ - name: Run lab format check
+ run: cd packages/lab && uv run poe fmt --check
+
+ - name: Run lab type checking
+ run: cd packages/lab && uv run poe pyright
+
+ - name: Run lab mypy
+ run: cd packages/lab && uv run poe mypy
+
+ # Surface failing tests
+ - name: Surface failing tests
+ if: always()
+ uses: pmeier/pytest-results-action@v0.7.2
+ with:
+ path: ./python/packages/lab/**.xml
+ summary: true
+ display-options: fEX
+ fail-on-empty: false
+ title: Lab Test Results
\ No newline at end of file
diff --git a/python/packages/lab/.gitignore b/python/packages/lab/.gitignore
new file mode 100644
index 0000000000..58bab04007
--- /dev/null
+++ b/python/packages/lab/.gitignore
@@ -0,0 +1 @@
+test-results.xml
\ No newline at end of file
diff --git a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/LICENSE b/python/packages/lab/LICENSE
similarity index 100%
rename from python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/LICENSE
rename to python/packages/lab/LICENSE
diff --git a/python/packages/lab/README.md b/python/packages/lab/README.md
index 5508375010..d585970f14 100644
--- a/python/packages/lab/README.md
+++ b/python/packages/lab/README.md
@@ -1,145 +1,99 @@
# Agent Framework Lab
-This directory contains experimental packages for Microsoft Agent Framework that are distributed as separate installable packages under the `agent_framework.lab` namespace.
-Lab packages are not part of the core framework and may experience breaking changes or be deprecated in the future.
+This is the experimental package for Microsoft Agent Framework, `agent-framework-lab`, which contains
+various lab modules built on top of the core framework.
+Lab modules are not part of the core framework and may experience breaking changes or be deprecated in the future.
-## What are Lab Packages?
+## What are Lab Modules?
-Lab packages are extensions to the core Agent Framework that falls into
+Lab modules are extensions to the core Agent Framework that fall into
one of the following categories:
+1. Incubation of new features that may get incorporated by the core framework.
1. Incubation of new features that may get incorporated by the core framework.
2. Research prototypes built on the core framework.
3. Benchmarks and experimentation tools.
-## Lab Packages
+## Lab Modules
-- [**gaia**](./gaia/): GAIA benchmark implementation (`agent-framework-lab-gaia`)
-- [**lightning**](./lightning/): Reinforcement learning for agents (`agent-framework-lab-lightning`)
-- [**tau2**](./tau2/): Customer service agent simulation framework (`agent-framework-lab-tau2`)
+- [**gaia**](./gaia/): Evaluate your agents using the GAIA benchmark for general assistant tasks
+- [**tau2**](./tau2/): Evaluate your agents using the TAU2 benchmark for customer support tasks
+- [**lightning**](./lightning/): RL training for agents (in development)
-## How do I contribute?
-
-This repo only contains lab packages maintained by Microsoft.
-If you want to contribute, please take the following steps:
-
-1. Follow the [Create a New Lab Package](#create-new-lab-package) guide
- below to create your own lab package.
-2. Create a new repo on GitHub and check in your package there.
-3. Tag your repo with `agent-framework-lab` for better discovery.
-4. Submit a PR to this repo (github.com/microsoft/agent-framework)
- to add a link to your repo in the [list](#lab-packages) above.
- **The PR title must contain "[New Lab Package]"**.
-5. We will review your repo and decide whether to approve it.
-
-Follow the [guidelines](#guidelines) when you create your package, our decision
-to accept your PR will be based on your idea as well as the quality of your
-code.
-
-We may decide to maintain your package in this repo. In that case, we will
-contact you directly.
-
-## Package Structure
-
-Each lab package follows this structure:
+## Repository Structure
```
-packages/lab/{lab_name}/
-├── agent_framework/
-│ └── lab/
-│ └── {lab_name}/
-│ └── __init__.py # Imports from agent_framework_lab_{lab_name}
-├── agent_framework_lab_{lab_name}/ # Actual implementation package
-│ ├── __init__.py # Main exports and __version__
-│ ├── {module_files}.py # Implementation modules
-│ └── py.typed # Type hints marker
-├── tests/
-│ ├── __init__.py
-│ └── test_{lab_name}.py # Package tests
-├── pyproject.toml # Package configuration
-├── README.md # Package-specific documentation
-└── LICENSE # MIT License
+agent-framework-lab/
+├── pyproject.toml # Single package configuration for agent-framework-lab
+├── README.md # This file
+├── LICENSE # License file
+├── namespace/ # Centralized namespace package files
+│ └── agent_framework/
+│ └── lab/
+│ ├── gaia/ # Re-exports from agent_framework_lab_gaia
+│ ├── lightning/ # Re-exports from agent_framework_lab_lightning
+│ └── tau2/ # Re-exports from agent_framework_lab_tau2
+├── gaia/ # GAIA module implementation
+│ └── agent_framework_lab_gaia/
+├── lightning/ # Lightning module implementation
+│ └── agent_framework_lab_lightning/
+└── tau2/ # TAU2 module implementation
+ └── agent_framework_lab_tau2/
```
-## Creating a New Lab Package
+This structure maintains a single PyPI package `agent-framework-lab` while supporting modular imports through the namespace package mechanism.
-### Create The Package
+## Installation
-First ensure `cookiecutter` is installed.
+Install the base lab package:
```bash
-pip install cookiecutter
+pip install agent-framework-lab
```
-Then go to the directory where you want to create the package:
+For details on installing individual modules, see their respective README files listed above.
-```bash
-cookiecutter /path/to/agent-framework/python/packages/lab/cookiecutter-agent-framework-lab
-```
+## Usage
-You will be prompted for:
-
-- **package_name**: The name of your lab package (e.g., "lightning", "vision")
-- **package_display_name**: Human-readable name (e.g., "Lighting Tools", "Computer Vision")
-- **package_description**: Brief description (auto-generated from display name)
-- **include_cli_script**: Whether to include a CLI script (y/n)
-
-### After Package Creation
-
-1. **Implement your functionality** in `agent_framework_lab_your_package_name/`
-2. **Update exports** in `__init__.py` `__all__` list
-3. **Add dependencies** to `pyproject.toml`
-4. **Write tests** in the `tests/` directory
-5. **Update README** with usage examples and API documentation
-
-### Add to Workspace (only for packages maintained in this repo)
-
-After creating your package, add it to the workspace configuration:
-
-```
-# Edit python/pyproject.toml
-# Add to dependencies section:
-dependencies = [
- # ... existing packages ...
- "agent-framework-lab-your-package-name",
-]
-
-# Add to [tool.uv.sources] section:
-agent-framework-lab-your-package-name = { workspace = true }
-```
-
-### Usage
-
-Once created, users can install your lab package
-
-1. directly from your repo:
-
-```bash
-pip install git+https://github.com/your-username/your-lab-package-repo.git
-```
-
-2. or from PyPI if you have uploaded your lab package there:
-
-```bash
-pip install "agent-framework-lab-your-package-name"
-```
-
-Then, they can use your lab package:
+Import and use lab modules from the `agent_framework.lab` namespace.
+For example, to use the GAIA module:
```python
-from agent_framework.lab.your_package_name import YourClass, your_function
-
-# Use the functionality
-instance = YourClass()
-result = your_function()
+# Using GAIA module
+from agent_framework.lab.gaia import GAIA
```
-## Guidelines
+## Should I consume Lab Modules?
-1. **Naming**: Use lowercase with hyphens for package names (`agent-framework-lab-your-package-name`)
-2. **Namespace**: Always use `agent_framework.lab.your_package_name` for imports
-3. **Versioning**: Start with `0.1.0b1` for beta releases
-4. **Dependencies**: Minimize external dependencies, always include `agent-framework`
-5. **Documentation**: Include comprehensive README with usage examples
-6. **Tests**: Write comprehensive tests with good coverage
-7. **Type hints**: Always include type hints and `py.typed` file
+If you are looking for stable and production-ready features, you should not use lab modules. Stick to the core framework.
+
+If you are looking for experimentation, research, or want to
+benchmark different approaches -- most importantly, if you don't mind breaking changes and potential deprecations --
+then lab modules are for you.
+
+## Contributing to Lab Modules
+
+### Microsoft-maintained modules
+
+For Microsoft-maintained modules in this repository, please follow standard contribution guidelines and submit pull requests directly to this repository.
+
+### Community modules
+
+If you want to contribute a community-maintained lab module:
+
+1. Create a new repository on GitHub for your module
+2. Tag your repository with `agent-framework-lab` for discoverability
+3. Submit a PR to add a link to your repository in the [Lab Modules](#lab-modules) section above
+4. Use the PR title format: `[New Lab Module] Your Module Name`
+
+We will review your submission based on the guidelines below.
+
+### Guidelines
+
+1. **Purpose**: Community modules should fit into one of the three categories of lab modules (incubation, research, benchmarks)
+2. **Namespace**: Community modules should avoid the `agent_framework.lab` namespace (reserved for modules maintained in this repository)
+3. **Dependencies**: Minimize external dependencies, always include `agent-framework` as a base dependency
+4. **Documentation**: Include comprehensive README with installation instructions and usage examples
+5. **Tests**: Write comprehensive tests with good coverage
+6. **Type hints**: Always include type hints and a `py.typed` file
+7. **Versioning**: Use semantic versioning, start with `0.1.0` for initial releases
diff --git a/python/packages/lab/cookiecutter-agent-framework-lab/README.md b/python/packages/lab/cookiecutter-agent-framework-lab/README.md
deleted file mode 100644
index 6a3ba77dca..0000000000
--- a/python/packages/lab/cookiecutter-agent-framework-lab/README.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# Cookiecutter Template for Agent Framework Lab Packages
-
-This is a cookiecutter template for creating new lab packages in the Microsoft Agent Framework.
-
-## Usage
-
-```bash
-cd /path/to/agent-framework/python/packages/lab
-cookiecutter ./cookiecutter-agent-framework-lab
-```
-
-You will be prompted for the following information:
-
-- **package_name**: The name of your lab package (e.g., "lightning", "vision")
-- **package_display_name**: Human-readable name (e.g., "Lighting Tools", "Computer Vision")
-- **package_description**: Brief description of the package (auto-generated from display name)
-- **version**: Starting version (default: 0.1.0b1)
-- **author_name**: Author name (default: Microsoft)
-- **author_email**: Author email (default: af-support@microsoft.com)
-- **include_cli_script**: Whether to include a CLI script (y/n)
-- **cli_script_name**: Name of CLI script if included
-
-## What Gets Generated
-
-The template creates a complete lab package structure:
-
-```
-{package_name}/
-├── agent_framework/
-│ └── lab/
-│ └── {package_name}/
-│ └── __init__.py
-├── agent_framework_lab_{package_name}/
-│ ├── __init__.py
-│ └── py.typed
-├── tests/
-│ ├── __init__.py
-│ └── test_{package_name}.py
-├── pyproject.toml
-├── README.md
-└── LICENSE
-```
-
-## After Generation
-
-1. Implement your functionality in `agent_framework_lab_{package_name}/`
-2. Update the `__all__` exports in `__init__.py`
-3. Add your dependencies to `pyproject.toml`
-4. Write comprehensive tests
-5. Update the README with usage examples
-
-## Integration
-
-Don't forget to add your new package to the workspace:
-
-1. Add to `python/pyproject.toml` dependencies
-2. Add to `[tool.uv.sources]` section
-3. Test installation with `uv run python -c "from agent_framework.lab.{name} import *"`
diff --git a/python/packages/lab/cookiecutter-agent-framework-lab/cookiecutter.json b/python/packages/lab/cookiecutter-agent-framework-lab/cookiecutter.json
deleted file mode 100644
index 1322ed6d8c..0000000000
--- a/python/packages/lab/cookiecutter-agent-framework-lab/cookiecutter.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "package_name": "",
- "package_display_name": "",
- "package_description": "{{ cookiecutter.package_display_name }} module for Microsoft Agent Framework.",
- "version": "0.1.0b1",
- "author_name": "Microsoft",
- "author_email": "af-support@microsoft.com",
- "license": "MIT",
- "include_cli_script": ["y", "n"],
- "cli_script_name": "{{ cookiecutter.package_name }}_cli",
- "python_requires": ">=3.10",
- "within_microsoft_agent_framework_repo": ["y", "n"],
- "__prompts__": {
- "within_microsoft_agent_framework_repo": "Are you creating this package within the github.com/microsoft/agent-framework repo or a fork of it? (If yes, ensure you create it in python/packages/lab/ directory)"
- },
- "_templates_suffix": "",
- "_copy_without_render": [
- "*.py.typed"
- ]
-}
diff --git a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/README.md b/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/README.md
deleted file mode 100644
index 586b2db371..0000000000
--- a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/README.md
+++ /dev/null
@@ -1,56 +0,0 @@
-# Agent Framework Lab - {{ cookiecutter.package_display_name }}
-
-{{ cookiecutter.package_description }}
-
-## Installation
-
-```bash
-pip install agent-framework-lab-{{ cookiecutter.package_name }}
-```
-
-## Usage
-
-```python
-from agent_framework.lab.{{ cookiecutter.package_name }} import YourClass
-
-# Your usage example here
-instance = YourClass()
-```
-
-## Overview
-
-Brief description of what this lab package provides and its main features.
-
-## Features
-
-- Feature 1: Description
-- Feature 2: Description
-- Feature 3: Description
-
-## Examples
-
-### Basic Usage
-
-```python
-from agent_framework.lab.{{ cookiecutter.package_name }} import YourClass
-
-# Example usage
-```
-
-### Advanced Usage
-
-```python
-# More advanced examples
-```
-
-## API Reference
-
-Document your main classes and functions here.
-
-## Contributing
-
-This package is part of the Microsoft Agent Framework Lab. Please see the main repository for contribution guidelines.
-
-## License
-
-This project is licensed under the {{ cookiecutter.license }} License - see the LICENSE file for details.
\ No newline at end of file
diff --git a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/pyproject.toml b/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/pyproject.toml
deleted file mode 100644
index 5dc5a22d10..0000000000
--- a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/pyproject.toml
+++ /dev/null
@@ -1,95 +0,0 @@
-[project]
-name = "agent-framework-lab-{{ cookiecutter.package_name }}"
-description = "{{ cookiecutter.package_description }}"
-authors = [{ name = "{{ cookiecutter.author_name }}", email = "{{ cookiecutter.author_email }}"}]
-readme = "README.md"
-requires-python = "{{ cookiecutter.python_requires }}"
-version = "{{ cookiecutter.version }}"
-license-files = ["LICENSE"]
-urls.homepage = "https://learn.microsoft.com/en-us/semantic-kernel/overview/"
-urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
-urls.release_notes = "https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true"
-urls.issues = "https://github.com/microsoft/agent-framework/issues"
-classifiers = [
- "License :: OSI Approved :: {{ cookiecutter.license }} License",
- "Development Status :: 2 - Pre-Alpha",
- "Intended Audience :: Developers",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
- "Programming Language :: Python :: 3.13",
-]
-dependencies = [
- "agent-framework",
- "pydantic>=2.0.0",
- # Add your specific dependencies here
-]
-
-{% if cookiecutter.include_cli_script == "y" %}
-[project.scripts]
-{{ cookiecutter.cli_script_name }} = "agent_framework_lab_{{ cookiecutter.package_name }}:main"
-{% endif %}
-
-[build-system]
-requires = ["setuptools>=64", "wheel"]
-build-backend = "setuptools.build_meta"
-
-[tool.setuptools]
-package-dir = {"" = "src"}
-packages = ["agent_framework_lab_{{ cookiecutter.package_name }}", "agent_framework.lab.{{ cookiecutter.package_name }}"]
-
-[tool.setuptools.package-data]
-agent_framework_lab_{{ cookiecutter.package_name }} = ["py.typed"]
-
-[tool.ruff]
-line-length = 120
-target-version = "py310"
-extend-exclude = ["tests", "__pycache__"]
-
-[tool.ruff.lint]
-select = ["E", "F", "I", "W", "UP", "C4", "N"]
-ignore = ["N803", "N806", "N999", "UP007"]
-
-[tool.ruff.format]
-quote-style = "double"
-
-[tool.mypy]
-python_version = "3.10"
-strict = true
-check_untyped_defs = true
-disallow_untyped_defs = true
-disallow_incomplete_defs = true
-disallow_untyped_decorators = true
-warn_redundant_casts = true
-warn_unused_ignores = true
-warn_return_any = true
-warn_unreachable = true
-show_error_codes = true
-implicit_reexport = true
-packages = ["src.agent_framework_lab_{{ cookiecutter.package_name }}"]
-
-{% if cookiecutter.within_microsoft_agent_framework_repo == "y" %}
-[tool.poe]
-executor.type = "uv"
-include = "../../../shared_tasks.toml"
-[tool.poe.tasks]
-test = "pytest --cov=agent_framework_lab_{{ cookiecutter.package_name }} --cov-report=term-missing:skip-covered tests"
-mypy = "mypy agent_framework_lab_{{ cookiecutter.package_name }}"
-{% else %}
-[tool.poe.tasks]
-fmt = "ruff format"
-format = "ruff format"
-lint = "ruff check"
-test = "pytest --cov=agent_framework_lab_{{ cookiecutter.package_name }} --cov-report=term-missing:skip-covered tests"
-mypy = "mypy agent_framework_lab_{{ cookiecutter.package_name }}"
-{% endif %}
-
-[tool.pytest.ini_options]
-testpaths = ["tests"]
-pythonpath = ["src"]
-addopts = "--strict-markers --strict-config"
-markers = [
- "unit: marks tests as unit tests",
- "integration: marks tests as integration tests",
-]
diff --git a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/src/agent_framework/lab/{{cookiecutter.package_name}}/__init__.py b/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/src/agent_framework/lab/{{cookiecutter.package_name}}/__init__.py
deleted file mode 100644
index 24ee74ae3e..0000000000
--- a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/src/agent_framework/lab/{{cookiecutter.package_name}}/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-# Import and re-export from the actual implementation
-from agent_framework_lab_{{cookiecutter.package_name}} import * # noqa: F403, F401
diff --git a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/src/agent_framework_lab_{{cookiecutter.package_name}}/__init__.py b/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/src/agent_framework_lab_{{cookiecutter.package_name}}/__init__.py
deleted file mode 100644
index 78d327cbe0..0000000000
--- a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/src/agent_framework_lab_{{cookiecutter.package_name}}/__init__.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-"""
-{{ cookiecutter.package_description }}
-"""
-
-import importlib.metadata
-
-# Import your main exports here
-# from .main_module import MainClass, main_function
-
-try:
- __version__ = importlib.metadata.version(__name__)
-except importlib.metadata.PackageNotFoundError:
- __version__ = "0.0.0" # Fallback for development mode
-
-__all__ = [
- # List your exports here
- # "MainClass",
- # "main_function",
-]
diff --git a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/src/agent_framework_lab_{{cookiecutter.package_name}}/py.typed b/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/src/agent_framework_lab_{{cookiecutter.package_name}}/py.typed
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/tests/__init__.py b/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/tests/__init__.py
deleted file mode 100644
index 2a50eae894..0000000000
--- a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/tests/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
diff --git a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/tests/test_{{cookiecutter.package_name}}.py b/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/tests/test_{{cookiecutter.package_name}}.py
deleted file mode 100644
index f832f0ab37..0000000000
--- a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/tests/test_{{cookiecutter.package_name}}.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-"""Tests for {{ cookiecutter.package_name }} module."""
-
-import pytest
-from agent_framework_lab_{{cookiecutter.package_name}} import __version__
-
-
-class Test{{cookiecutter.package_name | title}}:
- """Test the {{ cookiecutter.package_name }} module."""
-
- def test_version(self):
- """Test package version is defined."""
- assert __version__ is not None
- assert __version__ == "{{ cookiecutter.version }}"
diff --git a/python/packages/lab/gaia/LICENSE b/python/packages/lab/gaia/LICENSE
deleted file mode 100644
index 22aed37e65..0000000000
--- a/python/packages/lab/gaia/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) Microsoft Corporation.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/python/packages/lab/gaia/README.md b/python/packages/lab/gaia/README.md
index 235e1e4e54..f8734e65f9 100644
--- a/python/packages/lab/gaia/README.md
+++ b/python/packages/lab/gaia/README.md
@@ -3,12 +3,14 @@
The GAIA benchmark can be used for evaluating agents and workflows built using the Agent Framework.
It includes built-in benchmarks as well as utilities for running custom evaluations.
+> **Note**: This module is part of the consolidated `agent-framework-lab` package. Install the package with the `gaia` extra to use this module.
+
## Setup
-Use `uv` to install the package with GAIA dependencies:
+Install the agent-framework-lab package with GAIA dependencies:
```bash
-uv pip install "agent-framework-lab-gaia"
+pip install "agent-framework-lab[gaia]"
```
Set up Hugging Face token:
diff --git a/python/packages/lab/gaia/agent_framework/__init__.py b/python/packages/lab/gaia/agent_framework/__init__.py
deleted file mode 100644
index 1d3db512a4..0000000000
--- a/python/packages/lab/gaia/agent_framework/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-# This makes agent_framework a namespace package
-__path__ = __import__("pkgutil").extend_path(__path__, __name__)
diff --git a/python/packages/lab/gaia/agent_framework/lab/__init__.py b/python/packages/lab/gaia/agent_framework/lab/__init__.py
deleted file mode 100644
index 0d8d8fbaa4..0000000000
--- a/python/packages/lab/gaia/agent_framework/lab/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-# This makes agent_framework.lab a namespace package
-__path__ = __import__("pkgutil").extend_path(__path__, __name__)
diff --git a/python/packages/lab/gaia/agent_framework_lab_gaia/__init__.py b/python/packages/lab/gaia/agent_framework_lab_gaia/__init__.py
index 3c5902758a..9a9029d138 100644
--- a/python/packages/lab/gaia/agent_framework_lab_gaia/__init__.py
+++ b/python/packages/lab/gaia/agent_framework_lab_gaia/__init__.py
@@ -1,8 +1,6 @@
# Copyright (c) Microsoft. All rights reserved.
-"""
-GAIA benchmark module for Agent Framework.
-"""
+"""GAIA benchmark module for Agent Framework."""
import importlib.metadata
@@ -16,13 +14,13 @@ except importlib.metadata.PackageNotFoundError:
__all__ = [
"GAIA",
- "GAIATelemetryConfig",
- "gaia_scorer",
- "viewer_main",
- "Task",
- "Prediction",
"Evaluation",
+ "Evaluator",
+ "GAIATelemetryConfig",
+ "Prediction",
+ "Task",
"TaskResult",
"TaskRunner",
- "Evaluator",
+ "gaia_scorer",
+ "viewer_main",
]
diff --git a/python/packages/lab/gaia/agent_framework_lab_gaia/_types.py b/python/packages/lab/gaia/agent_framework_lab_gaia/_types.py
index d06ded1906..6bee3d230c 100644
--- a/python/packages/lab/gaia/agent_framework_lab_gaia/_types.py
+++ b/python/packages/lab/gaia/agent_framework_lab_gaia/_types.py
@@ -6,12 +6,12 @@ from dataclasses import dataclass
from typing import Any, Protocol, runtime_checkable
__all__ = [
- "Task",
- "Prediction",
"Evaluation",
+ "Evaluator",
+ "Prediction",
+ "Task",
"TaskResult",
"TaskRunner",
- "Evaluator",
]
diff --git a/python/packages/lab/gaia/agent_framework_lab_gaia/gaia.py b/python/packages/lab/gaia/agent_framework_lab_gaia/gaia.py
index 4fe15a8216..1ee2aae167 100644
--- a/python/packages/lab/gaia/agent_framework_lab_gaia/gaia.py
+++ b/python/packages/lab/gaia/agent_framework_lab_gaia/gaia.py
@@ -1,8 +1,6 @@
# Copyright (c) Microsoft. All rights reserved.
-"""
-GAIA benchmark implementation for Agent Framework.
-"""
+"""GAIA benchmark implementation for Agent Framework."""
import asyncio
import json
@@ -22,7 +20,7 @@ from tqdm import tqdm
from ._types import Evaluation, Evaluator, Prediction, Task, TaskResult, TaskRunner
-__all__ = ["GAIA", "gaia_scorer", "GAIATelemetryConfig"]
+__all__ = ["GAIA", "GAIATelemetryConfig", "gaia_scorer"]
class GAIATelemetryConfig:
@@ -36,8 +34,7 @@ class GAIATelemetryConfig:
trace_to_file: bool = False,
file_path: str | None = None,
):
- """
- Initialize telemetry configuration.
+ """Initialize telemetry configuration.
Args:
enable_tracing: Whether to enable OpenTelemetry tracing
@@ -74,8 +71,9 @@ class GAIATelemetryConfig:
try:
import json
import os
+ from collections.abc import Sequence
- from opentelemetry.sdk.trace import TracerProvider
+ from opentelemetry.sdk.trace import ReadableSpan, TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SpanExporter, SpanExportResult
from opentelemetry.trace import get_tracer_provider
@@ -85,7 +83,7 @@ class GAIATelemetryConfig:
# Ensure directory exists
os.makedirs(os.path.dirname(os.path.abspath(file_path)), exist_ok=True)
- def export(self, spans) -> SpanExportResult:
+ def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
try:
with open(self.file_path, "a", encoding="utf-8") as f:
for span in spans:
@@ -131,8 +129,10 @@ def _normalize_number_str(number_str: str) -> float:
return float("inf")
-def _split_string(s: str, chars: list[str] = [",", ";"]) -> list[str]:
+def _split_string(s: str, chars: list[str] | None = None) -> list[str]:
"""Split string by multiple delimiters."""
+ if chars is None:
+ chars = [",", ";"]
return re.split(f"[{''.join(chars)}]", s)
@@ -146,8 +146,7 @@ def _normalize_str(s: str, remove_punct: bool = True) -> str:
def gaia_scorer(model_answer: str, ground_truth: str) -> bool:
- """
- Official GAIA scoring function.
+ """Official GAIA scoring function.
Args:
model_answer: The model's answer
@@ -170,22 +169,21 @@ def gaia_scorer(model_answer: str, ground_truth: str) -> bool:
if is_float(ground_truth):
# numeric exact match after normalization
return _normalize_number_str(model_answer) == float(ground_truth)
- elif any(ch in ground_truth for ch in [",", ";"]):
+ if any(ch in ground_truth for ch in [",", ";"]):
# list with per-element compare (number or string)
gt_elems = _split_string(ground_truth)
ma_elems = _split_string(model_answer)
if len(gt_elems) != len(ma_elems):
return False
comparisons = []
- for ma, gt in zip(ma_elems, gt_elems):
+ for ma, gt in zip(ma_elems, gt_elems, strict=False):
if is_float(gt):
comparisons.append(_normalize_number_str(ma) == float(gt))
else:
comparisons.append(_normalize_str(ma, remove_punct=False) == _normalize_str(gt, remove_punct=False))
return all(comparisons)
- else:
- # string normalize + exact
- return _normalize_str(model_answer) == _normalize_str(ground_truth)
+ # string normalize + exact
+ return _normalize_str(model_answer) == _normalize_str(ground_truth)
def _read_jsonl(path: Path) -> Iterable[dict[str, Any]]:
@@ -238,8 +236,7 @@ def _load_gaia_local(repo_dir: Path, wanted_levels: list[int] | None = None, max
class GAIA:
- """
- GAIA benchmark runner for Agent Framework.
+ """GAIA benchmark runner for Agent Framework.
GAIA (General AI Assistant) is a benchmark for general-purpose AI assistants.
This class provides utilities to run the benchmark with custom agents.
@@ -252,8 +249,7 @@ class GAIA:
hf_token: str | None = None,
telemetry_config: GAIATelemetryConfig | None = None,
):
- """
- Initialize GAIA benchmark runner.
+ """Initialize GAIA benchmark runner.
Args:
evaluator: Custom evaluator function. If None, uses default GAIA scorer.
@@ -282,7 +278,6 @@ class GAIA:
def _ensure_data(self) -> Path:
"""Ensure GAIA data is available locally."""
-
if self.data_dir.exists() and any(self.data_dir.rglob("metadata.jsonl")):
return self.data_dir
@@ -347,14 +342,12 @@ class GAIA:
# Add results to span
if span:
- span.set_attributes(
- {
- "gaia.task.runtime_seconds": runtime_seconds,
- "gaia.task.is_correct": evaluation.is_correct,
- "gaia.task.score": evaluation.score,
- "gaia.task.prediction_length": len(prediction.prediction or ""),
- }
- )
+ span.set_attributes({
+ "gaia.task.runtime_seconds": runtime_seconds,
+ "gaia.task.is_correct": evaluation.is_correct,
+ "gaia.task.score": evaluation.score,
+ "gaia.task.prediction_length": len(prediction.prediction or ""),
+ })
return TaskResult(
task_id=task.task_id,
@@ -368,14 +361,12 @@ class GAIA:
# Record error in span
if span:
- span.set_attributes(
- {
- "gaia.task.runtime_seconds": runtime_seconds,
- "gaia.task.error": str(e),
- "gaia.task.is_correct": False,
- "gaia.task.score": 0.0,
- }
- )
+ span.set_attributes({
+ "gaia.task.runtime_seconds": runtime_seconds,
+ "gaia.task.error": str(e),
+ "gaia.task.is_correct": False,
+ "gaia.task.score": 0.0,
+ })
span.record_exception(e)
return TaskResult(
@@ -396,8 +387,7 @@ class GAIA:
timeout: int | None = None,
out: str | None = None,
) -> list[TaskResult]:
- """
- Run the GAIA benchmark.
+ """Run the GAIA benchmark.
Args:
task_runner: Function that takes a Task and returns a Prediction
@@ -425,10 +415,7 @@ class GAIA:
data_path = self._ensure_data()
# Parse level parameter
- if isinstance(level, int):
- levels = [level]
- else:
- levels = level
+ levels = [level] if isinstance(level, int) else level
# Load tasks
with self.tracer.start_as_current_span(
@@ -442,11 +429,9 @@ class GAIA:
tasks = _load_gaia_local(data_path, wanted_levels=levels, max_n=max_n)
if load_span:
- load_span.set_attributes(
- {
- "gaia.tasks.loaded_count": len(tasks),
- }
- )
+ load_span.set_attributes({
+ "gaia.tasks.loaded_count": len(tasks),
+ })
if not tasks:
raise RuntimeError(
@@ -458,11 +443,9 @@ class GAIA:
# Update benchmark span with task info
if benchmark_span:
- benchmark_span.set_attributes(
- {
- "gaia.benchmark.total_tasks": len(tasks),
- }
- )
+ benchmark_span.set_attributes({
+ "gaia.benchmark.total_tasks": len(tasks),
+ })
# Run tasks
semaphore = asyncio.Semaphore(parallel)
@@ -484,14 +467,12 @@ class GAIA:
# Update benchmark span with final results
if benchmark_span:
- benchmark_span.set_attributes(
- {
- "gaia.benchmark.accuracy": accuracy,
- "gaia.benchmark.correct_count": correct,
- "gaia.benchmark.total_count": len(results),
- "gaia.benchmark.avg_runtime_seconds": avg_runtime,
- }
- )
+ benchmark_span.set_attributes({
+ "gaia.benchmark.accuracy": accuracy,
+ "gaia.benchmark.correct_count": correct,
+ "gaia.benchmark.total_count": len(results),
+ "gaia.benchmark.avg_runtime_seconds": avg_runtime,
+ })
print("\nGAIA Benchmark Results:")
print(f"Accuracy: {accuracy:.3f} ({correct}/{len(results)})")
diff --git a/python/packages/lab/gaia/pyproject.toml b/python/packages/lab/gaia/pyproject.toml
deleted file mode 100644
index fac593bd3d..0000000000
--- a/python/packages/lab/gaia/pyproject.toml
+++ /dev/null
@@ -1,86 +0,0 @@
-[project]
-name = "agent-framework-lab-gaia"
-description = "GAIA benchmark module for Microsoft Agent Framework."
-authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
-readme = "README.md"
-requires-python = ">=3.10"
-version = "0.1.0b1"
-license-files = ["LICENSE"]
-urls.homepage = "https://learn.microsoft.com/en-us/semantic-kernel/overview/"
-urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
-urls.release_notes = "https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true"
-urls.issues = "https://github.com/microsoft/agent-framework/issues"
-classifiers = [
- "License :: OSI Approved :: MIT License",
- "Development Status :: 2 - Pre-Alpha",
- "Intended Audience :: Developers",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
- "Programming Language :: Python :: 3.13",
-]
-dependencies = [
- "agent-framework",
- "pydantic>=2.0.0",
- "opentelemetry-api>=1.24.0",
- "tqdm>=4.60.0",
- "huggingface-hub>=0.20.0",
- "orjson>=3.8.0",
-]
-
-[project.scripts]
-gaia_viewer = "agent_framework_lab_gaia:viewer_main"
-
-[build-system]
-requires = ["setuptools>=64", "wheel"]
-build-backend = "setuptools.build_meta"
-
-[tool.setuptools]
-packages = ["agent_framework_lab_gaia", "agent_framework.lab.gaia"]
-
-[tool.setuptools.package-data]
-agent_framework_lab_gaia = ["py.typed"]
-
-[tool.ruff]
-line-length = 120
-target-version = "py310"
-extend-exclude = ["tests", "__pycache__"]
-
-[tool.ruff.lint]
-select = ["E", "F", "I", "W", "UP", "C4", "N"]
-ignore = ["N803", "N806", "N999", "UP007"]
-
-[tool.ruff.format]
-quote-style = "double"
-
-[tool.mypy]
-python_version = "3.10"
-strict = true
-check_untyped_defs = true
-disallow_untyped_defs = true
-disallow_incomplete_defs = true
-disallow_untyped_decorators = true
-warn_redundant_casts = true
-warn_unused_ignores = true
-warn_return_any = true
-warn_unreachable = true
-show_error_codes = true
-implicit_reexport = true
-packages = ["agent_framework_lab_gaia"]
-
-[tool.poe]
-executor.type = "uv"
-include = "../../../shared_tasks.toml"
-
-[tool.poe.tasks]
-test = "pytest --cov=agent_framework_lab_gaia --cov-report=term-missing:skip-covered tests"
-
-[tool.pytest.ini_options]
-testpaths = ["tests"]
-pythonpath = ["."]
-addopts = "--strict-markers --strict-config"
-markers = [
- "unit: marks tests as unit tests",
- "integration: marks tests as integration tests",
-]
diff --git a/python/packages/lab/gaia/samples/gaia_sample.py b/python/packages/lab/gaia/samples/gaia_sample.py
index 8639bc7ac2..cb2d08b97e 100644
--- a/python/packages/lab/gaia/samples/gaia_sample.py
+++ b/python/packages/lab/gaia/samples/gaia_sample.py
@@ -1,7 +1,6 @@
# Copyright (c) Microsoft. All rights reserved.
-"""
-GAIA Benchmark Sample
+"""GAIA Benchmark Sample.
To run this sample, execute it from the root directory of the agent-framework repository:
cd /path/to/agent-framework
@@ -11,12 +10,11 @@ This avoids namespace package conflicts that occur when running from within the
"""
from agent_framework.azure import AzureAIAgentClient
+from agent_framework.lab.gaia import GAIA, Evaluation, GAIATelemetryConfig, Prediction, Task
from azure.identity.aio import AzureCliCredential
-from agent_framework.lab.gaia import GAIA, Evaluation, GAIATelemetryConfig, Prediction, Task
-
-async def evaluate_task(task: Task, prediction: Prediction) -> Evaluation:
+def evaluate_task(task: Task, prediction: Prediction) -> Evaluation:
"""Evaluate the prediction for a given task."""
# Simple evaluation: check if the prediction contains the answer
is_correct = (task.answer or "").lower() in prediction.prediction.lower()
@@ -24,12 +22,10 @@ async def evaluate_task(task: Task, prediction: Prediction) -> Evaluation:
async def main() -> None:
+ """Run GAIA benchmark with telemetry configuration."""
# Configure telemetry for tracing
telemetry_config = GAIATelemetryConfig(
enable_tracing=True, # Enable OpenTelemetry tracing
- # Optional: Configure external endpoints
- # otlp_endpoint="http://localhost:4317", # For Aspire Dashboard or other OTLP endpoints
- # applicationinsights_connection_string="your_connection_string", # For Azure Monitor
# Configure local file tracing
trace_to_file=True, # Export traces to local file
file_path="gaia_benchmark_traces.jsonl", # Custom file path for traces
diff --git a/python/packages/lab/gaia/tests/__init__.py b/python/packages/lab/gaia/tests/__init__.py
deleted file mode 100644
index 2a50eae894..0000000000
--- a/python/packages/lab/gaia/tests/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
diff --git a/python/packages/lab/gaia/tests/test_gaia.py b/python/packages/lab/gaia/tests/test_gaia.py
index 40d6791846..2af57b5f9a 100644
--- a/python/packages/lab/gaia/tests/test_gaia.py
+++ b/python/packages/lab/gaia/tests/test_gaia.py
@@ -2,27 +2,26 @@
"""Tests for GAIA benchmark implementation."""
-import pytest
from agent_framework_lab_gaia import gaia_scorer
class TestGAIAScorer:
"""Test the GAIA scoring function."""
-
+
def test_numeric_exact_match(self):
"""Test numeric exact matching."""
assert gaia_scorer("42", "42") is True
assert gaia_scorer("42.0", "42") is True
assert gaia_scorer("42", "42.0") is True
assert gaia_scorer("42", "43") is False
-
+
def test_string_normalization(self):
"""Test string normalization and matching."""
assert gaia_scorer("Hello World", "hello world") is True
assert gaia_scorer("Hello, World!", "helloworld") is True
assert gaia_scorer("test", "TEST") is True
assert gaia_scorer("test", "different") is False
-
+
def test_list_matching(self):
"""Test list matching with comma/semicolon separation."""
assert gaia_scorer("1,2,3", "1,2,3") is True
@@ -30,7 +29,7 @@ class TestGAIAScorer:
assert gaia_scorer("apple,banana", "apple,banana") is True
assert gaia_scorer("1,2,3", "1,2,4") is False
assert gaia_scorer("1,2", "1,2,3") is False
-
+
def test_none_handling(self):
"""Test handling of None values."""
assert gaia_scorer("None", "test") is False
diff --git a/python/packages/lab/lightning/LICENSE b/python/packages/lab/lightning/LICENSE
deleted file mode 100644
index 22aed37e65..0000000000
--- a/python/packages/lab/lightning/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) Microsoft Corporation.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/python/packages/lab/lightning/README.md b/python/packages/lab/lightning/README.md
index 3a936e7a17..f5c909c19c 100644
--- a/python/packages/lab/lightning/README.md
+++ b/python/packages/lab/lightning/README.md
@@ -1,11 +1,15 @@
-# Agent Framework Lab - Agent Framework x Agent Lightning
+# Agent Framework Lab - Lightning
RL Module for Microsoft Agent Framework
+> **Note**: This module is part of the consolidated `agent-framework-lab` package. Install the package with the `lightning` extra to use this module.
+
## Installation
+Install the agent-framework-lab package with Lightning dependencies:
+
```bash
-pip install agent-framework-lab-lightning
+pip install "agent-framework-lab[lightning]"
```
## Usage
diff --git a/python/packages/lab/lightning/agent_framework/__init__.py b/python/packages/lab/lightning/agent_framework/__init__.py
deleted file mode 100644
index 1d3db512a4..0000000000
--- a/python/packages/lab/lightning/agent_framework/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-# This makes agent_framework a namespace package
-__path__ = __import__("pkgutil").extend_path(__path__, __name__)
diff --git a/python/packages/lab/lightning/agent_framework/lab/__init__.py b/python/packages/lab/lightning/agent_framework/lab/__init__.py
deleted file mode 100644
index 0d8d8fbaa4..0000000000
--- a/python/packages/lab/lightning/agent_framework/lab/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-# This makes agent_framework.lab a namespace package
-__path__ = __import__("pkgutil").extend_path(__path__, __name__)
diff --git a/python/packages/lab/lightning/agent_framework_lab_lightning/__init__.py b/python/packages/lab/lightning/agent_framework_lab_lightning/__init__.py
index 2a726e805e..9d2ffd2de2 100644
--- a/python/packages/lab/lightning/agent_framework_lab_lightning/__init__.py
+++ b/python/packages/lab/lightning/agent_framework_lab_lightning/__init__.py
@@ -1,8 +1,6 @@
# Copyright (c) Microsoft. All rights reserved.
-"""
-RL Module for Microsoft Agent Framework
-"""
+"""RL Module for Microsoft Agent Framework."""
import importlib.metadata
@@ -11,11 +9,4 @@ try:
except importlib.metadata.PackageNotFoundError:
__version__ = "0.0.0" # Fallback for development mode
-# Import your main exports here
-# from .main_module import MainClass, main_function
-
-__all__ = [
- # List your exports here
- # "MainClass",
- # "main_function",
-]
+__all__: list[str] = []
diff --git a/python/packages/lab/lightning/pyproject.toml b/python/packages/lab/lightning/pyproject.toml
deleted file mode 100644
index 68d333ee17..0000000000
--- a/python/packages/lab/lightning/pyproject.toml
+++ /dev/null
@@ -1,87 +0,0 @@
-[project]
-name = "agent-framework-lab-lightning"
-description = "RL Module for Microsoft Agent Framework"
-authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
-readme = "README.md"
-requires-python = ">=3.10"
-version = "0.1.0b1"
-license-files = ["LICENSE"]
-urls.homepage = "https://learn.microsoft.com/en-us/semantic-kernel/overview/"
-urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
-urls.release_notes = "https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true"
-urls.issues = "https://github.com/microsoft/agent-framework/issues"
-classifiers = [
- "License :: OSI Approved :: MIT License",
- "Development Status :: 2 - Pre-Alpha",
- "Intended Audience :: Developers",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
- "Programming Language :: Python :: 3.13",
-]
-dependencies = [
- "agent-framework",
- "pydantic>=2.0.0",
- # Add your specific dependencies here
-]
-
-
-[project.scripts]
-lightning = "agent_framework_lab_lightning:main"
-
-
-[build-system]
-requires = ["setuptools>=64", "wheel"]
-build-backend = "setuptools.build_meta"
-
-[tool.setuptools]
-packages = ["agent_framework_lab_lightning", "agent_framework.lab.lightning"]
-
-[tool.setuptools.package-data]
-agent_framework_lab_lightning = ["py.typed"]
-
-[tool.ruff]
-line-length = 120
-target-version = "py310"
-extend-exclude = ["tests", "__pycache__"]
-
-[tool.ruff.lint]
-select = ["E", "F", "I", "W", "UP", "C4", "N"]
-ignore = ["N803", "N806", "N999", "UP007"]
-
-[tool.ruff.format]
-quote-style = "double"
-
-[tool.mypy]
-python_version = "3.10"
-strict = true
-check_untyped_defs = true
-disallow_untyped_defs = true
-disallow_incomplete_defs = true
-disallow_untyped_decorators = true
-warn_redundant_casts = true
-warn_unused_ignores = true
-warn_return_any = true
-warn_unreachable = true
-show_error_codes = true
-implicit_reexport = true
-packages = ["agent_framework_lab_lightning"]
-
-
-[tool.poe]
-executor.type = "uv"
-include = "../../../shared_tasks.toml"
-[tool.poe.tasks]
-test = "pytest --cov=agent_framework_lab_lightning --cov-report=term-missing:skip-covered tests"
-mypy = "mypy agent_framework_lab_lightning"
-
-
-[tool.pytest.ini_options]
-testpaths = ["tests"]
-pythonpath = ["."]
-addopts = "--strict-markers --strict-config"
-markers = [
- "unit: marks tests as unit tests",
- "integration: marks tests as integration tests",
-]
diff --git a/python/packages/lab/lightning/tests/__init__.py b/python/packages/lab/lightning/tests/__init__.py
deleted file mode 100644
index 2a50eae894..0000000000
--- a/python/packages/lab/lightning/tests/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
diff --git a/python/packages/lab/lightning/tests/test_lightning.py b/python/packages/lab/lightning/tests/test_lightning.py
index 52a60da224..f0491c265b 100644
--- a/python/packages/lab/lightning/tests/test_lightning.py
+++ b/python/packages/lab/lightning/tests/test_lightning.py
@@ -2,14 +2,16 @@
"""Tests for lightning module."""
-import pytest
from agent_framework_lab_lightning import __version__
class TestLightning:
"""Test the lightning module."""
-
+
def test_version(self):
"""Test package version is defined."""
assert __version__ is not None
- assert __version__ == "0.1.0b1"
+ # In development mode, version falls back to "0.0.0"
+ # In installed mode, it would be the actual package version
+ assert isinstance(__version__, str)
+ assert len(__version__) > 0
diff --git a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/src/agent_framework/__init__.py b/python/packages/lab/namespace/agent_framework/__init__.py
similarity index 100%
rename from python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/src/agent_framework/__init__.py
rename to python/packages/lab/namespace/agent_framework/__init__.py
diff --git a/python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/src/agent_framework/lab/__init__.py b/python/packages/lab/namespace/agent_framework/lab/__init__.py
similarity index 100%
rename from python/packages/lab/cookiecutter-agent-framework-lab/{{cookiecutter.package_name}}/src/agent_framework/lab/__init__.py
rename to python/packages/lab/namespace/agent_framework/lab/__init__.py
diff --git a/python/packages/lab/gaia/agent_framework/lab/gaia/__init__.py b/python/packages/lab/namespace/agent_framework/lab/gaia/__init__.py
similarity index 63%
rename from python/packages/lab/gaia/agent_framework/lab/gaia/__init__.py
rename to python/packages/lab/namespace/agent_framework/lab/gaia/__init__.py
index cc4cc7e9a6..391a57b4a3 100644
--- a/python/packages/lab/gaia/agent_framework/lab/gaia/__init__.py
+++ b/python/packages/lab/namespace/agent_framework/lab/gaia/__init__.py
@@ -1,4 +1,4 @@
# Copyright (c) Microsoft. All rights reserved.
# Import and re-export from the actual implementation
-from agent_framework_lab_gaia import * # noqa: F403, F401
+from agent_framework_lab_gaia import * # noqa: F403
diff --git a/python/packages/lab/tau2/namespace/agent_framework/lab/tau2/__init__.py b/python/packages/lab/namespace/agent_framework/lab/lightning/__init__.py
similarity index 63%
rename from python/packages/lab/tau2/namespace/agent_framework/lab/tau2/__init__.py
rename to python/packages/lab/namespace/agent_framework/lab/lightning/__init__.py
index ef268ffd23..3a857f38da 100644
--- a/python/packages/lab/tau2/namespace/agent_framework/lab/tau2/__init__.py
+++ b/python/packages/lab/namespace/agent_framework/lab/lightning/__init__.py
@@ -1,4 +1,4 @@
# Copyright (c) Microsoft. All rights reserved.
# Import and re-export from the actual implementation
-from agent_framework_lab_tau2 import * # noqa: F403, F401
+from agent_framework_lab_lightning import * # noqa: F403
diff --git a/python/packages/lab/lightning/agent_framework/lab/lightning/__init__.py b/python/packages/lab/namespace/agent_framework/lab/tau2/__init__.py
similarity index 61%
rename from python/packages/lab/lightning/agent_framework/lab/lightning/__init__.py
rename to python/packages/lab/namespace/agent_framework/lab/tau2/__init__.py
index 2591080d0d..56fda49217 100644
--- a/python/packages/lab/lightning/agent_framework/lab/lightning/__init__.py
+++ b/python/packages/lab/namespace/agent_framework/lab/tau2/__init__.py
@@ -1,4 +1,4 @@
# Copyright (c) Microsoft. All rights reserved.
# Import and re-export from the actual implementation
-from agent_framework_lab_lightning import * # noqa: F403, F401
+from agent_framework_lab_tau2 import * # noqa: F403
diff --git a/python/packages/lab/pyproject.toml b/python/packages/lab/pyproject.toml
new file mode 100644
index 0000000000..c023741937
--- /dev/null
+++ b/python/packages/lab/pyproject.toml
@@ -0,0 +1,136 @@
+[project]
+name = "agent-framework-lab"
+description = "Experimental modules for Microsoft Agent Framework"
+authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
+readme = "README.md"
+requires-python = ">=3.10"
+version = "0.1.0b1"
+license-files = ["LICENSE"]
+urls.homepage = "https://learn.microsoft.com/en-us/semantic-kernel/overview/"
+urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
+urls.release_notes = "https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true"
+urls.issues = "https://github.com/microsoft/agent-framework/issues"
+classifiers = [
+ "License :: OSI Approved :: MIT License",
+ "Development Status :: 2 - Pre-Alpha",
+ "Intended Audience :: Developers",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
+ "Programming Language :: Python :: 3.13",
+]
+dependencies = [
+ "agent-framework",
+]
+
+[project.optional-dependencies]
+# GAIA benchmark module dependencies
+gaia = [
+ "pydantic>=2.0.0",
+ "opentelemetry-api>=1.24.0",
+ "tqdm>=4.60.0",
+ "huggingface-hub>=0.20.0",
+ "orjson>=3.8.0",
+]
+
+# Lightning RL training module dependencies
+lightning = [
+ "pydantic>=2.0.0",
+]
+
+# TAU2 benchmark module dependencies
+tau2 = [
+ "pydantic>=2.0.0",
+ "tiktoken>=0.11.0",
+ "loguru>=0.7.3",
+ "numpy",
+ "tau2@ git+https://github.com/sierra-research/tau2-bench@5ba9e3e56db57c5e4114bf7f901291f09b2c5619",
+]
+
+
+[project.scripts]
+gaia_viewer = "agent_framework_lab_gaia:viewer_main"
+lightning = "agent_framework_lab_lightning:main"
+
+[build-system]
+requires = ["setuptools>=64", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[tool.setuptools]
+packages = [
+ "agent_framework_lab_gaia",
+ "agent_framework_lab_lightning",
+ "agent_framework_lab_tau2",
+ "agent_framework.lab.gaia",
+ "agent_framework.lab.lightning",
+ "agent_framework.lab.tau2",
+]
+
+[tool.setuptools.package-dir]
+"agent_framework_lab_gaia" = "gaia/agent_framework_lab_gaia"
+"agent_framework_lab_lightning" = "lightning/agent_framework_lab_lightning"
+"agent_framework_lab_tau2" = "tau2/agent_framework_lab_tau2"
+"agent_framework.lab.gaia" = "namespace/agent_framework/lab/gaia"
+"agent_framework.lab.lightning" = "namespace/agent_framework/lab/lightning"
+"agent_framework.lab.tau2" = "namespace/agent_framework/lab/tau2"
+
+[tool.setuptools.package-data]
+agent_framework_lab_gaia = ["py.typed"]
+agent_framework_lab_lightning = ["py.typed"]
+agent_framework_lab_tau2 = ["py.typed"]
+
+[tool.ruff]
+extend = "../../pyproject.toml"
+
+[tool.ruff.lint]
+ignore = ["T201", "ASYNC230", "INP001"] # Allow print statements, blocking file operations, and implicit namespace packages in lab modules
+
+[tool.coverage.run]
+omit = [
+ "**/__init__.py"
+]
+
+[tool.pyright]
+extend = "../../pyproject.toml"
+exclude = ['gaia/tests', 'lightning/tests', 'tau2/tests', 'namespace', '**/samples']
+
+[tool.mypy]
+plugins = ['pydantic.mypy']
+strict = true
+python_version = "3.10"
+ignore_missing_imports = true
+disallow_untyped_defs = true
+no_implicit_optional = true
+check_untyped_defs = true
+warn_return_any = true
+show_error_codes = true
+warn_unused_ignores = false
+disallow_incomplete_defs = true
+disallow_untyped_decorators = true
+
+[tool.bandit]
+targets = ["agent_framework_lab_gaia", "agent_framework_lab_lightning", "agent_framework_lab_tau2"]
+exclude_dirs = ["gaia/tests", "lightning/tests", "tau2/tests"]
+
+[tool.poe]
+executor.type = "uv"
+include = "../../shared_tasks.toml"
+
+[tool.poe.tasks]
+mypy-gaia = "mypy --config-file $POE_ROOT/pyproject.toml gaia/agent_framework_lab_gaia"
+mypy-lightning = "mypy --config-file $POE_ROOT/pyproject.toml lightning/agent_framework_lab_lightning"
+mypy-tau2 = "mypy --config-file $POE_ROOT/pyproject.toml tau2/agent_framework_lab_tau2"
+mypy = ["mypy-gaia", "mypy-lightning", "mypy-tau2"]
+test = "pytest --cov-report=term-missing:skip-covered --junitxml=test-results.xml"
+test-gaia = "pytest gaia/tests --cov=agent_framework_lab_gaia --cov-report=term-missing:skip-covered"
+test-lightning = "pytest lightning/tests --cov=agent_framework_lab_lightning --cov-report=term-missing:skip-covered"
+test-tau2 = "pytest tau2/tests --cov=agent_framework_lab_tau2 --cov-report=term-missing:skip-covered"
+
+[tool.pytest.ini_options]
+pythonpath = ["."]
+addopts = "--strict-markers --strict-config"
+markers = [
+ "unit: marks tests as unit tests",
+ "integration: marks tests as integration tests",
+]
\ No newline at end of file
diff --git a/python/packages/lab/tau2/LICENSE b/python/packages/lab/tau2/LICENSE
deleted file mode 100644
index 22aed37e65..0000000000
--- a/python/packages/lab/tau2/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) Microsoft Corporation.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/python/packages/lab/tau2/README.md b/python/packages/lab/tau2/README.md
index 0761247dec..22aacc6865 100644
--- a/python/packages/lab/tau2/README.md
+++ b/python/packages/lab/tau2/README.md
@@ -2,7 +2,10 @@
τ²-bench implements a simulation framework for evaluating customer service agents across various domains.
+> **Note**: This module is part of the consolidated `agent-framework-lab` package. Install the package with the `tau2` extra to use this module.
+
The framework orchestrates conversations between two AI agents:
+
- **Customer Service Agent**: Follows domain-specific policies and has access to tools (e.g., booking systems, databases)
- **User Simulator**: Simulates realistic customer behavior with specific goals and scenarios
@@ -20,8 +23,10 @@ Each evaluation runs a multi-turn conversation where the user simulator presents
## Installation
+Install the agent-framework-lab package with TAU2 dependencies:
+
```bash
-pip install agent-framework-lab-tau2
+pip install "agent-framework-lab[tau2]"
```
Download data from [Tau2-Bench](https://github.com/sierra-research/tau2-bench):
@@ -45,7 +50,7 @@ export TAU2_DATA_DIR="data"
```python
import asyncio
from agent_framework.openai import OpenAIChatClient
-from agent_framework_lab_tau2 import TaskRunner
+from agent_framework.lab.tau2 import TaskRunner
from tau2.domains.airline.environment import get_tasks
async def run_single_task():
@@ -126,7 +131,7 @@ export OPENAI_BASE_URL="https://your-custom-endpoint.com/v1"
### Custom Agent Implementation
```python
-from agent_framework_lab_tau2 import TaskRunner
+from agent_framework.lab.tau2 import TaskRunner
from agent_framework import ChatAgent
class CustomTaskRunner(TaskRunner):
@@ -149,8 +154,8 @@ class CustomTaskRunner(TaskRunner):
### Custom Workflow Integration
```python
-from agent_framework._workflow import WorkflowBuilder, AgentExecutor
-from agent_framework_lab_tau2 import TaskRunner
+from agent_framework import WorkflowBuilder, AgentExecutor
+from agent_framework.lab.tau2 import TaskRunner
class WorkflowTaskRunner(TaskRunner):
def build_conversation_workflow(self, assistant_agent, user_simulator_agent):
@@ -172,7 +177,7 @@ class WorkflowTaskRunner(TaskRunner):
### Utility Functions
```python
-from agent_framework_lab_tau2 import patch_env_set_state, unpatch_env_set_state
+from agent_framework.lab.tau2 import patch_env_set_state, unpatch_env_set_state
# Enable compatibility patches for τ²-bench integration
patch_env_set_state()
@@ -187,4 +192,4 @@ This package is part of the Microsoft Agent Framework Lab. Please see the main r
## License
-This project is licensed under the MIT License - see the LICENSE file for details.
\ No newline at end of file
+This project is licensed under the MIT License - see the LICENSE file for details.
diff --git a/python/packages/lab/tau2/agent_framework_lab_tau2/__init__.py b/python/packages/lab/tau2/agent_framework_lab_tau2/__init__.py
index a99b5b1911..1457b58fd1 100644
--- a/python/packages/lab/tau2/agent_framework_lab_tau2/__init__.py
+++ b/python/packages/lab/tau2/agent_framework_lab_tau2/__init__.py
@@ -1,8 +1,6 @@
# Copyright (c) Microsoft. All rights reserved.
-"""
-Tau2 Benchmark for Agent Framework.
-"""
+"""Tau2 Benchmark for Agent Framework."""
import importlib.metadata
diff --git a/python/packages/lab/tau2/agent_framework_lab_tau2/_message_utils.py b/python/packages/lab/tau2/agent_framework_lab_tau2/_message_utils.py
index 999432d691..6356ad038c 100644
--- a/python/packages/lab/tau2/agent_framework_lab_tau2/_message_utils.py
+++ b/python/packages/lab/tau2/agent_framework_lab_tau2/_message_utils.py
@@ -51,7 +51,7 @@ def log_messages(messages: list[ChatMessage]) -> None:
Provides visual debugging by color-coding different message roles and
content types. Escapes HTML-like characters to prevent log formatting issues.
"""
- _logger = logger.opt(colors=True)
+ logger_ = logger.opt(colors=True)
for msg in messages:
# Handle different content types
if hasattr(msg, "contents") and msg.contents:
@@ -60,53 +60,53 @@ def log_messages(messages: list[ChatMessage]) -> None:
if content.type == "text":
escape_text = content.text.replace("<", r"\<")
if msg.role == Role.SYSTEM:
- _logger.info(f"[SYSTEM] {escape_text}")
+ logger_.info(f"[SYSTEM] {escape_text}")
elif msg.role == Role.USER:
- _logger.info(f"[USER] {escape_text}")
+ logger_.info(f"[USER] {escape_text}")
elif msg.role == Role.ASSISTANT:
- _logger.info(f"[ASSISTANT] {escape_text}")
+ logger_.info(f"[ASSISTANT] {escape_text}")
elif msg.role == Role.TOOL:
- _logger.info(f"[TOOL] {escape_text}")
+ logger_.info(f"[TOOL] {escape_text}")
else:
- _logger.info(f"[{msg.role.value.upper()}] {escape_text}")
+ logger_.info(f"[{msg.role.value.upper()}] {escape_text}")
elif content.type == "function_call":
function_call_text = f"{content.name}({content.arguments})"
function_call_text = function_call_text.replace("<", r"\<")
- _logger.info(f"[TOOL_CALL] 🔧 {function_call_text}")
+ logger_.info(f"[TOOL_CALL] 🔧 {function_call_text}")
elif content.type == "function_result":
function_result_text = f"ID:{content.call_id} -> {content.result}"
function_result_text = function_result_text.replace("<", r"\<")
- _logger.info(f"[TOOL_RESULT] 🔨 {function_result_text}")
+ logger_.info(f"[TOOL_RESULT] 🔨 {function_result_text}")
else:
content_text = str(content).replace("<", r"\<")
- _logger.info(f"[{msg.role.value.upper()}] ({content.type}) {content_text}")
+ logger_.info(f"[{msg.role.value.upper()}] ({content.type}) {content_text}")
else:
# Fallback for content without type
text_content = str(content).replace("<", r"\<")
if msg.role == Role.SYSTEM:
- _logger.info(f"[SYSTEM] {text_content}")
+ logger_.info(f"[SYSTEM] {text_content}")
elif msg.role == Role.USER:
- _logger.info(f"[USER] {text_content}")
+ logger_.info(f"[USER] {text_content}")
elif msg.role == Role.ASSISTANT:
- _logger.info(f"[ASSISTANT] {text_content}")
+ logger_.info(f"[ASSISTANT] {text_content}")
elif msg.role == Role.TOOL:
- _logger.info(f"[TOOL] {text_content}")
+ logger_.info(f"[TOOL] {text_content}")
else:
- _logger.info(f"[{msg.role.value.upper()}] {text_content}")
+ logger_.info(f"[{msg.role.value.upper()}] {text_content}")
elif hasattr(msg, "text") and msg.text:
# Handle simple text messages
text_content = msg.text.replace("<", r"\<")
if msg.role == Role.SYSTEM:
- _logger.info(f"[SYSTEM] {text_content}")
+ logger_.info(f"[SYSTEM] {text_content}")
elif msg.role == Role.USER:
- _logger.info(f"[USER] {text_content}")
+ logger_.info(f"[USER] {text_content}")
elif msg.role == Role.ASSISTANT:
- _logger.info(f"[ASSISTANT] {text_content}")
+ logger_.info(f"[ASSISTANT] {text_content}")
elif msg.role == Role.TOOL:
- _logger.info(f"[TOOL] {text_content}")
+ logger_.info(f"[TOOL] {text_content}")
else:
- _logger.info(f"[{msg.role.value.upper()}] {text_content}")
+ logger_.info(f"[{msg.role.value.upper()}] {text_content}")
else:
# Fallback for other message formats
text_content = str(msg).replace("<", r"\<")
- _logger.info(f"[{msg.role.value.upper()}] {text_content}")
+ logger_.info(f"[{msg.role.value.upper()}] {text_content}")
diff --git a/python/packages/lab/tau2/agent_framework_lab_tau2/_sliding_window.py b/python/packages/lab/tau2/agent_framework_lab_tau2/_sliding_window.py
index 4148430251..160c04fe62 100644
--- a/python/packages/lab/tau2/agent_framework_lab_tau2/_sliding_window.py
+++ b/python/packages/lab/tau2/agent_framework_lab_tau2/_sliding_window.py
@@ -58,6 +58,7 @@ class SlidingWindowChatMessageList(ChatMessageList):
def get_token_count(self) -> int:
"""Estimate token count for a list of messages using tiktoken.
+
Args:
messages: List of ChatMessage objects
system_message: Optional system message to include in count
diff --git a/python/packages/lab/tau2/agent_framework_lab_tau2/_tau2_utils.py b/python/packages/lab/tau2/agent_framework_lab_tau2/_tau2_utils.py
index ec50bf77e4..228072aae1 100644
--- a/python/packages/lab/tau2/agent_framework_lab_tau2/_tau2_utils.py
+++ b/python/packages/lab/tau2/agent_framework_lab_tau2/_tau2_utils.py
@@ -35,11 +35,7 @@ def convert_tau2_tool_to_ai_function(tau2_tool: Tool) -> AIFunction[Any, Any]:
def wrapped_func(**kwargs: Any) -> Any:
result = tau2_tool(**kwargs)
# Deep copy to prevent mutations of returned data
- if isinstance(result, BaseModel):
- result = result.model_copy(deep=True)
- else:
- result = deepcopy(result)
- return result
+ return result.model_copy(deep=True) if isinstance(result, BaseModel) else deepcopy(result)
return AIFunction(
name=tau2_tool.name,
@@ -55,7 +51,6 @@ def convert_agent_framework_messages_to_tau2_messages(messages: list[ChatMessage
Handles role mapping, text extraction, function calls, and function results.
Function results are converted to separate ToolMessage instances.
"""
-
tau2_messages = []
for msg in messages:
@@ -126,16 +121,13 @@ def patch_env_set_state() -> None:
initialization_actions: list[EnvFunctionCall] | None,
message_history: list[Message],
) -> None:
- if self.solo_mode:
- if any(isinstance(message, UserMessage) for message in message_history):
- raise ValueError("User messages are not allowed in solo mode")
+ if self.solo_mode and any(isinstance(message, UserMessage) for message in message_history):
+ raise ValueError("User messages are not allowed in solo mode")
def get_actions_from_messages(
messages: list[Message],
) -> list[tuple[ToolCall, ToolMessage]]:
- """
- Get the actions from the messages.
- """
+ """Get the actions from the messages."""
messages = deepcopy(messages)[::-1]
actions = []
while messages:
@@ -194,14 +186,13 @@ def unpatch_env_set_state() -> None:
def _dump_function_result(result: Any) -> Any:
if isinstance(result, BaseModel):
return result.model_dump_json()
- elif isinstance(result, list):
+ if isinstance(result, list):
return [_dump_function_result(item) for item in result]
- elif isinstance(result, dict):
+ if isinstance(result, dict):
return {k: _dump_function_result(v) for k, v in result.items()}
- elif result is None:
+ if result is None:
return None
- else:
- return result
+ return result
def _to_native(obj: Any) -> Any:
@@ -227,9 +218,7 @@ def _to_native(obj: Any) -> Any:
def _recursive_json_deserialize(obj: Any) -> Any:
- """
- Recursively deserialize a JSON object.
- """
+ """Recursively deserialize a JSON object."""
if isinstance(obj, str):
try:
deserialized = json.loads(obj)
diff --git a/python/packages/lab/tau2/agent_framework_lab_tau2/runner.py b/python/packages/lab/tau2/agent_framework_lab_tau2/runner.py
index d6709530ca..4234698b6f 100644
--- a/python/packages/lab/tau2/agent_framework_lab_tau2/runner.py
+++ b/python/packages/lab/tau2/agent_framework_lab_tau2/runner.py
@@ -100,6 +100,7 @@ class TaskRunner:
return self
def __repr__(self) -> str:
+ """Return string representation of TaskRunner."""
return (
f"TaskRunner(max_steps={self.max_steps}, step_count={self.step_count}, "
f"full_conversation_length={len(self.full_conversation)}, "
@@ -108,7 +109,6 @@ class TaskRunner:
def should_not_stop(self, response: AgentExecutorResponse) -> bool:
"""Based on the response, check whether we should or not stop the conversation."""
-
# Determine who sent this based on executor_id
is_from_agent = response.executor_id == ASSISTANT_AGENT_ID
is_from_user = response.executor_id == USER_SIMULATOR_ID
@@ -165,7 +165,6 @@ class TaskRunner:
Returns:
The assistant agent.
"""
-
# Initialize tau2 environment and extract tools/policy
# This provides the domain-specific context (airline customer service in this case)
env = get_environment()
@@ -216,7 +215,6 @@ class TaskRunner:
Returns:
The user simulator agent.
"""
-
# User simulator follows tau2's guidelines for realistic customer behavior
# No tools available - users typically don't have direct system access
user_sim_guidelines = get_global_user_sim_guidelines(use_tools=False)
@@ -277,7 +275,6 @@ class TaskRunner:
Returns:
The conversation workflow.
"""
-
# STEP 1: Create workflow executors
# Each executor wraps an agent or function for workflow orchestration
self._assistant_executor = AgentExecutor(assistant_agent, id=ASSISTANT_AGENT_ID)
@@ -287,7 +284,7 @@ class TaskRunner:
# STEP 2: Build the conversation workflow
# Creates a cyclic workflow: Orchestrator -> Assistant -> Orchestrator -> User -> Orchestrator...
# The orchestrator acts as a message router that flips roles and routes to appropriate agent
- workflow = (
+ return (
WorkflowBuilder(max_iterations=10000) # Unlimited - we control termination via should_not_stop
.set_start_executor(orchestrator) # Orchestrator manages the conversation flow
.add_edge(orchestrator, self._assistant_executor) # Route messages to assistant
@@ -299,8 +296,6 @@ class TaskRunner:
.build()
)
- return workflow
-
async def run(
self,
task: Task,
@@ -325,7 +320,6 @@ class TaskRunner:
Returns:
Complete conversation history as ChatMessage list for evaluation
"""
-
logger.info(f"Starting workflow agent for task {task.id}: {task.description.purpose}") # type: ignore[unused-ignore]
logger.info(f"Assistant chat client: {assistant_chat_client}")
logger.info(f"User simulator chat client: {user_simuator_chat_client}")
@@ -390,7 +384,6 @@ class TaskRunner:
Side Effects:
Stores detailed evaluation results in self.full_reward_info
"""
-
# Handle missing termination reason (can happen with unexpected workflow endings)
if termination_reason is None:
termination_reason = TerminationReason.TOO_MANY_ERRORS
diff --git a/python/packages/lab/tau2/namespace/agent_framework/__init__.py b/python/packages/lab/tau2/namespace/agent_framework/__init__.py
deleted file mode 100644
index 1d3db512a4..0000000000
--- a/python/packages/lab/tau2/namespace/agent_framework/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-# This makes agent_framework a namespace package
-__path__ = __import__("pkgutil").extend_path(__path__, __name__)
diff --git a/python/packages/lab/tau2/namespace/agent_framework/lab/__init__.py b/python/packages/lab/tau2/namespace/agent_framework/lab/__init__.py
deleted file mode 100644
index 0d8d8fbaa4..0000000000
--- a/python/packages/lab/tau2/namespace/agent_framework/lab/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
-
-# This makes agent_framework.lab a namespace package
-__path__ = __import__("pkgutil").extend_path(__path__, __name__)
diff --git a/python/packages/lab/tau2/pyproject.toml b/python/packages/lab/tau2/pyproject.toml
deleted file mode 100644
index 3610304cd8..0000000000
--- a/python/packages/lab/tau2/pyproject.toml
+++ /dev/null
@@ -1,99 +0,0 @@
-[project]
-name = "agent-framework-lab-tau2"
-description = "Tau2 Benchmark for Agent Framework."
-authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
-readme = "README.md"
-requires-python = ">=3.10"
-version = "0.1.0b1"
-license-files = ["LICENSE"]
-urls.homepage = "https://learn.microsoft.com/en-us/semantic-kernel/overview/"
-urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
-urls.release_notes = "https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true"
-urls.issues = "https://github.com/microsoft/agent-framework/issues"
-classifiers = [
- "License :: OSI Approved :: MIT License",
- "Development Status :: 2 - Pre-Alpha",
- "Intended Audience :: Developers",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
- "Programming Language :: Python :: 3.13",
-]
-dependencies = [
- "agent-framework",
- "pydantic>=2.0.0",
- "tiktoken>=0.11.0",
- "loguru>=0.7.3",
- "tau2@git+https://github.com/sierra-research/tau2-bench@5ba9e3e56db57c5e4114bf7f901291f09b2c5619",
-]
-
-[build-system]
-requires = ["setuptools>=64", "wheel"]
-build-backend = "setuptools.build_meta"
-
-[tool.setuptools]
-packages = ["agent_framework_lab_tau2", "agent_framework.lab.tau2"]
-
-[tool.setuptools.package-dir]
-"agent_framework.lab.tau2" = "namespace/agent_framework/lab/tau2"
-"agent_framework_lab_tau2" = "agent_framework_lab_tau2"
-
-[tool.setuptools.package-data]
-agent_framework_lab_tau2 = ["py.typed"]
-
-[tool.ruff]
-line-length = 120
-target-version = "py310"
-extend-exclude = ["tests", "__pycache__"]
-
-[tool.ruff.lint]
-select = ["E", "F", "I", "W", "UP", "C4", "N"]
-ignore = ["N803", "N806", "N999", "UP007"]
-
-[tool.ruff.format]
-quote-style = "double"
-
-[tool.mypy]
-python_version = "3.10"
-strict = true
-check_untyped_defs = true
-disallow_untyped_defs = true
-disallow_incomplete_defs = true
-disallow_untyped_decorators = true
-warn_redundant_casts = true
-warn_unused_ignores = true
-warn_return_any = true
-warn_unreachable = true
-show_error_codes = true
-implicit_reexport = true
-packages = ["agent_framework_lab_tau2"]
-exclude = [
- "data",
-]
-
-[tool.pyright]
-exclude = ["**/data"]
-
-
-[tool.poe]
-executor.type = "uv"
-include = "../../../shared_tasks.toml"
-
-[tool.poe.tasks]
-test = "pytest --cov=agent_framework_lab_tau2 --cov-report=term-missing:skip-covered tests"
-mypy = "mypy agent_framework_lab_tau2"
-setup-data = "python tests/setup_data.py"
-purge-data = "python tests/purge_data.py"
-
-[tool.pytest.ini_options]
-testpaths = ["tests"]
-pythonpath = ["."]
-addopts = "--strict-markers --strict-config"
-markers = [
- "unit: marks tests as unit tests",
- "integration: marks tests as integration tests",
-]
-env = [
- "TAU2_DATA_DIR=data",
-]
diff --git a/python/packages/lab/tau2/samples/run_benchmark.py b/python/packages/lab/tau2/samples/run_benchmark.py
index 6462ad65e1..53ced32af4 100644
--- a/python/packages/lab/tau2/samples/run_benchmark.py
+++ b/python/packages/lab/tau2/samples/run_benchmark.py
@@ -8,12 +8,11 @@ import traceback
from datetime import datetime
from typing import Any
+from agent_framework.lab.tau2 import TaskRunner, patch_env_set_state
from agent_framework.openai import OpenAIChatClient
from loguru import logger
from tau2.domains.airline.environment import get_tasks
-from agent_framework_lab_tau2 import TaskRunner, patch_env_set_state
-
def to_dumpable(result: dict[str, Any]) -> dict[str, Any]:
"""Convert benchmark result to JSONL-serializable format.
@@ -33,16 +32,15 @@ def to_dumpable(result: dict[str, Any]) -> dict[str, Any]:
"config": result["config"],
"task": result["task"].model_dump(),
}
- else:
- # Success case: full result structure
- return {
- "id": result["task"].id,
- "evaluation": result["evaluation"].model_dump(), # Detailed evaluation metrics
- "config": result["config"], # Model configuration used
- "termination_reason": result["termination_reason"].value, # Enum to string
- "messages": [m.model_dump() for m in result["messages"]], # Full conversation
- "task": result["task"].model_dump(), # Task specification
- }
+ # Success case: full result structure
+ return {
+ "id": result["task"].id,
+ "evaluation": result["evaluation"].model_dump(), # Detailed evaluation metrics
+ "config": result["config"], # Model configuration used
+ "termination_reason": result["termination_reason"].value, # Enum to string
+ "messages": [m.model_dump() for m in result["messages"]], # Full conversation
+ "task": result["task"].model_dump(), # Task specification
+ }
async def run_benchmark(assistant_model: str, user_model: str, debug_task_id: str | None, max_steps: int):
@@ -66,15 +64,13 @@ async def run_benchmark(assistant_model: str, user_model: str, debug_task_id: st
Creates timestamped JSONL file with detailed results for analysis
Prints summary statistics to console with colored logging
"""
-
# STEP 1: Configure output handling based on execution mode
- result_fp = None
+ result_filename = None
if debug_task_id is None:
# Full benchmark mode: create timestamped results file
timestamp = datetime.now().strftime("%m%d%H%M") # Format: MMDDHHMM
result_filename = f"results/{assistant_model}_user-{user_model}_{timestamp}.jsonl"
os.makedirs("results", exist_ok=True)
- result_fp = open(result_filename, "a") # Append mode for resumability
logger.info(f"Results will be saved to: {result_filename}")
else:
# Debug mode: single task, no file output, verbose logging
@@ -84,7 +80,7 @@ async def run_benchmark(assistant_model: str, user_model: str, debug_task_id: st
tasks = get_tasks() # Loads all tau2 airline customer service tasks
logger.info(f"Found {len(tasks)} tasks in the dataset")
- _logger = logger.opt(colors=True) # Enable colored console output
+ logger_ = logger.opt(colors=True) # Enable colored console output
# Validate required OpenAI configuration
# Both models use the same endpoint but can be different model types
@@ -121,67 +117,110 @@ async def run_benchmark(assistant_model: str, user_model: str, debug_task_id: st
all_rewards: list[float] = [] # Stores reward scores for final statistics
task_runner = TaskRunner(max_steps=max_steps) # Reusable workflow orchestrator
- # STEP 6: Execute benchmark across all tasks
- for task in tasks:
- _logger.info(f"Testing task #{task.id}")
- _logger.info(f"Purpose: {task.description.purpose}") # type: ignore
-
- # Initialize result structure for this task
- result: dict[str, Any] = {
- "config": {
- "assistant": assistant_chat_client.ai_model_id,
- "user": user_simulator_chat_client.ai_model_id,
- },
- "task": task,
- }
-
- # Log user scenario context for transparency
- if task.user_scenario and task.user_scenario.instructions:
- _logger.info(f"User scenario: {task.user_scenario.instructions.reason_for_call}") # type: ignore
-
- try:
- # Execute the workflow: agent + user simulator conversation
- conversation = await task_runner.run(task, assistant_chat_client, user_simulator_chat_client)
-
- # Evaluate performance using tau2's comprehensive metrics
- reward_value = task_runner.evaluate(task, conversation, task_runner.termination_reason)
-
- # Store detailed results for analysis
- result["evaluation"] = task_runner.full_reward_info # Full evaluation breakdown
- result["messages"] = conversation # Complete conversation history
- result["termination_reason"] = task_runner.termination_reason # How conversation ended
-
- # Log evaluation results (escape HTML for colored output)
- reward_str = str(task_runner.full_reward_info).replace("<", r"\<")
- _logger.info(f"Final evaluation: {reward_str}")
-
- except Exception as e:
- # Robust error handling: capture all failures for analysis
- _logger.error(f"Error testing task #{task.id}: {e}")
- result["error"] = traceback.format_exc() # Full stack trace for debugging
-
- traceback.print_exc() # Console output for immediate debugging
- reward_value = 0.0 # Zero score for failed runs
-
- # STEP 7: Persist results incrementally (enables partial analysis)
+ # STEP 6: Execute benchmark across all tasks with proper file handling
+ def write_result(result_fp, result):
+ """Write result to file if file pointer is provided."""
if result_fp is not None:
result_fp.write(json.dumps(to_dumpable(result), default=str) + "\n")
- all_rewards.append(reward_value) # Track for final statistics
+ # Use context manager for file handling
+ if result_filename:
+ with open(result_filename, "a") as result_fp:
+ for task in tasks:
+ logger_.info(f"Testing task #{task.id}")
+ logger_.info(f"Purpose: {task.description.purpose}") # type: ignore
- # Reset runner state for next task
- task_runner.reinit()
+ # Initialize result structure for this task
+ result: dict[str, Any] = {
+ "config": {
+ "assistant": assistant_chat_client.ai_model_id,
+ "user": user_simulator_chat_client.ai_model_id,
+ },
+ "task": task,
+ }
- # STEP 8: Finalize and report aggregate results
- if result_fp is not None:
- result_fp.close()
+ # Log user scenario context for transparency
+ if task.user_scenario and task.user_scenario.instructions:
+ logger_.info(f"User scenario: {task.user_scenario.instructions.reason_for_call}") # type: ignore
- # Calculate overall benchmark performance
+ try:
+ # Execute the workflow: agent + user simulator conversation
+ conversation = await task_runner.run(task, assistant_chat_client, user_simulator_chat_client)
+
+ # Evaluate performance using tau2's comprehensive metrics
+ reward_value = task_runner.evaluate(task, conversation, task_runner.termination_reason)
+
+ # Store detailed results for analysis
+ result["evaluation"] = task_runner.full_reward_info # Full evaluation breakdown
+ result["messages"] = conversation # Complete conversation history
+ result["termination_reason"] = task_runner.termination_reason # How conversation ended
+
+ # Log evaluation results (escape HTML for colored output)
+ reward_str = str(task_runner.full_reward_info).replace("<", r"\<")
+ logger_.info(f"Final evaluation: {reward_str}")
+
+ except Exception as e:
+ # Robust error handling: capture all failures for analysis
+ logger_.error(f"Error testing task #{task.id}: {e}")
+ result["error"] = traceback.format_exc() # Full stack trace for debugging
+
+ traceback.print_exc() # Console output for immediate debugging
+ reward_value = 0.0 # Zero score for failed runs
+
+ # STEP 7: Persist results incrementally (enables partial analysis)
+ write_result(result_fp, result)
+
+ all_rewards.append(reward_value) # Track for final statistics
+
+ # Reset runner state for next task
+ task_runner.reinit()
+ else:
+ # Debug mode without file output
+ for task in tasks:
+ logger_.info(f"Testing task #{task.id}")
+ logger_.info(f"Purpose: {task.description.purpose}") # type: ignore
+
+ # Initialize result structure for this task
+ result: dict[str, Any] = {
+ "config": {
+ "assistant": assistant_chat_client.ai_model_id,
+ "user": user_simulator_chat_client.ai_model_id,
+ },
+ "task": task,
+ }
+
+ # Log user scenario context for transparency
+ if task.user_scenario and task.user_scenario.instructions:
+ logger_.info(f"User scenario: {task.user_scenario.instructions.reason_for_call}") # type: ignore
+
+ try:
+ # Execute the workflow: agent + user simulator conversation
+ conversation = await task_runner.run(task, assistant_chat_client, user_simulator_chat_client)
+
+ # Evaluate performance using tau2's comprehensive metrics
+ reward_value = task_runner.evaluate(task, conversation, task_runner.termination_reason)
+
+ # Log evaluation results (escape HTML for colored output)
+ reward_str = str(task_runner.full_reward_info).replace("<", r"\<")
+ logger_.info(f"Final evaluation: {reward_str}")
+
+ except Exception as e:
+ # Robust error handling: capture all failures for analysis
+ logger_.error(f"Error testing task #{task.id}: {e}")
+ traceback.print_exc() # Console output for immediate debugging
+ reward_value = 0.0 # Zero score for failed runs
+
+ all_rewards.append(reward_value) # Track for final statistics
+
+ # Reset runner state for next task
+ task_runner.reinit()
+
+ # STEP 8: Calculate overall benchmark performance and report final statistics
all_accuracy = sum(all_rewards) / len(all_rewards) if all_rewards else 0.0
# Report final statistics with colored formatting
- _logger.info("Final Results:")
- _logger.info(f"All tasks accuracy: {all_accuracy:.2f} ({int(sum(all_rewards))}/{len(tasks)})")
+ logger_.info("Final Results:")
+ logger_.info(f"All tasks accuracy: {all_accuracy:.2f} ({int(sum(all_rewards))}/{len(tasks)})")
if __name__ == "__main__":
diff --git a/python/packages/lab/tau2/tests/__init__.py b/python/packages/lab/tau2/tests/__init__.py
deleted file mode 100644
index 2a50eae894..0000000000
--- a/python/packages/lab/tau2/tests/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# Copyright (c) Microsoft. All rights reserved.
diff --git a/python/packages/lab/tau2/tests/test_message_utils.py b/python/packages/lab/tau2/tests/test_message_utils.py
index d86d16085d..547d20ff26 100644
--- a/python/packages/lab/tau2/tests/test_message_utils.py
+++ b/python/packages/lab/tau2/tests/test_message_utils.py
@@ -2,7 +2,7 @@
from unittest.mock import patch
-from agent_framework._types import ChatMessage, Role, TextContent, FunctionCallContent, FunctionResultContent
+from agent_framework._types import ChatMessage, FunctionCallContent, FunctionResultContent, Role, TextContent
from agent_framework_lab_tau2._message_utils import flip_messages, log_messages
@@ -120,7 +120,8 @@ def test_flip_messages_mixed_conversation():
flipped = flip_messages(messages)
- # Should have: system (unchanged), assistant (from user), user (from assistant, filtered), assistant (from final assistant)
+ # Should have: system (unchanged), assistant (from user), user (from assistant, filtered),
+ # assistant (from final assistant)
assert len(flipped) == 4
# Check each flipped message
diff --git a/python/packages/lab/tau2/tests/test_sliding_window.py b/python/packages/lab/tau2/tests/test_sliding_window.py
index 4ab5d9c04a..6939cd7017 100644
--- a/python/packages/lab/tau2/tests/test_sliding_window.py
+++ b/python/packages/lab/tau2/tests/test_sliding_window.py
@@ -2,10 +2,10 @@
"""Tests for sliding window message list."""
-import pytest
from unittest.mock import patch
-from agent_framework._types import ChatMessage, Role, TextContent, FunctionCallContent, FunctionResultContent
+import pytest
+from agent_framework._types import ChatMessage, FunctionCallContent, FunctionResultContent, Role, TextContent
from agent_framework_lab_tau2._sliding_window import SlidingWindowChatMessageList
@@ -225,7 +225,8 @@ def test_estimate_any_object_token_count_non_serializable():
async def test_real_world_scenario():
"""Test a realistic conversation scenario."""
sliding_window = SlidingWindowChatMessageList(
- max_tokens=30, system_message="You are a helpful assistant" # Moderate limit
+ max_tokens=30,
+ system_message="You are a helpful assistant", # Moderate limit
)
# Simulate a conversation
@@ -239,7 +240,8 @@ async def test_real_world_scenario():
role=Role.ASSISTANT,
contents=[
TextContent(
- text="I'd be happy to help with weather information, but I don't have access to current weather data."
+ text="I'd be happy to help with weather information, "
+ "but I don't have access to current weather data."
)
],
),
diff --git a/python/packages/lab/tau2/tests/test_tau2_utils.py b/python/packages/lab/tau2/tests/test_tau2_utils.py
index b942baba22..e0c856d5a2 100644
--- a/python/packages/lab/tau2/tests/test_tau2_utils.py
+++ b/python/packages/lab/tau2/tests/test_tau2_utils.py
@@ -2,19 +2,30 @@
"""Tests for tau2 utils module."""
-from typing import Any, cast
-from pydantic import BaseModel
-
+import pytest
from agent_framework._tools import AIFunction
-from agent_framework._types import ChatMessage, Role, TextContent, FunctionCallContent, FunctionResultContent
+from agent_framework._types import ChatMessage, FunctionCallContent, FunctionResultContent, Role, TextContent
from agent_framework_lab_tau2._tau2_utils import (
- convert_tau2_tool_to_ai_function,
convert_agent_framework_messages_to_tau2_messages,
+ convert_tau2_tool_to_ai_function,
)
-from tau2.data_model.message import SystemMessage, UserMessage, AssistantMessage, ToolMessage, ToolCall
-from tau2.domains.airline.environment import get_environment
+from tau2.data_model.message import AssistantMessage, SystemMessage, ToolCall, ToolMessage, UserMessage
+
+# Try to import get_environment and handle missing data files
+try:
+ from tau2.domains.airline.environment import get_environment
+
+ # Try to initialize the environment to check if data files are available
+ try:
+ get_environment()
+ TAU2_DATA_AVAILABLE = True
+ except FileNotFoundError:
+ TAU2_DATA_AVAILABLE = False
+except ImportError:
+ TAU2_DATA_AVAILABLE = False
+@pytest.mark.skipif(not TAU2_DATA_AVAILABLE, reason="tau2 data files not available")
def test_convert_tau2_tool_to_ai_function_basic():
"""Test basic conversion from tau2 tool to AIFunction."""
# Get real tools from tau2 environment
@@ -38,6 +49,7 @@ def test_convert_tau2_tool_to_ai_function_basic():
assert callable(ai_function.func)
+@pytest.mark.skipif(not TAU2_DATA_AVAILABLE, reason="tau2 data files not available")
def test_convert_tau2_tool_to_ai_function_multiple_tools():
"""Test conversion with multiple tau2 tools."""
# Get real tools from tau2 environment
@@ -48,7 +60,7 @@ def test_convert_tau2_tool_to_ai_function_multiple_tools():
ai_functions = [convert_tau2_tool_to_ai_function(tool) for tool in tools[:3]] # Test first 3 tools
# Verify all conversions
- for ai_function, tau2_tool in zip(ai_functions, tools[:3]):
+ for ai_function, tau2_tool in zip(ai_functions, tools[:3], strict=False):
assert isinstance(ai_function, AIFunction)
assert ai_function.name == tau2_tool.name
assert ai_function.description == tau2_tool._get_description()
diff --git a/python/pyproject.toml b/python/pyproject.toml
index 6837629887..ec96cfb1d9 100644
--- a/python/pyproject.toml
+++ b/python/pyproject.toml
@@ -10,7 +10,7 @@ dependencies = [
"agent-framework-mem0",
"agent-framework-redis",
"agent-framework-devui",
- "agent-framework-lab-gaia",
+ "agent-framework-lab",
]
[dependency-groups]
@@ -49,14 +49,14 @@ environments = [
]
[tool.uv.workspace]
-members = [ "packages/*", "packages/lab/*" ]
-exclude = [ "packages/agent_framework_project.egg-info", "packages/lab", "packages/lab/cookiecutter-agent-framework-lab", "packages/lab/README.md" ]
+members = [ "packages/*" ]
+exclude = [ "packages/agent_framework_project.egg-info" ]
[tool.uv.sources]
agent-framework = { workspace = true }
agent-framework-azure-ai = { workspace = true }
agent-framework-copilotstudio = { workspace = true }
-agent-framework-lab-gaia = { workspace = true }
+agent-framework-lab = { workspace = true }
agent-framework-mem0 = { workspace = true }
agent-framework-redis = { workspace = true }
agent-framework-runtime = { workspace = true }
diff --git a/python/uv.lock b/python/uv.lock
index 39630cf91a..eee1d3aa8f 100644
--- a/python/uv.lock
+++ b/python/uv.lock
@@ -27,9 +27,7 @@ members = [
"agent-framework-azure-ai",
"agent-framework-copilotstudio",
"agent-framework-devui",
- "agent-framework-lab-gaia",
- "agent-framework-lab-lightning",
- "agent-framework-lab-tau2",
+ "agent-framework-lab",
"agent-framework-mem0",
"agent-framework-project",
"agent-framework-redis",
@@ -206,50 +204,28 @@ requires-dist = [
provides-extras = ["dev", "all"]
[[package]]
-name = "agent-framework-lab-gaia"
+name = "agent-framework-lab"
version = "0.1.0b1"
-source = { editable = "packages/lab/gaia" }
+source = { editable = "packages/lab" }
dependencies = [
{ name = "agent-framework", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
+]
+
+[package.optional-dependencies]
+gaia = [
{ name = "huggingface-hub", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "opentelemetry-api", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "orjson", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "pydantic", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "tqdm", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
]
-
-[package.metadata]
-requires-dist = [
- { name = "agent-framework", editable = "packages/main" },
- { name = "huggingface-hub", specifier = ">=0.20.0" },
- { name = "opentelemetry-api", specifier = ">=1.24.0" },
- { name = "orjson", specifier = ">=3.8.0" },
- { name = "pydantic", specifier = ">=2.0.0" },
- { name = "tqdm", specifier = ">=4.60.0" },
-]
-
-[[package]]
-name = "agent-framework-lab-lightning"
-version = "0.1.0b1"
-source = { editable = "packages/lab/lightning" }
-dependencies = [
- { name = "agent-framework", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
+lightning = [
{ name = "pydantic", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
]
-
-[package.metadata]
-requires-dist = [
- { name = "agent-framework", editable = "packages/main" },
- { name = "pydantic", specifier = ">=2.0.0" },
-]
-
-[[package]]
-name = "agent-framework-lab-tau2"
-version = "0.1.0b1"
-source = { editable = "packages/lab/tau2" }
-dependencies = [
- { name = "agent-framework", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
+tau2 = [
{ name = "loguru", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and sys_platform == 'darwin') or (python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" },
+ { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and sys_platform == 'darwin') or (python_full_version >= '3.11' and sys_platform == 'linux') or (python_full_version >= '3.11' and sys_platform == 'win32')" },
{ name = "pydantic", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "tau2", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "tiktoken", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -258,11 +234,19 @@ dependencies = [
[package.metadata]
requires-dist = [
{ name = "agent-framework", editable = "packages/main" },
- { name = "loguru", specifier = ">=0.7.3" },
- { name = "pydantic", specifier = ">=2.0.0" },
- { name = "tau2", git = "https://github.com/sierra-research/tau2-bench?rev=5ba9e3e56db57c5e4114bf7f901291f09b2c5619" },
- { name = "tiktoken", specifier = ">=0.11.0" },
+ { name = "huggingface-hub", marker = "extra == 'gaia'", specifier = ">=0.20.0" },
+ { name = "loguru", marker = "extra == 'tau2'", specifier = ">=0.7.3" },
+ { name = "numpy", marker = "extra == 'tau2'" },
+ { name = "opentelemetry-api", marker = "extra == 'gaia'", specifier = ">=1.24.0" },
+ { name = "orjson", marker = "extra == 'gaia'", specifier = ">=3.8.0" },
+ { name = "pydantic", marker = "extra == 'gaia'", specifier = ">=2.0.0" },
+ { name = "pydantic", marker = "extra == 'lightning'", specifier = ">=2.0.0" },
+ { name = "pydantic", marker = "extra == 'tau2'", specifier = ">=2.0.0" },
+ { name = "tau2", marker = "extra == 'tau2'", git = "https://github.com/sierra-research/tau2-bench?rev=5ba9e3e56db57c5e4114bf7f901291f09b2c5619" },
+ { name = "tiktoken", marker = "extra == 'tau2'", specifier = ">=0.11.0" },
+ { name = "tqdm", marker = "extra == 'gaia'", specifier = ">=4.60.0" },
]
+provides-extras = ["gaia", "lightning", "tau2"]
[[package]]
name = "agent-framework-mem0"
@@ -288,7 +272,7 @@ dependencies = [
{ name = "agent-framework-azure-ai", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "agent-framework-copilotstudio", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "agent-framework-devui", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
- { name = "agent-framework-lab-gaia", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
+ { name = "agent-framework-lab", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "agent-framework-mem0", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "agent-framework-redis", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
]
@@ -323,7 +307,7 @@ requires-dist = [
{ name = "agent-framework-azure-ai", editable = "packages/azure-ai" },
{ name = "agent-framework-copilotstudio", editable = "packages/copilotstudio" },
{ name = "agent-framework-devui", editable = "packages/devui" },
- { name = "agent-framework-lab-gaia", editable = "packages/lab/gaia" },
+ { name = "agent-framework-lab", editable = "packages/lab" },
{ name = "agent-framework-mem0", editable = "packages/mem0" },
{ name = "agent-framework-redis", editable = "packages/redis" },
]
@@ -1338,7 +1322,7 @@ name = "exceptiongroup"
version = "1.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "typing-extensions", marker = "(python_full_version < '3.13' and sys_platform == 'darwin') or (python_full_version < '3.13' and sys_platform == 'linux') or (python_full_version < '3.13' and sys_platform == 'win32')" },
+ { name = "typing-extensions", marker = "(python_full_version < '3.11' and sys_platform == 'darwin') or (python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" }
wheels = [
@@ -1370,53 +1354,54 @@ wheels = [
[[package]]
name = "fastuuid"
-version = "0.13.3"
+version = "0.13.5"
source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/15/80/3c16a1edad2e6cd82fbd15ac998cc1b881f478bf1f80ca717d941c441874/fastuuid-0.13.5.tar.gz", hash = "sha256:d4976821ab424d41542e1ea39bc828a9d454c3f8a04067c06fca123c5b95a1a1", size = 18255, upload-time = "2025-09-26T09:05:38.281Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/87/85/08371c62cd86a4826f4bf90b885784475b232ac2512d45f0193592fbae46/fastuuid-0.13.3-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a445d61106c0bbca80630d00de3d17025da6542da7f95adfa90fd5ac7641d1f8", size = 494073, upload-time = "2025-09-25T17:13:53.822Z" },
- { url = "https://files.pythonhosted.org/packages/e1/b0/0be84b80bd1e9febf4cd06358b46ce536ffc3e426ba2a4d7da04d6b66ca2/fastuuid-0.13.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3ce1a5f3cfec829f326dd9278d90448e62fa531802349f64fe159ab17cedda1d", size = 252783, upload-time = "2025-09-25T17:12:30.108Z" },
- { url = "https://files.pythonhosted.org/packages/22/b1/f6ce4cf41effb67696c91e0e30aa7e3ef81a4f15ece23875ace121eabe9d/fastuuid-0.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2cec2d49df6c2f5ae4adc680dd674664d788d8d48247fb23118ef8775e020ed3", size = 244261, upload-time = "2025-09-25T17:13:13.445Z" },
- { url = "https://files.pythonhosted.org/packages/83/f7/f2617df3e48d3c5eabb1ee335169831d008790bae0e41bc44075a2c141c2/fastuuid-0.13.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a36eef2b7f63521b073475a1b84672b539204090b0f85ffce52a7fce648aad7", size = 271651, upload-time = "2025-09-25T17:13:49.759Z" },
- { url = "https://files.pythonhosted.org/packages/b4/cf/902cc47c8088830b37a2075898a71b94ddfd77735727e08693053cd3bfa2/fastuuid-0.13.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b27970d859e2f2bf04d17d505c3337dfe8e74b94ddf75b742a4e4ab8dbc5a0f", size = 272301, upload-time = "2025-09-25T17:10:47.738Z" },
- { url = "https://files.pythonhosted.org/packages/98/32/f5d7bc98baa2e5011301e86a481a392812b6b48724ca549a6479a30e79e7/fastuuid-0.13.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4e6ebe585f1fca4d2dd62e7fb6eaba9a657a554b5cde682213d93ba657478922", size = 291024, upload-time = "2025-09-25T17:11:08.746Z" },
- { url = "https://files.pythonhosted.org/packages/6b/bc/44973d159d70d38bf80e6506365dc7bc897ade431035b7162eeb04ffa79b/fastuuid-0.13.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:415696c6a268967a66e4dd0ef8db490b126f79001cde05dd87a62613e5ebc72b", size = 453067, upload-time = "2025-09-25T17:10:39.656Z" },
- { url = "https://files.pythonhosted.org/packages/db/66/7e561dc8ee1b1b76f360512bee3ed652d5c6fb0e5a662ebb4d66edc8988c/fastuuid-0.13.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:133a633bfa040f1b35b0d2470dc07c87d7e992857414fe455395040c5bd1d46f", size = 468462, upload-time = "2025-09-25T17:12:22.629Z" },
- { url = "https://files.pythonhosted.org/packages/2a/08/f5d63e07f53c612c78b39159928c7e8f2e616969f4e4f921b7c72eeb41b7/fastuuid-0.13.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6013aec0a317ccc299b826fa7c4a26938f1c663148d479f1adba546a62cdc320", size = 444980, upload-time = "2025-09-25T17:10:49.865Z" },
- { url = "https://files.pythonhosted.org/packages/e5/e2/31adfe18e9f889d81415aea428174bcea9da1addf565cddc094f30ccdfbd/fastuuid-0.13.3-cp310-cp310-win32.whl", hash = "sha256:4b09c5684904e222a6f15006862999e2a94a6e5c754e60f5dccf316aa758cbdf", size = 144941, upload-time = "2025-09-25T17:12:15.184Z" },
- { url = "https://files.pythonhosted.org/packages/7a/9a/9bc7ee4833031dd0a483fee85c5a3d0361986acb03c5d17f9ff0815c0da9/fastuuid-0.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:87377b41895ab467dfa78cc0044af21ee2f7f956e0697cfddd79edf2b06d21c4", size = 150708, upload-time = "2025-09-25T17:12:36.003Z" },
- { url = "https://files.pythonhosted.org/packages/c6/52/4fbba2812dd3601886dc7e3deb922b7c46807b9a820517bc5f459431e745/fastuuid-0.13.3-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:9a9f50d397d59467448eac8949d2be500634f77b1b96f3cc07f7d1084e82e794", size = 493949, upload-time = "2025-09-25T17:15:08.369Z" },
- { url = "https://files.pythonhosted.org/packages/5d/46/e96705e86273ce9d0e45557ca2ab21190b86b01ff4ed3fdd5c6b97058c2f/fastuuid-0.13.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6de517642c15c67daf36bc20d0b48d9ef1495e6035a9e78ec83ea1ff603353c1", size = 252638, upload-time = "2025-09-25T17:17:14.938Z" },
- { url = "https://files.pythonhosted.org/packages/c5/6e/d473a7e44908addb5abbaa65161a0e43c7f0ca1ebec5ff5dcfc0096a0c14/fastuuid-0.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8dfc15c727ddbd170e7a11faa3668ca4cb5a61980c50cc2d7e6f49a2a61036bf", size = 244266, upload-time = "2025-09-25T17:12:05.832Z" },
- { url = "https://files.pythonhosted.org/packages/2f/fb/64396531447deca86989a5231013e8deed5449df57bd178140a6f390adfc/fastuuid-0.13.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a6469267b7944d73581db1781385879d23457b706db4cdd13b90516bab906b2", size = 271490, upload-time = "2025-09-25T17:12:35.724Z" },
- { url = "https://files.pythonhosted.org/packages/09/1b/e3cdc12e7ba53827c4a9900ed6d55146687824b13d4977399de8bc1d37e2/fastuuid-0.13.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9d22455bbd32de6f538e7d589e9ee2e85632dea474f3f4ece0af4142dbb8ef5", size = 272151, upload-time = "2025-09-25T17:13:37.296Z" },
- { url = "https://files.pythonhosted.org/packages/04/b2/0916a6f3651c7d4601114b2095d71ece51ae69dd71943d596957f4e84dc3/fastuuid-0.13.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7a87bca69ea721d87af5d3877553a8ea1da54ecc3a906d7fac2991e8781d80ae", size = 290967, upload-time = "2025-09-25T17:11:07.344Z" },
- { url = "https://files.pythonhosted.org/packages/39/68/c7a3701eb9876899dc8b9a435fb8c88bc6586b5492a3bbdf4ecdb5025b91/fastuuid-0.13.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ee41bd445c20771347daa230fc059557db25e0cf2b392c2f0f0767afa775b90e", size = 452924, upload-time = "2025-09-25T17:12:15.521Z" },
- { url = "https://files.pythonhosted.org/packages/8d/90/e3c04cfbb245b9c9997db4c526f794203784607222c3ff343b8d358178f6/fastuuid-0.13.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8d357eae16f0aea47241cfe5d1a6d82426cd28d86fbbd86b86a36d84a8a75075", size = 468318, upload-time = "2025-09-25T17:13:51.847Z" },
- { url = "https://files.pythonhosted.org/packages/88/e3/35f225a1e239cb9e1017e3e0dedef8f6a7f65eb4d99ae2f10cbe5501177d/fastuuid-0.13.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:44e4d72b6cbafe11c0522815257ce1ea5f737a23d14991d5667a7f14854c6f6b", size = 444868, upload-time = "2025-09-25T17:12:42.825Z" },
- { url = "https://files.pythonhosted.org/packages/c0/46/68259e2a07fe353778826f1fc3f87e2c0550174861d9d963a5dbc3f67b4f/fastuuid-0.13.3-cp311-cp311-win32.whl", hash = "sha256:d96c35e388054adc71ecaf17b7041996fdd45ae5a9a5b40dbe0549ed0bd76e99", size = 144856, upload-time = "2025-09-25T17:15:37.739Z" },
- { url = "https://files.pythonhosted.org/packages/b2/c2/71c117f675c156d2cf87be6f2d6363bc117ac48cb59e38b9b791b997fbee/fastuuid-0.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:761eb49d46ac9556d8dcbed216d28ff19cd4b7ec6d9723735439d016e19977dc", size = 150527, upload-time = "2025-09-25T17:13:07.426Z" },
- { url = "https://files.pythonhosted.org/packages/75/b0/7e1a7f2410aafc381c5df31f402dbc5255bec079cec403de1d24539b27a6/fastuuid-0.13.3-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:acdb9e11324180b82732d1c683bf97d36da0ce0fc34582b0330022fba3120c06", size = 494620, upload-time = "2025-09-25T17:17:14.021Z" },
- { url = "https://files.pythonhosted.org/packages/8d/4d/ecb8e82dda6bb42f5a6fb06ebdeb10f02f7e8da6d70cc4c031fa149b703c/fastuuid-0.13.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7712996e7b01c5034487eebec9bbc1307c5936d414653ba5cb4a77a601dce3d8", size = 253086, upload-time = "2025-09-25T17:12:41.237Z" },
- { url = "https://files.pythonhosted.org/packages/2b/7e/9164f9a93b6518042805d2a8646d052420795c84210ac5647b060254be06/fastuuid-0.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41bc3b9e7fdf4c756f1fb29a5be12353630cfcef3919ee6483c573869cdb30fd", size = 244517, upload-time = "2025-09-25T17:10:27.669Z" },
- { url = "https://files.pythonhosted.org/packages/79/ed/d591956acb1132e9be464393e806b8714d96676f5d855b16681b917ee19d/fastuuid-0.13.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef61a6ba6b86de2ef03842817cc7bd9bdddd1ff7db60b6e2e47d6e45057e01c", size = 271530, upload-time = "2025-09-25T17:11:09.067Z" },
- { url = "https://files.pythonhosted.org/packages/dc/68/51682716872f4454ed6f24530ff4e9759cd15021b48cd513016725a16c4a/fastuuid-0.13.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43f782974fe3d0c6637d5bb312409e7f52b27ae54ef690238c796875718932ea", size = 272306, upload-time = "2025-09-25T17:10:45.482Z" },
- { url = "https://files.pythonhosted.org/packages/87/6a/4f45e5ef70f78b17761e22a2477d7525bb85f87c98f188bd755a74284c65/fastuuid-0.13.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc53993b41817c522a9b8700bcadfdd3db6c7858eaf51b2f9d5254bed0075d08", size = 290557, upload-time = "2025-09-25T17:19:39.373Z" },
- { url = "https://files.pythonhosted.org/packages/0a/e5/3f3def87fb7f7b93ba01107f3e5e0fae9a2b2aec5b3ee933e1fbb1d102e6/fastuuid-0.13.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4f364b9e39a3f056f2b70eb066f1066daf5e73fd6d88fd42d70bc113c76b969b", size = 452803, upload-time = "2025-09-25T17:12:12.13Z" },
- { url = "https://files.pythonhosted.org/packages/01/df/496d13bf593a06aab4efdab7064460e674979f1b5556389c65df2807dae1/fastuuid-0.13.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:b7bb143762fe851c4065826e6e835e2461879eb030aacc4ee397bdcbadbfa73d", size = 468133, upload-time = "2025-09-25T17:10:47.457Z" },
- { url = "https://files.pythonhosted.org/packages/4c/8f/36f08d313201f4e8fc857e55a6ef5d5c81b2f2058380d91521fbf4803aaa/fastuuid-0.13.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff6ba513a728dc6ae80367acbcb92d4c388aee9db552d8c326df2e490ba0cabc", size = 444939, upload-time = "2025-09-25T17:18:21.415Z" },
- { url = "https://files.pythonhosted.org/packages/7c/21/7312862b8a4326e5e2b419a9c7e1a9e8712d4750ac9ca57c9d03879aaac5/fastuuid-0.13.3-cp312-cp312-win32.whl", hash = "sha256:48046ba0dbecc07a35c9f7ef5d78443d6eea39fcf9f6dc2957da4b4f753f6175", size = 145419, upload-time = "2025-09-25T17:17:14.105Z" },
- { url = "https://files.pythonhosted.org/packages/2a/dd/f60bee16a60a711659e27bcb5499b13601d57c779725e6168a9e0586eee2/fastuuid-0.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:fbb6f8273827b96d221c5973a7ef9d431f8e082554a16a17e51362fcf6f3c982", size = 150823, upload-time = "2025-09-25T17:19:43.188Z" },
- { url = "https://files.pythonhosted.org/packages/73/41/9482a375d3af33e2cdb99d3fa1bbbdb95f2e698ceb29e38880f81d919ebe/fastuuid-0.13.3-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e5be92899120006ed44b263c02588d38632b49aa1fb2a8fcd18bb5b93a1fa7f2", size = 494635, upload-time = "2025-09-25T17:18:44.961Z" },
- { url = "https://files.pythonhosted.org/packages/46/bf/50530bb9bcc505ea74c06ac376af44c2b4e085a897b2d4fb168729267418/fastuuid-0.13.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:217c8438e4b2d727c810ff4c49123e45f2109925b04463745e382c7d808472fa", size = 253079, upload-time = "2025-09-25T17:18:19.086Z" },
- { url = "https://files.pythonhosted.org/packages/0c/11/cb674d840ab86f3486cca060b93401b51a7b45eca81c269288d2efb98928/fastuuid-0.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1bffec9780ecab477f6d003dfae917720bb1485f44d15a469974e78be67d13d3", size = 244547, upload-time = "2025-09-25T17:15:05.277Z" },
- { url = "https://files.pythonhosted.org/packages/21/fd/9302cde221ec2e33f2284263e3f75758334f5cf6c93be2dcaee8ca5d717e/fastuuid-0.13.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa4744abf7203567ccc8e79c5c8585922c79a1b7d5a3bbbd7f3cb688e87192c9", size = 271469, upload-time = "2025-09-25T17:18:10.156Z" },
- { url = "https://files.pythonhosted.org/packages/dd/f8/de9a6bc73fbd43cdc7419e1b791f2c6a1300d3638db07ba2380bf6addaf4/fastuuid-0.13.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd73098a9057f109f59cf28752b18519dd2a8c708741e26154d4c208cef9ed01", size = 272278, upload-time = "2025-09-25T17:12:26.19Z" },
- { url = "https://files.pythonhosted.org/packages/05/99/93af7a69451918ecb434a90e8e373dccc1d6bdae030bd67c24bde87df463/fastuuid-0.13.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9927b96ff5982ef18a4dccbcd1fee677faaa486b86a9f48c235f2e969b0b3956", size = 290406, upload-time = "2025-09-25T17:18:12.611Z" },
- { url = "https://files.pythonhosted.org/packages/9f/4e/39b459085cd90cbb3c2a483fdbdeed0e4edd67c1ff036705a8486abfd29e/fastuuid-0.13.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2a64486c5e52f132fb225c248c4c9bd174946514a38ab1b293595ee9bd16bb6d", size = 452823, upload-time = "2025-09-25T17:10:37.088Z" },
- { url = "https://files.pythonhosted.org/packages/fa/b6/289aefee8cbfc8f0afaf2e9462be703a062f2686901cf25cc65ad71eba3b/fastuuid-0.13.3-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:f4e9c4552e3ffaec33f8af09067dcafd435b1188a68d86cc26aef50a4b200de6", size = 468092, upload-time = "2025-09-25T17:19:11.065Z" },
- { url = "https://files.pythonhosted.org/packages/fe/1f/5994c4d3a298b2116417f49abb1893950600087dbbc3839016347679c9ba/fastuuid-0.13.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:4817671973467d8c32bdc1d9dae9ad2727664ac1363dbe94e42e0a890fbc521d", size = 444968, upload-time = "2025-09-25T17:19:24.896Z" },
- { url = "https://files.pythonhosted.org/packages/89/82/31cefe573bc19f2d1b07b86af9b9db8d0a74487685dfbaf16edf4ec91055/fastuuid-0.13.3-cp313-cp313-win32.whl", hash = "sha256:ad55c13069711c3fb30c7080d117516ee7a419f64f073212c2e9a9536051b743", size = 145463, upload-time = "2025-09-25T17:17:15.705Z" },
- { url = "https://files.pythonhosted.org/packages/f9/49/3d41776751d207526c8917d8e6ec35290f78be396f8c05102c32c0d63558/fastuuid-0.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:ffe6a759e15e0968d2022d6a07957bc1f9830127b2d1bef2ee56d4e21c5a90b6", size = 150918, upload-time = "2025-09-25T17:15:56.942Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/17/f8ed7f707c1bf994ff4e38f163b367cc2060f13a8aa60b03a3c821daaf0f/fastuuid-0.13.5-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b9edf8ee30718aee787cdd2e9e1ff3d4a3ec6ddb32fba0a23fa04956df69ab07", size = 494134, upload-time = "2025-09-26T09:14:35.852Z" },
+ { url = "https://files.pythonhosted.org/packages/18/de/b03e4a083a307fb5a2c8afcfbcc6ab45578fba7996f69f329e35d18e0e67/fastuuid-0.13.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f67ea1e25c5e782f7fb5aaa5208f157d950401dd9321ce56bcc6d4dc3d72ed60", size = 252832, upload-time = "2025-09-26T09:10:21.321Z" },
+ { url = "https://files.pythonhosted.org/packages/62/65/3a8be5ce86e2a1eb3947be32512b62fcb0a360a998ba2405cd3e54e54f04/fastuuid-0.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9ff3fc87e1f19603dd53c38f42c2ea8d5d5462554deab69e9cf1800574e4756c", size = 244309, upload-time = "2025-09-26T09:09:08.333Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/eb/7b9c98d25a810fcc5f4a3e10e1e051c18e10cdad4527242e18c998fab4b1/fastuuid-0.13.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6e5337fa7698dc52bc724da7e9239e93c5b24a09f6904b8660dfb8c41ce3dee", size = 271629, upload-time = "2025-09-26T09:13:37.525Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/37/6331f626852c2aeea8d666af049b1337e273d11e700a26333c402d0e7a94/fastuuid-0.13.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9db596023c10dabb12489a88c51b75297c3a2478cb2be645e06905934e7b9fc", size = 272312, upload-time = "2025-09-26T09:13:05.252Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/d3/e4d3f3c2968689e17d5c73bd0da808d1673329d5ff3b4065db03d58f36e3/fastuuid-0.13.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:191ff6192fe53c5fc9d4d241ee1156b30a7ed6f1677b1cc2423e7ecdbc26222b", size = 291049, upload-time = "2025-09-26T09:13:31.817Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/4e/f27539c9b15b1947ba50907b1a83bbe905363770472c0a1c3175fb2a0ebf/fastuuid-0.13.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:348ce9f296dda701ba46d8dceeff309f90dbc75dd85080bbed2b299aa908890a", size = 453074, upload-time = "2025-09-26T09:11:42.674Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/5c/57cba66a8f04cd26d3118b21393a0dda221cb82ac992b9fe153b69a22a0a/fastuuid-0.13.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:46954fb644995d7fc8bbd710fbd4c65cedaa48c921c86fdbafef0229168a8c96", size = 468531, upload-time = "2025-09-26T09:10:30.626Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/90/dbc19dc18282b3c2264554c595901b520224efe65907c5ff5595e688ab28/fastuuid-0.13.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22da0f66041e1c10c7d465b495cc6cd8e17e080dda34b4bd5ff5240b860fbb82", size = 444933, upload-time = "2025-09-26T09:09:33.405Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/03/4652cc314fc5163db12bc451512b087e5b5e4f36ba513f111fd5a5ff1c07/fastuuid-0.13.5-cp310-cp310-win32.whl", hash = "sha256:3e6b548f06c1ed7bad951a17a09eef69d6f24eb2b874cb4833e26b886d82990f", size = 144981, upload-time = "2025-09-26T09:08:14.812Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/0b/85b3a68418911923acb8955219ab33ac728eaa9337ef0135b9e5c9d1ed9d/fastuuid-0.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:c82838e52189d16b1307631179cb2cd37778dd8f4ddc00e9ce3c26f920b3b2f7", size = 150741, upload-time = "2025-09-26T09:09:00.161Z" },
+ { url = "https://files.pythonhosted.org/packages/04/ab/9351bfc04ff2144115758233130b5469993d3d379323903a4634cb9c78c1/fastuuid-0.13.5-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:c122558ca4b5487e2bd0863467e4ccfe636afd1274803741487d48f2e32ea0e1", size = 493910, upload-time = "2025-09-26T09:12:36.995Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/ab/84fac529cc12a03d49595e70ac459380f7cb12c70f0fe401781b276f9e94/fastuuid-0.13.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d7abd42a03a17a681abddd19aa4d44ca2747138cf8a48373b395cf1341a10de2", size = 252621, upload-time = "2025-09-26T09:12:22.222Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/9d/f4c734d7b74a04ca695781c58a1376f07b206fe2849e58e7778d476a0e94/fastuuid-0.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2705cf7c2d6f7c03053404b75a4c44f872a73f6f9d5ea34f1dc6bba400c4a97c", size = 244269, upload-time = "2025-09-26T09:08:31.921Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/da/b42b7eb84523d69cfe9dac82950e105061c8d59f4d4d2cc3e170dbd20937/fastuuid-0.13.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d220a056fcbad25932c1f25304261198612f271f4d150b2a84e81adb877daf7", size = 271528, upload-time = "2025-09-26T09:12:42.718Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/45/6eee36929119e9544b0906fd6591e685d682e4b51cfad4c25d96ccf04009/fastuuid-0.13.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f29f93b5a0c5f5579f97f77d5319e9bfefd61d8678ec59d850201544faf33bf", size = 272168, upload-time = "2025-09-26T09:07:04.238Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/ac/75b70f13515e12194a25b0459dd8a8a33de4ab0a92142f0776d21e41ca84/fastuuid-0.13.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:399d86623fb806151b1feb9fdd818ebfc1d50387199a35f7264f98dfc1540af5", size = 290948, upload-time = "2025-09-26T09:07:53.433Z" },
+ { url = "https://files.pythonhosted.org/packages/76/30/1801326a5b433aafc04eae906e6b005e8a3d1120fd996409fe88124edb06/fastuuid-0.13.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:689e8795a1edd573b2c9a455024e4edf605a9690339bba29709857f7180894ea", size = 452932, upload-time = "2025-09-26T09:09:28.017Z" },
+ { url = "https://files.pythonhosted.org/packages/61/2a/080b6b2ac4ef2ead54a7463ae4162d66a52867bbd4447ad5354427b82ae2/fastuuid-0.13.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:25e82c4a1734da168b36f7308e397afbe9c9b353799a9c69563a605f11dd4641", size = 468384, upload-time = "2025-09-26T09:08:14.32Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/d3/4a3ffcaf8d874f7f208dad7e98ded7c5359b6599073960e3aa0530ca6139/fastuuid-0.13.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f62299e3cca69aad6a6fb37e26e45055587954d498ad98903fea24382377ea0e", size = 444815, upload-time = "2025-09-26T09:06:38.691Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/a0/08dd8663f7bff3e9c0b2416708b01d1fb65f52bcd4bce18760f77c4735fd/fastuuid-0.13.5-cp311-cp311-win32.whl", hash = "sha256:68227f2230381b89fb1ad362ca6e433de85c6c11c36312b41757cad47b8a8e32", size = 144897, upload-time = "2025-09-26T09:14:53.695Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/e2/2c2a37dcc56e2323c6214c38c8faac22f9d03d98c481f8a40843e0b9526a/fastuuid-0.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:4a32306982bd031cb20d5d1a726b7b958a55babebd2300ce6c8e352d3496e931", size = 150523, upload-time = "2025-09-26T09:12:24.031Z" },
+ { url = "https://files.pythonhosted.org/packages/21/36/434f137c5970cac19e57834e1f7680e85301619d49891618c00666700c61/fastuuid-0.13.5-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:35fe8045e866bc6846f8de6fa05acb1de0c32478048484a995e96d31e21dff2a", size = 494638, upload-time = "2025-09-26T09:14:58.695Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/3c/083de2ac007b2b305523b9c006dba5051e5afd87a626ef1a39f76e2c6b82/fastuuid-0.13.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:02a460333f52d731a006d18a52ef6fcb2d295a1f5b1a5938d30744191b2f77b7", size = 253138, upload-time = "2025-09-26T09:13:33.283Z" },
+ { url = "https://files.pythonhosted.org/packages/73/5e/630cffa1c8775db526e39e9e4c5c7db0c27be0786bb21ba82c912ae19f63/fastuuid-0.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:74b0e4f8c307b9f477a5d7284db4431ce53a3c1e3f4173db7a97db18564a6202", size = 244521, upload-time = "2025-09-26T09:14:40.682Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/51/55d78705f4fbdadf88fb40f382f508d6c7a4941ceddd7825fafebb4cc778/fastuuid-0.13.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6955a99ef455c2986f3851f4e0ccc35dec56ac1a7720f2b92e88a75d6684512e", size = 271557, upload-time = "2025-09-26T09:15:09.75Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/2b/1b89e90a8635e5587ccdbbeb169c590672ce7637880f2c047482a0359950/fastuuid-0.13.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f10c77b826738c1a27dcdaa92ea4dc1ec9d869748a99e1fde54f1379553d4854", size = 272334, upload-time = "2025-09-26T09:07:48.865Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/06/4c8207894eeb30414999e5c3f66ac039bc4003437eb4060d8a1bceb4cc6f/fastuuid-0.13.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bb25dccbeb249d16d5e664f65f17ebec05136821d5ef462c4110e3f76b86fb86", size = 290594, upload-time = "2025-09-26T09:12:54.124Z" },
+ { url = "https://files.pythonhosted.org/packages/50/69/96d221931a31d77a47cc2487bdfacfb3091edfc2e7a04b1795df1aec05df/fastuuid-0.13.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a5becc646a3eeafb76ce0a6783ba190cd182e3790a8b2c78ca9db2b5e87af952", size = 452835, upload-time = "2025-09-26T09:14:00.994Z" },
+ { url = "https://files.pythonhosted.org/packages/25/ef/bf045f0a47dcec96247497ef3f7a31d86ebc074330e2dccc34b8dbc0468a/fastuuid-0.13.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:69b34363752d06e9bb0dbdf02ae391ec56ac948c6f2eb00be90dad68e80774b9", size = 468225, upload-time = "2025-09-26T09:13:38.585Z" },
+ { url = "https://files.pythonhosted.org/packages/30/46/4817ab5a3778927155a4bde92540d4c4fa996161ec8b8e080c8928b0984e/fastuuid-0.13.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57d0768afcad0eab8770c9b8cf904716bd3c547e8b9a4e755ee8a673b060a3a3", size = 444907, upload-time = "2025-09-26T09:14:30.163Z" },
+ { url = "https://files.pythonhosted.org/packages/80/27/ab284117ce4dc9b356a7196bdbf220510285f201d27f1f078592cdc8187b/fastuuid-0.13.5-cp312-cp312-win32.whl", hash = "sha256:8ac6c6f5129d52eaa6ef9ea4b6e2f7c69468a053f3ab8e439661186b9c06bb85", size = 145415, upload-time = "2025-09-26T09:08:59.494Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/0c/f970a4222773b248931819f8940800b760283216ca3dda173ed027e94bdd/fastuuid-0.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:ad630e97715beefef07ec37c9c162336e500400774e2c1cbe1a0df6f80d15b9a", size = 150840, upload-time = "2025-09-26T09:13:46.115Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/62/74fc53f6e04a4dc5b36c34e4e679f85a4c14eec800dcdb0f2c14b5442217/fastuuid-0.13.5-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:ea17dfd35e0e91920a35d91e65e5f9c9d1985db55ac4ff2f1667a0f61189cefa", size = 494678, upload-time = "2025-09-26T09:14:30.908Z" },
+ { url = "https://files.pythonhosted.org/packages/09/ba/f28b9b7045738a8bfccfb9cd6aff4b91fce2669e6b383a48b0694ee9b3ff/fastuuid-0.13.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:be6ad91e5fefbcc2a4b478858a2715e386d405834ea3ae337c3b6b95cc0e47d6", size = 253162, upload-time = "2025-09-26T09:13:35.879Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/18/13fac89cb4c9f0cd7e81a9154a77ecebcc95d2b03477aa91d4d50f7227ee/fastuuid-0.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ea6df13a306aab3e0439d58c312ff1e6f4f07f09f667579679239b4a6121f64a", size = 244546, upload-time = "2025-09-26T09:14:58.13Z" },
+ { url = "https://files.pythonhosted.org/packages/04/bf/9691167804d59411cc4269841df949f6dd5e76452ab10dcfcd1dbe04c5bc/fastuuid-0.13.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2354c1996d3cf12dc2ba3752e2c4d6edc46e1a38c63893146777b1939f3062d4", size = 271528, upload-time = "2025-09-26T09:14:48.996Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/b5/7a75a03d1c7aa0b6d573032fcca39391f0aef7f2caabeeb45a672bc0bd3c/fastuuid-0.13.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6cf9b7469fc26d1f9b1c43ac4b192e219e85b88fdf81d71aa755a6c08c8a817", size = 272292, upload-time = "2025-09-26T09:14:42.82Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/db/fa0f16cbf76e6880599533af4ef01bb586949c5320612e9d884eff13e603/fastuuid-0.13.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92ba539170097b9047551375f1ca09d8d2b4aefcc79eeae3e1c43fe49b42072e", size = 290466, upload-time = "2025-09-26T09:08:33.161Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/02/6b8c45bfbc8500994dd94edba7f59555f9683c4d8c9a164ae1d25d03c7c7/fastuuid-0.13.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:dbb81d05617bc2970765c1ad82db7e8716f6a2b7a361a14b83de5b9240ade448", size = 452838, upload-time = "2025-09-26T09:13:44.747Z" },
+ { url = "https://files.pythonhosted.org/packages/27/12/85d95a84f265b888e8eb9f9e2b5aaf331e8be60c0a7060146364b3544b6a/fastuuid-0.13.5-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:d973bd6bf9d754d3cca874714ac0a6b22a47f239fb3d3c8687569db05aac3471", size = 468149, upload-time = "2025-09-26T09:13:18.712Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/da/dd9a137e9ea707e883c92470113a432233482ec9ad3e9b99c4defc4904e6/fastuuid-0.13.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e725ceef79486423f05ee657634d4b4c1ca5fb2c8a94e0708f5d6356a83f2a83", size = 444933, upload-time = "2025-09-26T09:14:09.494Z" },
+ { url = "https://files.pythonhosted.org/packages/12/f4/ab363d7f4ac3989691e2dc5ae2d8391cfb0b4169e52ef7fa0ac363e936f0/fastuuid-0.13.5-cp313-cp313-win32.whl", hash = "sha256:a1c430a332ead0b2674f1ef71b17f43b8139ec5a4201182766a21f131a31e021", size = 145462, upload-time = "2025-09-26T09:14:15.105Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/8a/52eb77d9c294a54caa0d2d8cc9f906207aa6d916a22de963687ab6db8b86/fastuuid-0.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:241fdd362fd96e6b337db62a65dd7cb3dfac20adf854573247a47510e192db6f", size = 150923, upload-time = "2025-09-26T09:13:03.923Z" },
]
[[package]]