agent-framework-core 1.3.0__tar.gz → 1.4.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 (91) hide show
  1. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/PKG-INFO +1 -1
  2. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/__init__.py +2 -0
  3. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_mcp.py +56 -6
  4. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_skills.py +580 -181
  5. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/pyproject.toml +1 -1
  6. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/LICENSE +0 -0
  7. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/README.md +0 -0
  8. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_agents.py +0 -0
  9. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_clients.py +0 -0
  10. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_compaction.py +0 -0
  11. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_docstrings.py +0 -0
  12. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_evaluation.py +0 -0
  13. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_feature_stage.py +0 -0
  14. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_harness/__init__.py +0 -0
  15. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_harness/_memory.py +0 -0
  16. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_harness/_mode.py +0 -0
  17. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_harness/_todo.py +0 -0
  18. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_middleware.py +0 -0
  19. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_serialization.py +0 -0
  20. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_sessions.py +0 -0
  21. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_settings.py +0 -0
  22. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_telemetry.py +0 -0
  23. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_tools.py +0 -0
  24. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_types.py +0 -0
  25. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/__init__.py +0 -0
  26. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_agent.py +0 -0
  27. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_agent_executor.py +0 -0
  28. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_agent_utils.py +0 -0
  29. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_checkpoint.py +0 -0
  30. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_checkpoint_encoding.py +0 -0
  31. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_const.py +0 -0
  32. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_conversation_history.py +0 -0
  33. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_edge.py +0 -0
  34. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_edge_runner.py +0 -0
  35. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_events.py +0 -0
  36. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_executor.py +0 -0
  37. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_function_executor.py +0 -0
  38. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_functional.py +0 -0
  39. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_message_utils.py +0 -0
  40. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_model_utils.py +0 -0
  41. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_request_info_mixin.py +0 -0
  42. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_runner.py +0 -0
  43. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_runner_context.py +0 -0
  44. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_state.py +0 -0
  45. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_typing_utils.py +0 -0
  46. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_validation.py +0 -0
  47. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_viz.py +0 -0
  48. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_workflow.py +0 -0
  49. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_workflow_builder.py +0 -0
  50. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_workflow_context.py +0 -0
  51. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_workflow_executor.py +0 -0
  52. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/a2a/__init__.py +0 -0
  53. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/a2a/__init__.pyi +0 -0
  54. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/ag_ui/__init__.py +0 -0
  55. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/ag_ui/__init__.pyi +0 -0
  56. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/amazon/__init__.py +0 -0
  57. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/amazon/__init__.pyi +0 -0
  58. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/anthropic/__init__.py +0 -0
  59. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/anthropic/__init__.pyi +0 -0
  60. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/azure/__init__.py +0 -0
  61. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/azure/__init__.pyi +0 -0
  62. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/chatkit/__init__.py +0 -0
  63. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/chatkit/__init__.pyi +0 -0
  64. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/declarative/__init__.py +0 -0
  65. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/declarative/__init__.pyi +0 -0
  66. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/devui/__init__.py +0 -0
  67. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/devui/__init__.pyi +0 -0
  68. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/exceptions.py +0 -0
  69. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/foundry/__init__.py +0 -0
  70. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/foundry/__init__.pyi +0 -0
  71. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/github/__init__.py +0 -0
  72. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/github/__init__.pyi +0 -0
  73. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/google/__init__.py +0 -0
  74. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/google/__init__.pyi +0 -0
  75. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/hyperlight/__init__.py +0 -0
  76. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/lab/__init__.py +0 -0
  77. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/mem0/__init__.py +0 -0
  78. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/mem0/__init__.pyi +0 -0
  79. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/microsoft/__init__.py +0 -0
  80. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/microsoft/__init__.pyi +0 -0
  81. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/observability.py +0 -0
  82. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/ollama/__init__.py +0 -0
  83. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/ollama/__init__.pyi +0 -0
  84. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/openai/__init__.py +0 -0
  85. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/openai/__init__.pyi +0 -0
  86. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/orchestrations/__init__.py +0 -0
  87. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/orchestrations/__init__.pyi +0 -0
  88. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/py.typed +0 -0
  89. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/redis/__init__.py +0 -0
  90. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/redis/__init__.pyi +0 -0
  91. {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/security.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-framework-core
3
- Version: 1.3.0
3
+ Version: 1.4.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
6
  Requires-Python: >=3.10
@@ -147,6 +147,7 @@ from ._skills import (
147
147
  InlineSkillScript,
148
148
  InMemorySkillsSource,
149
149
  Skill,
150
+ SkillFrontmatter,
150
151
  SkillResource,
151
152
  SkillScript,
152
153
  SkillScriptRunner,
@@ -432,6 +433,7 @@ __all__ = [
432
433
  "SessionContext",
433
434
  "SingleEdgeGroup",
434
435
  "Skill",
436
+ "SkillFrontmatter",
435
437
  "SkillResource",
436
438
  "SkillScript",
437
439
  "SkillScriptRunner",
@@ -10,7 +10,7 @@ import logging
10
10
  import re
11
11
  import sys
12
12
  from abc import abstractmethod
13
- from collections.abc import Callable, Collection, Sequence
13
+ from collections.abc import Callable, Collection, Coroutine, Sequence
14
14
  from contextlib import AsyncExitStack, _AsyncGeneratorContextManager # type: ignore
15
15
  from datetime import timedelta
16
16
  from functools import partial
@@ -261,9 +261,11 @@ class MCPTool:
261
261
  self.request_timeout = request_timeout
262
262
  self.client = client
263
263
  self._functions: list[FunctionTool] = []
264
+ self._tool_call_meta_by_name: dict[str, dict[str, Any]] = {}
264
265
  self.is_connected: bool = False
265
266
  self._tools_loaded: bool = False
266
267
  self._prompts_loaded: bool = False
268
+ self._pending_reload_tasks: set[asyncio.Task[None]] = set()
267
269
 
268
270
  def __str__(self) -> str:
269
271
  return f"MCPTool(name={self.name}, description={self.description})"
@@ -905,12 +907,47 @@ class MCPTool:
905
907
  if isinstance(message, types.ServerNotification):
906
908
  match message.root.method:
907
909
  case "notifications/tools/list_changed":
908
- await self.load_tools()
910
+ self._schedule_reload(self.load_tools())
909
911
  case "notifications/prompts/list_changed":
910
- await self.load_prompts()
912
+ self._schedule_reload(self.load_prompts())
911
913
  case _:
912
914
  logger.debug("Unhandled notification: %s", message.root.method)
913
915
 
916
+ def _schedule_reload(self, coro: Coroutine[Any, Any, None]) -> None:
917
+ """Schedule a reload coroutine as a background task.
918
+
919
+ Reloads (load_tools / load_prompts) triggered by MCP server
920
+ notifications must NOT be awaited inside the message handler because
921
+ the handler runs on the MCP SDK's single-threaded receive loop.
922
+ Awaiting a session request (e.g. ``list_tools``) from within that loop
923
+ deadlocks: the receive loop cannot read the response while it is
924
+ blocked waiting for the handler to return.
925
+
926
+ Instead we fire the reload as an independent ``asyncio.Task`` and keep
927
+ a strong reference in ``_pending_reload_tasks`` so it is not garbage-
928
+ collected before completion. Only one reload per kind (tools / prompts)
929
+ is kept in flight; a new notification cancels the previous pending task
930
+ for the same coroutine name to avoid unbounded growth.
931
+ """
932
+ # Cancel-and-replace: only one reload per kind should be in flight.
933
+ reload_name = f"mcp-reload:{self.name}:{coro.__qualname__}"
934
+ for existing in list(self._pending_reload_tasks):
935
+ if existing.get_name() == reload_name and not existing.done():
936
+ logger.debug("Cancelling in-flight reload %s; superseded by new notification", reload_name)
937
+ existing.cancel()
938
+
939
+ async def _safe_reload() -> None:
940
+ try:
941
+ await coro
942
+ except asyncio.CancelledError:
943
+ raise
944
+ except Exception:
945
+ logger.warning("Background MCP reload failed", exc_info=True)
946
+
947
+ task = asyncio.create_task(_safe_reload(), name=reload_name)
948
+ self._pending_reload_tasks.add(task)
949
+ task.add_done_callback(self._pending_reload_tasks.discard)
950
+
914
951
  def _determine_approval_mode(
915
952
  self,
916
953
  *candidate_names: str,
@@ -990,6 +1027,7 @@ class MCPTool:
990
1027
 
991
1028
  # Track existing function names to prevent duplicates
992
1029
  existing_names = {func.name for func in self._functions}
1030
+ self._tool_call_meta_by_name.clear()
993
1031
 
994
1032
  params: types.PaginatedRequestParams | None = None
995
1033
  while True:
@@ -999,6 +1037,9 @@ class MCPTool:
999
1037
  tool_list = await self.session.list_tools(params=params) # type: ignore[union-attr]
1000
1038
 
1001
1039
  for tool in tool_list.tools:
1040
+ if tool.meta is not None:
1041
+ self._tool_call_meta_by_name[tool.name] = dict(tool.meta)
1042
+
1002
1043
  normalized_name = _normalize_mcp_name(tool.name)
1003
1044
  local_name = _build_prefixed_mcp_name(normalized_name, self.tool_name_prefix)
1004
1045
 
@@ -1047,6 +1088,14 @@ class MCPTool:
1047
1088
  params = types.PaginatedRequestParams(cursor=tool_list.nextCursor)
1048
1089
 
1049
1090
  async def _close_on_owner(self) -> None:
1091
+ # Cancel any pending reload tasks before tearing down the session.
1092
+ tasks = list(self._pending_reload_tasks)
1093
+ for task in tasks:
1094
+ task.cancel()
1095
+ self._pending_reload_tasks.clear()
1096
+ if tasks:
1097
+ await asyncio.gather(*tasks, return_exceptions=True)
1098
+
1050
1099
  await self._safe_close_exit_stack()
1051
1100
  self._exit_stack = AsyncExitStack()
1052
1101
  self.session = None
@@ -1141,14 +1190,15 @@ class MCPTool:
1141
1190
  }
1142
1191
  }
1143
1192
 
1144
- # Inject OpenTelemetry trace context into MCP _meta for distributed tracing.
1145
- otel_meta = _inject_otel_into_mcp_meta()
1193
+ # Some MCP proxies require their tools/list metadata to be echoed on tools/call.
1194
+ tool_meta = self._tool_call_meta_by_name.get(tool_name)
1195
+ meta = _inject_otel_into_mcp_meta(dict(tool_meta) if tool_meta is not None else None)
1146
1196
 
1147
1197
  parser = self.parse_tool_results or self._parse_tool_result_from_mcp
1148
1198
  # Try the operation, reconnecting once if the connection is closed
1149
1199
  for attempt in range(2):
1150
1200
  try:
1151
- result = await self.session.call_tool(tool_name, arguments=filtered_kwargs, meta=otel_meta) # type: ignore
1201
+ result = await self.session.call_tool(tool_name, arguments=filtered_kwargs, meta=meta) # type: ignore
1152
1202
  if result.isError:
1153
1203
  parsed = parser(result)
1154
1204
  text = (