agent-framework-core 1.24.0__tar.gz → 1.25.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/PKG-INFO +59 -35
  2. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/README.md +30 -6
  3. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_agents.py +49 -7
  4. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_clients.py +26 -8
  5. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_evaluation.py +58 -4
  6. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_harness/_background_agents.py +156 -37
  7. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_harness/_file_access.py +1 -1
  8. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_harness/_loop.py +5 -2
  9. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_harness/_memory.py +127 -32
  10. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_harness/_todo.py +2 -2
  11. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_harness/_tool_approval.py +13 -0
  12. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_mcp.py +713 -210
  13. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_middleware.py +49 -12
  14. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_settings.py +2 -4
  15. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_tools.py +117 -17
  16. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_types.py +130 -64
  17. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_vectors.py +2 -1
  18. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_agent.py +10 -1
  19. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_agent_executor.py +8 -2
  20. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_executor.py +3 -2
  21. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_function_executor.py +1 -7
  22. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_functional.py +5 -22
  23. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_model_utils.py +1 -7
  24. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_request_info_mixin.py +1 -7
  25. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_typing_utils.py +17 -1
  26. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_viz.py +9 -9
  27. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_workflow.py +2 -1
  28. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_workflow_builder.py +17 -15
  29. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_workflow_context.py +2 -2
  30. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/observability.py +27 -10
  31. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/security.py +512 -148
  32. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/pyproject.toml +30 -30
  33. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/LICENSE +0 -0
  34. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/__init__.py +0 -0
  35. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/__init__.pyi +0 -0
  36. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_agent_hooks.py +0 -0
  37. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_compaction.py +0 -0
  38. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_docstrings.py +0 -0
  39. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_feature_stage.py +0 -0
  40. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_filesystem.py +0 -0
  41. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_harness/__init__.py +0 -0
  42. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_harness/_agent.py +0 -0
  43. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_harness/_agent.pyi +0 -0
  44. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_harness/_file_memory.py +0 -0
  45. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_harness/_mode.py +0 -0
  46. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_in_memory.py +0 -0
  47. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_serialization.py +0 -0
  48. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_sessions.py +0 -0
  49. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_skills.py +0 -0
  50. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_telemetry.py +0 -0
  51. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_vector_filters.py +0 -0
  52. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/__init__.py +0 -0
  53. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_agent_utils.py +0 -0
  54. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_checkpoint.py +0 -0
  55. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_checkpoint_encoding.py +0 -0
  56. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_const.py +0 -0
  57. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_conversation_history.py +0 -0
  58. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_edge.py +0 -0
  59. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_edge_runner.py +0 -0
  60. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_events.py +0 -0
  61. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_message_utils.py +0 -0
  62. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_runner.py +0 -0
  63. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_runner_context.py +0 -0
  64. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_state.py +0 -0
  65. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_validation.py +0 -0
  66. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/_workflows/_workflow_executor.py +0 -0
  67. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/a2a/__init__.py +0 -0
  68. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/a2a/__init__.pyi +0 -0
  69. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/ag_ui/__init__.py +0 -0
  70. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/ag_ui/__init__.pyi +0 -0
  71. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/amazon/__init__.py +0 -0
  72. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/amazon/__init__.pyi +0 -0
  73. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/anthropic/__init__.py +0 -0
  74. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/anthropic/__init__.pyi +0 -0
  75. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/azure/__init__.py +0 -0
  76. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/azure/__init__.pyi +0 -0
  77. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/chatkit/__init__.py +0 -0
  78. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/chatkit/__init__.pyi +0 -0
  79. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/declarative/__init__.py +0 -0
  80. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/declarative/__init__.pyi +0 -0
  81. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/devui/__init__.py +0 -0
  82. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/devui/__init__.pyi +0 -0
  83. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/exceptions.py +0 -0
  84. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/foundry/__init__.py +0 -0
  85. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/foundry/__init__.pyi +0 -0
  86. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/gemini/__init__.py +0 -0
  87. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/gemini/__init__.pyi +0 -0
  88. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/github/__init__.py +0 -0
  89. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/github/__init__.pyi +0 -0
  90. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/google/__init__.py +0 -0
  91. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/google/__init__.pyi +0 -0
  92. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/hyperlight/__init__.py +0 -0
  93. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/lab/__init__.py +0 -0
  94. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/mem0/__init__.py +0 -0
  95. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/mem0/__init__.pyi +0 -0
  96. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/microsoft/__init__.py +0 -0
  97. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/microsoft/__init__.pyi +0 -0
  98. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/mistral/__init__.py +0 -0
  99. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/mistral/__init__.pyi +0 -0
  100. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/monty/__init__.py +0 -0
  101. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/monty/__init__.pyi +0 -0
  102. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/ollama/__init__.py +0 -0
  103. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/ollama/__init__.pyi +0 -0
  104. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/openai/__init__.py +0 -0
  105. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/openai/__init__.pyi +0 -0
  106. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/orchestrations/__init__.py +0 -0
  107. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/orchestrations/__init__.pyi +0 -0
  108. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/py.typed +0 -0
  109. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/redis/__init__.py +0 -0
  110. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/redis/__init__.pyi +0 -0
  111. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/tools/__init__.py +0 -0
  112. {agent_framework_core-1.24.0 → agent_framework_core-1.25.0}/agent_framework/tools/__init__.pyi +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agent-framework-core
3
- Version: 1.24.0
3
+ Version: 1.25.0
4
4
  Summary: Microsoft Agent Framework for building AI Agents with Python. This is the core package that has all the core abstractions and implementations.
5
5
  Author-email: Microsoft <af-support@microsoft.com>
6
- Requires-Python: >=3.10
6
+ Requires-Python: >=3.11
7
7
  Description-Content-Type: text/markdown
8
8
  Classifier: License :: OSI Approved :: MIT License
9
9
  Classifier: Development Status :: 5 - Production/Stable
@@ -25,35 +25,35 @@ Requires-Dist: pyyaml>=6.0,<7.0
25
25
  Requires-Dist: regex>=2024.11.6
26
26
  Requires-Dist: mcp>=2.2.0,<3 ; extra == "all"
27
27
  Requires-Dist: tenacity>=9.1.4,<9.2.0 ; extra == "all"
28
- Requires-Dist: agent-framework-a2a>=1.0.0b261030,<2 ; extra == "all"
29
- Requires-Dist: agent-framework-ag-ui>=1.7.1,<2 ; extra == "all"
30
- Requires-Dist: agent-framework-anthropic>=1.0.0b261030,<2 ; extra == "all"
31
- Requires-Dist: agent-framework-azure-ai-search>=1.0.0b261030,<2 ; extra == "all"
32
- Requires-Dist: agent-framework-azure-contentunderstanding>=1.0.0b261030,<2 ; extra == "all"
33
- Requires-Dist: agent-framework-azure-cosmos>=1.0.0b261030,<2 ; extra == "all"
28
+ Requires-Dist: agent-framework-a2a>=1.0.0b261106,<2 ; extra == "all"
29
+ Requires-Dist: agent-framework-ag-ui>=1.8.0,<2 ; extra == "all"
30
+ Requires-Dist: agent-framework-anthropic>=1.0.0b261106,<2 ; extra == "all"
31
+ Requires-Dist: agent-framework-azure-ai-search>=1.0.0b261106,<2 ; extra == "all"
32
+ Requires-Dist: agent-framework-azure-contentunderstanding>=1.0.0b261106,<2 ; extra == "all"
33
+ Requires-Dist: agent-framework-azure-cosmos>=1.0.0b261106,<2 ; extra == "all"
34
34
  Requires-Dist: agent-framework-azurefunctions>=1.0.0b260922,<2 ; extra == "all"
35
- Requires-Dist: agent-framework-bedrock>=1.0.0b261030,<2 ; extra == "all"
36
- Requires-Dist: agent-framework-chatkit>=1.0.0b261030,<2 ; extra == "all"
37
- Requires-Dist: agent-framework-claude>=1.0.0b261030,<2 ; extra == "all"
38
- Requires-Dist: agent-framework-copilotstudio>=1.0.0b261030,<2 ; extra == "all"
39
- Requires-Dist: agent-framework-declarative>=1.4.1,<2 ; extra == "all"
40
- Requires-Dist: agent-framework-devui>=1.0.0b261030,<2 ; extra == "all"
35
+ Requires-Dist: agent-framework-bedrock>=1.0.0b261106,<2 ; extra == "all"
36
+ Requires-Dist: agent-framework-chatkit>=1.0.0b261106,<2 ; extra == "all"
37
+ Requires-Dist: agent-framework-claude>=1.0.0b261106,<2 ; extra == "all"
38
+ Requires-Dist: agent-framework-copilotstudio>=1.0.0b261106,<2 ; extra == "all"
39
+ Requires-Dist: agent-framework-declarative>=1.5.0,<2 ; extra == "all"
40
+ Requires-Dist: agent-framework-devui>=1.0.0b261106,<2 ; extra == "all"
41
41
  Requires-Dist: agent-framework-durabletask>=1.0.0b260922,<2 ; extra == "all"
42
- Requires-Dist: agent-framework-foundry>=1.16.0,<2 ; extra == "all"
43
- Requires-Dist: agent-framework-foundry-hosting>=1.0.0b261030,<2 ; extra == "all"
44
- Requires-Dist: agent-framework-foundry-local>=1.0.0b261030,<2 ; extra == "all"
45
- Requires-Dist: agent-framework-gemini>=1.0.0b261030,<2 ; extra == "all"
46
- Requires-Dist: agent-framework-github-copilot>=2.1.1,<3 ; extra == "all" and ( python_version >= '3.11')
47
- Requires-Dist: agent-framework-hyperlight>=1.0.0b261030,<2 ; extra == "all" and ( (sys_platform == 'linux' and platform_machine == 'x86_64') or (sys_platform == 'win32' and platform_machine == 'AMD64'))
48
- Requires-Dist: agent-framework-mem0>=1.0.0b261030,<2 ; extra == "all"
49
- Requires-Dist: agent-framework-mistral>=1.0.0b261030,<2 ; extra == "all"
50
- Requires-Dist: agent-framework-monty>=1.0.0b261030,<2 ; extra == "all"
51
- Requires-Dist: agent-framework-ollama>=1.0.0b261030,<2 ; extra == "all"
52
- Requires-Dist: agent-framework-openai>=1.18.0,<2 ; extra == "all"
53
- Requires-Dist: agent-framework-orchestrations>=1.4.1,<2 ; extra == "all"
54
- Requires-Dist: agent-framework-purview>=1.0.0b261030,<2 ; extra == "all"
55
- Requires-Dist: agent-framework-redis>=1.0.0b261030,<2 ; extra == "all" and ( python_version < '3.15')
56
- Requires-Dist: agent-framework-tools>=1.0.0b261030,<2 ; extra == "all"
42
+ Requires-Dist: agent-framework-foundry>=1.16.1,<2 ; extra == "all"
43
+ Requires-Dist: agent-framework-foundry-hosting>=1.0.0b261106,<2 ; extra == "all"
44
+ Requires-Dist: agent-framework-foundry-local>=1.0.0b261106,<2 ; extra == "all" and ( python_version >= '3.11' and python_version < '3.15' and ((sys_platform == 'darwin' and platform_machine == 'arm64') or (sys_platform == 'linux' and (platform_machine == 'x86_64' or platform_machine == 'aarch64')) or (sys_platform == 'win32' and (platform_machine == 'AMD64' or platform_machine == 'ARM64' or platform_machine == 'x86_64' or platform_machine == 'aarch64'))))
45
+ Requires-Dist: agent-framework-gemini>=1.0.0b261106,<2 ; extra == "all"
46
+ Requires-Dist: agent-framework-github-copilot>=2.1.2,<3 ; extra == "all"
47
+ Requires-Dist: agent-framework-hyperlight>=1.0.0b261106,<2 ; extra == "all" and ( (sys_platform == 'linux' and platform_machine == 'x86_64') or (sys_platform == 'win32' and platform_machine == 'AMD64'))
48
+ Requires-Dist: agent-framework-mem0>=1.0.0b261106,<2 ; extra == "all"
49
+ Requires-Dist: agent-framework-mistral>=1.0.0b261106,<2 ; extra == "all"
50
+ Requires-Dist: agent-framework-monty>=1.0.0b261106,<2 ; extra == "all"
51
+ Requires-Dist: agent-framework-ollama>=1.0.0b261106,<2 ; extra == "all"
52
+ Requires-Dist: agent-framework-openai>=1.18.1,<2 ; extra == "all"
53
+ Requires-Dist: agent-framework-orchestrations>=1.4.2,<2 ; extra == "all"
54
+ Requires-Dist: agent-framework-purview>=1.0.0b261106,<2 ; extra == "all"
55
+ Requires-Dist: agent-framework-redis>=1.0.0b261106,<2 ; extra == "all"
56
+ Requires-Dist: agent-framework-tools>=1.0.0b261106,<2 ; extra == "all"
57
57
  Project-URL: homepage, https://aka.ms/agent-framework
58
58
  Project-URL: issues, https://github.com/microsoft/agent-framework/issues
59
59
  Project-URL: release_notes, https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true
@@ -88,12 +88,8 @@ Supported Platforms:
88
88
  - Python: 3.11–3.15
89
89
  - OS: Windows, macOS, Linux
90
90
 
91
- Python 3.10 is no longer supported because it has reached upstream end of life.
92
- Package metadata still permits Python 3.10 installation, but CI no longer runs
93
- unit or integration tests on it and compatibility is not guaranteed. Use
94
- Python 3.11–3.15 for supported environments, subject to
95
- [integration-specific limits](../../README.md#python-315-limitations). Raising
96
- the installation minimum will be handled separately.
91
+ Python 3.11 or later is required. Supported environments are subject to
92
+ [integration-specific limits](../../README.md#python-315-limitations).
97
93
 
98
94
  ## 1. Setup API Keys
99
95
 
@@ -261,6 +257,34 @@ cookie-bearing clients and MCP tool sessions to one authenticated principal; do
261
257
  share a user-specific cookie jar across users. Rejecting cookies does not partition
262
258
  MCP protocol sessions or other server-side state between principals.
263
259
 
260
+ ### MCP HTTP concurrency and timeouts
261
+
262
+ `MCPStreamableHTTPTool` and `FoundryToolbox` attach a separate header snapshot to each
263
+ outgoing HTTP request. Calls with identical effective static and dynamic headers can
264
+ overlap on one MCP session. A different identity waits for active operations before
265
+ reconnecting and refreshing discovery. Discovery, reset, close, and recovery are
266
+ exclusive against active network attempts on framework-owned MCP connections, with
267
+ or without a header provider. Same-identity Agent run preparation does not drain
268
+ active calls. Direct prompt calls resolve current headers rather than reusing an
269
+ inherited invocation snapshot; generated prompts resolve host runtime kwargs
270
+ separately from model arguments. Calls still share server-side session state;
271
+ applications must order state-dependent operations themselves.
272
+
273
+ Resource reads wait for replacement initialization before requiring the connection.
274
+ Catalog discovery restarts the complete snapshot once after a connection replacement,
275
+ without reusing old pages or cursors. A second replacement fails explicitly.
276
+
277
+ `request_timeout` bounds header admission and session reconciliation together, and
278
+ connection recovery separately from the RPC timeout. These are separate budgets,
279
+ not an end-to-end deadline. `None` disables these budgets. An admission timeout does
280
+ not cancel another caller's active operation. Cleanup may continue after a timeout
281
+ or cancellation so the lifecycle owner can finish releasing resources safely.
282
+ Caller-owned MCP clients retain their own RPC timeout policy and are not recreated.
283
+
284
+ Concurrent failures of the same connection share its replacement. Calling `close()`
285
+ interrupts older recovery so it cannot reopen the connection or retry the failed
286
+ operation after shutdown. A later explicit `connect()` remains supported.
287
+
264
288
  ## 5. Multi-Agent Orchestration
265
289
 
266
290
  Coordinate multiple agents to collaborate on complex tasks using orchestration patterns:
@@ -25,12 +25,8 @@ Supported Platforms:
25
25
  - Python: 3.11–3.15
26
26
  - OS: Windows, macOS, Linux
27
27
 
28
- Python 3.10 is no longer supported because it has reached upstream end of life.
29
- Package metadata still permits Python 3.10 installation, but CI no longer runs
30
- unit or integration tests on it and compatibility is not guaranteed. Use
31
- Python 3.11–3.15 for supported environments, subject to
32
- [integration-specific limits](../../README.md#python-315-limitations). Raising
33
- the installation minimum will be handled separately.
28
+ Python 3.11 or later is required. Supported environments are subject to
29
+ [integration-specific limits](../../README.md#python-315-limitations).
34
30
 
35
31
  ## 1. Setup API Keys
36
32
 
@@ -198,6 +194,34 @@ cookie-bearing clients and MCP tool sessions to one authenticated principal; do
198
194
  share a user-specific cookie jar across users. Rejecting cookies does not partition
199
195
  MCP protocol sessions or other server-side state between principals.
200
196
 
197
+ ### MCP HTTP concurrency and timeouts
198
+
199
+ `MCPStreamableHTTPTool` and `FoundryToolbox` attach a separate header snapshot to each
200
+ outgoing HTTP request. Calls with identical effective static and dynamic headers can
201
+ overlap on one MCP session. A different identity waits for active operations before
202
+ reconnecting and refreshing discovery. Discovery, reset, close, and recovery are
203
+ exclusive against active network attempts on framework-owned MCP connections, with
204
+ or without a header provider. Same-identity Agent run preparation does not drain
205
+ active calls. Direct prompt calls resolve current headers rather than reusing an
206
+ inherited invocation snapshot; generated prompts resolve host runtime kwargs
207
+ separately from model arguments. Calls still share server-side session state;
208
+ applications must order state-dependent operations themselves.
209
+
210
+ Resource reads wait for replacement initialization before requiring the connection.
211
+ Catalog discovery restarts the complete snapshot once after a connection replacement,
212
+ without reusing old pages or cursors. A second replacement fails explicitly.
213
+
214
+ `request_timeout` bounds header admission and session reconciliation together, and
215
+ connection recovery separately from the RPC timeout. These are separate budgets,
216
+ not an end-to-end deadline. `None` disables these budgets. An admission timeout does
217
+ not cancel another caller's active operation. Cleanup may continue after a timeout
218
+ or cancellation so the lifecycle owner can finish releasing resources safely.
219
+ Caller-owned MCP clients retain their own RPC timeout policy and are not recreated.
220
+
221
+ Concurrent failures of the same connection share its replacement. Calling `close()`
222
+ interrupts older recovery so it cannot reopen the connection or retry the failed
223
+ operation after shutdown. A later explicit `connect()` remains supported.
224
+
201
225
  ## 5. Multi-Agent Orchestration
202
226
 
203
227
  Coordinate multiple agents to collaborate on complex tasks using orchestration patterns:
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  import logging
6
6
  import re
7
7
  import sys
8
- from collections.abc import Awaitable, Callable, Mapping, MutableMapping, Sequence
8
+ from collections.abc import AsyncIterable, Awaitable, Callable, Mapping, MutableMapping, Sequence
9
9
  from contextlib import AbstractAsyncContextManager, AsyncExitStack
10
10
  from copy import deepcopy
11
11
  from functools import partial
@@ -18,6 +18,8 @@ from typing import (
18
18
  Generic,
19
19
  Literal,
20
20
  Protocol,
21
+ Self,
22
+ TypedDict,
21
23
  cast,
22
24
  overload,
23
25
  runtime_checkable,
@@ -51,6 +53,7 @@ from ._sessions import (
51
53
  )
52
54
  from ._telemetry import FeatureIndex, mark_feature_used
53
55
  from ._types import (
56
+ _EVALUATION_TOOLS_METADATA_KEY, # pyright: ignore[reportPrivateUsage]
54
57
  AgentResponse,
55
58
  AgentResponseUpdate,
56
59
  AgentRunInputs,
@@ -60,6 +63,8 @@ from ._types import (
60
63
  ResponseStream,
61
64
  _append_instructions, # pyright: ignore[reportPrivateUsage]
62
65
  _build_agent_response_from_chat_response, # pyright: ignore[reportPrivateUsage]
66
+ _capture_evaluation_tools, # pyright: ignore[reportPrivateUsage]
67
+ _copy_operation_state, # pyright: ignore[reportPrivateUsage]
63
68
  map_chat_to_agent_update,
64
69
  normalize_messages,
65
70
  )
@@ -75,10 +80,6 @@ if sys.version_info >= (3, 13):
75
80
  from typing import TypeVar # pragma: no cover
76
81
  else:
77
82
  from typing_extensions import TypeVar # pragma: no cover
78
- if sys.version_info >= (3, 11):
79
- from typing import Self, TypedDict # pragma: no cover
80
- else:
81
- from typing_extensions import Self, TypedDict # pragma: no cover
82
83
 
83
84
  if TYPE_CHECKING:
84
85
  from collections.abc import Collection
@@ -275,6 +276,7 @@ class _RunContext(TypedDict):
275
276
  agent_name: str
276
277
  suppress_response_id: bool
277
278
  chat_options: MutableMapping[str, Any]
279
+ evaluation_tools: dict[str, dict[str, Any]]
278
280
  compaction_strategy: CompactionStrategy | None
279
281
  tokenizer: TokenizerProtocol | None
280
282
  client_kwargs: Mapping[str, Any]
@@ -396,7 +398,8 @@ class SupportsAgentRun(Protocol):
396
398
  messages: The message(s) to send to the agent.
397
399
 
398
400
  Keyword Args:
399
- stream: Whether to stream the response. Defaults to False.
401
+ stream: Whether to stream the response. Defaults to False. Streams
402
+ may include response metadata updates without message contents.
400
403
  session: The conversation session associated with the message(s).
401
404
  function_invocation_kwargs: Keyword arguments forwarded to tool invocation.
402
405
  client_kwargs: Additional client-specific keyword arguments.
@@ -701,6 +704,9 @@ class BaseAgent(SerializationMixin):
701
704
  :attr:`FunctionInvocationContext.parent_service_session_state_keys` when
702
705
  the parent session is non-empty. Automatic function calling supplies it.
703
706
 
707
+ ``WorkflowAgent.as_tool()`` is not supported, because every caller of
708
+ the tool would share the state of one workflow.
709
+
704
710
  Examples:
705
711
  .. code-block:: python
706
712
 
@@ -882,6 +888,8 @@ class BaseAgent(SerializationMixin):
882
888
  func=_agent_wrapper,
883
889
  input_model=input_schema,
884
890
  approval_mode=approval_mode,
891
+ # Private link for hosts that must know which agent a tool delegates to. Serialization skips it.
892
+ _wrapped_agent=self,
885
893
  )
886
894
 
887
895
 
@@ -1406,6 +1414,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]):
1406
1414
  response_format=context["chat_options"].get("response_format"),
1407
1415
  suppress_response_id=context["suppress_response_id"],
1408
1416
  )
1417
+ agent_response.additional_properties[_EVALUATION_TOOLS_METADATA_KEY] = context["evaluation_tools"]
1409
1418
  session_context = context["session_context"]
1410
1419
  session_context._response = agent_response # type: ignore[assignment]
1411
1420
  await self._run_after_providers(session=session, context=session_context)
@@ -1442,6 +1451,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]):
1442
1451
  session_context = context["session_context"]
1443
1452
  if context["suppress_response_id"]:
1444
1453
  response.response_id = None
1454
+ response.additional_properties[_EVALUATION_TOOLS_METADATA_KEY] = context["evaluation_tools"]
1445
1455
  session_context._response = response # type: ignore[assignment]
1446
1456
  # Result hooks run during finalization, outside the per-pull identity
1447
1457
  # scope registered below, so re-stamp this run's identity around its
@@ -1482,7 +1492,28 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]):
1482
1492
  # carries this run's identity; nested runs re-stamp their own within theirs.
1483
1493
  stream = stream.with_pull_context_manager(partial(_run_identity_scope, run_identity))
1484
1494
 
1485
- return stream.with_transform_hook(_propagate_conversation_id).with_result_hook(_post_hook)
1495
+ stream = stream.with_transform_hook(_propagate_conversation_id).with_result_hook(_post_hook)
1496
+
1497
+ async def _with_evaluation_metadata() -> AsyncIterable[AgentResponseUpdate]:
1498
+ async with stream:
1499
+ async for update in stream:
1500
+ yield update
1501
+ response = await stream.get_final_response()
1502
+ metadata_update = AgentResponseUpdate(
1503
+ continuation_token=response.continuation_token,
1504
+ additional_properties={
1505
+ _EVALUATION_TOOLS_METADATA_KEY: deepcopy(
1506
+ response.additional_properties[_EVALUATION_TOOLS_METADATA_KEY]
1507
+ )
1508
+ },
1509
+ )
1510
+ _copy_operation_state(response, metadata_update)
1511
+ yield metadata_update
1512
+
1513
+ async def _finalize_with_metadata(updates: Sequence[AgentResponseUpdate]) -> AgentResponse[Any]:
1514
+ return await stream.get_final_response()
1515
+
1516
+ return ResponseStream(_with_evaluation_metadata(), finalizer=_finalize_with_metadata)
1486
1517
 
1487
1518
  def _finalize_response_updates(
1488
1519
  self,
@@ -1491,6 +1522,10 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]):
1491
1522
  response_format: Any | None = None,
1492
1523
  ) -> AgentResponse[Any]:
1493
1524
  """Finalize response updates into a single AgentResponse."""
1525
+ if isinstance(self.client, BaseChatClient):
1526
+ return self.client._finalize_agent_response_updates( # pyright: ignore[reportPrivateUsage]
1527
+ updates, response_format=response_format
1528
+ )
1494
1529
  return AgentResponse.from_updates(
1495
1530
  updates,
1496
1531
  output_format_type=response_format,
@@ -1760,6 +1795,12 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]):
1760
1795
  per_service_call_history_middleware,
1761
1796
  ]
1762
1797
 
1798
+ evaluation_tools: dict[str, dict[str, Any]] = {}
1799
+ if isinstance(self.client, BaseChatClient):
1800
+ effective_client_kwargs["_evaluation_tool_capture"] = partial(_capture_evaluation_tools, evaluation_tools)
1801
+ else:
1802
+ _capture_evaluation_tools(evaluation_tools, co.get("tools"))
1803
+
1763
1804
  return {
1764
1805
  "session": active_session,
1765
1806
  "session_context": session_context,
@@ -1768,6 +1809,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]):
1768
1809
  "agent_name": agent_name,
1769
1810
  "suppress_response_id": bool(per_service_call_history_providers) and not service_stores_history,
1770
1811
  "chat_options": co,
1812
+ "evaluation_tools": evaluation_tools,
1771
1813
  "compaction_strategy": compaction_strategy or self.compaction_strategy,
1772
1814
  "tokenizer": tokenizer or self.tokenizer,
1773
1815
  "client_kwargs": effective_client_kwargs,
@@ -21,6 +21,7 @@ from typing import (
21
21
  Generic,
22
22
  Literal,
23
23
  Protocol,
24
+ Self,
24
25
  TypedDict,
25
26
  cast,
26
27
  overload,
@@ -30,6 +31,8 @@ from typing import (
30
31
  from ._docstrings import apply_layered_docstring
31
32
  from ._serialization import SerializationMixin
32
33
  from ._types import (
34
+ AgentResponse,
35
+ AgentResponseUpdate,
33
36
  ChatResponse,
34
37
  ChatResponseUpdate,
35
38
  EmbeddingGenerationOptions,
@@ -47,11 +50,6 @@ if sys.version_info >= (3, 13):
47
50
  else:
48
51
  from typing_extensions import TypeVar # pragma: no cover
49
52
 
50
- if sys.version_info >= (3, 11):
51
- from typing import Self # pragma: no cover
52
- else:
53
- from typing_extensions import Self # pragma: no cover
54
-
55
53
 
56
54
  if TYPE_CHECKING:
57
55
  from pydantic import BaseModel
@@ -360,9 +358,15 @@ class BaseChatClient(SerializationMixin, ABC, Generic[OptionsCoT]):
360
358
  # Get the base dict from SerializationMixin
361
359
  result = super().to_dict(exclude=exclude, exclude_none=exclude_none)
362
360
 
363
- # Extract additional_properties to root level
364
- if self.additional_properties:
365
- result.update(self.additional_properties)
361
+ # Extract additional_properties to root level respecting exclusions and exclude_none
362
+ if self.additional_properties and (exclude is None or "additional_properties" not in exclude):
363
+ exclude_set = exclude or set()
364
+ for key, value in self.additional_properties.items():
365
+ if key in exclude_set:
366
+ continue
367
+ if exclude_none and value is None:
368
+ continue
369
+ result[key] = value
366
370
 
367
371
  return result
368
372
 
@@ -391,6 +395,15 @@ class BaseChatClient(SerializationMixin, ABC, Generic[OptionsCoT]):
391
395
  output_format_type=response_format,
392
396
  )
393
397
 
398
+ def _finalize_agent_response_updates(
399
+ self,
400
+ updates: Sequence[AgentResponseUpdate],
401
+ *,
402
+ response_format: Any | None = None,
403
+ ) -> AgentResponse[Any]:
404
+ """Aggregate mapped agent updates without reapplying per-model-turn processing."""
405
+ return AgentResponse.from_updates(updates, output_format_type=response_format)
406
+
394
407
  def _build_response_stream(
395
408
  self,
396
409
  stream: AsyncIterable[ChatResponseUpdate] | Awaitable[AsyncIterable[ChatResponseUpdate]],
@@ -581,6 +594,11 @@ class BaseChatClient(SerializationMixin, ABC, Generic[OptionsCoT]):
581
594
  tokenizer=tokenizer,
582
595
  )
583
596
  merged_client_kwargs = dict(client_kwargs) if client_kwargs is not None else {}
597
+ evaluation_tool_capture = cast(
598
+ Callable[[Any], None] | None, merged_client_kwargs.pop("_evaluation_tool_capture", None)
599
+ )
600
+ if evaluation_tool_capture is not None:
601
+ evaluation_tool_capture((options or {}).get("tools"))
584
602
 
585
603
  if not compaction_overrides:
586
604
  return self._inner_get_response(
@@ -56,7 +56,11 @@ from typing import (
56
56
 
57
57
  from ._feature_stage import ExperimentalFeature, experimental
58
58
  from ._tools import FunctionTool, normalize_tools
59
- from ._types import AgentResponse, Message
59
+ from ._types import (
60
+ _EVALUATION_TOOLS_METADATA_KEY, # pyright: ignore[reportPrivateUsage]
61
+ AgentResponse,
62
+ Message,
63
+ )
60
64
 
61
65
  if TYPE_CHECKING:
62
66
  from ._agents import SupportsAgentRun
@@ -872,8 +876,44 @@ def _to_eval_item(
872
876
  all_msgs = list(input_msgs) + list(response.messages or [])
873
877
 
874
878
  typed_tools: list[FunctionTool] = []
875
- if tools:
879
+ if tools is not None:
876
880
  typed_tools = [tool for tool in normalize_tools(tools) if isinstance(tool, FunctionTool)]
881
+ elif _EVALUATION_TOOLS_METADATA_KEY in response.additional_properties:
882
+ called_tools = {
883
+ content.name for message in all_msgs for content in message.contents if content.type == "function_call"
884
+ }
885
+ definitions = response.additional_properties[_EVALUATION_TOOLS_METADATA_KEY]
886
+ if not isinstance(definitions, dict):
887
+ raise ValueError("Invalid agent_framework.evaluation metadata: expected tool definitions keyed by name.")
888
+ for name, definition in cast(dict[str, Any], definitions).items():
889
+ if not isinstance(name, str) or not name or not isinstance(definition, dict):
890
+ raise ValueError("Invalid agent_framework.evaluation metadata: expected named tool definition objects.")
891
+ definition = cast(dict[str, Any], definition)
892
+ description = definition.get("description")
893
+ schema = definition.get("input_schema")
894
+ if not isinstance(description, str) or not isinstance(schema, dict):
895
+ raise ValueError(
896
+ f"Invalid agent_framework.evaluation definition for {name!r}: "
897
+ "expected a string description and an input_schema object."
898
+ )
899
+ schema_changed = definition.get("schema_changed", False)
900
+ if not isinstance(schema_changed, bool):
901
+ raise ValueError(
902
+ f"Invalid agent_framework.evaluation definition for {name!r}: schema_changed must be bool."
903
+ )
904
+ if schema_changed and name in called_tools:
905
+ raise ValueError(
906
+ f"Tool {name!r} changed input schema during the captured conversation; "
907
+ "automatic evaluation cannot represent multiple schemas for the same called tool. "
908
+ "Use distinct tool names or supply an explicit tools= override."
909
+ )
910
+ try:
911
+ schema = json.loads(json.dumps(schema, allow_nan=False))
912
+ except (TypeError, ValueError) as exc:
913
+ raise ValueError(
914
+ f"Invalid agent_framework.evaluation input_schema for {name!r}: expected JSON-serializable data."
915
+ ) from exc
916
+ typed_tools.append(FunctionTool(name=name, description=description, input_model=schema))
877
917
  elif agent:
878
918
  raw_tools = getattr(agent, "default_options", {}).get("tools", [])
879
919
  typed_tools = [tool for tool in normalize_tools(raw_tools) if isinstance(tool, FunctionTool)]
@@ -1604,6 +1644,7 @@ async def evaluate_agent(
1604
1644
  expected_output: str | Sequence[str] | None = None,
1605
1645
  expected_tool_calls: Sequence[ExpectedToolCall] | Sequence[Sequence[ExpectedToolCall]] | None = None,
1606
1646
  responses: AgentResponse[Any] | Sequence[AgentResponse[Any]] | None = None,
1647
+ tools: FunctionTool | Callable[..., Any] | Sequence[FunctionTool | Callable[..., Any]] | None = None,
1607
1648
  evaluators: Evaluator | Callable[..., Any] | Sequence[Evaluator | Callable[..., Any]],
1608
1649
  eval_name: str | None = None,
1609
1650
  context: str | None = None,
@@ -1621,8 +1662,16 @@ async def evaluate_agent(
1621
1662
  or a list for convenience.
1622
1663
 
1623
1664
  If ``responses`` is provided, skips running the agent and evaluates those
1624
- responses directly — but still extracts tool definitions from the agent.
1625
- In this mode ``queries`` is required to construct the conversation.
1665
+ responses directly. Tool definitions come from the original run when
1666
+ available, including schema-only snapshots retained through JSON or pickle
1667
+ serialization. Responses without captured definitions fall back to the
1668
+ agent's configured tools; supply ``tools`` when those definitions are
1669
+ unavailable or need to be overridden. In this mode ``queries`` is required
1670
+ to construct the conversation.
1671
+
1672
+ Automatic discovery rejects a called tool whose captured input schema changed
1673
+ under the same name, even if the schemas might be compatible. Use distinct
1674
+ names for different schemas or supply an explicit ``tools`` override.
1626
1675
 
1627
1676
  Args:
1628
1677
  agent: An agent-framework agent instance.
@@ -1642,6 +1691,9 @@ async def evaluate_agent(
1642
1691
  running the agent. A single response is wrapped into a one-element
1643
1692
  list. When provided, ``queries`` must also be provided to
1644
1693
  construct the conversation for evaluation.
1694
+ tools: Tool definitions for evaluation, overriding automatic discovery
1695
+ for every item. These are not passed to ``agent.run``. An empty
1696
+ sequence disables tool definitions.
1645
1697
  evaluators: One or more ``Evaluator`` instances.
1646
1698
  eval_name: Display name (defaults to agent name).
1647
1699
  context: Optional context for groundedness evaluation.
@@ -1746,6 +1798,7 @@ async def evaluate_agent(
1746
1798
  query=q,
1747
1799
  response=r,
1748
1800
  agent=agent,
1801
+ tools=tools,
1749
1802
  context=context,
1750
1803
  )
1751
1804
  )
@@ -1766,6 +1819,7 @@ async def evaluate_agent(
1766
1819
  query=query,
1767
1820
  response=response,
1768
1821
  agent=agent,
1822
+ tools=tools,
1769
1823
  context=context,
1770
1824
  )
1771
1825
  )