agentenv-framework-protocol 0.1.350__tar.gz → 0.1.351__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.
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/PKG-INFO +26 -1
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/README.md +24 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/pyproject.toml +2 -1
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/__init__.py +2 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/a2a_agent/extensions.py +2 -2
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/a2a_agent/framework.py +69 -4
- agentenv_framework_protocol-0.1.351/src/agentenv_protocol/a2a_agent/peer_agents.py +422 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/agent_env_environment.py +16 -2
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/transfers.py +11 -4
- agentenv_framework_protocol-0.1.351/tests/test_a2a_peer_agents.py +338 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_agent_env_environment.py +44 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/.gitignore +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/LICENSE +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/NOTICE +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/THIRD_PARTY_NOTICES.md +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/examples/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/examples/advanced_agent.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/examples/basic_agent.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/examples/custom_extensions_agent.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/examples/multimodal_agent.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/examples/reference_model.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/examples/streaming_agent.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/a2a_agent/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/a2a_agent/_trajectory_log.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/a2a_agent/_triggers.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/a2a_agent/registry.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/a2a_agent/staging.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/a2a_agent/tasks/__init__.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/a2a_agent/tasks/v1.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/client.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/manifest.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/preflight.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/tool_client.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/tool_context.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/src/agentenv_protocol/types.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_a2a_agent.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_a2a_agent_examples.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_a2a_object_transfers.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_a2a_staging.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_a2a_trajectory_log.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_client.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_data_objects.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_intake.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_manifest.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_preflight.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_tool_client.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_tool_context.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_tool_context_fastmcp.py +0 -0
- {agentenv_framework_protocol-0.1.350 → agentenv_framework_protocol-0.1.351}/tests/test_tool_context_injection.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentenv-framework-protocol
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.351
|
|
4
4
|
Summary: Open data-plane protocol and server SDK for agent environments.
|
|
5
5
|
Project-URL: Homepage, https://www.agentenvframework.com
|
|
6
6
|
Project-URL: Documentation, https://www.agentenvframework.com/docs
|
|
@@ -30,6 +30,7 @@ Requires-Dist: pydantic>=2.11
|
|
|
30
30
|
Requires-Dist: starlette>=0.37
|
|
31
31
|
Provides-Extra: agent
|
|
32
32
|
Requires-Dist: a2a-sdk[http-server]<0.4,>=0.3.26; extra == 'agent'
|
|
33
|
+
Requires-Dist: mcp<2,>=1.25; extra == 'agent'
|
|
33
34
|
Requires-Dist: python-multipart>=0.0.13; extra == 'agent'
|
|
34
35
|
Requires-Dist: regex>=2023.12.25; extra == 'agent'
|
|
35
36
|
Requires-Dist: uvicorn>=0.30; extra == 'agent'
|
|
@@ -126,6 +127,15 @@ environment-prefixed tools without knowing the name at class-definition time; an
|
|
|
126
127
|
servers an env deploys behind one gateway: if two serve a name, the gateway serves none of their
|
|
127
128
|
tools and the deploy fails naming it, so prefix with `{environment_name}` when servers may share one.
|
|
128
129
|
|
|
130
|
+
`@tool(..., hidden_by_default=True)` makes being hidden a fixed property of the tool, for plumbing a
|
|
131
|
+
task drives (a trigger's tool action, a simulated party) that the agent under test must not see. The
|
|
132
|
+
tool is listed with `_meta` `{"agentenv.io/hiddenByDefault": true}` (`HIDDEN_BY_DEFAULT_META_KEY`),
|
|
133
|
+
and the gateway hides it from every role, in its MCP `tools/list` and `/step`, until a tool-access
|
|
134
|
+
step names it. Steps that name it show and hide it as they do any tool. Steps for every tool
|
|
135
|
+
(`tools: "*"`) never show it, but as with any tool they replace earlier steps: one for a role clears
|
|
136
|
+
that role's earlier named steps, and a full reset (`role: "*", tools: "*"`) clears all of them, so
|
|
137
|
+
grant a hidden tool after such steps. Trigger tool actions call it as usual.
|
|
138
|
+
|
|
129
139
|
`AgentEnvStarletteApplication` mounts the same handler onto a Starlette/FastAPI app instead of
|
|
130
140
|
FastMCP; since those apps have no MCP tool registry, constructing one with `@tool` methods
|
|
131
141
|
raises.
|
|
@@ -706,6 +716,21 @@ tools with (agent-env relays the env card's name: the MultiEnv's declared name,
|
|
|
706
716
|
`env` + 4 random digits, giving e.g. `mcp__env4821__<tool>`); when absent the agent mints
|
|
707
717
|
`mcp_<8 hex>`.
|
|
708
718
|
|
|
719
|
+
`PEER_AGENTS_V1` lets an agent delegate to the other agents in its task. AgentEnv
|
|
720
|
+
sets the routing table with `POST /ext/peer-agents` (`{"peers": [{"name", "url",
|
|
721
|
+
"card", "description"}]}`; an empty list clears it, and names must be unique), and
|
|
722
|
+
`GET /ext/peer-agents` returns it. An agent that enables the extension without
|
|
723
|
+
handlers of its own gets the SDK's: the SDK serves six MCP tools, `peer_list`,
|
|
724
|
+
`peer_get_card`, `peer_send_message` (send and wait, for at most 50 s, so a call
|
|
725
|
+
answers within the 60 s MCP clients commonly give a request), `peer_start_task`,
|
|
726
|
+
`peer_get_task` and `peer_cancel_task`, at `/ext/peer-agents/mcp` on the agent's
|
|
727
|
+
own port, and adds them to every task's `request.mcp_servers` as `peer_agents`, so
|
|
728
|
+
a harness that connects the task's MCP servers gives its model the tools with no
|
|
729
|
+
code of its own. The tools wrap the peers' A2A `message/send`, `tasks/get` and
|
|
730
|
+
`tasks/cancel`; they answer loopback callers only, while the application's lifespan
|
|
731
|
+
runs, and the name `peer_agents` is reserved from `MCP_CONFIG_V1.add`. An agent that
|
|
732
|
+
overrides both operations keeps the table itself and gets no tools.
|
|
733
|
+
|
|
709
734
|
`ATTRIBUTION_PROBE_V1.probe` lets a caller check that an agent forwards attribution
|
|
710
735
|
upstream. Attribution is an open map of string dimensions, like AgentEnv's cost
|
|
711
736
|
attribution: the SDK assigns no keys, and each deployment uses whatever dimensions
|
|
@@ -81,6 +81,15 @@ environment-prefixed tools without knowing the name at class-definition time; an
|
|
|
81
81
|
servers an env deploys behind one gateway: if two serve a name, the gateway serves none of their
|
|
82
82
|
tools and the deploy fails naming it, so prefix with `{environment_name}` when servers may share one.
|
|
83
83
|
|
|
84
|
+
`@tool(..., hidden_by_default=True)` makes being hidden a fixed property of the tool, for plumbing a
|
|
85
|
+
task drives (a trigger's tool action, a simulated party) that the agent under test must not see. The
|
|
86
|
+
tool is listed with `_meta` `{"agentenv.io/hiddenByDefault": true}` (`HIDDEN_BY_DEFAULT_META_KEY`),
|
|
87
|
+
and the gateway hides it from every role, in its MCP `tools/list` and `/step`, until a tool-access
|
|
88
|
+
step names it. Steps that name it show and hide it as they do any tool. Steps for every tool
|
|
89
|
+
(`tools: "*"`) never show it, but as with any tool they replace earlier steps: one for a role clears
|
|
90
|
+
that role's earlier named steps, and a full reset (`role: "*", tools: "*"`) clears all of them, so
|
|
91
|
+
grant a hidden tool after such steps. Trigger tool actions call it as usual.
|
|
92
|
+
|
|
84
93
|
`AgentEnvStarletteApplication` mounts the same handler onto a Starlette/FastAPI app instead of
|
|
85
94
|
FastMCP; since those apps have no MCP tool registry, constructing one with `@tool` methods
|
|
86
95
|
raises.
|
|
@@ -661,6 +670,21 @@ tools with (agent-env relays the env card's name: the MultiEnv's declared name,
|
|
|
661
670
|
`env` + 4 random digits, giving e.g. `mcp__env4821__<tool>`); when absent the agent mints
|
|
662
671
|
`mcp_<8 hex>`.
|
|
663
672
|
|
|
673
|
+
`PEER_AGENTS_V1` lets an agent delegate to the other agents in its task. AgentEnv
|
|
674
|
+
sets the routing table with `POST /ext/peer-agents` (`{"peers": [{"name", "url",
|
|
675
|
+
"card", "description"}]}`; an empty list clears it, and names must be unique), and
|
|
676
|
+
`GET /ext/peer-agents` returns it. An agent that enables the extension without
|
|
677
|
+
handlers of its own gets the SDK's: the SDK serves six MCP tools, `peer_list`,
|
|
678
|
+
`peer_get_card`, `peer_send_message` (send and wait, for at most 50 s, so a call
|
|
679
|
+
answers within the 60 s MCP clients commonly give a request), `peer_start_task`,
|
|
680
|
+
`peer_get_task` and `peer_cancel_task`, at `/ext/peer-agents/mcp` on the agent's
|
|
681
|
+
own port, and adds them to every task's `request.mcp_servers` as `peer_agents`, so
|
|
682
|
+
a harness that connects the task's MCP servers gives its model the tools with no
|
|
683
|
+
code of its own. The tools wrap the peers' A2A `message/send`, `tasks/get` and
|
|
684
|
+
`tasks/cancel`; they answer loopback callers only, while the application's lifespan
|
|
685
|
+
runs, and the name `peer_agents` is reserved from `MCP_CONFIG_V1.add`. An agent that
|
|
686
|
+
overrides both operations keeps the table itself and gets no tools.
|
|
687
|
+
|
|
664
688
|
`ATTRIBUTION_PROBE_V1.probe` lets a caller check that an agent forwards attribution
|
|
665
689
|
upstream. Attribution is an open map of string dimensions, like AgentEnv's cost
|
|
666
690
|
attribution: the SDK assigns no keys, and each deployment uses whatever dimensions
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "agentenv-framework-protocol"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.351"
|
|
4
4
|
description = "Open data-plane protocol and server SDK for agent environments."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -30,6 +30,7 @@ dependencies = [
|
|
|
30
30
|
[project.optional-dependencies]
|
|
31
31
|
agent = [
|
|
32
32
|
"a2a-sdk[http-server]>=0.3.26,<0.4",
|
|
33
|
+
"mcp>=1.25,<2", # the peer-agents tools' MCP server; 2.0 removed the server API it serves them with
|
|
33
34
|
"python-multipart>=0.0.13", # the staging extension's upload forms
|
|
34
35
|
"regex>=2023.12.25",
|
|
35
36
|
"uvicorn>=0.30",
|
|
@@ -4,6 +4,7 @@ from . import client
|
|
|
4
4
|
from .preflight import intake_fit_check
|
|
5
5
|
from .tool_client import ToolResult, ToolSession, ToolSessionError
|
|
6
6
|
from .agent_env_environment import (
|
|
7
|
+
HIDDEN_BY_DEFAULT_META_KEY,
|
|
7
8
|
AgentEnvApplication,
|
|
8
9
|
AgentEnvEnvironment,
|
|
9
10
|
AgentEnvFastMCPApplication,
|
|
@@ -97,6 +98,7 @@ __all__ = [
|
|
|
97
98
|
"bound",
|
|
98
99
|
"ROLE_META_KEY",
|
|
99
100
|
"SESSION_META_KEY",
|
|
101
|
+
"HIDDEN_BY_DEFAULT_META_KEY",
|
|
100
102
|
"ROLE_HEADER",
|
|
101
103
|
"DEFAULT_ROLE",
|
|
102
104
|
"EnvironmentCapabilities",
|
|
@@ -1106,11 +1106,11 @@ PEER_AGENTS_V1 = ExtensionDefinition(
|
|
|
1106
1106
|
"set",
|
|
1107
1107
|
"POST",
|
|
1108
1108
|
"/ext/peer-agents",
|
|
1109
|
-
|
|
1109
|
+
SDK,
|
|
1110
1110
|
request_model=PeerAgentsSetRequest,
|
|
1111
1111
|
),
|
|
1112
1112
|
"list": _op(
|
|
1113
|
-
"list", "GET", "/ext/peer-agents",
|
|
1113
|
+
"list", "GET", "/ext/peer-agents", SDK, response_required=("peers",)
|
|
1114
1114
|
),
|
|
1115
1115
|
},
|
|
1116
1116
|
)
|
|
@@ -34,6 +34,7 @@ from .extensions import (
|
|
|
34
34
|
AGENT_CONFIG_V1,
|
|
35
35
|
MAX_TRAJECTORY_READ_EVENTS,
|
|
36
36
|
MCP_CONFIG_V1,
|
|
37
|
+
PEER_AGENTS_V1,
|
|
37
38
|
SKILL_CONFIG_V1,
|
|
38
39
|
TRAJECTORY_V1,
|
|
39
40
|
TRIGGERS_V1,
|
|
@@ -45,6 +46,7 @@ from .extensions import (
|
|
|
45
46
|
ImplementationOwner,
|
|
46
47
|
McpAddRequest,
|
|
47
48
|
OperationReference,
|
|
49
|
+
PeerAgentsSetRequest,
|
|
48
50
|
TaskEventsTrajectoryRequest,
|
|
49
51
|
TaskObjectTrajectoryRequest,
|
|
50
52
|
TaskTrajectoryRequest,
|
|
@@ -54,6 +56,7 @@ from .extensions import (
|
|
|
54
56
|
TriggerRegisterRequest,
|
|
55
57
|
enable,
|
|
56
58
|
)
|
|
59
|
+
from .peer_agents import PEER_MCP_PATH, PEER_MCP_SERVER_NAME, PeerAgents
|
|
57
60
|
from .registry import RegisteredOperation, build_registry
|
|
58
61
|
from .staging import STAGING_ENDPOINT, StagingStore, staging_routes
|
|
59
62
|
from .tasks.v1 import (
|
|
@@ -545,6 +548,8 @@ class _SdkServices:
|
|
|
545
548
|
self._skill_registration_lock = asyncio.Lock()
|
|
546
549
|
self.card: Any = None
|
|
547
550
|
self.trigger_engine = TriggerEngine()
|
|
551
|
+
# Set when the SDK serves peer-agents/v1 for this agent.
|
|
552
|
+
self.peers: PeerAgents | None = None
|
|
548
553
|
|
|
549
554
|
def task_config(self) -> AgentConfig:
|
|
550
555
|
return self.config_model.model_validate(
|
|
@@ -611,6 +616,8 @@ class _SdkServices:
|
|
|
611
616
|
(AGENT_CONFIG_V1.uri, "get"): self.agent_config_get,
|
|
612
617
|
(MCP_CONFIG_V1.uri, "add"): self.mcp_add,
|
|
613
618
|
(MCP_CONFIG_V1.uri, "list"): self.mcp_list,
|
|
619
|
+
(PEER_AGENTS_V1.uri, "set"): self.peer_agents_set,
|
|
620
|
+
(PEER_AGENTS_V1.uri, "list"): self.peer_agents_list,
|
|
614
621
|
(SKILL_CONFIG_V1.uri, "list"): self.skill_list,
|
|
615
622
|
(TRAJECTORY_V1.uri, "get"): self.trajectory_get,
|
|
616
623
|
(TRIGGERS_V1.uri, "register"): self.triggers_register,
|
|
@@ -695,6 +702,8 @@ class _SdkServices:
|
|
|
695
702
|
name = request.name or f"mcp_{uuid.uuid4().hex[:8]}"
|
|
696
703
|
if name in self.mcp_servers:
|
|
697
704
|
raise HTTPException(status_code=409, detail=f"MCP name '{name}' is already registered")
|
|
705
|
+
if self.peers is not None and name == PEER_MCP_SERVER_NAME:
|
|
706
|
+
raise HTTPException(status_code=409, detail=f"MCP name '{name}' is the SDK's peer-agents server")
|
|
698
707
|
self.mcp_servers[name] = {
|
|
699
708
|
"url": url,
|
|
700
709
|
"headers": dict(request.headers) if request.headers else None,
|
|
@@ -708,10 +717,30 @@ class _SdkServices:
|
|
|
708
717
|
"url": registration["url"],
|
|
709
718
|
"has_headers": bool(registration.get("headers")),
|
|
710
719
|
}
|
|
711
|
-
for name, registration in self.
|
|
720
|
+
for name, registration in self.task_mcp_servers().items()
|
|
712
721
|
}
|
|
713
722
|
}
|
|
714
723
|
|
|
724
|
+
def task_mcp_servers(self) -> dict[str, dict[str, Any]]:
|
|
725
|
+
"""The MCP servers a task gets: those registered, and the SDK's peer-agents server when it serves one."""
|
|
726
|
+
peer_tools = self.peers.registration() if self.peers is not None else None
|
|
727
|
+
return {**self.mcp_servers, **({PEER_MCP_SERVER_NAME: peer_tools} if peer_tools else {})}
|
|
728
|
+
|
|
729
|
+
async def peer_agents_set(self, request: PeerAgentsSetRequest) -> dict[str, Any]:
|
|
730
|
+
names = [peer.name for peer in request.peers]
|
|
731
|
+
if len(set(names)) != len(names):
|
|
732
|
+
raise HTTPException(status_code=400, detail="peer names must be unique")
|
|
733
|
+
self._served_peers().set(request.peers)
|
|
734
|
+
return {"status": "updated", "peers": len(names)}
|
|
735
|
+
|
|
736
|
+
async def peer_agents_list(self) -> dict[str, Any]:
|
|
737
|
+
return {"peers": self._served_peers().listing()}
|
|
738
|
+
|
|
739
|
+
def _served_peers(self) -> PeerAgents:
|
|
740
|
+
if self.peers is None:
|
|
741
|
+
raise HTTPException(status_code=500, detail="the SDK serves no peer-agents tools for this agent")
|
|
742
|
+
return self.peers
|
|
743
|
+
|
|
715
744
|
async def skill_list(self) -> dict[str, Any]:
|
|
716
745
|
skills = {
|
|
717
746
|
name: {"description": description}
|
|
@@ -874,6 +903,24 @@ class DefaultExtensionHandlers:
|
|
|
874
903
|
return await _invoke(handler, request)
|
|
875
904
|
|
|
876
905
|
|
|
906
|
+
def _serving_peer_tools(
|
|
907
|
+
peers: PeerAgents,
|
|
908
|
+
inner: Callable[[Starlette], AbstractAsyncContextManager] | None,
|
|
909
|
+
) -> Callable[[Starlette], AbstractAsyncContextManager]:
|
|
910
|
+
"""The application's lifespan, ``inner``'s if it has one, with the peer-agents tools served throughout."""
|
|
911
|
+
|
|
912
|
+
@asynccontextmanager
|
|
913
|
+
async def lifespan(app: Starlette) -> AsyncIterator[Any]:
|
|
914
|
+
async with peers.serving():
|
|
915
|
+
if inner is None:
|
|
916
|
+
yield None
|
|
917
|
+
else:
|
|
918
|
+
async with inner(app) as state:
|
|
919
|
+
yield state
|
|
920
|
+
|
|
921
|
+
return lifespan
|
|
922
|
+
|
|
923
|
+
|
|
877
924
|
class A2AAgentApplication:
|
|
878
925
|
"""Resolved Agent Card, extension routes, and A2A task executor."""
|
|
879
926
|
|
|
@@ -930,6 +977,20 @@ class A2AAgentApplication:
|
|
|
930
977
|
f"extension operation {extension.definition.uri}.{operation.definition.name} "
|
|
931
978
|
f"conflicts with the staging routes below {STAGING_ENDPOINT}"
|
|
932
979
|
)
|
|
980
|
+
# The SDK serves peer-agents/v1's tools to an agent that enables it without handlers of its own.
|
|
981
|
+
peer_agents = next(
|
|
982
|
+
(extension for extension in self.registry.extensions if extension.definition.uri == PEER_AGENTS_V1.uri),
|
|
983
|
+
None,
|
|
984
|
+
)
|
|
985
|
+
if peer_agents is not None and not peer_agents.operations["set"].overridden:
|
|
986
|
+
for extension in self.registry.extensions:
|
|
987
|
+
for operation in extension.operations.values():
|
|
988
|
+
if operation.definition.path == PEER_MCP_PATH:
|
|
989
|
+
raise ValueError(
|
|
990
|
+
f"extension operation {extension.definition.uri}.{operation.definition.name} "
|
|
991
|
+
f"conflicts with the peer-agents tools at {PEER_MCP_PATH}"
|
|
992
|
+
)
|
|
993
|
+
self.services.peers = PeerAgents()
|
|
933
994
|
conformance = self.registry.conformance()
|
|
934
995
|
for override in conformance["standard_operation_overrides"]:
|
|
935
996
|
logger.warning(
|
|
@@ -965,9 +1026,13 @@ class A2AAgentApplication:
|
|
|
965
1026
|
)
|
|
966
1027
|
if self.staging.max_bytes:
|
|
967
1028
|
routes.extend(staging_routes(self.staging))
|
|
1029
|
+
lifespan = definition.lifespan
|
|
1030
|
+
if self.services.peers is not None:
|
|
1031
|
+
routes.append(Route(PEER_MCP_PATH, self.services.peers.app))
|
|
1032
|
+
lifespan = _serving_peer_tools(self.services.peers, lifespan)
|
|
968
1033
|
kwargs = {"routes": routes, "middleware": [Middleware(_ServingOnItsPort)]}
|
|
969
|
-
if
|
|
970
|
-
kwargs["lifespan"] =
|
|
1034
|
+
if lifespan is not None:
|
|
1035
|
+
kwargs["lifespan"] = lifespan
|
|
971
1036
|
self.app = Starlette(**kwargs)
|
|
972
1037
|
|
|
973
1038
|
try:
|
|
@@ -1171,7 +1236,7 @@ class _StandardExecutor:
|
|
|
1171
1236
|
_from_a2a_part(part) for part in (context.message.parts or [])
|
|
1172
1237
|
),
|
|
1173
1238
|
config=task_config,
|
|
1174
|
-
mcp_servers=self._services.
|
|
1239
|
+
mcp_servers=self._services.task_mcp_servers(),
|
|
1175
1240
|
skills=tuple(self._services.skills),
|
|
1176
1241
|
metadata=metadata,
|
|
1177
1242
|
session_ref=self._services.session_ref_for_context(task.context_id),
|