chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:25 +08:00
commit db620d33df
5151 changed files with 925932 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
# Anthropic Package (agent-framework-anthropic)
Integration with Anthropic's Claude API.
## Main Classes
- **`AnthropicClient`** - Chat client for Anthropic Claude models
- **`AnthropicFoundryClient`** - Anthropic chat client for Azure AI Foundry's Anthropic-compatible endpoint
- **`AnthropicBedrockClient`** - Anthropic chat client for Amazon Bedrock
- **`AnthropicVertexClient`** - Anthropic chat client for Google Vertex AI
- **`AnthropicChatOptions`** - Options TypedDict for Anthropic-specific parameters
## Usage
```python
from agent_framework.anthropic import AnthropicClient
client = AnthropicClient(model="claude-sonnet-4-20250514")
response = await client.get_response("Hello")
```
## Import Path
```python
from agent_framework.anthropic import AnthropicClient
# or directly:
from agent_framework_anthropic import AnthropicClient
```
+21
View File
@@ -0,0 +1,21 @@
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
+42
View File
@@ -0,0 +1,42 @@
# Get Started with Microsoft Agent Framework Anthropic
Please install this package via pip:
```bash
pip install agent-framework-anthropic --pre
```
## Anthropic Integration
The Anthropic integration enables communication with the Anthropic API, allowing your Agent Framework applications to leverage Anthropic's capabilities.
The package also includes Anthropic-hosted transport wrappers for:
- Azure AI Foundry via `AnthropicFoundryClient`
- Amazon Bedrock via `AnthropicBedrockClient`
- Google Vertex AI via `AnthropicVertexClient`
### Basic Usage Example
See the [Anthropic agent examples](../../samples/02-agents/providers/anthropic/) which demonstrate:
- Connecting to a Anthropic endpoint with an agent
- Streaming and non-streaming responses
### Structured system blocks for prompt caching
Use `instructions` with Anthropic-native system blocks when you need structured system prompt content, such as
prompt-cache `cache_control` metadata. Do not combine structured `instructions` blocks with a leading system message.
```python
from anthropic.types.beta import BetaTextBlockParam
from agent_framework_anthropic import AnthropicClient
client = AnthropicClient()
system_blocks: list[BetaTextBlockParam] = [
{"type": "text", "text": "Stable instructions", "cache_control": {"type": "ephemeral", "ttl": "1h"}},
]
response = await client.get_response("Hello", options={"instructions": system_blocks})
```
@@ -0,0 +1,30 @@
# Copyright (c) Microsoft. All rights reserved.
import importlib.metadata
from ._bedrock_client import AnthropicBedrockClient, RawAnthropicBedrockClient
from ._chat_client import (
AnthropicChatOptions,
AnthropicClient,
RawAnthropicClient,
)
from ._foundry_client import AnthropicFoundryClient, RawAnthropicFoundryClient
from ._vertex_client import AnthropicVertexClient, RawAnthropicVertexClient
try:
__version__ = importlib.metadata.version(__name__)
except importlib.metadata.PackageNotFoundError:
__version__ = "0.0.0" # Fallback for development mode
__all__ = [
"AnthropicBedrockClient",
"AnthropicChatOptions",
"AnthropicClient",
"AnthropicFoundryClient",
"AnthropicVertexClient",
"RawAnthropicBedrockClient",
"RawAnthropicClient",
"RawAnthropicFoundryClient",
"RawAnthropicVertexClient",
"__version__",
]
@@ -0,0 +1,168 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
from collections.abc import Sequence
from typing import Any, ClassVar, Generic, TypedDict
from agent_framework import (
ChatAndFunctionMiddlewareTypes,
ChatMiddlewareLayer,
FunctionInvocationConfiguration,
FunctionInvocationLayer,
)
from agent_framework._settings import SecretString, load_settings
from agent_framework._telemetry import get_user_agent
from agent_framework.observability import ChatTelemetryLayer
from anthropic.lib.bedrock import AsyncAnthropicBedrock
from ._chat_client import AnthropicOptionsT, RawAnthropicClient
class AnthropicBedrockSettings(TypedDict, total=False):
"""Resolved settings for Anthropic Bedrock wrappers."""
aws_access_key_id: SecretString | None
aws_secret_access_key: SecretString | None
aws_region: str | None
aws_profile: str | None
aws_session_token: SecretString | None
anthropic_bedrock_base_url: str | None
anthropic_chat_model: str | None
class RawAnthropicBedrockClient(RawAnthropicClient[AnthropicOptionsT], Generic[AnthropicOptionsT]):
"""Raw Anthropic Bedrock chat client without middleware, telemetry, or function invocation support."""
OTEL_PROVIDER_NAME: ClassVar[str] = "aws.bedrock"
def __init__(
self,
*,
model: str | None = None,
aws_secret_key: str | None = None,
aws_access_key: str | None = None,
aws_region: str | None = None,
aws_profile: str | None = None,
aws_session_token: str | None = None,
base_url: str | None = None,
anthropic_client: AsyncAnthropicBedrock | None = None,
additional_beta_flags: list[str] | None = None,
additional_properties: dict[str, Any] | None = None,
env_file_path: str | None = None,
env_file_encoding: str | None = None,
) -> None:
"""Initialize a raw Anthropic Bedrock client.
Keyword Args:
model: The Anthropic model to use.
aws_secret_key: AWS secret access key.
aws_access_key: AWS access key ID.
aws_region: AWS region.
aws_profile: AWS profile name.
aws_session_token: AWS session token.
base_url: Optional custom Anthropic Bedrock base URL.
anthropic_client: Existing AsyncAnthropicBedrock client to reuse.
additional_beta_flags: Additional beta flags to enable on the client.
additional_properties: Additional properties stored on the client instance.
env_file_path: Path to environment file for loading settings.
env_file_encoding: Encoding of the environment file.
"""
settings = load_settings(
AnthropicBedrockSettings,
env_prefix="",
aws_access_key_id=aws_access_key,
aws_secret_access_key=aws_secret_key,
aws_region=aws_region,
aws_profile=aws_profile,
aws_session_token=aws_session_token,
anthropic_bedrock_base_url=base_url,
anthropic_chat_model=model,
env_file_path=env_file_path,
env_file_encoding=env_file_encoding,
)
model_setting = settings.get("anthropic_chat_model")
access_key_secret = settings.get("aws_access_key_id")
secret_key_secret = settings.get("aws_secret_access_key")
session_token_secret = settings.get("aws_session_token")
if anthropic_client is None:
anthropic_client = AsyncAnthropicBedrock(
aws_secret_key=secret_key_secret.get_secret_value() if secret_key_secret is not None else None,
aws_access_key=access_key_secret.get_secret_value() if access_key_secret is not None else None,
aws_region=settings.get("aws_region"),
aws_profile=settings.get("aws_profile"),
aws_session_token=session_token_secret.get_secret_value() if session_token_secret is not None else None,
base_url=settings.get("anthropic_bedrock_base_url"),
default_headers={"User-Agent": get_user_agent()},
)
super().__init__(
model=model_setting,
anthropic_client=anthropic_client,
additional_beta_flags=additional_beta_flags,
additional_properties=additional_properties,
)
class AnthropicBedrockClient(
FunctionInvocationLayer[AnthropicOptionsT],
ChatMiddlewareLayer[AnthropicOptionsT],
ChatTelemetryLayer[AnthropicOptionsT],
RawAnthropicBedrockClient[AnthropicOptionsT],
Generic[AnthropicOptionsT],
):
"""Anthropic Bedrock chat client with middleware, telemetry, and function invocation support."""
def __init__(
self,
*,
model: str | None = None,
aws_secret_key: str | None = None,
aws_access_key: str | None = None,
aws_region: str | None = None,
aws_profile: str | None = None,
aws_session_token: str | None = None,
base_url: str | None = None,
anthropic_client: AsyncAnthropicBedrock | None = None,
additional_beta_flags: list[str] | None = None,
additional_properties: dict[str, Any] | None = None,
middleware: Sequence[ChatAndFunctionMiddlewareTypes] | None = None,
function_invocation_configuration: FunctionInvocationConfiguration | None = None,
env_file_path: str | None = None,
env_file_encoding: str | None = None,
) -> None:
"""Initialize an Anthropic Bedrock client.
Keyword Args:
model: The Anthropic model to use.
aws_secret_key: AWS secret access key.
aws_access_key: AWS access key ID.
aws_region: AWS region.
aws_profile: AWS profile name.
aws_session_token: AWS session token.
base_url: Optional custom Anthropic Bedrock base URL.
anthropic_client: Existing AsyncAnthropicBedrock client to reuse.
additional_beta_flags: Additional beta flags to enable on the client.
additional_properties: Additional properties stored on the client instance.
middleware: Optional middleware to apply to the client.
function_invocation_configuration: Optional function invocation configuration override.
env_file_path: Path to environment file for loading settings.
env_file_encoding: Encoding of the environment file.
"""
super().__init__(
model=model,
aws_secret_key=aws_secret_key,
aws_access_key=aws_access_key,
aws_region=aws_region,
aws_profile=aws_profile,
aws_session_token=aws_session_token,
base_url=base_url,
anthropic_client=anthropic_client,
additional_beta_flags=additional_beta_flags,
additional_properties=additional_properties,
middleware=middleware,
function_invocation_configuration=function_invocation_configuration,
env_file_path=env_file_path,
env_file_encoding=env_file_encoding,
)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,166 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
from collections.abc import Awaitable, Callable, Sequence
from typing import Any, ClassVar, Generic, TypedDict
from agent_framework import (
ChatAndFunctionMiddlewareTypes,
ChatMiddlewareLayer,
FunctionInvocationConfiguration,
FunctionInvocationLayer,
)
from agent_framework._settings import SecretString, load_settings
from agent_framework._telemetry import get_user_agent
from agent_framework.observability import ChatTelemetryLayer
from anthropic import AsyncAnthropicFoundry
from ._chat_client import AnthropicOptionsT, RawAnthropicClient
AnthropicFoundryAzureADTokenProvider = Callable[[], str | Awaitable[str]]
class AnthropicFoundrySettings(TypedDict, total=False):
"""Resolved settings for Anthropic Foundry wrappers."""
anthropic_foundry_api_key: SecretString | None
anthropic_foundry_resource: str | None
anthropic_foundry_base_url: str | None
anthropic_chat_model: str | None
class RawAnthropicFoundryClient(RawAnthropicClient[AnthropicOptionsT], Generic[AnthropicOptionsT]):
"""Raw Anthropic Foundry chat client without middleware, telemetry, or function invocation support."""
OTEL_PROVIDER_NAME: ClassVar[str] = "azure.ai.foundry"
def __init__(
self,
*,
model: str | None = None,
resource: str | None = None,
api_key: str | None = None,
azure_ad_token_provider: AnthropicFoundryAzureADTokenProvider | None = None,
base_url: str | None = None,
anthropic_client: AsyncAnthropicFoundry | None = None,
additional_beta_flags: list[str] | None = None,
additional_properties: dict[str, Any] | None = None,
env_file_path: str | None = None,
env_file_encoding: str | None = None,
) -> None:
"""Initialize a raw Anthropic Foundry client.
Keyword Args:
model: The Anthropic model to use.
resource: The Foundry resource name.
api_key: The Foundry Anthropic API key.
azure_ad_token_provider: Azure AD token provider used by the Anthropic SDK.
base_url: Full Anthropic-compatible Foundry base URL.
anthropic_client: Existing AsyncAnthropicFoundry client to reuse.
additional_beta_flags: Additional beta flags to enable on the client.
additional_properties: Additional properties stored on the client instance.
env_file_path: Path to environment file for loading settings.
env_file_encoding: Encoding of the environment file.
"""
settings = load_settings(
AnthropicFoundrySettings,
env_prefix="",
anthropic_foundry_api_key=api_key,
anthropic_foundry_resource=resource,
anthropic_foundry_base_url=base_url,
anthropic_chat_model=model,
env_file_path=env_file_path,
env_file_encoding=env_file_encoding,
)
api_key_secret = settings.get("anthropic_foundry_api_key")
model_setting = settings.get("anthropic_chat_model")
resource_setting = settings.get("anthropic_foundry_resource")
base_url_setting = settings.get("anthropic_foundry_base_url")
api_key_value = api_key_secret.get_secret_value() if api_key_secret is not None else None
if anthropic_client is None:
if base_url_setting is None and resource_setting is None:
message = (
"Anthropic Foundry requires either `resource`/`ANTHROPIC_FOUNDRY_RESOURCE` "
"or `base_url`/`ANTHROPIC_FOUNDRY_BASE_URL`."
)
raise ValueError(message)
if base_url_setting is not None:
anthropic_client = AsyncAnthropicFoundry(
base_url=base_url_setting,
api_key=api_key_value,
azure_ad_token_provider=azure_ad_token_provider,
default_headers={"User-Agent": get_user_agent()},
)
else:
anthropic_client = AsyncAnthropicFoundry(
resource=resource_setting,
api_key=api_key_value,
azure_ad_token_provider=azure_ad_token_provider,
default_headers={"User-Agent": get_user_agent()},
)
super().__init__(
model=model_setting,
anthropic_client=anthropic_client,
additional_beta_flags=additional_beta_flags,
additional_properties=additional_properties,
)
class AnthropicFoundryClient(
FunctionInvocationLayer[AnthropicOptionsT],
ChatMiddlewareLayer[AnthropicOptionsT],
ChatTelemetryLayer[AnthropicOptionsT],
RawAnthropicFoundryClient[AnthropicOptionsT],
Generic[AnthropicOptionsT],
):
"""Anthropic Foundry chat client with middleware, telemetry, and function invocation support."""
def __init__(
self,
*,
model: str | None = None,
resource: str | None = None,
api_key: str | None = None,
azure_ad_token_provider: AnthropicFoundryAzureADTokenProvider | None = None,
base_url: str | None = None,
anthropic_client: AsyncAnthropicFoundry | None = None,
additional_beta_flags: list[str] | None = None,
additional_properties: dict[str, Any] | None = None,
middleware: Sequence[ChatAndFunctionMiddlewareTypes] | None = None,
function_invocation_configuration: FunctionInvocationConfiguration | None = None,
env_file_path: str | None = None,
env_file_encoding: str | None = None,
) -> None:
"""Initialize an Anthropic Foundry client.
Keyword Args:
model: The Anthropic model to use.
resource: The Foundry resource name.
api_key: The Foundry Anthropic API key.
azure_ad_token_provider: Azure AD token provider used by the Anthropic SDK.
base_url: Full Anthropic-compatible Foundry base URL.
anthropic_client: Existing AsyncAnthropicFoundry client to reuse.
additional_beta_flags: Additional beta flags to enable on the client.
additional_properties: Additional properties stored on the client instance.
middleware: Optional middleware to apply to the client.
function_invocation_configuration: Optional function invocation configuration override.
env_file_path: Path to environment file for loading settings.
env_file_encoding: Encoding of the environment file.
"""
super().__init__(
model=model,
resource=resource,
api_key=api_key,
azure_ad_token_provider=azure_ad_token_provider,
base_url=base_url,
anthropic_client=anthropic_client,
additional_beta_flags=additional_beta_flags,
additional_properties=additional_properties,
middleware=middleware,
function_invocation_configuration=function_invocation_configuration,
env_file_path=env_file_path,
env_file_encoding=env_file_encoding,
)
@@ -0,0 +1,161 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
from collections.abc import Sequence
from typing import TYPE_CHECKING, Any, ClassVar, Generic, TypedDict
from agent_framework import (
ChatAndFunctionMiddlewareTypes,
ChatMiddlewareLayer,
FunctionInvocationConfiguration,
FunctionInvocationLayer,
)
from agent_framework._settings import load_settings
from agent_framework._telemetry import get_user_agent
from agent_framework.observability import ChatTelemetryLayer
from anthropic import NOT_GIVEN
from anthropic.lib.vertex import AsyncAnthropicVertex
from ._chat_client import AnthropicOptionsT, RawAnthropicClient
if TYPE_CHECKING:
from google.auth.credentials import Credentials as GoogleCredentials
class AnthropicVertexSettings(TypedDict, total=False):
"""Resolved settings for Anthropic Vertex wrappers."""
cloud_ml_region: str | None
anthropic_vertex_project_id: str | None
anthropic_vertex_base_url: str | None
anthropic_chat_model: str | None
class RawAnthropicVertexClient(RawAnthropicClient[AnthropicOptionsT], Generic[AnthropicOptionsT]):
"""Raw Anthropic Vertex chat client without middleware, telemetry, or function invocation support."""
OTEL_PROVIDER_NAME: ClassVar[str] = "google.vertex.ai"
def __init__(
self,
*,
model: str | None = None,
region: str | None = None,
project_id: str | None = None,
access_token: str | None = None,
credentials: GoogleCredentials | None = None,
base_url: str | None = None,
anthropic_client: AsyncAnthropicVertex | None = None,
additional_beta_flags: list[str] | None = None,
additional_properties: dict[str, Any] | None = None,
env_file_path: str | None = None,
env_file_encoding: str | None = None,
) -> None:
"""Initialize a raw Anthropic Vertex client.
Keyword Args:
model: The Anthropic model to use.
region: Vertex region. Falls back to `CLOUD_ML_REGION`.
project_id: Vertex project ID. Falls back to `ANTHROPIC_VERTEX_PROJECT_ID`.
access_token: Explicit OAuth access token.
credentials: Google credentials object.
base_url: Optional custom Anthropic Vertex base URL.
anthropic_client: Existing AsyncAnthropicVertex client to reuse.
additional_beta_flags: Additional beta flags to enable on the client.
additional_properties: Additional properties stored on the client instance.
env_file_path: Path to environment file for loading settings.
env_file_encoding: Encoding of the environment file.
"""
settings = load_settings(
AnthropicVertexSettings,
env_prefix="",
cloud_ml_region=region,
anthropic_vertex_project_id=project_id,
anthropic_vertex_base_url=base_url,
anthropic_chat_model=model,
env_file_path=env_file_path,
env_file_encoding=env_file_encoding,
)
model_setting = settings.get("anthropic_chat_model")
region_setting = settings.get("cloud_ml_region")
project_id_setting = settings.get("anthropic_vertex_project_id")
if anthropic_client is None:
resolved_region = region_setting if region_setting is not None else NOT_GIVEN
resolved_project_id = project_id_setting if project_id_setting is not None else NOT_GIVEN
anthropic_client = AsyncAnthropicVertex(
region=resolved_region,
project_id=resolved_project_id,
access_token=access_token,
credentials=credentials,
base_url=settings.get("anthropic_vertex_base_url"),
default_headers={"User-Agent": get_user_agent()},
)
super().__init__(
model=model_setting,
anthropic_client=anthropic_client,
additional_beta_flags=additional_beta_flags,
additional_properties=additional_properties,
)
class AnthropicVertexClient(
FunctionInvocationLayer[AnthropicOptionsT],
ChatMiddlewareLayer[AnthropicOptionsT],
ChatTelemetryLayer[AnthropicOptionsT],
RawAnthropicVertexClient[AnthropicOptionsT],
Generic[AnthropicOptionsT],
):
"""Anthropic Vertex chat client with middleware, telemetry, and function invocation support."""
def __init__(
self,
*,
model: str | None = None,
region: str | None = None,
project_id: str | None = None,
access_token: str | None = None,
credentials: GoogleCredentials | None = None,
base_url: str | None = None,
anthropic_client: AsyncAnthropicVertex | None = None,
additional_beta_flags: list[str] | None = None,
additional_properties: dict[str, Any] | None = None,
middleware: Sequence[ChatAndFunctionMiddlewareTypes] | None = None,
function_invocation_configuration: FunctionInvocationConfiguration | None = None,
env_file_path: str | None = None,
env_file_encoding: str | None = None,
) -> None:
"""Initialize an Anthropic Vertex client.
Keyword Args:
model: The Anthropic model to use.
region: Vertex region. Falls back to `CLOUD_ML_REGION`.
project_id: Vertex project ID. Falls back to `ANTHROPIC_VERTEX_PROJECT_ID`.
access_token: Explicit OAuth access token.
credentials: Google credentials object.
base_url: Optional custom Anthropic Vertex base URL.
anthropic_client: Existing AsyncAnthropicVertex client to reuse.
additional_beta_flags: Additional beta flags to enable on the client.
additional_properties: Additional properties stored on the client instance.
middleware: Optional middleware to apply to the client.
function_invocation_configuration: Optional function invocation configuration override.
env_file_path: Path to environment file for loading settings.
env_file_encoding: Encoding of the environment file.
"""
super().__init__(
model=model,
region=region,
project_id=project_id,
access_token=access_token,
credentials=credentials,
base_url=base_url,
anthropic_client=anthropic_client,
additional_beta_flags=additional_beta_flags,
additional_properties=additional_properties,
middleware=middleware,
function_invocation_configuration=function_invocation_configuration,
env_file_path=env_file_path,
env_file_encoding=env_file_encoding,
)
+98
View File
@@ -0,0 +1,98 @@
[project]
name = "agent-framework-anthropic"
description = "Anthropic integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260709"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
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 :: 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",
"Programming Language :: Python :: 3.14",
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.11.0,<2",
"anthropic>=0.80.0,<0.117.0",
]
[tool.uv]
prerelease = "if-necessary-or-explicit"
environments = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform == 'win32'"
]
[tool.uv-dynamic-versioning]
fallback-version = "0.0.0"
[tool.pytest.ini_options]
testpaths = 'tests'
addopts = "-ra -q -r fEX"
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
filterwarnings = [
"ignore:Support for class-based `config` is deprecated:DeprecationWarning:pydantic.*"
]
timeout = 120
markers = [
"integration: marks tests as integration tests that require external services",
]
[tool.ruff]
extend = "../../pyproject.toml"
[tool.coverage.run]
omit = [
"**/__init__.py"
]
[tool.pyright]
extends = "../../pyproject.toml"
exclude = ['tests']
[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_anthropic"]
exclude_dirs = ["tests"]
[tool.poe]
executor.type = "uv"
include = "../../shared_tasks.toml"
[tool.poe.tasks.mypy]
help = "Run MyPy for this package."
cmd = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_anthropic"
[tool.poe.tasks.test]
help = "Run the default unit test suite for this package."
cmd = '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"]
build-backend = "flit_core.buildapi"
Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

@@ -0,0 +1,56 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import Any
from unittest.mock import AsyncMock, MagicMock
from pytest import fixture
@fixture
def exclude_list(request: Any) -> list[str]:
"""Fixture that returns a list of environment variables to exclude."""
return request.param if hasattr(request, "param") else []
@fixture
def override_env_param_dict(request: Any) -> dict[str, str]:
"""Fixture that returns a dict of environment variables to override."""
return request.param if hasattr(request, "param") else {}
@fixture
def anthropic_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): # type: ignore
"""Fixture to set environment variables for AnthropicSettings."""
if exclude_list is None:
exclude_list = []
if override_env_param_dict is None:
override_env_param_dict = {}
env_vars = {
"ANTHROPIC_API_KEY": "test-api-key-12345",
"ANTHROPIC_CHAT_MODEL": "claude-3-5-sonnet-20241022",
}
env_vars.update(override_env_param_dict) # type: ignore
for key, value in env_vars.items():
if key in exclude_list:
monkeypatch.delenv(key, raising=False) # type: ignore
continue
monkeypatch.setenv(key, value) # type: ignore
return env_vars
@fixture
def mock_anthropic_client() -> MagicMock:
"""Fixture that provides a mock AsyncAnthropic client."""
mock_client = MagicMock()
mock_client.base_url = "https://api.anthropic.com"
# Mock beta.messages property
mock_client.beta = MagicMock()
mock_client.beta.messages = MagicMock()
mock_client.beta.messages.create = AsyncMock()
return mock_client
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,222 @@
# Copyright (c) Microsoft. All rights reserved.
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from agent_framework import Agent, ChatMiddlewareLayer, FunctionInvocationLayer
from agent_framework._telemetry import get_user_agent
from agent_framework.observability import ChatTelemetryLayer
from agent_framework_anthropic import (
AnthropicBedrockClient,
AnthropicFoundryClient,
AnthropicVertexClient,
RawAnthropicBedrockClient,
RawAnthropicFoundryClient,
RawAnthropicVertexClient,
)
def _create_mock_transport(base_url: str) -> MagicMock:
transport = MagicMock()
transport.base_url = base_url
transport.beta = MagicMock()
transport.beta.messages = MagicMock()
transport.beta.messages.create = AsyncMock()
return transport
@pytest.mark.parametrize(
("public_client", "raw_client"),
[
(AnthropicFoundryClient, RawAnthropicFoundryClient),
(AnthropicBedrockClient, RawAnthropicBedrockClient),
(AnthropicVertexClient, RawAnthropicVertexClient),
],
)
def test_provider_client_wraps_raw_client_with_standard_layer_order(public_client, raw_client) -> None:
assert issubclass(public_client, raw_client)
mro = public_client.__mro__
assert mro.index(FunctionInvocationLayer) < mro.index(ChatMiddlewareLayer)
assert mro.index(ChatMiddlewareLayer) < mro.index(ChatTelemetryLayer)
assert mro.index(ChatTelemetryLayer) < mro.index(raw_client)
def test_agent_accepts_anthropic_foundry_clients() -> None:
mock_transport = _create_mock_transport("https://test-resource.services.ai.azure.com/anthropic/")
with patch("agent_framework_anthropic._foundry_client.AsyncAnthropicFoundry", return_value=mock_transport):
raw_client = RawAnthropicFoundryClient(
model="claude-foundry-test",
resource="test-resource",
api_key="test-key",
)
raw_agent = Agent(client=raw_client, instructions="test agent")
assert raw_agent.client is raw_client
with patch("agent_framework_anthropic._foundry_client.AsyncAnthropicFoundry", return_value=mock_transport):
client = AnthropicFoundryClient(
model="claude-foundry-test",
resource="test-resource",
api_key="test-key",
)
agent = Agent(client=client, instructions="test agent")
assert agent.client is client
def test_agent_accepts_anthropic_bedrock_clients() -> None:
mock_transport = _create_mock_transport("https://bedrock-runtime.us-east-1.amazonaws.com")
with patch("agent_framework_anthropic._bedrock_client.AsyncAnthropicBedrock", return_value=mock_transport):
raw_client = RawAnthropicBedrockClient(
model="claude-bedrock-test",
aws_access_key="access-key",
aws_secret_key="secret-key",
aws_region="us-east-1",
)
raw_agent = Agent(client=raw_client, instructions="test agent")
assert raw_agent.client is raw_client
with patch("agent_framework_anthropic._bedrock_client.AsyncAnthropicBedrock", return_value=mock_transport):
client = AnthropicBedrockClient(
model="claude-bedrock-test",
aws_access_key="access-key",
aws_secret_key="secret-key",
aws_region="us-east-1",
)
agent = Agent(client=client, instructions="test agent")
assert agent.client is client
def test_agent_accepts_anthropic_vertex_clients() -> None:
mock_transport = _create_mock_transport("https://us-central1-aiplatform.googleapis.com/v1")
with patch("agent_framework_anthropic._vertex_client.AsyncAnthropicVertex", return_value=mock_transport):
raw_client = RawAnthropicVertexClient(
model="claude-vertex-test",
region="us-central1",
project_id="test-project",
)
raw_agent = Agent(client=raw_client, instructions="test agent")
assert raw_agent.client is raw_client
with patch("agent_framework_anthropic._vertex_client.AsyncAnthropicVertex", return_value=mock_transport):
client = AnthropicVertexClient(
model="claude-vertex-test",
region="us-central1",
project_id="test-project",
)
agent = Agent(client=client, instructions="test agent")
assert agent.client is client
def test_raw_anthropic_foundry_client_creates_sdk_client_from_settings(tmp_path) -> None:
env_file = tmp_path / ".env"
env_file.write_text(
"ANTHROPIC_CHAT_MODEL=claude-foundry-test\n"
"ANTHROPIC_FOUNDRY_API_KEY=test-key\n"
"ANTHROPIC_FOUNDRY_RESOURCE=test-resource\n"
)
mock_transport = _create_mock_transport("https://test-resource.services.ai.azure.com/anthropic/")
with patch(
"agent_framework_anthropic._foundry_client.AsyncAnthropicFoundry", return_value=mock_transport
) as factory:
client = RawAnthropicFoundryClient(env_file_path=str(env_file))
assert client.model == "claude-foundry-test"
assert client.anthropic_client is mock_transport
factory.assert_called_once_with(
resource="test-resource",
api_key="test-key",
azure_ad_token_provider=None,
default_headers={"User-Agent": get_user_agent()},
)
def test_raw_anthropic_foundry_client_creates_sdk_client_from_base_url_settings(tmp_path) -> None:
env_file = tmp_path / ".env"
env_file.write_text(
"ANTHROPIC_CHAT_MODEL=claude-foundry-test\n"
"ANTHROPIC_FOUNDRY_API_KEY=test-key\n"
"ANTHROPIC_FOUNDRY_BASE_URL=https://test-resource.services.ai.azure.com/anthropic/\n"
)
mock_transport = _create_mock_transport("https://test-resource.services.ai.azure.com/anthropic/")
with patch(
"agent_framework_anthropic._foundry_client.AsyncAnthropicFoundry", return_value=mock_transport
) as factory:
client = RawAnthropicFoundryClient(env_file_path=str(env_file))
assert client.model == "claude-foundry-test"
assert client.anthropic_client is mock_transport
factory.assert_called_once_with(
base_url="https://test-resource.services.ai.azure.com/anthropic/",
api_key="test-key",
azure_ad_token_provider=None,
default_headers={"User-Agent": get_user_agent()},
)
def test_raw_anthropic_foundry_client_requires_resource_or_base_url() -> None:
with patch("agent_framework_anthropic._foundry_client.load_settings") as mock_load:
mock_load.return_value = {
"anthropic_foundry_api_key": None,
"anthropic_foundry_resource": None,
"anthropic_foundry_base_url": None,
"anthropic_chat_model": None,
}
with pytest.raises(
ValueError,
match=(
"Anthropic Foundry requires either `resource`/`ANTHROPIC_FOUNDRY_RESOURCE` "
"or `base_url`/`ANTHROPIC_FOUNDRY_BASE_URL`\\."
),
):
RawAnthropicFoundryClient()
def test_raw_anthropic_bedrock_client_creates_sdk_client_from_arguments() -> None:
mock_transport = _create_mock_transport("https://bedrock-runtime.us-east-1.amazonaws.com")
with patch(
"agent_framework_anthropic._bedrock_client.AsyncAnthropicBedrock", return_value=mock_transport
) as factory:
client = RawAnthropicBedrockClient(
model="claude-bedrock-test",
aws_access_key="access-key",
aws_secret_key="secret-key",
aws_region="us-east-1",
)
assert client.model == "claude-bedrock-test"
assert client.anthropic_client is mock_transport
factory.assert_called_once_with(
aws_secret_key="secret-key",
aws_access_key="access-key",
aws_region="us-east-1",
aws_profile=None,
aws_session_token=None,
base_url=None,
default_headers={"User-Agent": get_user_agent()},
)
def test_raw_anthropic_vertex_client_creates_sdk_client_from_arguments() -> None:
mock_transport = _create_mock_transport("https://us-central1-aiplatform.googleapis.com/v1")
with patch("agent_framework_anthropic._vertex_client.AsyncAnthropicVertex", return_value=mock_transport) as factory:
client = RawAnthropicVertexClient(
model="claude-vertex-test",
region="us-central1",
project_id="test-project",
)
assert client.model == "claude-vertex-test"
assert client.anthropic_client is mock_transport
factory.assert_called_once_with(
region="us-central1",
project_id="test-project",
access_token=None,
credentials=None,
base_url=None,
default_headers={"User-Agent": get_user_agent()},
)