Python: chore(python): improve dependency range automation (#4343)

* chore(python): improve dependency range automation

- tighten dependency bounds and coding standards guidance\n- add dependency range validation workflow, reporting, and issue automation\n- update related tests and dependency pins for compatibility

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* updated text and pyarrow

* new lock

* fixed workflow

* updated deps

* fix tiktoken

* chore(python): refine dependency validation workflows

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(python): add high-level dependency validation comments

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* WIP

* added additional comments and excludes

* added dev dependency handling and workflow and updates to package ranges

* added readme and simplified commands

* fix markers

* chore(python): address dependency review feedback

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Tighten dependency bounds, remove stale overrides, restore Python 3.10 support

- Apply dependency bound policy across all packages: stable >=1.0 deps use
  >=floor,<next_major; pre-1.0/prerelease deps use validated hard-bounded ranges
- Remove stale root tool.uv.override-dependencies (uvicorn, websockets, grpcio)
- Lower github_copilot requires-python to >=3.10 with github-copilot-sdk gated
  behind python_version >= 3.11 marker; import raises ImportError on 3.10
- Skip github_copilot pyright/mypy/test tasks on Python <3.11
- Use version-conditional pyrightconfig for samples on Python 3.10
- Add compatibility fix in core responses client for older openai typed dicts
- Normalize uv.lock prerelease mode and refresh dev dependencies
- Update CODING_STANDARD.md, DEV_SETUP.md, and package management skill docs

Closes #902

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* small tweaks

* add note in workflow

* fix workflows and several versions

* fix duplicate

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Eduard van Valkenburg
2026-03-13 13:32:37 +01:00
committed by GitHub
Unverified
parent 67b0282813
commit 50fdcbaf57
61 changed files with 5500 additions and 779 deletions
+2 -2
View File
@@ -24,7 +24,7 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"a2a-sdk>=0.3.5",
"a2a-sdk>=0.3.5,<0.3.24",
]
[tool.uv]
@@ -87,7 +87,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_a2a"
test = "pytest -m \"not integration\" --cov=agent_framework_a2a --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_a2a --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
@@ -6,13 +6,12 @@ from __future__ import annotations
import logging
import os
from typing import cast
from typing import Any, cast
import uvicorn
from agent_framework import ChatOptions
from agent_framework._clients import SupportsChatGetResponse
from agent_framework.ag_ui import add_agent_framework_fastapi_endpoint
from agent_framework.anthropic import AnthropicClient
from agent_framework.azure import AzureOpenAIChatClient
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
@@ -26,6 +25,15 @@ from ..agents.task_steps_agent import task_steps_agent_wrapped
from ..agents.ui_generator_agent import ui_generator_agent
from ..agents.weather_agent import weather_agent
AnthropicClient: type[Any] | None
try:
import agent_framework.anthropic as _anthropic_namespace
except ImportError:
# If the Anthropic client isn't installed, we can still run the server with Azure OpenAI as the default chat client
AnthropicClient = None
else:
AnthropicClient = cast(type[Any] | None, getattr(_anthropic_namespace, "AnthropicClient", None))
# Configure logging to file and console (disabled by default - set ENABLE_DEBUG_LOGGING=1 to enable)
if os.getenv("ENABLE_DEBUG_LOGGING"):
log_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "ag_ui_server.log")
@@ -70,7 +78,9 @@ app.add_middleware(
# Set CHAT_CLIENT=anthropic to use Anthropic, defaults to Azure OpenAI
client: SupportsChatGetResponse[ChatOptions] = cast(
SupportsChatGetResponse[ChatOptions],
AnthropicClient() if os.getenv("CHAT_CLIENT", "").lower() == "anthropic" else AzureOpenAIChatClient(),
AnthropicClient()
if AnthropicClient is not None and os.getenv("CHAT_CLIENT", "").lower() == "anthropic"
else AzureOpenAIChatClient(),
)
# Agentic Chat - basic chat agent
+6 -6
View File
@@ -23,15 +23,15 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"ag-ui-protocol>=0.1.9",
"fastapi>=0.115.0",
"uvicorn>=0.30.0"
"ag-ui-protocol==0.1.13",
"fastapi>=0.115.0,<0.133.1",
"uvicorn[standard]>=0.30.0,<0.42.0"
]
[project.optional-dependencies]
dev = [
"pytest>=8.0.0",
"httpx>=0.27.0",
"pytest==9.0.2",
"httpx==0.28.1",
]
[build-system]
@@ -74,4 +74,4 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_ag_ui"
test = "pytest -m \"not integration\" --cov=agent_framework_ag_ui --cov-report=term-missing:skip-covered -n auto --dist worksteal tests/ag_ui"
test = 'pytest -m "not integration" --cov=agent_framework_ag_ui --cov-report=term-missing:skip-covered -n auto --dist worksteal tests/ag_ui'
+2 -2
View File
@@ -24,7 +24,7 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"anthropic>=0.70.0,<1",
"anthropic>=0.80.0,<0.80.1",
]
[tool.uv]
@@ -87,7 +87,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_anthropic"
test = "pytest -m \"not integration\" --cov=agent_framework_anthropic --cov-report=term-missing:skip-covered -n auto --dist worksteal tests"
test = 'pytest -m "not integration" --cov=agent_framework_anthropic --cov-report=term-missing:skip-covered -n auto --dist worksteal tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
@@ -24,7 +24,7 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"azure-search-documents==11.7.0b2",
"azure-search-documents>=11.7.0b2,<11.7.0b3",
]
[tool.uv]
@@ -89,7 +89,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_azure_ai_search"
test = "pytest -m \"not integration\" --cov=agent_framework_azure_ai_search --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_azure_ai_search --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
+4 -4
View File
@@ -24,9 +24,9 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"azure-ai-agents == 1.2.0b5",
"azure-ai-inference>=1.0.0b9",
"aiohttp",
"azure-ai-agents>=1.2.0b5,<1.2.0b6",
"azure-ai-inference>=1.0.0b9,<1.0.0b10",
"aiohttp>=3.7.0,<4",
]
[tool.uv]
@@ -87,7 +87,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_azure_ai"
test = "pytest -m \"not integration\" --cov=agent_framework_azure_ai --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_azure_ai --cov-report=term-missing:skip-covered tests'
[tool.poe.tasks.integration-tests]
cmd = """
+1 -1
View File
@@ -24,7 +24,7 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"azure-cosmos>=4.9.0",
"azure-cosmos>=4.3.0,<5",
]
[tool.uv]
@@ -24,8 +24,8 @@ classifiers = [
dependencies = [
"agent-framework-core>=1.0.0rc4",
"agent-framework-durabletask",
"azure-functions",
"azure-functions-durable",
"azure-functions>=1.24.0,<2",
"azure-functions-durable>=1.3.1,<2",
]
[dependency-groups]
@@ -93,7 +93,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_azurefunctions"
test = "pytest -m \"not integration\" --cov=agent_framework_azurefunctions --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_azurefunctions --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
+1 -1
View File
@@ -86,7 +86,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_bedrock"
test = "pytest -m \"not integration\" --cov=agent_framework_bedrock --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_bedrock --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["hatchling"]
+2 -2
View File
@@ -23,7 +23,7 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"openai-chatkit>=1.4.0,<2.0.0",
"openai-chatkit>=1.4.1,<2.0.0",
]
[tool.uv]
@@ -88,7 +88,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_chatkit"
test = "pytest -m \"not integration\" --cov=agent_framework_chatkit --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_chatkit --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
+2 -2
View File
@@ -24,7 +24,7 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"claude-agent-sdk>=0.1.25",
"claude-agent-sdk>=0.1.36,<0.1.49",
]
[tool.uv]
@@ -88,7 +88,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_claude"
test = "pytest -m \"not integration\" --cov=agent_framework_claude --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_claude --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
+2 -2
View File
@@ -24,7 +24,7 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"microsoft-agents-copilotstudio-client>=0.3.1",
"microsoft-agents-copilotstudio-client>=0.3.1,<0.3.2",
]
[tool.uv]
@@ -87,7 +87,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_copilotstudio"
test = "pytest -m \"not integration\" --cov=agent_framework_copilotstudio --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_copilotstudio --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
@@ -1,5 +1,6 @@
# Copyright (c) Microsoft. All rights reserved.
# ruff: noqa: RUF070, RUF100
from __future__ import annotations
import asyncio
@@ -665,7 +665,7 @@ class RawOpenAIResponsesClient( # type: ignore[misc]
if output_format:
tool["output_format"] = output_format
if model:
tool["model"] = model
tool["model"] = model # type: ignore
if quality:
tool["quality"] = quality
if partial_images is not None:
+8 -16
View File
@@ -24,19 +24,19 @@ classifiers = [
]
dependencies = [
# utilities
"typing-extensions",
"typing-extensions>=4.15.0,<5",
"pydantic>=2,<3",
"python-dotenv>=1,<2",
# telemetry
"opentelemetry-api>=1.39.0",
"opentelemetry-sdk>=1.39.0",
"opentelemetry-semantic-conventions-ai>=0.4.13",
"opentelemetry-api>=1.39.0,<2",
"opentelemetry-sdk>=1.39.0,<2",
"opentelemetry-semantic-conventions-ai>=0.4.13,<0.4.14",
# connectors and functions
"openai>=1.99.0",
"openai>=1.99.0,<3",
"azure-identity>=1,<2",
"azure-ai-projects>=2.0.0,<3.0",
"mcp[ws]>=1.24.0,<2",
"packaging>=24.1",
"packaging>=24.1,<25",
]
[project.optional-dependencies]
@@ -76,15 +76,7 @@ environments = [
fallback-version = "0.0.0"
[tool.pytest.ini_options]
testpaths = [
'tests',
'packages/core/tests',
'packages/a2a/tests',
'packages/azure-ai/tests',
'packages/copilotstudio/tests',
'packages/mem0/tests',
'packages/runtime/tests'
]
testpaths = ['tests']
addopts = "-ra -q -r fEX"
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
@@ -131,7 +123,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework"
test = "pytest -m \"not integration\" --cov=agent_framework --cov-report=term-missing:skip-covered -n auto --dist worksteal tests"
test = 'pytest -m "not integration" --cov=agent_framework --cov-report=term-missing:skip-covered -n auto --dist worksteal tests'
[tool.flit.module]
name = "agent_framework"
@@ -0,0 +1,159 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import os
from unittest.mock import AsyncMock, MagicMock
import pytest
from openai.types import CreateEmbeddingResponse
from openai.types import Embedding as OpenAIEmbedding
from openai.types.create_embedding_response import Usage
from agent_framework.azure import AzureOpenAIEmbeddingClient
from agent_framework.openai import OpenAIEmbeddingOptions
def _make_openai_response(
embeddings: list[list[float]],
model: str = "text-embedding-3-small",
prompt_tokens: int = 5,
total_tokens: int = 5,
) -> CreateEmbeddingResponse:
"""Helper to create a mock OpenAI embeddings response."""
data = [OpenAIEmbedding(embedding=emb, index=i, object="embedding") for i, emb in enumerate(embeddings)]
return CreateEmbeddingResponse(
data=data,
model=model,
object="list",
usage=Usage(prompt_tokens=prompt_tokens, total_tokens=total_tokens),
)
@pytest.fixture
def azure_embedding_unit_test_env(monkeypatch: pytest.MonkeyPatch) -> None:
"""Clear ambient Azure OpenAI embedding env vars for deterministic unit tests."""
for key in (
"AZURE_OPENAI_ENDPOINT",
"AZURE_OPENAI_API_KEY",
"AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME",
"AZURE_OPENAI_BASE_URL",
"AZURE_OPENAI_TOKEN_ENDPOINT",
):
monkeypatch.delenv(key, raising=False)
def test_azure_construction_with_deployment_name(azure_embedding_unit_test_env: None) -> None:
client = AzureOpenAIEmbeddingClient(
deployment_name="text-embedding-3-small",
api_key="test-key",
endpoint="https://test.openai.azure.com/",
)
assert client.model_id == "text-embedding-3-small"
def test_azure_construction_with_existing_client(azure_embedding_unit_test_env: None) -> None:
mock_client = MagicMock()
client = AzureOpenAIEmbeddingClient(
deployment_name="my-deployment",
async_client=mock_client,
)
assert client.model_id == "my-deployment"
assert client.client is mock_client
def test_azure_construction_missing_deployment_name_raises(azure_embedding_unit_test_env: None) -> None:
with pytest.raises(ValueError, match="deployment name is required"):
AzureOpenAIEmbeddingClient(
api_key="test-key",
endpoint="https://test.openai.azure.com/",
)
def test_azure_construction_missing_credentials_raises(azure_embedding_unit_test_env: None) -> None:
with pytest.raises(ValueError, match="api_key, credential, or a client"):
AzureOpenAIEmbeddingClient(
deployment_name="test",
endpoint="https://test.openai.azure.com/",
)
async def test_azure_get_embeddings(azure_embedding_unit_test_env: None) -> None:
mock_response = _make_openai_response(
embeddings=[[0.1, 0.2]],
)
mock_async_client = MagicMock()
mock_async_client.embeddings = MagicMock()
mock_async_client.embeddings.create = AsyncMock(return_value=mock_response)
client = AzureOpenAIEmbeddingClient(
deployment_name="text-embedding-3-small",
async_client=mock_async_client,
)
result = await client.get_embeddings(["hello"])
assert len(result) == 1
assert result[0].vector == [0.1, 0.2]
def test_azure_otel_provider_name(azure_embedding_unit_test_env: None) -> None:
mock_client = MagicMock()
client = AzureOpenAIEmbeddingClient(
deployment_name="test",
async_client=mock_client,
)
assert client.OTEL_PROVIDER_NAME == "azure.ai.openai"
skip_if_azure_openai_integration_tests_disabled = pytest.mark.skipif(
not os.getenv("AZURE_OPENAI_ENDPOINT")
or (not os.getenv("AZURE_OPENAI_API_KEY") and not os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME")),
reason="No Azure OpenAI credentials provided; skipping integration tests.",
)
@pytest.mark.flaky
@pytest.mark.integration
@skip_if_azure_openai_integration_tests_disabled
async def test_integration_azure_openai_get_embeddings() -> None:
"""End-to-end test of Azure OpenAI embedding generation."""
client = AzureOpenAIEmbeddingClient()
result = await client.get_embeddings(["hello world"])
assert len(result) == 1
assert isinstance(result[0].vector, list)
assert len(result[0].vector) > 0
assert all(isinstance(v, float) for v in result[0].vector)
assert result[0].model_id is not None
assert result.usage is not None
assert result.usage["input_token_count"] > 0
@pytest.mark.flaky
@pytest.mark.integration
@skip_if_azure_openai_integration_tests_disabled
async def test_integration_azure_openai_get_embeddings_multiple() -> None:
"""Test Azure OpenAI embedding generation for multiple inputs."""
client = AzureOpenAIEmbeddingClient()
result = await client.get_embeddings(["hello", "world", "test"])
assert len(result) == 3
dims = [len(e.vector) for e in result]
assert all(d == dims[0] for d in dims)
@pytest.mark.flaky
@pytest.mark.integration
@skip_if_azure_openai_integration_tests_disabled
async def test_integration_azure_openai_get_embeddings_with_dimensions() -> None:
"""Test Azure OpenAI embedding generation with custom dimensions."""
client = AzureOpenAIEmbeddingClient()
options: OpenAIEmbeddingOptions = {"dimensions": 256}
result = await client.get_embeddings(["hello world"], options=options)
assert len(result) == 1
assert len(result[0].vector) == 256
@@ -10,7 +10,6 @@ from openai.types import CreateEmbeddingResponse
from openai.types import Embedding as OpenAIEmbedding
from openai.types.create_embedding_response import Usage
from agent_framework.azure import AzureOpenAIEmbeddingClient
from agent_framework.openai import (
OpenAIEmbeddingClient,
OpenAIEmbeddingOptions,
@@ -190,73 +189,6 @@ async def test_openai_empty_values_returns_empty(openai_unit_test_env: None) ->
client.client.embeddings.create.assert_not_called()
# --- Azure OpenAI unit tests ---
def test_azure_construction_with_deployment_name() -> None:
client = AzureOpenAIEmbeddingClient(
deployment_name="text-embedding-3-small",
api_key="test-key",
endpoint="https://test.openai.azure.com/",
)
assert client.model_id == "text-embedding-3-small"
def test_azure_construction_with_existing_client() -> None:
mock_client = MagicMock()
client = AzureOpenAIEmbeddingClient(
deployment_name="my-deployment",
async_client=mock_client,
)
assert client.model_id == "my-deployment"
assert client.client is mock_client
def test_azure_construction_missing_deployment_name_raises(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.delenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME", raising=False)
with pytest.raises(ValueError, match="deployment name is required"):
AzureOpenAIEmbeddingClient(
api_key="test-key",
endpoint="https://test.openai.azure.com/",
)
def test_azure_construction_missing_credentials_raises() -> None:
with pytest.raises(ValueError, match="api_key, credential, or a client"):
AzureOpenAIEmbeddingClient(
deployment_name="test",
endpoint="https://test.openai.azure.com/",
)
async def test_azure_get_embeddings() -> None:
mock_response = _make_openai_response(
embeddings=[[0.1, 0.2]],
)
mock_async_client = MagicMock()
mock_async_client.embeddings = MagicMock()
mock_async_client.embeddings.create = AsyncMock(return_value=mock_response)
client = AzureOpenAIEmbeddingClient(
deployment_name="text-embedding-3-small",
async_client=mock_async_client,
)
result = await client.get_embeddings(["hello"])
assert len(result) == 1
assert result[0].vector == [0.1, 0.2]
def test_azure_otel_provider_name() -> None:
mock_client = MagicMock()
client = AzureOpenAIEmbeddingClient(
deployment_name="test",
async_client=mock_client,
)
assert client.OTEL_PROVIDER_NAME == "azure.ai.openai"
# --- Integration tests ---
skip_if_openai_integration_tests_disabled = pytest.mark.skipif(
@@ -264,12 +196,6 @@ skip_if_openai_integration_tests_disabled = pytest.mark.skipif(
reason="No real OPENAI_API_KEY provided; skipping integration tests.",
)
skip_if_azure_openai_integration_tests_disabled = pytest.mark.skipif(
not os.getenv("AZURE_OPENAI_ENDPOINT")
or (not os.getenv("AZURE_OPENAI_API_KEY") and not os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME")),
reason="No Azure OpenAI credentials provided; skipping integration tests.",
)
@skip_if_openai_integration_tests_disabled
@pytest.mark.flaky
@@ -315,49 +241,3 @@ async def test_integration_openai_get_embeddings_with_dimensions() -> None:
assert len(result) == 1
assert len(result[0].vector) == 256
@skip_if_azure_openai_integration_tests_disabled
@pytest.mark.flaky
@pytest.mark.integration
async def test_integration_azure_openai_get_embeddings() -> None:
"""End-to-end test of Azure OpenAI embedding generation."""
client = AzureOpenAIEmbeddingClient()
result = await client.get_embeddings(["hello world"])
assert len(result) == 1
assert isinstance(result[0].vector, list)
assert len(result[0].vector) > 0
assert all(isinstance(v, float) for v in result[0].vector)
assert result[0].model_id is not None
assert result.usage is not None
assert result.usage["input_token_count"] > 0
@skip_if_azure_openai_integration_tests_disabled
@pytest.mark.flaky
@pytest.mark.integration
async def test_integration_azure_openai_get_embeddings_multiple() -> None:
"""Test Azure OpenAI embedding generation for multiple inputs."""
client = AzureOpenAIEmbeddingClient()
result = await client.get_embeddings(["hello", "world", "test"])
assert len(result) == 3
dims = [len(e.vector) for e in result]
assert all(d == dims[0] for d in dims)
@skip_if_azure_openai_integration_tests_disabled
@pytest.mark.flaky
@pytest.mark.integration
async def test_integration_azure_openai_get_embeddings_with_dimensions() -> None:
"""Test Azure OpenAI embedding generation with custom dimensions."""
client = AzureOpenAIEmbeddingClient()
options: OpenAIEmbeddingOptions = {"dimensions": 256}
result = await client.get_embeddings(["hello world"], options=options)
assert len(result) == 1
assert len(result[0].vector) == 256
@@ -1876,6 +1876,19 @@ def test_prepare_tools_for_openai_with_image_generation_options() -> None:
assert image_tool["quality"] == "high"
def test_prepare_tools_for_openai_with_custom_image_generation_model() -> None:
"""Test image generation tool conversion with a custom model string."""
client = OpenAIResponsesClient(model_id="test-model", api_key="test-key")
tool = OpenAIResponsesClient.get_image_generation_tool(model="custom-image-model")
resp_tools = client._prepare_tools_for_openai([tool])
assert len(resp_tools) == 1
image_tool = resp_tools[0]
assert image_tool["type"] == "image_generation"
assert image_tool["model"] == "custom-image-model"
def test_parse_chunk_from_openai_with_mcp_approval_request() -> None:
"""Test that a streaming mcp_approval_request event is parsed into FunctionApprovalRequestContent."""
client = OpenAIResponsesClient(model_id="test-model", api_key="test-key")
+3 -3
View File
@@ -23,12 +23,12 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"powerfx>=0.0.31; python_version < '3.14'",
"powerfx>=0.0.32,<0.0.35; python_version < '3.14'",
"pyyaml>=6.0,<7.0",
]
[dependency-groups]
dev = [
"types-PyYaml"
"types-PyYaml==6.0.12.20250915"
]
[tool.uv]
@@ -94,7 +94,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_declarative"
test = "pytest -m \"not integration\" --cov=agent_framework_declarative --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_declarative --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
+12 -6
View File
@@ -24,14 +24,20 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"fastapi>=0.104.0",
"uvicorn[standard]>=0.24.0",
"python-dotenv>=1.0.0",
"fastapi>=0.115.0,<0.133.1",
"uvicorn[standard]>=0.30.0,<0.42.0"
]
[project.optional-dependencies]
dev = ["pytest>=7.0.0", "watchdog>=3.0.0", "agent-framework-orchestrations"]
all = ["pytest>=7.0.0", "watchdog>=3.0.0"]
dev = [
"pytest==9.0.2",
"watchdog==6.0.0",
"agent-framework-orchestrations==1.0.0b260304",
]
all = [
"pytest==9.0.2",
"watchdog==6.0.0",
]
[project.scripts]
devui = "agent_framework_devui:main"
@@ -94,7 +100,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_devui"
test = "pytest -m \"not integration\" --cov=agent_framework_devui --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_devui --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
+5 -9
View File
@@ -29,18 +29,16 @@ Durable execution support for long-running agent workflows using Azure Durable F
## Usage
```python
from durabletask.client import TaskHubGrpcClient
from durabletask.worker import TaskHubGrpcWorker
from agent_framework import ChatAgent
from agent_framework import Agent
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework_durabletask import DurableAIAgentClient, DurableAIAgentWorker
from durabletask.client import TaskHubGrpcClient
from durabletask.worker import TaskHubGrpcWorker
# Client side
dt_client = TaskHubGrpcClient(host_address="localhost:4001")
agent_client = DurableAIAgentClient(dt_client)
agent = agent_client.get_agent("assistant")
response = agent.run("Hello, how are you?")
print(response.text)
durable_agent = agent_client.get_agent("assistant")
# Worker side
dt_worker = TaskHubGrpcWorker(host_address="localhost:4001")
@@ -48,10 +46,8 @@ agent_worker = DurableAIAgentWorker(dt_worker)
# Create a chat client for the agent
chat_client = AzureOpenAIChatClient()
my_agent = ChatAgent(chat_client=chat_client, name="assistant")
my_agent = Agent(client=chat_client, name="assistant")
agent_worker.add_agent(my_agent)
dt_worker.start()
```
## Import Path
+8 -7
View File
@@ -15,17 +15,18 @@ The durable task integration lets you host Microsoft Agent Framework agents usin
### Basic Usage Example
```python
from agent_framework import Agent
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework_durabletask import DurableAIAgentWorker
from durabletask.worker import TaskHubGrpcWorker
from agent_framework.azure import DurableAIAgentWorker
# Create the worker
with TaskHubGrpcWorker(...) as worker:
worker = TaskHubGrpcWorker(host_address="localhost:4001")
agent_worker = DurableAIAgentWorker(worker)
# Register the agent worker wrapper
agent_worker = DurableAIAgentWorker(worker)
# Register the agent
agent_worker.add_agent(my_agent)
chat_client = AzureOpenAIChatClient()
my_agent = Agent(client=chat_client, name="assistant")
agent_worker.add_agent(my_agent)
```
For more details, review the Python [README](https://github.com/microsoft/agent-framework/tree/main/python/README.md) and the samples directory.
@@ -29,9 +29,10 @@ class DurableAIAgentWorker:
Example:
```python
from durabletask import TaskHubGrpcWorker
from durabletask.worker import TaskHubGrpcWorker
from agent_framework import Agent
from agent_framework.azure import DurableAIAgentWorker
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework_durabletask import DurableAIAgentWorker
# Create the underlying worker
worker = TaskHubGrpcWorker(host_address="localhost:4001")
@@ -40,6 +41,7 @@ class DurableAIAgentWorker:
agent_worker = DurableAIAgentWorker(worker)
# Register agents
client = AzureOpenAIChatClient()
my_agent = Agent(client=client, name="assistant")
agent_worker.add_agent(my_agent)
+5 -5
View File
@@ -23,14 +23,14 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"durabletask>=1.3.0",
"durabletask-azuremanaged>=1.3.0",
"python-dateutil>=2.8.0",
"durabletask>=1.3.0,<2",
"durabletask-azuremanaged>=1.3.0,<2",
"python-dateutil>=2.8.0,<3",
]
[dependency-groups]
dev = [
"types-python-dateutil>=2.9.0",
"types-python-dateutil==2.9.0.20260305",
]
[tool.uv]
@@ -99,7 +99,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_durabletask"
test = "pytest -m \"not integration\" --cov=agent_framework_durabletask --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_durabletask --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
+2 -2
View File
@@ -24,7 +24,7 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"foundry-local-sdk>=0.5.1,<1",
"foundry-local-sdk>=0.5.1,<0.5.2",
]
[tool.uv]
@@ -86,7 +86,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_foundry_local"
test = "pytest -m \"not integration\" --cov=agent_framework_foundry_local --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_foundry_local --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
@@ -25,20 +25,27 @@ from agent_framework._settings import load_settings
from agent_framework._tools import FunctionTool, ToolTypes
from agent_framework._types import AgentRunInputs, normalize_tools
from agent_framework.exceptions import AgentException
from copilot import CopilotClient, CopilotSession
from copilot.generated.session_events import PermissionRequest, SessionEvent, SessionEventType
from copilot.types import (
CopilotClientOptions,
MCPServerConfig,
MessageOptions,
PermissionRequestResult,
ResumeSessionConfig,
SessionConfig,
SystemMessageConfig,
ToolInvocation,
ToolResult,
)
from copilot.types import Tool as CopilotTool
try:
from copilot import CopilotClient, CopilotSession
from copilot.generated.session_events import PermissionRequest, SessionEvent, SessionEventType
from copilot.types import (
CopilotClientOptions,
MCPServerConfig,
MessageOptions,
PermissionRequestResult,
ResumeSessionConfig,
SessionConfig,
SystemMessageConfig,
ToolInvocation,
ToolResult,
)
from copilot.types import Tool as CopilotTool
except ImportError as _copilot_import_error:
raise ImportError(
"GitHubCopilotAgent requires the 'github-copilot-sdk' package, which is only available on Python 3.11+. "
"Please use Python 3.11 or later."
) from _copilot_import_error
if sys.version_info >= (3, 13):
from typing import TypeVar
+11 -3
View File
@@ -3,7 +3,7 @@ name = "agent-framework-github-copilot"
description = "GitHub Copilot integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.11"
requires-python = ">=3.10"
version = "1.0.0b260311"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
@@ -15,6 +15,7 @@ classifiers = [
"Development Status :: 4 - Beta",
"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",
@@ -23,7 +24,7 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"github-copilot-sdk>=0.1.32",
"github-copilot-sdk>=0.1.31,<0.1.33; python_version >= '3.11'",
]
[tool.uv]
@@ -85,9 +86,16 @@ executor.type = "uv"
include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_github_copilot"
test = "pytest -m \"not integration\" --cov=agent_framework_github_copilot --cov-report=term-missing:skip-covered tests"
[tool.poe.tasks.pyright]
shell = "python -c \"import sys; exit(0 if sys.version_info < (3,11) else 1)\" || pyright"
interpreter = "posix"
[tool.poe.tasks.mypy]
shell = "python -c \"import sys; exit(0 if sys.version_info < (3,11) else 1)\" || mypy --config-file $POE_ROOT/pyproject.toml agent_framework_github_copilot"
interpreter = "posix"
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
build-backend = "flit_core.buildapi"
@@ -1,5 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
# ruff: noqa: E402
import unittest.mock
from datetime import datetime, timezone
from typing import Any
@@ -7,6 +9,9 @@ from unittest.mock import AsyncMock, MagicMock, patch
from uuid import uuid4
import pytest
copilot = pytest.importorskip("copilot")
from agent_framework import (
AgentResponse,
AgentResponseUpdate,
+21
View File
@@ -62,6 +62,27 @@ For example, to use the GAIA module:
from agent_framework.lab.gaia import GAIA
```
## Running Tests Locally
For machine-safe local runs, prefer package-scoped commands first:
```bash
uv run --directory packages/lab poe test
uv run --directory packages/lab pytest -q -m "not integration"
```
When you need to run package tasks from the repository root, use sequential mode to avoid launching all package tests in parallel:
```bash
uv run poe test --seq
```
Lightning observability tests intentionally exercise heavier tracing paths and are marked as `resource_intensive`:
```bash
uv run --directory packages/lab pytest lightning/tests/test_lightning.py -m "resource_intensive" -q
```
## Should I consume Lab Modules?
If you are looking for stable and production-ready features, you should not use lab modules. Stick to the core framework.
@@ -10,10 +10,11 @@ import re
import string
import tempfile
import time
from collections.abc import Iterable
from collections.abc import Callable, Iterable
from datetime import datetime
from functools import lru_cache
from pathlib import Path
from typing import Any, cast
from typing import Any, Protocol, cast
from opentelemetry.trace import NoOpTracer, SpanKind, get_tracer
from tqdm import tqdm
@@ -23,6 +24,33 @@ from ._types import Evaluation, Evaluator, Prediction, Task, TaskResult, TaskRun
__all__ = ["GAIA", "GAIATelemetryConfig", "gaia_scorer"]
class _OrjsonModule(Protocol):
def dumps(self, obj: object, /, default: Callable[[Any], object] | None = None) -> bytes: ...
def loads(self, obj: str | bytes | bytearray, /) -> object: ...
@lru_cache(maxsize=1)
def _get_orjson() -> _OrjsonModule | None:
try:
import orjson as runtime_orjson # pyright: ignore[reportMissingImports]
except ImportError:
return None
return cast(_OrjsonModule, runtime_orjson)
def _dump_json_line(value: object) -> str:
if (runtime_orjson := _get_orjson()) is not None:
return runtime_orjson.dumps(value, default=str).decode("utf-8")
return json.dumps(value, default=str)
def _load_json_value(value: str | bytes) -> object:
if (runtime_orjson := _get_orjson()) is not None:
return runtime_orjson.loads(value)
return json.loads(value)
class GAIATelemetryConfig:
"""Configuration for GAIA telemetry and tracing."""
@@ -226,13 +254,7 @@ def _read_jsonl(path: Path) -> Iterable[dict[str, Any]]:
for line in f:
if not line.strip():
continue
parsed: object
try:
import orjson
parsed = orjson.loads(line)
except Exception:
parsed = json.loads(line)
parsed = _load_json_value(line)
record = _coerce_record(parsed)
if record is not None:
@@ -620,12 +642,7 @@ class GAIA:
"prediction_metadata": result.prediction.metadata,
"evaluation_details": result.evaluation.details,
}
try:
import orjson
f.write(orjson.dumps(record, default=str).decode("utf-8") + "\n")
except ImportError:
f.write(json.dumps(record, default=str) + "\n")
f.write(_dump_json_line(record) + "\n")
def viewer_main() -> None:
@@ -646,13 +663,7 @@ def viewer_main() -> None:
with open(args.results_file, encoding="utf-8") as f:
for line in f:
if line.strip():
try:
import orjson
parsed: object = orjson.loads(line)
except ImportError:
parsed = json.loads(line)
parsed = _load_json_value(line)
record = _coerce_record(parsed)
if record is not None:
results.append(record)
@@ -2,10 +2,14 @@
"""RL Module for Microsoft Agent Framework."""
from __future__ import annotations
import importlib.metadata
from agent_framework.observability import enable_instrumentation
from agentlightning import AgentOpsTracer # type: ignore
from agentlightning.tracer import (
AgentOpsTracer, # pyright: ignore[reportMissingImports] # type: ignore[import-not-found]
)
try:
__version__ = importlib.metadata.version(__name__)
@@ -23,11 +27,11 @@ class AgentFrameworkTracer(AgentOpsTracer): # type: ignore
def init(self) -> None:
"""Initialize the agent-framework-lab-lightning for training."""
enable_instrumentation()
super().init()
super().init() # pyright: ignore[reportUnknownMemberType]
def teardown(self) -> None:
"""Teardown the agent-framework-lab-lightning for training."""
super().teardown()
super().teardown() # pyright: ignore[reportUnknownMemberType]
__all__: list[str] = ["AgentFrameworkTracer"]
@@ -7,12 +7,8 @@ from unittest.mock import AsyncMock, patch
import pytest
agentlightning = pytest.importorskip("agentlightning")
from agent_framework import AgentExecutor, AgentResponse, Agent, WorkflowBuilder, Workflow
from agent_framework_lab_lightning import AgentFrameworkTracer
from agent_framework.openai import OpenAIChatClient
from agentlightning import TracerTraceToTriplet
from openai.types.chat import ChatCompletion, ChatCompletionMessage
from openai.types.chat.chat_completion import Choice
@@ -118,6 +114,7 @@ async def test_openai_workflow_two_agents(workflow_two_agents: Workflow):
)
@pytest.mark.resource_intensive
async def test_observability(workflow_two_agents: Workflow):
r"""Expected trace tree:
@@ -129,6 +126,10 @@ async def test_observability(workflow_two_agents: Workflow):
| |
[chat gpt-4o] [chat gpt-4o]
"""
pytest.importorskip("agentlightning")
from agent_framework_lab_lightning import AgentFrameworkTracer
from agentlightning.adapter import TracerTraceToTriplet
tracer = AgentFrameworkTracer()
try:
tracer.init()
+17 -17
View File
@@ -32,8 +32,8 @@ gaia = [
"opentelemetry-api>=1.39.0",
"tqdm>=4.60.0",
"huggingface-hub>=0.20.0",
"orjson>=3.8.0",
"pyarrow>=10.0.0", # For reading parquet files
"orjson>=3.10.7,<4",
"pyarrow>=18.0.0", # For reading parquet files
]
# Lightning RL training module dependencies
@@ -56,19 +56,19 @@ math = [
[dependency-groups]
dev = [
"uv",
"ruff>=0.11.8",
"pytest>=8.4.1",
"mypy>=1.16.1",
"pyright>=1.1.402",
"uv==0.10.9",
"ruff==0.15.5",
"pytest==9.0.2",
"mypy==1.19.1",
"pyright==1.1.408",
#tasks
"poethepoet>=0.36.0",
"rich",
"tomli",
"tomli-w",
"poethepoet==0.42.1",
"rich==13.7.1",
"tomli==2.4.0",
"tomli-w==1.2.0",
# tau2 from source (not available on PyPI)
"tau2@ git+https://github.com/sierra-research/tau2-bench@5ba9e3e56db57c5e4114bf7f901291f09b2c5619",
"prek>=0.3.2",
"prek==0.3.4",
]
[project.scripts]
@@ -144,7 +144,6 @@ targets = ["agent_framework_lab_gaia", "agent_framework_lab_lightning", "agent_f
exclude_dirs = ["gaia/tests", "lightning/tests", "tau2/tests"]
[tool.poe]
executor.type = "uv"
include = "../../shared_tasks.toml"
[tool.poe.tasks]
@@ -152,10 +151,10 @@ mypy-gaia = "mypy --config-file $POE_ROOT/pyproject.toml gaia/agent_framework_la
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 -m \"not integration\" --cov-report=term-missing:skip-covered --junitxml=test-results.xml"
test-gaia = "pytest -m \"not integration\" gaia/tests --cov=agent_framework_lab_gaia --cov-report=term-missing:skip-covered"
test-lightning = "pytest -m \"not integration\" lightning/tests --cov=agent_framework_lab_lightning --cov-report=term-missing:skip-covered"
test-tau2 = "pytest -m \"not integration\" tau2/tests --cov=agent_framework_lab_tau2 --cov-report=term-missing:skip-covered"
test = 'pytest -m "not integration and not resource_intensive" --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"
build = "echo 'Skipping build'"
publish = "echo 'Skipping publish'"
@@ -167,4 +166,5 @@ asyncio_default_fixture_loop_scope = "function"
markers = [
"unit: marks tests as unit tests",
"integration: marks tests as integration tests",
"resource_intensive: marks tests that are expensive and excluded from default package test runs",
]
@@ -2,62 +2,39 @@
"""Tests for tau2 utils module."""
import urllib.request
from pathlib import Path
import pytest
from agent_framework import Content, FunctionTool, Message
from agent_framework_lab_tau2._tau2_utils import (
convert_agent_framework_messages_to_tau2_messages,
convert_tau2_tool_to_function_tool,
)
from pydantic import BaseModel
from tau2.data_model.message import AssistantMessage, SystemMessage, ToolCall, ToolMessage, UserMessage
from tau2.domains.airline.data_model import FlightDB
from tau2.domains.airline.tools import AirlineTools
from tau2.environment.environment import Environment
@pytest.fixture(scope="session")
def tau2_airline_environment() -> Environment:
airline_db_remote_path = "https://raw.githubusercontent.com/sierra-research/tau2-bench/5ba9e3e56db57c5e4114bf7f901291f09b2c5619/data/tau2/domains/airline/db.json"
airline_policy_remote_path = "https://raw.githubusercontent.com/sierra-research/tau2-bench/5ba9e3e56db57c5e4114bf7f901291f09b2c5619/data/tau2/domains/airline/policy.md"
# Create cache directory
cache_dir = Path(__file__).parent / "data"
cache_dir.mkdir(exist_ok=True)
# Define cache file paths
db_cache_path = cache_dir / "airline_db.json"
policy_cache_path = cache_dir / "airline_policy.md"
# Download files only if they don't exist in cache
if not db_cache_path.exists():
urllib.request.urlretrieve(airline_db_remote_path, db_cache_path)
if not policy_cache_path.exists():
urllib.request.urlretrieve(airline_policy_remote_path, policy_cache_path)
# Load data from cached files
db = FlightDB.load(str(db_cache_path))
tools = AirlineTools(db)
with open(policy_cache_path) as fp:
policy = fp.read()
yield Environment(
domain_name="airline",
policy=policy,
tools=tools,
)
class _DummyToolInput(BaseModel):
param: str
def test_convert_tau2_tool_to_function_tool_basic(tau2_airline_environment):
class _DummyToolResult(BaseModel):
output: str
class _DummyTau2Tool:
def __init__(self, name: str, description: str) -> None:
self.name = name
self._description = description
self.params = _DummyToolInput
def _get_description(self) -> str:
return self._description
def __call__(self, **kwargs: str) -> _DummyToolResult:
return _DummyToolResult(output=kwargs["param"])
def test_convert_tau2_tool_to_function_tool_basic():
"""Test basic conversion from tau2 tool to FunctionTool."""
# Get real tools from tau2 environment
tools = tau2_airline_environment.get_tools()
# Use the first available tool for testing
assert len(tools) > 0, "No tools available in environment"
tau2_tool = tools[0]
tau2_tool = _DummyTau2Tool(name="lookup_booking", description="Lookup booking by id.")
# Convert the tool
tool = convert_tau2_tool_to_function_tool(tau2_tool)
@@ -68,20 +45,25 @@ def test_convert_tau2_tool_to_function_tool_basic(tau2_airline_environment):
assert tool.description == tau2_tool._get_description()
assert tool.input_model == tau2_tool.params
# Test that the function is callable (we won't call it with real params to avoid side effects)
result = tool.func(param="ABC123")
assert isinstance(result, _DummyToolResult)
assert result.output == "ABC123"
assert callable(tool.func)
def test_convert_tau2_tool_to_function_tool_multiple_tools(tau2_airline_environment):
def test_convert_tau2_tool_to_function_tool_multiple_tools():
"""Test conversion with multiple tau2 tools."""
# Get real tools from tau2 environment
tools = tau2_airline_environment.get_tools()
tools = [
_DummyTau2Tool(name="lookup_booking", description="Lookup booking by id."),
_DummyTau2Tool(name="cancel_booking", description="Cancel an existing booking."),
_DummyTau2Tool(name="check_policy", description="Get policy details."),
]
# Convert multiple tools
function_tools = [convert_tau2_tool_to_function_tool(tool) for tool in tools[:3]] # Test first 3 tools
function_tools = [convert_tau2_tool_to_function_tool(tool) for tool in tools]
# Verify all conversions
for tool, tau2_tool in zip(function_tools, tools[:3], strict=False):
for tool, tau2_tool in zip(function_tools, tools, strict=False):
assert isinstance(tool, FunctionTool)
assert tool.name == tau2_tool.name
assert tool.description == tau2_tool._get_description()
+8 -6
View File
@@ -4,23 +4,25 @@ Integration with Mem0 for agent memory management.
## Main Classes
- **`Mem0Provider`** - Context provider that integrates Mem0 memory into agents
- **`Mem0ContextProvider`** - Context provider that integrates Mem0 memory into agents
## Usage
```python
from agent_framework.mem0 import Mem0Provider
from agent_framework.mem0 import Mem0ContextProvider
provider = Mem0Provider(api_key="your-key")
agent = Agent(..., context_provider=provider)
provider = Mem0ContextProvider(
api_key="your-key",
user_id="user-id",
)
```
## Import Path
```python
from agent_framework.mem0 import Mem0Provider
from agent_framework.mem0 import Mem0ContextProvider
# or directly:
from agent_framework_mem0 import Mem0Provider
from agent_framework_mem0 import Mem0ContextProvider
```
## Notes
+2 -2
View File
@@ -24,7 +24,7 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"mem0ai>=1.0.0",
"mem0ai>=1.0.0,<2",
]
[tool.uv]
@@ -87,7 +87,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_mem0"
test = "pytest -m \"not integration\" --cov=agent_framework_mem0 --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_mem0 --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
+2 -2
View File
@@ -24,7 +24,7 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"ollama >= 0.5.3",
"ollama>=0.5.3,<0.5.4",
]
[tool.uv]
@@ -90,7 +90,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_ollama"
test = "pytest -m \"not integration\" --cov=agent_framework_ollama --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_ollama --cov-report=term-missing:skip-covered tests'
[tool.uv.build-backend]
module-name = "agent_framework_ollama"
@@ -85,7 +85,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_orchestrations"
test = "pytest -m \"not integration\" --cov=agent_framework_orchestrations --cov-report=term-missing:skip-covered -n auto --dist worksteal tests"
test = 'pytest -m "not integration" --cov=agent_framework_orchestrations --cov-report=term-missing:skip-covered -n auto --dist worksteal tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]
+3 -3
View File
@@ -25,8 +25,8 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"azure-core>=1.30.0",
"httpx>=0.27.0",
"azure-core>=1.30.0,<2",
"httpx>=0.27.0,<0.29",
]
[tool.uv]
@@ -86,7 +86,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_purview"
test = "pytest -m \"not integration\" --cov=agent_framework_purview --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_purview --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.9,<4.0"]
+7 -7
View File
@@ -4,22 +4,22 @@ Redis-based storage for agent threads and context.
## Main Classes
- **`RedisChatMessageStore`** - Persistent message store using Redis
- **`RedisProvider`** - Context provider with Redis backing
- **`RedisHistoryProvider`** - Persistent chat history provider using Redis
- **`RedisContextProvider`** - Context provider with Redis-backed retrieval
## Usage
```python
from agent_framework.redis import RedisChatMessageStore
from agent_framework.redis import RedisContextProvider, RedisHistoryProvider
store = RedisChatMessageStore(redis_url="redis://localhost:6379")
agent = Agent(..., chat_message_store_factory=lambda: store)
context_provider = RedisContextProvider(redis_url="redis://localhost:6379")
history_provider = RedisHistoryProvider(redis_url="redis://localhost:6379")
```
## Import Path
```python
from agent_framework.redis import RedisChatMessageStore, RedisProvider
from agent_framework.redis import RedisContextProvider, RedisHistoryProvider
# or directly:
from agent_framework_redis import RedisChatMessageStore
from agent_framework_redis import RedisContextProvider, RedisHistoryProvider
```
+3 -3
View File
@@ -10,15 +10,15 @@ pip install agent-framework-redis --pre
### Memory Context Provider
The `RedisProvider` enables persistent context & memory capabilities for your agents, allowing them to remember user preferences and conversation context across sessions and threads.
The `RedisContextProvider` enables persistent context and memory capabilities for your agents, allowing them to remember user preferences and conversation context across sessions and threads.
#### Basic Usage Examples
Review the set of [getting started examples](../../samples/02-agents/context_providers/redis/README.md) for using the Redis context provider.
### Redis Chat Message Store
### Redis History Provider
The `RedisChatMessageStore` provides persistent conversation storage using Redis Lists, enabling chat history to survive application restarts and support distributed applications.
The `RedisHistoryProvider` provides persistent conversation storage using Redis Lists, enabling chat history to survive application restarts and support distributed applications.
#### Key Features
+4 -4
View File
@@ -24,9 +24,9 @@ classifiers = [
]
dependencies = [
"agent-framework-core>=1.0.0rc4",
"redis>=6.4.0",
"redisvl>=0.8.2",
"numpy>=2.2.6"
"redis>=6.4.0,<7.2.1",
"redisvl>=0.11.0,<0.16",
"numpy>=2.2.6,<3"
]
[tool.uv]
@@ -89,7 +89,7 @@ include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_redis"
test = "pytest -m \"not integration\" --cov=agent_framework_redis --cov-report=term-missing:skip-covered tests"
test = 'pytest -m "not integration" --cov=agent_framework_redis --cov-report=term-missing:skip-covered tests'
[build-system]
requires = ["flit-core >= 3.11,<4.0"]