solace-agent-mesh 1.0.9__py3-none-any.whl → 1.3.0__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 solace-agent-mesh might be problematic. Click here for more details.
- solace_agent_mesh/agent/adk/adk_llm.txt +182 -42
- solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +171 -0
- solace_agent_mesh/agent/adk/callbacks.py +165 -104
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +0 -18
- solace_agent_mesh/agent/adk/models/models_llm.txt +104 -55
- solace_agent_mesh/agent/adk/runner.py +25 -17
- solace_agent_mesh/agent/adk/services.py +3 -3
- solace_agent_mesh/agent/adk/setup.py +11 -0
- solace_agent_mesh/agent/adk/stream_parser.py +8 -1
- solace_agent_mesh/agent/adk/tool_wrapper.py +10 -3
- solace_agent_mesh/agent/agent_llm.txt +355 -18
- solace_agent_mesh/agent/protocol/event_handlers.py +460 -317
- solace_agent_mesh/agent/protocol/protocol_llm.txt +54 -7
- solace_agent_mesh/agent/sac/app.py +2 -2
- solace_agent_mesh/agent/sac/component.py +211 -517
- solace_agent_mesh/agent/sac/sac_llm.txt +133 -63
- solace_agent_mesh/agent/testing/testing_llm.txt +25 -58
- solace_agent_mesh/agent/tools/peer_agent_tool.py +15 -11
- solace_agent_mesh/agent/tools/tools_llm.txt +234 -69
- solace_agent_mesh/agent/utils/artifact_helpers.py +35 -1
- solace_agent_mesh/agent/utils/utils_llm.txt +90 -105
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/6e0db977.39a79ca9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{75384d09.ccd480c4.js → 75384d09.bf78fbdb.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/90dd9cf6.88f385ea.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.fb68323a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.08d30374.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +105 -0
- solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html +53 -0
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
- solace_agent_mesh/assets/docs/lunr-index-1757433031159.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1757433031159.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/assets/docs/sitemap.xml +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +125 -48
- solace_agent_mesh/cli/commands/eval_cmd.py +14 -0
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +53 -31
- solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +19 -8
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +80 -25
- solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +32 -10
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +74 -15
- solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +0 -2
- solace_agent_mesh/cli/commands/run_cmd.py +5 -3
- solace_agent_mesh/cli/utils.py +68 -12
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-vY5eu2lI.js +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/client-BeBkzgWW.js +25 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-Bjys1KQs.js +339 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-CE0AeXyK.js +395 -0
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -2
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -3
- solace_agent_mesh/common/a2a/__init__.py +213 -0
- solace_agent_mesh/common/a2a/a2a_llm.txt +182 -0
- solace_agent_mesh/common/a2a/artifact.py +328 -0
- solace_agent_mesh/common/a2a/events.py +183 -0
- solace_agent_mesh/common/a2a/message.py +307 -0
- solace_agent_mesh/common/a2a/protocol.py +513 -0
- solace_agent_mesh/common/a2a/task.py +127 -0
- solace_agent_mesh/common/a2a/translation.py +653 -0
- solace_agent_mesh/common/a2a/types.py +54 -0
- solace_agent_mesh/common/a2a_spec/a2a.json +2576 -0
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +407 -0
- solace_agent_mesh/common/a2a_spec/schemas/agent_progress_update.json +18 -0
- solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +31 -0
- solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +18 -0
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +235 -0
- solace_agent_mesh/common/a2a_spec/schemas/tool_invocation_start.json +26 -0
- solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +25 -0
- solace_agent_mesh/common/agent_registry.py +1 -1
- solace_agent_mesh/common/common_llm.txt +192 -70
- solace_agent_mesh/common/data_parts.py +99 -0
- solace_agent_mesh/common/middleware/middleware_llm.txt +17 -17
- solace_agent_mesh/common/sac/__init__.py +0 -0
- solace_agent_mesh/common/sac/sac_llm.txt +71 -0
- solace_agent_mesh/common/sac/sam_component_base.py +252 -0
- solace_agent_mesh/common/services/providers/providers_llm.txt +51 -84
- solace_agent_mesh/common/services/services_llm.txt +206 -26
- solace_agent_mesh/common/utils/artifact_utils.py +29 -0
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +176 -80
- solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
- solace_agent_mesh/common/utils/utils_llm.txt +323 -42
- solace_agent_mesh/config_portal/backend/common.py +2 -2
- solace_agent_mesh/config_portal/backend/plugin_catalog/constants.py +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-bFMKlzKf.js +98 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d845808d.js → manifest-89db7c30.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
- solace_agent_mesh/core_a2a/core_a2a_llm.txt +10 -8
- solace_agent_mesh/core_a2a/service.py +20 -44
- solace_agent_mesh/evaluation/message_organizer.py +35 -56
- solace_agent_mesh/evaluation/run.py +26 -5
- solace_agent_mesh/evaluation/subscriber.py +35 -10
- solace_agent_mesh/evaluation/summary_builder.py +27 -34
- solace_agent_mesh/gateway/base/app.py +27 -1
- solace_agent_mesh/gateway/base/base_llm.txt +177 -72
- solace_agent_mesh/gateway/base/component.py +294 -523
- solace_agent_mesh/gateway/gateway_llm.txt +299 -58
- solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +676 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +85 -0
- solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/b1c2d3e4f5g6_add_database_indexes.py +83 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/d5b3f8f2e9a0_create_initial_database.py +58 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +147 -0
- solace_agent_mesh/gateway/http_sse/api/__init__.py +11 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/session_controller.py +355 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +279 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/user_controller.py +35 -0
- solace_agent_mesh/gateway/http_sse/api/dto/__init__.py +10 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +37 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/session_requests.py +49 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +66 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +43 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/session_responses.py +68 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +74 -0
- solace_agent_mesh/gateway/http_sse/app.py +31 -1
- solace_agent_mesh/gateway/http_sse/application/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/application/services/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/application/services/session_service.py +135 -0
- solace_agent_mesh/gateway/http_sse/component.py +371 -236
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +29 -29
- solace_agent_mesh/gateway/http_sse/dependencies.py +142 -39
- solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/domain/entities/session.py +90 -0
- solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +54 -0
- solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +272 -36
- solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +123 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +16 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +119 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +31 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +12 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +174 -0
- solace_agent_mesh/gateway/http_sse/main.py +293 -91
- solace_agent_mesh/gateway/http_sse/routers/agents.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +137 -56
- solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +231 -5
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +199 -171
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
- solace_agent_mesh/gateway/http_sse/services/agent_service.py +1 -1
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +89 -135
- solace_agent_mesh/gateway/http_sse/services/task_service.py +2 -5
- solace_agent_mesh/gateway/http_sse/session_manager.py +64 -30
- solace_agent_mesh/gateway/http_sse/shared/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
- solace_agent_mesh/gateway/http_sse/shared/enums.py +45 -0
- solace_agent_mesh/gateway/http_sse/shared/types.py +45 -0
- solace_agent_mesh/solace_agent_mesh_llm.txt +362 -0
- solace_agent_mesh/templates/gateway_component_template.py +149 -98
- solace_agent_mesh/templates/shared_config.yaml +4 -5
- solace_agent_mesh/templates/webui.yaml +8 -10
- {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/METADATA +9 -6
- {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/RECORD +197 -141
- solace_agent_mesh/assets/docs/assets/js/f284c35a.731836ad.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.3d0e7879.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.05d19492.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1757091012487.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1757091012487.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-BmF2l6vg.js +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/client-D881Dttc.js +0 -49
- solace_agent_mesh/client/webui/frontend/static/assets/main-D0FnP_W4.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-Do32sFPX.js +0 -708
- solace_agent_mesh/common/a2a_protocol.py +0 -564
- solace_agent_mesh/common/client/__init__.py +0 -4
- solace_agent_mesh/common/client/card_resolver.py +0 -21
- solace_agent_mesh/common/client/client.py +0 -85
- solace_agent_mesh/common/client/client_llm.txt +0 -133
- solace_agent_mesh/common/server/__init__.py +0 -4
- solace_agent_mesh/common/server/server.py +0 -122
- solace_agent_mesh/common/server/server_llm.txt +0 -169
- solace_agent_mesh/common/server/task_manager.py +0 -291
- solace_agent_mesh/common/server/utils.py +0 -28
- solace_agent_mesh/common/types.py +0 -411
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -80
- solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
- /solace_agent_mesh/assets/docs/assets/js/{main.3d0e7879.js.LICENSE.txt → main.08d30374.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Helpers for A2A protocol-level concerns, such as topic construction and
|
|
3
|
+
parsing of JSON-RPC requests and responses.
|
|
4
|
+
"""
|
|
5
|
+
import re
|
|
6
|
+
import uuid
|
|
7
|
+
from typing import Any, Dict, Optional, Union
|
|
8
|
+
|
|
9
|
+
from solace_ai_connector.common.log import log
|
|
10
|
+
|
|
11
|
+
from a2a.types import (
|
|
12
|
+
A2ARequest,
|
|
13
|
+
CancelTaskRequest,
|
|
14
|
+
GetTaskSuccessResponse,
|
|
15
|
+
InternalError,
|
|
16
|
+
InvalidRequestError,
|
|
17
|
+
JSONRPCError,
|
|
18
|
+
JSONRPCResponse,
|
|
19
|
+
JSONRPCSuccessResponse,
|
|
20
|
+
Message,
|
|
21
|
+
MessageSendParams,
|
|
22
|
+
SendMessageRequest,
|
|
23
|
+
SendMessageSuccessResponse,
|
|
24
|
+
SendStreamingMessageRequest,
|
|
25
|
+
SendStreamingMessageSuccessResponse,
|
|
26
|
+
Task,
|
|
27
|
+
TaskArtifactUpdateEvent,
|
|
28
|
+
TaskIdParams,
|
|
29
|
+
TaskStatusUpdateEvent,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# --- Topic Construction Helpers ---
|
|
33
|
+
|
|
34
|
+
A2A_VERSION = "v1"
|
|
35
|
+
A2A_BASE_PATH = f"a2a/{A2A_VERSION}"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_a2a_base_topic(namespace: str) -> str:
|
|
39
|
+
"""Returns the base topic prefix for all A2A communication."""
|
|
40
|
+
if not namespace:
|
|
41
|
+
raise ValueError("A2A namespace cannot be empty.")
|
|
42
|
+
return f"{namespace.rstrip('/')}/{A2A_BASE_PATH}"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_discovery_topic(namespace: str) -> str:
|
|
46
|
+
"""Returns the topic for agent card discovery."""
|
|
47
|
+
return f"{get_a2a_base_topic(namespace)}/discovery/agentcards"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_agent_request_topic(namespace: str, agent_name: str) -> str:
|
|
51
|
+
"""Returns the topic for sending requests to a specific agent."""
|
|
52
|
+
if not agent_name:
|
|
53
|
+
raise ValueError("Agent name cannot be empty.")
|
|
54
|
+
return f"{get_a2a_base_topic(namespace)}/agent/request/{agent_name}"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_gateway_status_topic(namespace: str, gateway_id: str, task_id: str) -> str:
|
|
58
|
+
"""
|
|
59
|
+
Returns the specific topic for an agent to publish status updates TO a specific gateway instance.
|
|
60
|
+
"""
|
|
61
|
+
if not gateway_id:
|
|
62
|
+
raise ValueError("Gateway ID cannot be empty.")
|
|
63
|
+
if not task_id:
|
|
64
|
+
raise ValueError("Task ID cannot be empty.")
|
|
65
|
+
return f"{get_a2a_base_topic(namespace)}/gateway/status/{gateway_id}/{task_id}"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_gateway_response_topic(namespace: str, gateway_id: str, task_id: str) -> str:
|
|
69
|
+
"""
|
|
70
|
+
Returns the specific topic for an agent to publish the final response TO a specific gateway instance.
|
|
71
|
+
Includes task_id for potential correlation/filtering, though gateway might subscribe more broadly.
|
|
72
|
+
"""
|
|
73
|
+
if not gateway_id:
|
|
74
|
+
raise ValueError("Gateway ID cannot be empty.")
|
|
75
|
+
if not task_id:
|
|
76
|
+
raise ValueError("Task ID cannot be empty.")
|
|
77
|
+
return f"{get_a2a_base_topic(namespace)}/gateway/response/{gateway_id}/{task_id}"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_gateway_status_subscription_topic(namespace: str, self_gateway_id: str) -> str:
|
|
81
|
+
"""
|
|
82
|
+
Returns the wildcard topic for a gateway instance to subscribe to receive status updates
|
|
83
|
+
intended for it.
|
|
84
|
+
"""
|
|
85
|
+
if not self_gateway_id:
|
|
86
|
+
raise ValueError("Gateway ID is required for gateway status subscription")
|
|
87
|
+
return f"{get_a2a_base_topic(namespace)}/gateway/status/{self_gateway_id}/>"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def get_gateway_response_subscription_topic(
|
|
91
|
+
namespace: str, self_gateway_id: str
|
|
92
|
+
) -> str:
|
|
93
|
+
"""
|
|
94
|
+
Returns the wildcard topic for a gateway instance to subscribe to receive final responses
|
|
95
|
+
intended for it.
|
|
96
|
+
"""
|
|
97
|
+
if not self_gateway_id:
|
|
98
|
+
raise ValueError("Gateway ID is required for gateway response subscription")
|
|
99
|
+
return f"{get_a2a_base_topic(namespace)}/gateway/response/{self_gateway_id}/>"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def get_peer_agent_status_topic(
|
|
103
|
+
namespace: str, delegating_agent_name: str, sub_task_id: str
|
|
104
|
+
) -> str:
|
|
105
|
+
"""
|
|
106
|
+
Returns the topic for publishing status updates for a sub-task *back to the delegating agent*.
|
|
107
|
+
This topic includes the delegating agent's name.
|
|
108
|
+
"""
|
|
109
|
+
if not delegating_agent_name:
|
|
110
|
+
raise ValueError("delegating_agent_name is required for peer status topic")
|
|
111
|
+
return (
|
|
112
|
+
f"{get_a2a_base_topic(namespace)}/agent/status/{delegating_agent_name}/{sub_task_id}"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def get_agent_response_topic(
|
|
117
|
+
namespace: str, delegating_agent_name: str, sub_task_id: str
|
|
118
|
+
) -> str:
|
|
119
|
+
"""
|
|
120
|
+
Returns the specific topic for publishing the final response for a sub-task
|
|
121
|
+
back to the delegating agent. Includes the delegating agent's name.
|
|
122
|
+
"""
|
|
123
|
+
if not delegating_agent_name:
|
|
124
|
+
raise ValueError("delegating_agent_name is required for peer response topic")
|
|
125
|
+
if not sub_task_id:
|
|
126
|
+
raise ValueError("sub_task_id is required for peer response topic")
|
|
127
|
+
return f"{get_a2a_base_topic(namespace)}/agent/response/{delegating_agent_name}/{sub_task_id}"
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def get_agent_response_subscription_topic(namespace: str, self_agent_name: str) -> str:
|
|
131
|
+
"""
|
|
132
|
+
Returns the wildcard topic for an agent to subscribe to receive responses
|
|
133
|
+
for tasks it delegated. Includes the agent's own name.
|
|
134
|
+
"""
|
|
135
|
+
if not self_agent_name:
|
|
136
|
+
raise ValueError("self_agent_name is required for agent response subscription")
|
|
137
|
+
return f"{get_a2a_base_topic(namespace)}/agent/response/{self_agent_name}/>"
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def get_agent_status_subscription_topic(namespace: str, self_agent_name: str) -> str:
|
|
141
|
+
"""
|
|
142
|
+
Returns the wildcard topic for an agent to subscribe to receive status updates
|
|
143
|
+
for tasks it delegated. Includes the agent's own name.
|
|
144
|
+
"""
|
|
145
|
+
if not self_agent_name:
|
|
146
|
+
raise ValueError("self_agent_name is required for agent status subscription")
|
|
147
|
+
return f"{get_a2a_base_topic(namespace)}/agent/status/{self_agent_name}/>"
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def get_client_response_topic(namespace: str, client_id: str) -> str:
|
|
151
|
+
"""Returns the topic for publishing the final response TO a specific client."""
|
|
152
|
+
if not client_id:
|
|
153
|
+
raise ValueError("Client ID cannot be empty.")
|
|
154
|
+
return f"{get_a2a_base_topic(namespace)}/client/response/{client_id}"
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def get_client_status_topic(namespace: str, client_id: str, task_id: str) -> str:
|
|
158
|
+
"""
|
|
159
|
+
Returns the specific topic for publishing status updates for a task *to the original client*.
|
|
160
|
+
This topic is client and task-specific.
|
|
161
|
+
"""
|
|
162
|
+
if not client_id:
|
|
163
|
+
raise ValueError("Client ID cannot be empty.")
|
|
164
|
+
if not task_id:
|
|
165
|
+
raise ValueError("Task ID cannot be empty.")
|
|
166
|
+
return f"{get_a2a_base_topic(namespace)}/client/status/{client_id}/{task_id}"
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def get_client_status_subscription_topic(namespace: str, client_id: str) -> str:
|
|
170
|
+
"""
|
|
171
|
+
Returns the wildcard topic for a client to subscribe to receive status updates
|
|
172
|
+
for tasks it initiated. Includes the client's own ID.
|
|
173
|
+
"""
|
|
174
|
+
if not client_id:
|
|
175
|
+
raise ValueError("Client ID cannot be empty.")
|
|
176
|
+
return f"{get_a2a_base_topic(namespace)}/client/status/{client_id}/>"
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def subscription_to_regex(subscription: str) -> str:
|
|
180
|
+
"""Converts a Solace topic subscription string to a regex pattern."""
|
|
181
|
+
# Escape regex special characters except for Solace wildcards
|
|
182
|
+
pattern = re.escape(subscription)
|
|
183
|
+
# Replace Solace single-level wildcard '*' with regex equivalent '[^/]+'
|
|
184
|
+
pattern = pattern.replace(r"\*", r"[^/]+")
|
|
185
|
+
# Replace Solace multi-level wildcard '>' at the end with regex equivalent '.*'
|
|
186
|
+
if pattern.endswith(r"/>"):
|
|
187
|
+
pattern = pattern[:-1] + r".*" # Remove escaped '>' and add '.*'
|
|
188
|
+
return pattern
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def topic_matches_subscription(topic: str, subscription: str) -> bool:
|
|
192
|
+
"""Checks if a topic matches a Solace subscription pattern."""
|
|
193
|
+
regex_pattern = subscription_to_regex(subscription)
|
|
194
|
+
return re.fullmatch(regex_pattern, topic) is not None
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# --- JSON-RPC Envelope Helpers ---
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def get_request_id(request: A2ARequest) -> str | int:
|
|
201
|
+
"""Gets the JSON-RPC request ID from any A2A request object."""
|
|
202
|
+
return request.root.id
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def get_request_method(request: A2ARequest) -> str:
|
|
206
|
+
"""Gets the JSON-RPC method name from any A2A request object."""
|
|
207
|
+
return request.root.method
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def get_message_from_send_request(request: A2ARequest) -> Optional[Message]:
|
|
211
|
+
"""
|
|
212
|
+
Safely gets the Message object from a SendMessageRequest or
|
|
213
|
+
SendStreamingMessageRequest. Returns None for other request types.
|
|
214
|
+
"""
|
|
215
|
+
if isinstance(request.root, (SendMessageRequest, SendStreamingMessageRequest)):
|
|
216
|
+
return request.root.params.message
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def get_task_id_from_cancel_request(request: A2ARequest) -> Optional[str]:
|
|
221
|
+
"""Safely gets the task ID from a CancelTaskRequest."""
|
|
222
|
+
if isinstance(request.root, CancelTaskRequest):
|
|
223
|
+
return request.root.params.id
|
|
224
|
+
return None
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def get_response_id(response: JSONRPCResponse) -> Optional[Union[str, int]]:
|
|
228
|
+
"""Safely gets the ID from any JSON-RPC response object."""
|
|
229
|
+
if hasattr(response.root, "id"):
|
|
230
|
+
return response.root.id
|
|
231
|
+
return None
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def get_response_result(response: JSONRPCResponse) -> Optional[Any]:
|
|
235
|
+
"""Safely gets the result object from any successful JSON-RPC response."""
|
|
236
|
+
if hasattr(response.root, "result"):
|
|
237
|
+
return response.root.result
|
|
238
|
+
return None
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def get_response_error(response: JSONRPCResponse) -> Optional[JSONRPCError]:
|
|
242
|
+
"""Safely gets the error object from any JSON-RPC error response."""
|
|
243
|
+
if hasattr(response.root, "error"):
|
|
244
|
+
return response.root.error
|
|
245
|
+
return None
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def get_error_message(error: JSONRPCError) -> str:
|
|
249
|
+
"""Safely gets the message string from a JSONRPCError object."""
|
|
250
|
+
return error.message
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def get_error_code(error: JSONRPCError) -> int:
|
|
254
|
+
"""Safely gets the code from a JSONRPCError object."""
|
|
255
|
+
return error.code
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def get_error_data(error: JSONRPCError) -> Optional[Any]:
|
|
259
|
+
"""Safely gets the data from a JSONRPCError object."""
|
|
260
|
+
return error.data
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def create_success_response(
|
|
264
|
+
result: Any, request_id: Optional[Union[str, int]]
|
|
265
|
+
) -> JSONRPCResponse:
|
|
266
|
+
"""
|
|
267
|
+
Creates a successful JSON-RPC response object by wrapping the result in the
|
|
268
|
+
appropriate specific success response model based on the result's type.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
result: The result payload (e.g., Task, TaskStatusUpdateEvent).
|
|
272
|
+
request_id: The ID of the original request.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
A new `JSONRPCResponse` object.
|
|
276
|
+
|
|
277
|
+
Raises:
|
|
278
|
+
TypeError: If the result type is not a supported A2A model.
|
|
279
|
+
"""
|
|
280
|
+
specific_response: Any
|
|
281
|
+
if isinstance(result, (TaskStatusUpdateEvent, TaskArtifactUpdateEvent)):
|
|
282
|
+
specific_response = SendStreamingMessageSuccessResponse(
|
|
283
|
+
id=request_id, result=result
|
|
284
|
+
)
|
|
285
|
+
elif isinstance(result, Task):
|
|
286
|
+
# When returning a final task, GetTaskSuccessResponse is a suitable choice.
|
|
287
|
+
specific_response = GetTaskSuccessResponse(id=request_id, result=result)
|
|
288
|
+
else:
|
|
289
|
+
raise TypeError(
|
|
290
|
+
f"Unsupported result type for create_success_response: {type(result).__name__}"
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
return JSONRPCResponse(root=specific_response)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def create_internal_error_response(
|
|
297
|
+
message: str,
|
|
298
|
+
request_id: Optional[Union[str, int]],
|
|
299
|
+
data: Optional[Dict[str, Any]] = None,
|
|
300
|
+
) -> JSONRPCResponse:
|
|
301
|
+
"""
|
|
302
|
+
Creates a JSON-RPC response object for an InternalError.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
message: The error message.
|
|
306
|
+
request_id: The ID of the original request.
|
|
307
|
+
data: Optional structured data to include with the error.
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
A new `JSONRPCResponse` object containing an `InternalError`.
|
|
311
|
+
"""
|
|
312
|
+
error = create_internal_error(message=message, data=data)
|
|
313
|
+
return JSONRPCResponse(id=request_id, error=error)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def create_invalid_request_error_response(
|
|
317
|
+
message: str,
|
|
318
|
+
request_id: Optional[Union[str, int]],
|
|
319
|
+
data: Optional[Any] = None,
|
|
320
|
+
) -> JSONRPCResponse:
|
|
321
|
+
"""
|
|
322
|
+
Creates a JSON-RPC response object for an InvalidRequestError.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
message: The error message.
|
|
326
|
+
request_id: The ID of the original request.
|
|
327
|
+
data: Optional structured data to include with the error.
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
A new `JSONRPCResponse` object containing an `InvalidRequestError`.
|
|
331
|
+
"""
|
|
332
|
+
error = create_invalid_request_error(message=message, data=data)
|
|
333
|
+
return JSONRPCResponse(id=request_id, error=error)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def create_internal_error(
|
|
337
|
+
message: str,
|
|
338
|
+
data: Optional[Dict[str, Any]] = None,
|
|
339
|
+
) -> InternalError:
|
|
340
|
+
"""
|
|
341
|
+
Creates an InternalError object.
|
|
342
|
+
|
|
343
|
+
Args:
|
|
344
|
+
message: The error message.
|
|
345
|
+
data: Optional structured data to include with the error.
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
A new `InternalError` object.
|
|
349
|
+
"""
|
|
350
|
+
return InternalError(message=message, data=data)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def create_invalid_request_error(
|
|
354
|
+
message: str, data: Optional[Any] = None
|
|
355
|
+
) -> InvalidRequestError:
|
|
356
|
+
"""
|
|
357
|
+
Creates an InvalidRequestError object.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
message: The error message.
|
|
361
|
+
data: Optional structured data to include with the error.
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
A new `InvalidRequestError` object.
|
|
365
|
+
"""
|
|
366
|
+
return InvalidRequestError(message=message, data=data)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def create_generic_success_response(
|
|
370
|
+
result: Any, request_id: Optional[Union[str, int]] = None
|
|
371
|
+
) -> JSONRPCSuccessResponse:
|
|
372
|
+
"""
|
|
373
|
+
Creates a generic successful JSON-RPC response object.
|
|
374
|
+
Note: This is for non-A2A-spec-compliant endpoints that use a similar structure.
|
|
375
|
+
|
|
376
|
+
Args:
|
|
377
|
+
result: The result payload for the response.
|
|
378
|
+
request_id: The ID of the original request.
|
|
379
|
+
|
|
380
|
+
Returns:
|
|
381
|
+
A new `JSONRPCSuccessResponse` object.
|
|
382
|
+
"""
|
|
383
|
+
return JSONRPCSuccessResponse(id=request_id, result=result)
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def create_error_response(
|
|
387
|
+
error: JSONRPCError,
|
|
388
|
+
request_id: Optional[Union[str, int]],
|
|
389
|
+
) -> JSONRPCResponse:
|
|
390
|
+
"""
|
|
391
|
+
Creates a JSON-RPC error response object from a given error model.
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
error: The JSONRPCError model instance.
|
|
395
|
+
request_id: The ID of the original request.
|
|
396
|
+
|
|
397
|
+
Returns:
|
|
398
|
+
A new `JSONRPCResponse` object containing the error.
|
|
399
|
+
"""
|
|
400
|
+
return JSONRPCResponse(id=request_id, error=error)
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def create_cancel_task_request(task_id: str) -> CancelTaskRequest:
|
|
404
|
+
"""
|
|
405
|
+
Creates a CancelTaskRequest object.
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
task_id: The ID of the task to cancel.
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
A new `CancelTaskRequest` object.
|
|
412
|
+
"""
|
|
413
|
+
params = TaskIdParams(id=task_id)
|
|
414
|
+
return CancelTaskRequest(id=uuid.uuid4().hex, params=params)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def create_send_message_request(
|
|
418
|
+
message: Message,
|
|
419
|
+
task_id: str,
|
|
420
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
421
|
+
) -> SendMessageRequest:
|
|
422
|
+
"""
|
|
423
|
+
Creates a SendMessageRequest object.
|
|
424
|
+
|
|
425
|
+
Args:
|
|
426
|
+
message: The A2AMessage object to send.
|
|
427
|
+
task_id: The unique ID for the task.
|
|
428
|
+
metadata: Optional metadata for the send request.
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
A new `SendMessageRequest` object.
|
|
432
|
+
"""
|
|
433
|
+
send_params = MessageSendParams(message=message, metadata=metadata)
|
|
434
|
+
return SendMessageRequest(id=task_id, params=send_params)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def create_send_streaming_message_request(
|
|
438
|
+
message: Message,
|
|
439
|
+
task_id: str,
|
|
440
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
441
|
+
) -> SendStreamingMessageRequest:
|
|
442
|
+
"""
|
|
443
|
+
Creates a SendStreamingMessageRequest object.
|
|
444
|
+
|
|
445
|
+
Args:
|
|
446
|
+
message: The A2AMessage object to send.
|
|
447
|
+
task_id: The unique ID for the task.
|
|
448
|
+
metadata: Optional metadata for the send request.
|
|
449
|
+
|
|
450
|
+
Returns:
|
|
451
|
+
A new `SendStreamingMessageRequest` object.
|
|
452
|
+
"""
|
|
453
|
+
send_params = MessageSendParams(message=message, metadata=metadata)
|
|
454
|
+
return SendStreamingMessageRequest(id=task_id, params=send_params)
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def create_send_message_success_response(
|
|
458
|
+
result: Union[Task, Message], request_id: Optional[Union[str, int]]
|
|
459
|
+
) -> SendMessageSuccessResponse:
|
|
460
|
+
"""
|
|
461
|
+
Creates a SendMessageSuccessResponse object.
|
|
462
|
+
|
|
463
|
+
Args:
|
|
464
|
+
result: The result payload (Task or Message).
|
|
465
|
+
request_id: The ID of the original request.
|
|
466
|
+
|
|
467
|
+
Returns:
|
|
468
|
+
A new `SendMessageSuccessResponse` object.
|
|
469
|
+
"""
|
|
470
|
+
return SendMessageSuccessResponse(id=request_id, result=result)
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def create_send_streaming_message_success_response(
|
|
474
|
+
result: Union[Task, Message, TaskStatusUpdateEvent, TaskArtifactUpdateEvent],
|
|
475
|
+
request_id: Optional[Union[str, int]],
|
|
476
|
+
) -> SendStreamingMessageSuccessResponse:
|
|
477
|
+
"""
|
|
478
|
+
Creates a SendStreamingMessageSuccessResponse object.
|
|
479
|
+
|
|
480
|
+
Args:
|
|
481
|
+
result: The result payload.
|
|
482
|
+
request_id: The ID of the original request.
|
|
483
|
+
|
|
484
|
+
Returns:
|
|
485
|
+
A new `SendStreamingMessageSuccessResponse` object.
|
|
486
|
+
"""
|
|
487
|
+
return SendStreamingMessageSuccessResponse(id=request_id, result=result)
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def extract_task_id_from_topic(
|
|
491
|
+
topic: str, subscription_pattern: str, log_identifier: str
|
|
492
|
+
) -> Optional[str]:
|
|
493
|
+
"""Extracts the task ID from the end of a topic string based on the subscription."""
|
|
494
|
+
base_regex_str = subscription_to_regex(subscription_pattern).replace(r".*", "")
|
|
495
|
+
match = re.match(base_regex_str, topic)
|
|
496
|
+
if match:
|
|
497
|
+
task_id_part = topic[match.end() :]
|
|
498
|
+
task_id = task_id_part.lstrip("/")
|
|
499
|
+
if task_id:
|
|
500
|
+
log.debug(
|
|
501
|
+
"%s Extracted Task ID '%s' from topic '%s'",
|
|
502
|
+
log_identifier,
|
|
503
|
+
task_id,
|
|
504
|
+
topic,
|
|
505
|
+
)
|
|
506
|
+
return task_id
|
|
507
|
+
log.warning(
|
|
508
|
+
"%s Could not extract Task ID from topic '%s' using pattern '%s'",
|
|
509
|
+
log_identifier,
|
|
510
|
+
topic,
|
|
511
|
+
subscription_pattern,
|
|
512
|
+
)
|
|
513
|
+
return None
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Helpers for creating and consuming A2A Task objects.
|
|
3
|
+
"""
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
from a2a.types import (
|
|
8
|
+
Artifact,
|
|
9
|
+
Message,
|
|
10
|
+
Task,
|
|
11
|
+
TaskState,
|
|
12
|
+
TaskStatus,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# --- Creation Helpers ---
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def create_initial_task(
|
|
20
|
+
task_id: str,
|
|
21
|
+
context_id: str,
|
|
22
|
+
agent_name: str,
|
|
23
|
+
) -> Task:
|
|
24
|
+
"""
|
|
25
|
+
Creates an initial Task object, typically for returning to a client
|
|
26
|
+
after a task has been submitted.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
task_id: The unique ID for the task.
|
|
30
|
+
context_id: The context/session ID for the task.
|
|
31
|
+
agent_name: The name of the agent handling the task.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
A new `Task` object with 'submitted' status.
|
|
35
|
+
"""
|
|
36
|
+
initial_status = TaskStatus(state=TaskState.submitted)
|
|
37
|
+
return Task(
|
|
38
|
+
id=task_id,
|
|
39
|
+
context_id=context_id,
|
|
40
|
+
status=initial_status,
|
|
41
|
+
kind="task",
|
|
42
|
+
metadata={"agent_name": agent_name},
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def create_task_status(
|
|
47
|
+
state: TaskState,
|
|
48
|
+
message: Optional[Message] = None,
|
|
49
|
+
) -> TaskStatus:
|
|
50
|
+
"""
|
|
51
|
+
Creates a TaskStatus object.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
state: The state of the task.
|
|
55
|
+
message: An optional message providing more details.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
A new `TaskStatus` object with a current timestamp.
|
|
59
|
+
"""
|
|
60
|
+
return TaskStatus(
|
|
61
|
+
state=state,
|
|
62
|
+
message=message,
|
|
63
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def create_final_task(
|
|
68
|
+
task_id: str,
|
|
69
|
+
context_id: str,
|
|
70
|
+
final_status: TaskStatus,
|
|
71
|
+
artifacts: Optional[List[Artifact]] = None,
|
|
72
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
73
|
+
) -> Task:
|
|
74
|
+
"""
|
|
75
|
+
Creates a final Task object, typically for sending as a final response.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
task_id: The unique ID for the task.
|
|
79
|
+
context_id: The context/session ID for the task.
|
|
80
|
+
final_status: The final status of the task (e.g., completed, failed).
|
|
81
|
+
artifacts: A list of artifacts produced by the task.
|
|
82
|
+
metadata: Optional metadata to include in the task.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
A new `Task` object representing the final state.
|
|
86
|
+
"""
|
|
87
|
+
return Task(
|
|
88
|
+
id=task_id,
|
|
89
|
+
context_id=context_id,
|
|
90
|
+
status=final_status,
|
|
91
|
+
artifacts=artifacts,
|
|
92
|
+
metadata=metadata,
|
|
93
|
+
kind="task",
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# --- Consumption Helpers ---
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def get_task_id(task: Task) -> str:
|
|
101
|
+
"""Safely retrieves the ID from a Task object."""
|
|
102
|
+
return task.id
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def get_task_context_id(task: Task) -> str:
|
|
106
|
+
"""Safely retrieves the context ID from a Task object."""
|
|
107
|
+
return task.context_id
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def get_task_status(task: Task) -> TaskState:
|
|
111
|
+
"""Safely retrieves the state from a Task's status."""
|
|
112
|
+
return task.status.state
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def get_task_history(task: Task) -> Optional[List[Message]]:
|
|
116
|
+
"""Safely retrieves the history from a Task object."""
|
|
117
|
+
return task.history
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def get_task_artifacts(task: Task) -> Optional[List[Artifact]]:
|
|
121
|
+
"""Safely retrieves the artifacts from a Task object."""
|
|
122
|
+
return task.artifacts
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def get_task_metadata(task: Task) -> Optional[Dict[str, Any]]:
|
|
126
|
+
"""Safely retrieves the metadata from a Task object."""
|
|
127
|
+
return task.metadata
|