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.
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/PKG-INFO +1 -1
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/__init__.py +2 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_mcp.py +56 -6
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_skills.py +580 -181
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/pyproject.toml +1 -1
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/LICENSE +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/README.md +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_agents.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_clients.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_compaction.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_docstrings.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_evaluation.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_feature_stage.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_harness/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_harness/_memory.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_harness/_mode.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_harness/_todo.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_middleware.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_serialization.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_sessions.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_settings.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_telemetry.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_tools.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_types.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_agent.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_agent_executor.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_agent_utils.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_checkpoint.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_checkpoint_encoding.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_const.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_conversation_history.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_edge.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_edge_runner.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_events.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_executor.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_function_executor.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_functional.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_message_utils.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_model_utils.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_request_info_mixin.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_runner.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_runner_context.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_state.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_typing_utils.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_validation.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_viz.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_workflow.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_workflow_builder.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_workflow_context.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/_workflows/_workflow_executor.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/a2a/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/a2a/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/ag_ui/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/ag_ui/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/amazon/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/amazon/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/anthropic/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/anthropic/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/azure/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/azure/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/chatkit/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/chatkit/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/declarative/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/declarative/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/devui/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/devui/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/exceptions.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/foundry/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/foundry/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/github/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/github/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/google/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/google/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/hyperlight/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/lab/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/mem0/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/mem0/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/microsoft/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/microsoft/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/observability.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/ollama/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/ollama/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/openai/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/openai/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/orchestrations/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/orchestrations/__init__.pyi +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/py.typed +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/redis/__init__.py +0 -0
- {agent_framework_core-1.3.0 → agent_framework_core-1.4.0}/agent_framework/redis/__init__.pyi +0 -0
- {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
|
+
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
|
-
|
|
910
|
+
self._schedule_reload(self.load_tools())
|
|
909
911
|
case "notifications/prompts/list_changed":
|
|
910
|
-
|
|
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
|
-
#
|
|
1145
|
-
|
|
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=
|
|
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 = (
|