Python: [BREAKING]: Introducing Options as TypedDict and Generic (#3140)

* WIP typeddict for options

* updated all clients and ChatAgents

* updated everything

* added ADR

* fix mypy

* proper typevar imports

* fixed import

* fixed other imports

* slight update in the sample

* updated from feedback

* fixes

* fixed missing covariants and test fixes

* fixed typing

* updated anthropic thinking config

* ruff fixes

* fixed int tests

* fix tests and mypy

* updated integration tests

* updated docstring and test fix

* improved options handling in obser

* mypy fix

* updated a host of integration tests

* fix tests

* bedrock fix
This commit is contained in:
Eduard van Valkenburg
2026-01-13 17:41:05 +01:00
committed by GitHub
Unverified
parent 5faa2851bb
commit 3e97425245
111 changed files with 6141 additions and 4715 deletions
@@ -2,13 +2,13 @@
import asyncio
import random
import sys
from collections.abc import AsyncIterable, MutableSequence
from typing import Any, ClassVar
from typing import Any, ClassVar, Generic
from agent_framework import (
BaseChatClient,
ChatMessage,
ChatOptions,
ChatResponse,
ChatResponseUpdate,
Role,
@@ -16,6 +16,12 @@ from agent_framework import (
use_chat_middleware,
use_function_invocation,
)
from agent_framework._clients import TOptions_co
if sys.version_info >= (3, 12):
from typing import override # type: ignore # pragma: no cover
else:
from typing_extensions import override # type: ignore[import] # pragma: no cover
"""
Custom Chat Client Implementation Example
@@ -27,7 +33,7 @@ showing integration with ChatAgent and both streaming and non-streaming response
@use_function_invocation
@use_chat_middleware
class EchoingChatClient(BaseChatClient):
class EchoingChatClient(BaseChatClient[TOptions_co], Generic[TOptions_co]):
"""A custom chat client that echoes messages back with modifications.
This demonstrates how to implement a custom chat client by extending BaseChatClient
@@ -46,11 +52,12 @@ class EchoingChatClient(BaseChatClient):
super().__init__(**kwargs)
self.prefix = prefix
@override
async def _inner_get_response(
self,
*,
messages: MutableSequence[ChatMessage],
chat_options: ChatOptions,
options: dict[str, Any],
**kwargs: Any,
) -> ChatResponse:
"""Echo back the user's message with a prefix."""
@@ -77,16 +84,17 @@ class EchoingChatClient(BaseChatClient):
response_id=f"echo-resp-{random.randint(1000, 9999)}",
)
@override
async def _inner_get_streaming_response(
self,
*,
messages: MutableSequence[ChatMessage],
chat_options: ChatOptions,
options: dict[str, Any],
**kwargs: Any,
) -> AsyncIterable[ChatResponseUpdate]:
"""Stream back the echoed message character by character."""
# Get the complete response first
response = await self._inner_get_response(messages=messages, chat_options=chat_options, **kwargs)
response = await self._inner_get_response(messages=messages, options=options, **kwargs)
if response.messages:
response_text = response.messages[0].text or ""