agentrun-sdk 0.1.2__py3-none-any.whl
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.
Potentially problematic release.
This version of agentrun-sdk might be problematic. Click here for more details.
- agentrun_operation_sdk/cli/__init__.py +1 -0
- agentrun_operation_sdk/cli/cli.py +19 -0
- agentrun_operation_sdk/cli/common.py +21 -0
- agentrun_operation_sdk/cli/runtime/__init__.py +1 -0
- agentrun_operation_sdk/cli/runtime/commands.py +203 -0
- agentrun_operation_sdk/client/client.py +75 -0
- agentrun_operation_sdk/operations/runtime/__init__.py +8 -0
- agentrun_operation_sdk/operations/runtime/configure.py +101 -0
- agentrun_operation_sdk/operations/runtime/launch.py +82 -0
- agentrun_operation_sdk/operations/runtime/models.py +31 -0
- agentrun_operation_sdk/services/runtime.py +152 -0
- agentrun_operation_sdk/utils/logging_config.py +72 -0
- agentrun_operation_sdk/utils/runtime/config.py +94 -0
- agentrun_operation_sdk/utils/runtime/container.py +280 -0
- agentrun_operation_sdk/utils/runtime/entrypoint.py +203 -0
- agentrun_operation_sdk/utils/runtime/schema.py +56 -0
- agentrun_sdk/__init__.py +7 -0
- agentrun_sdk/agent/__init__.py +25 -0
- agentrun_sdk/agent/agent.py +696 -0
- agentrun_sdk/agent/agent_result.py +46 -0
- agentrun_sdk/agent/conversation_manager/__init__.py +26 -0
- agentrun_sdk/agent/conversation_manager/conversation_manager.py +88 -0
- agentrun_sdk/agent/conversation_manager/null_conversation_manager.py +46 -0
- agentrun_sdk/agent/conversation_manager/sliding_window_conversation_manager.py +179 -0
- agentrun_sdk/agent/conversation_manager/summarizing_conversation_manager.py +252 -0
- agentrun_sdk/agent/state.py +97 -0
- agentrun_sdk/event_loop/__init__.py +9 -0
- agentrun_sdk/event_loop/event_loop.py +499 -0
- agentrun_sdk/event_loop/streaming.py +319 -0
- agentrun_sdk/experimental/__init__.py +4 -0
- agentrun_sdk/experimental/hooks/__init__.py +15 -0
- agentrun_sdk/experimental/hooks/events.py +123 -0
- agentrun_sdk/handlers/__init__.py +10 -0
- agentrun_sdk/handlers/callback_handler.py +70 -0
- agentrun_sdk/hooks/__init__.py +49 -0
- agentrun_sdk/hooks/events.py +80 -0
- agentrun_sdk/hooks/registry.py +247 -0
- agentrun_sdk/models/__init__.py +10 -0
- agentrun_sdk/models/anthropic.py +432 -0
- agentrun_sdk/models/bedrock.py +649 -0
- agentrun_sdk/models/litellm.py +225 -0
- agentrun_sdk/models/llamaapi.py +438 -0
- agentrun_sdk/models/mistral.py +539 -0
- agentrun_sdk/models/model.py +95 -0
- agentrun_sdk/models/ollama.py +357 -0
- agentrun_sdk/models/openai.py +436 -0
- agentrun_sdk/models/sagemaker.py +598 -0
- agentrun_sdk/models/writer.py +449 -0
- agentrun_sdk/multiagent/__init__.py +22 -0
- agentrun_sdk/multiagent/a2a/__init__.py +15 -0
- agentrun_sdk/multiagent/a2a/executor.py +148 -0
- agentrun_sdk/multiagent/a2a/server.py +252 -0
- agentrun_sdk/multiagent/base.py +92 -0
- agentrun_sdk/multiagent/graph.py +555 -0
- agentrun_sdk/multiagent/swarm.py +656 -0
- agentrun_sdk/py.typed +1 -0
- agentrun_sdk/session/__init__.py +18 -0
- agentrun_sdk/session/file_session_manager.py +216 -0
- agentrun_sdk/session/repository_session_manager.py +152 -0
- agentrun_sdk/session/s3_session_manager.py +272 -0
- agentrun_sdk/session/session_manager.py +73 -0
- agentrun_sdk/session/session_repository.py +51 -0
- agentrun_sdk/telemetry/__init__.py +21 -0
- agentrun_sdk/telemetry/config.py +194 -0
- agentrun_sdk/telemetry/metrics.py +476 -0
- agentrun_sdk/telemetry/metrics_constants.py +15 -0
- agentrun_sdk/telemetry/tracer.py +563 -0
- agentrun_sdk/tools/__init__.py +17 -0
- agentrun_sdk/tools/decorator.py +569 -0
- agentrun_sdk/tools/executor.py +137 -0
- agentrun_sdk/tools/loader.py +152 -0
- agentrun_sdk/tools/mcp/__init__.py +13 -0
- agentrun_sdk/tools/mcp/mcp_agent_tool.py +99 -0
- agentrun_sdk/tools/mcp/mcp_client.py +423 -0
- agentrun_sdk/tools/mcp/mcp_instrumentation.py +322 -0
- agentrun_sdk/tools/mcp/mcp_types.py +63 -0
- agentrun_sdk/tools/registry.py +607 -0
- agentrun_sdk/tools/structured_output.py +421 -0
- agentrun_sdk/tools/tools.py +217 -0
- agentrun_sdk/tools/watcher.py +136 -0
- agentrun_sdk/types/__init__.py +5 -0
- agentrun_sdk/types/collections.py +23 -0
- agentrun_sdk/types/content.py +188 -0
- agentrun_sdk/types/event_loop.py +48 -0
- agentrun_sdk/types/exceptions.py +81 -0
- agentrun_sdk/types/guardrails.py +254 -0
- agentrun_sdk/types/media.py +89 -0
- agentrun_sdk/types/session.py +152 -0
- agentrun_sdk/types/streaming.py +201 -0
- agentrun_sdk/types/tools.py +258 -0
- agentrun_sdk/types/traces.py +5 -0
- agentrun_sdk-0.1.2.dist-info/METADATA +51 -0
- agentrun_sdk-0.1.2.dist-info/RECORD +115 -0
- agentrun_sdk-0.1.2.dist-info/WHEEL +5 -0
- agentrun_sdk-0.1.2.dist-info/entry_points.txt +2 -0
- agentrun_sdk-0.1.2.dist-info/top_level.txt +3 -0
- agentrun_wrapper/__init__.py +11 -0
- agentrun_wrapper/_utils/__init__.py +6 -0
- agentrun_wrapper/_utils/endpoints.py +16 -0
- agentrun_wrapper/identity/__init__.py +5 -0
- agentrun_wrapper/identity/auth.py +211 -0
- agentrun_wrapper/memory/__init__.py +6 -0
- agentrun_wrapper/memory/client.py +1697 -0
- agentrun_wrapper/memory/constants.py +103 -0
- agentrun_wrapper/memory/controlplane.py +626 -0
- agentrun_wrapper/py.typed +1 -0
- agentrun_wrapper/runtime/__init__.py +13 -0
- agentrun_wrapper/runtime/app.py +473 -0
- agentrun_wrapper/runtime/context.py +34 -0
- agentrun_wrapper/runtime/models.py +25 -0
- agentrun_wrapper/services/__init__.py +1 -0
- agentrun_wrapper/services/identity.py +192 -0
- agentrun_wrapper/tools/__init__.py +6 -0
- agentrun_wrapper/tools/browser_client.py +325 -0
- agentrun_wrapper/tools/code_interpreter_client.py +186 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""A2A-compatible wrapper for Strands Agent.
|
|
2
|
+
|
|
3
|
+
This module provides the A2AAgent class, which adapts a Strands Agent to the A2A protocol,
|
|
4
|
+
allowing it to be used in A2A-compatible systems.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Any, Literal
|
|
9
|
+
from urllib.parse import urlparse
|
|
10
|
+
|
|
11
|
+
import uvicorn
|
|
12
|
+
from a2a.server.apps import A2AFastAPIApplication, A2AStarletteApplication
|
|
13
|
+
from a2a.server.events import QueueManager
|
|
14
|
+
from a2a.server.request_handlers import DefaultRequestHandler
|
|
15
|
+
from a2a.server.tasks import InMemoryTaskStore, PushNotificationConfigStore, PushNotificationSender, TaskStore
|
|
16
|
+
from a2a.types import AgentCapabilities, AgentCard, AgentSkill
|
|
17
|
+
from fastapi import FastAPI
|
|
18
|
+
from starlette.applications import Starlette
|
|
19
|
+
|
|
20
|
+
from ...agent.agent import Agent as SAAgent
|
|
21
|
+
from .executor import StrandsA2AExecutor
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class A2AServer:
|
|
27
|
+
"""A2A-compatible wrapper for Strands Agent."""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
agent: SAAgent,
|
|
32
|
+
*,
|
|
33
|
+
# AgentCard
|
|
34
|
+
host: str = "0.0.0.0",
|
|
35
|
+
port: int = 9000,
|
|
36
|
+
http_url: str | None = None,
|
|
37
|
+
serve_at_root: bool = False,
|
|
38
|
+
version: str = "0.0.1",
|
|
39
|
+
skills: list[AgentSkill] | None = None,
|
|
40
|
+
# RequestHandler
|
|
41
|
+
task_store: TaskStore | None = None,
|
|
42
|
+
queue_manager: QueueManager | None = None,
|
|
43
|
+
push_config_store: PushNotificationConfigStore | None = None,
|
|
44
|
+
push_sender: PushNotificationSender | None = None,
|
|
45
|
+
|
|
46
|
+
):
|
|
47
|
+
"""Initialize an A2A-compatible server from a Strands agent.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
agent: The Strands Agent to wrap with A2A compatibility.
|
|
51
|
+
host: The hostname or IP address to bind the A2A server to. Defaults to "0.0.0.0".
|
|
52
|
+
port: The port to bind the A2A server to. Defaults to 9000.
|
|
53
|
+
http_url: The public HTTP URL where this agent will be accessible. If provided,
|
|
54
|
+
this overrides the generated URL from host/port and enables automatic
|
|
55
|
+
path-based mounting for load balancer scenarios.
|
|
56
|
+
Example: "http://my-alb.amazonaws.com/agent1"
|
|
57
|
+
serve_at_root: If True, forces the server to serve at root path regardless of
|
|
58
|
+
http_url path component. Use this when your load balancer strips path prefixes.
|
|
59
|
+
Defaults to False.
|
|
60
|
+
version: The version of the agent. Defaults to "0.0.1".
|
|
61
|
+
skills: The list of capabilities or functions the agent can perform.
|
|
62
|
+
task_store: Custom task store implementation for managing agent tasks. If None,
|
|
63
|
+
uses InMemoryTaskStore.
|
|
64
|
+
queue_manager: Custom queue manager for handling message queues. If None,
|
|
65
|
+
no queue management is used.
|
|
66
|
+
push_config_store: Custom store for push notification configurations. If None,
|
|
67
|
+
no push notification configuration is used.
|
|
68
|
+
push_sender: Custom push notification sender implementation. If None,
|
|
69
|
+
no push notifications are sent.
|
|
70
|
+
"""
|
|
71
|
+
self.host = host
|
|
72
|
+
self.port = port
|
|
73
|
+
self.version = version
|
|
74
|
+
|
|
75
|
+
if http_url:
|
|
76
|
+
# Parse the provided URL to extract components for mounting
|
|
77
|
+
self.public_base_url, self.mount_path = self._parse_public_url(http_url)
|
|
78
|
+
self.http_url = http_url.rstrip("/") + "/"
|
|
79
|
+
|
|
80
|
+
# Override mount path if serve_at_root is requested
|
|
81
|
+
if serve_at_root:
|
|
82
|
+
self.mount_path = ""
|
|
83
|
+
else:
|
|
84
|
+
# Fall back to constructing the URL from host and port
|
|
85
|
+
self.public_base_url = f"http://{host}:{port}"
|
|
86
|
+
self.http_url = f"{self.public_base_url}/"
|
|
87
|
+
self.mount_path = ""
|
|
88
|
+
|
|
89
|
+
self.strands_agent = agent
|
|
90
|
+
self.name = self.strands_agent.name
|
|
91
|
+
self.description = self.strands_agent.description
|
|
92
|
+
self.capabilities = AgentCapabilities(streaming=True)
|
|
93
|
+
self.request_handler = DefaultRequestHandler(
|
|
94
|
+
agent_executor=StrandsA2AExecutor(self.strands_agent),
|
|
95
|
+
task_store=task_store or InMemoryTaskStore(),
|
|
96
|
+
queue_manager=queue_manager,
|
|
97
|
+
push_config_store=push_config_store,
|
|
98
|
+
push_sender=push_sender,
|
|
99
|
+
)
|
|
100
|
+
self._agent_skills = skills
|
|
101
|
+
logger.info("Strands' integration with A2A is experimental. Be aware of frequent breaking changes.")
|
|
102
|
+
|
|
103
|
+
def _parse_public_url(self, url: str) -> tuple[str, str]:
|
|
104
|
+
"""Parse the public URL into base URL and mount path components.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
url: The full public URL (e.g., "http://my-alb.amazonaws.com/agent1")
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
tuple: (base_url, mount_path) where base_url is the scheme+netloc
|
|
111
|
+
and mount_path is the path component
|
|
112
|
+
|
|
113
|
+
Example:
|
|
114
|
+
_parse_public_url("http://my-alb.amazonaws.com/agent1")
|
|
115
|
+
Returns: ("http://my-alb.amazonaws.com", "/agent1")
|
|
116
|
+
"""
|
|
117
|
+
parsed = urlparse(url.rstrip("/"))
|
|
118
|
+
base_url = f"{parsed.scheme}://{parsed.netloc}"
|
|
119
|
+
mount_path = parsed.path if parsed.path != "/" else ""
|
|
120
|
+
return base_url, mount_path
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
def public_agent_card(self) -> AgentCard:
|
|
124
|
+
"""Get the public AgentCard for this agent.
|
|
125
|
+
|
|
126
|
+
The AgentCard contains metadata about the agent, including its name,
|
|
127
|
+
description, URL, version, skills, and capabilities. This information
|
|
128
|
+
is used by other agents and systems to discover and interact with this agent.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
AgentCard: The public agent card containing metadata about this agent.
|
|
132
|
+
|
|
133
|
+
Raises:
|
|
134
|
+
ValueError: If name or description is None or empty.
|
|
135
|
+
"""
|
|
136
|
+
if not self.name:
|
|
137
|
+
raise ValueError("A2A agent name cannot be None or empty")
|
|
138
|
+
if not self.description:
|
|
139
|
+
raise ValueError("A2A agent description cannot be None or empty")
|
|
140
|
+
|
|
141
|
+
return AgentCard(
|
|
142
|
+
name=self.name,
|
|
143
|
+
description=self.description,
|
|
144
|
+
url=self.http_url,
|
|
145
|
+
version=self.version,
|
|
146
|
+
skills=self.agent_skills,
|
|
147
|
+
default_input_modes=["text"],
|
|
148
|
+
default_output_modes=["text"],
|
|
149
|
+
capabilities=self.capabilities,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def _get_skills_from_tools(self) -> list[AgentSkill]:
|
|
153
|
+
"""Get the list of skills from Strands agent tools.
|
|
154
|
+
|
|
155
|
+
Skills represent specific capabilities that the agent can perform.
|
|
156
|
+
Strands agent tools are adapted to A2A skills.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
list[AgentSkill]: A list of skills this agent provides.
|
|
160
|
+
"""
|
|
161
|
+
return [
|
|
162
|
+
AgentSkill(name=config["name"], id=config["name"], description=config["description"], tags=[])
|
|
163
|
+
for config in self.strands_agent.tool_registry.get_all_tools_config().values()
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def agent_skills(self) -> list[AgentSkill]:
|
|
168
|
+
"""Get the list of skills this agent provides."""
|
|
169
|
+
return self._agent_skills if self._agent_skills is not None else self._get_skills_from_tools()
|
|
170
|
+
|
|
171
|
+
@agent_skills.setter
|
|
172
|
+
def agent_skills(self, skills: list[AgentSkill]) -> None:
|
|
173
|
+
"""Set the list of skills this agent provides.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
skills: A list of AgentSkill objects to set for this agent.
|
|
177
|
+
"""
|
|
178
|
+
self._agent_skills = skills
|
|
179
|
+
|
|
180
|
+
def to_starlette_app(self) -> Starlette:
|
|
181
|
+
"""Create a Starlette application for serving this agent via HTTP.
|
|
182
|
+
|
|
183
|
+
Automatically handles path-based mounting if a mount path was derived
|
|
184
|
+
from the http_url parameter.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Starlette: A Starlette application configured to serve this agent.
|
|
188
|
+
"""
|
|
189
|
+
a2a_app = A2AStarletteApplication(agent_card=self.public_agent_card, http_handler=self.request_handler).build()
|
|
190
|
+
|
|
191
|
+
if self.mount_path:
|
|
192
|
+
# Create parent app and mount the A2A app at the specified path
|
|
193
|
+
parent_app = Starlette()
|
|
194
|
+
parent_app.mount(self.mount_path, a2a_app)
|
|
195
|
+
logger.info("Mounting A2A server at path: %s", self.mount_path)
|
|
196
|
+
return parent_app
|
|
197
|
+
|
|
198
|
+
return a2a_app
|
|
199
|
+
|
|
200
|
+
def to_fastapi_app(self) -> FastAPI:
|
|
201
|
+
"""Create a FastAPI application for serving this agent via HTTP.
|
|
202
|
+
|
|
203
|
+
Automatically handles path-based mounting if a mount path was derived
|
|
204
|
+
from the http_url parameter.
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
FastAPI: A FastAPI application configured to serve this agent.
|
|
208
|
+
"""
|
|
209
|
+
a2a_app = A2AFastAPIApplication(agent_card=self.public_agent_card, http_handler=self.request_handler).build()
|
|
210
|
+
|
|
211
|
+
if self.mount_path:
|
|
212
|
+
# Create parent app and mount the A2A app at the specified path
|
|
213
|
+
parent_app = FastAPI()
|
|
214
|
+
parent_app.mount(self.mount_path, a2a_app)
|
|
215
|
+
logger.info("Mounting A2A server at path: %s", self.mount_path)
|
|
216
|
+
return parent_app
|
|
217
|
+
|
|
218
|
+
return a2a_app
|
|
219
|
+
|
|
220
|
+
def serve(
|
|
221
|
+
self,
|
|
222
|
+
app_type: Literal["fastapi", "starlette"] = "starlette",
|
|
223
|
+
*,
|
|
224
|
+
host: str | None = None,
|
|
225
|
+
port: int | None = None,
|
|
226
|
+
**kwargs: Any,
|
|
227
|
+
) -> None:
|
|
228
|
+
"""Start the A2A server with the specified application type.
|
|
229
|
+
|
|
230
|
+
This method starts an HTTP server that exposes the agent via the A2A protocol.
|
|
231
|
+
The server can be implemented using either FastAPI or Starlette, depending on
|
|
232
|
+
the specified app_type.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
app_type: The type of application to serve, either "fastapi" or "starlette".
|
|
236
|
+
Defaults to "starlette".
|
|
237
|
+
host: The host address to bind the server to. Defaults to "0.0.0.0".
|
|
238
|
+
port: The port number to bind the server to. Defaults to 9000.
|
|
239
|
+
**kwargs: Additional keyword arguments to pass to uvicorn.run.
|
|
240
|
+
"""
|
|
241
|
+
try:
|
|
242
|
+
logger.info("Starting Strands A2A server...")
|
|
243
|
+
if app_type == "fastapi":
|
|
244
|
+
uvicorn.run(self.to_fastapi_app(), host=host or self.host, port=port or self.port, **kwargs)
|
|
245
|
+
else:
|
|
246
|
+
uvicorn.run(self.to_starlette_app(), host=host or self.host, port=port or self.port, **kwargs)
|
|
247
|
+
except KeyboardInterrupt:
|
|
248
|
+
logger.warning("Strands A2A server shutdown requested (KeyboardInterrupt).")
|
|
249
|
+
except Exception:
|
|
250
|
+
logger.exception("Strands A2A server encountered exception.")
|
|
251
|
+
finally:
|
|
252
|
+
logger.info("Strands A2A server has shutdown.")
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Multi-Agent Base Class.
|
|
2
|
+
|
|
3
|
+
Provides minimal foundation for multi-agent patterns (Swarm, Graph).
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from typing import Any, Union
|
|
10
|
+
|
|
11
|
+
from ..agent import AgentResult
|
|
12
|
+
from ..types.content import ContentBlock
|
|
13
|
+
from ..types.event_loop import Metrics, Usage
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Status(Enum):
|
|
17
|
+
"""Execution status for both graphs and nodes."""
|
|
18
|
+
|
|
19
|
+
PENDING = "pending"
|
|
20
|
+
EXECUTING = "executing"
|
|
21
|
+
COMPLETED = "completed"
|
|
22
|
+
FAILED = "failed"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class NodeResult:
|
|
27
|
+
"""Unified result from node execution - handles both Agent and nested MultiAgentBase results.
|
|
28
|
+
|
|
29
|
+
The status field represents the semantic outcome of the node's work:
|
|
30
|
+
- COMPLETED: The node's task was successfully accomplished
|
|
31
|
+
- FAILED: The node's task failed or produced an error
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
# Core result data - single AgentResult, nested MultiAgentResult, or Exception
|
|
35
|
+
result: Union[AgentResult, "MultiAgentResult", Exception]
|
|
36
|
+
|
|
37
|
+
# Execution metadata
|
|
38
|
+
execution_time: int = 0
|
|
39
|
+
status: Status = Status.PENDING
|
|
40
|
+
|
|
41
|
+
# Accumulated metrics from this node and all children
|
|
42
|
+
accumulated_usage: Usage = field(default_factory=lambda: Usage(inputTokens=0, outputTokens=0, totalTokens=0))
|
|
43
|
+
accumulated_metrics: Metrics = field(default_factory=lambda: Metrics(latencyMs=0))
|
|
44
|
+
execution_count: int = 0
|
|
45
|
+
|
|
46
|
+
def get_agent_results(self) -> list[AgentResult]:
|
|
47
|
+
"""Get all AgentResult objects from this node, flattened if nested."""
|
|
48
|
+
if isinstance(self.result, Exception):
|
|
49
|
+
return [] # No agent results for exceptions
|
|
50
|
+
elif isinstance(self.result, AgentResult):
|
|
51
|
+
return [self.result]
|
|
52
|
+
else:
|
|
53
|
+
# Flatten nested results from MultiAgentResult
|
|
54
|
+
flattened = []
|
|
55
|
+
for nested_node_result in self.result.results.values():
|
|
56
|
+
flattened.extend(nested_node_result.get_agent_results())
|
|
57
|
+
return flattened
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class MultiAgentResult:
|
|
62
|
+
"""Result from multi-agent execution with accumulated metrics.
|
|
63
|
+
|
|
64
|
+
The status field represents the outcome of the MultiAgentBase execution:
|
|
65
|
+
- COMPLETED: The execution was successfully accomplished
|
|
66
|
+
- FAILED: The execution failed or produced an error
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
status: Status = Status.PENDING
|
|
70
|
+
results: dict[str, NodeResult] = field(default_factory=lambda: {})
|
|
71
|
+
accumulated_usage: Usage = field(default_factory=lambda: Usage(inputTokens=0, outputTokens=0, totalTokens=0))
|
|
72
|
+
accumulated_metrics: Metrics = field(default_factory=lambda: Metrics(latencyMs=0))
|
|
73
|
+
execution_count: int = 0
|
|
74
|
+
execution_time: int = 0
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class MultiAgentBase(ABC):
|
|
78
|
+
"""Base class for multi-agent helpers.
|
|
79
|
+
|
|
80
|
+
This class integrates with existing Strands Agent instances and provides
|
|
81
|
+
multi-agent orchestration capabilities.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
@abstractmethod
|
|
85
|
+
async def invoke_async(self, task: str | list[ContentBlock], **kwargs: Any) -> MultiAgentResult:
|
|
86
|
+
"""Invoke asynchronously."""
|
|
87
|
+
raise NotImplementedError("invoke_async not implemented")
|
|
88
|
+
|
|
89
|
+
@abstractmethod
|
|
90
|
+
def __call__(self, task: str | list[ContentBlock], **kwargs: Any) -> MultiAgentResult:
|
|
91
|
+
"""Invoke synchronously."""
|
|
92
|
+
raise NotImplementedError("__call__ not implemented")
|