-
Notifications
You must be signed in to change notification settings - Fork 1k
Python: [BREAKING]: Introducing Options as TypedDict and Generic #3140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
eavanvalkenburg
merged 24 commits into
microsoft:main
from
eavanvalkenburg:python_options_typeddict
Jan 13, 2026
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
3273d28
WIP typeddict for options
eavanvalkenburg 7d317c2
updated all clients and ChatAgents
eavanvalkenburg 94e9c2b
updated everything
eavanvalkenburg eab5c70
added ADR
eavanvalkenburg f61fdcc
fix mypy
eavanvalkenburg 087013a
proper typevar imports
eavanvalkenburg f0ed788
fixed import
eavanvalkenburg c9a3f6d
fixed other imports
eavanvalkenburg ac879a6
slight update in the sample
eavanvalkenburg 0acd9c0
updated from feedback
eavanvalkenburg 53b0928
fixes
eavanvalkenburg 259638b
fixed missing covariants and test fixes
eavanvalkenburg a142abe
fixed typing
eavanvalkenburg 52ea79a
updated anthropic thinking config
eavanvalkenburg c58a0ca
ruff fixes
eavanvalkenburg 2b3e860
fixed int tests
eavanvalkenburg 93a7803
fix tests and mypy
eavanvalkenburg a087094
updated integration tests
eavanvalkenburg 59d36a1
updated docstring and test fix
eavanvalkenburg 9905a07
improved options handling in obser
eavanvalkenburg b6e0e18
mypy fix
eavanvalkenburg df341b3
updated a host of integration tests
eavanvalkenburg 820de8c
fix tests
eavanvalkenburg a53e1ab
bedrock fix
eavanvalkenburg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| --- | ||
| # These are optional elements. Feel free to remove any of them. | ||
| status: proposed | ||
| contact: eavanvalkenburg | ||
| date: 2026-01-08 | ||
| deciders: eavanvalkenburg, markwallace-microsoft, sphenry, alliscode, johanst, brettcannon | ||
| consulted: taochenosu, moonbox3, dmytrostruk, giles17 | ||
| --- | ||
|
|
||
| # Leveraging TypedDict and Generic Options in Python Chat Clients | ||
|
|
||
| ## Context and Problem Statement | ||
|
|
||
| The Agent Framework Python SDK provides multiple chat client implementations for different providers (OpenAI, Anthropic, Azure AI, Bedrock, Ollama, etc.). Each provider has unique configuration options beyond the common parameters defined in `ChatOptions`. Currently, developers using these clients lack type safety and IDE autocompletion for provider-specific options, leading to runtime errors and a poor developer experience. | ||
|
|
||
| How can we provide type-safe, discoverable options for each chat client while maintaining a consistent API across all implementations? | ||
|
|
||
| ## Decision Drivers | ||
|
|
||
| - **Type Safety**: Developers should get compile-time/static analysis errors when using invalid options | ||
| - **IDE Support**: Full autocompletion and inline documentation for all available options | ||
| - **Extensibility**: Users should be able to define custom options that extend provider-specific options | ||
| - **Consistency**: All chat clients should follow the same pattern for options handling | ||
| - **Provider Flexibility**: Each provider can expose its unique options without affecting the common interface | ||
|
|
||
| ## Considered Options | ||
|
|
||
| - **Option 1: Status Quo - Class `ChatOptions` with `**kwargs`** | ||
| - **Option 2: TypedDict with Generic Type Parameters** | ||
|
|
||
| ### Option 1: Status Quo - Class `ChatOptions` with `**kwargs` | ||
|
|
||
| The current approach uses a base `ChatOptions` Class with common parameters, and provider-specific options are passed via `**kwargs` or loosely typed dictionaries. | ||
|
|
||
| ```python | ||
| # Current usage - no type safety for provider-specific options | ||
| response = await client.get_response( | ||
| messages=messages, | ||
| temperature=0.7, | ||
| top_k=40, | ||
| random=42, # No validation | ||
| ) | ||
| ``` | ||
|
|
||
| **Pros:** | ||
| - Simple implementation | ||
| - Maximum flexibility | ||
|
|
||
| **Cons:** | ||
| - No type checking for provider-specific options | ||
| - No IDE autocompletion for available options | ||
| - Runtime errors for typos or invalid options | ||
| - Documentation must be consulted for each provider | ||
|
|
||
| ### Option 2: TypedDict with Generic Type Parameters (Chosen) | ||
|
|
||
| Each chat client is parameterized with a TypeVar bound to a provider-specific `TypedDict` that extends `ChatOptions`. This enables full type safety and IDE support. | ||
|
|
||
| ```python | ||
| # Provider-specific TypedDict | ||
| class AnthropicChatOptions(ChatOptions, total=False): | ||
| """Anthropic-specific chat options.""" | ||
| top_k: int | ||
| thinking: ThinkingConfig | ||
| # ... other Anthropic-specific options | ||
|
|
||
| # Generic chat client | ||
| class AnthropicChatClient(ChatClientBase[TAnthropicChatOptions]): | ||
| ... | ||
|
|
||
| client = AnthropicChatClient(...) | ||
|
|
||
| # Usage with full type safety | ||
| response = await client.get_response( | ||
| messages=messages, | ||
| options={ | ||
| "temperature": 0.7, | ||
| "top_k": 40, | ||
| "random": 42, # fails type checking and IDE would flag this | ||
| } | ||
| ) | ||
|
|
||
| # Users can extend for custom options | ||
| class MyAnthropicOptions(AnthropicChatOptions, total=False): | ||
| custom_field: str | ||
|
|
||
|
|
||
| client = AnthropicChatClient[MyAnthropicOptions](...) | ||
|
|
||
| # Usage of custom options with full type safety | ||
| response = await client.get_response( | ||
| messages=messages, | ||
| options={ | ||
| "temperature": 0.7, | ||
| "top_k": 40, | ||
| "custom_field": "value", | ||
| } | ||
| ) | ||
|
|
||
| ``` | ||
|
|
||
| **Pros:** | ||
| - Full type safety with static analysis | ||
| - IDE autocompletion for all options | ||
| - Compile-time error detection | ||
| - Self-documenting through type hints | ||
| - Users can extend options for their specific needs or advances in models | ||
|
|
||
| **Cons:** | ||
| - More complex implementation | ||
| - Some type: ignore comments needed for TypedDict field overrides | ||
| - Minor: Requires TypeVar with default (Python 3.13+ or typing_extensions) | ||
|
|
||
| > [NOTE!] | ||
| > In .NET this is already achieved through overloads on the `GetResponseAsync` method for each provider-specific options class, e.g., `AnthropicChatOptions`, `OpenAIChatOptions`, etc. So this does not apply to .NET. | ||
|
|
||
| ### Implementation Details | ||
|
|
||
| 1. **Base Protocol**: `ChatClientProtocol[TOptions]` is generic over options type, with default set to `ChatOptions` (the new TypedDict) | ||
| 2. **Provider TypedDicts**: Each provider defines its options extending `ChatOptions` | ||
| They can even override fields with type=None to indicate they are not supported. | ||
| 3. **TypeVar Pattern**: `TProviderOptions = TypeVar("TProviderOptions", bound=TypedDict, default=ProviderChatOptions, contravariant=True)` | ||
| 4. **Option Translation**: Common options are kept in place,and explicitly documented in the Options class how they are used. (e.g., `user` → `metadata.user_id`) in `_prepare_options` (for Anthropic) to preserve easy use of common options. | ||
|
|
||
| ## Decision Outcome | ||
|
|
||
| Chosen option: **"Option 2: TypedDict with Generic Type Parameters"**, because it provides full type safety, excellent IDE support with autocompletion, and allows users to extend provider-specific options for their use cases. Extended this Generic to ChatAgents in order to also properly type the options used in agent construction and run methods. | ||
|
|
||
| See [typed_options.py](../../python/samples/getting_started/chat_client/typed_options.py) for a complete example demonstrating the usage of typed options with custom extensions. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,6 +25,7 @@ | |
| "words": [ | ||
| "aeiou", | ||
| "aiplatform", | ||
| "agui", | ||
| "azuredocindex", | ||
| "azuredocs", | ||
| "azurefunctions", | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.