solace-agent-mesh 1.0.7__py3-none-any.whl → 1.1.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.

Files changed (163) hide show
  1. solace_agent_mesh/agent/adk/adk_llm.txt +182 -42
  2. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +171 -0
  3. solace_agent_mesh/agent/adk/callbacks.py +165 -104
  4. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +0 -18
  5. solace_agent_mesh/agent/adk/models/models_llm.txt +104 -55
  6. solace_agent_mesh/agent/adk/runner.py +7 -5
  7. solace_agent_mesh/agent/adk/services.py +9 -1
  8. solace_agent_mesh/agent/adk/setup.py +11 -0
  9. solace_agent_mesh/agent/adk/stream_parser.py +8 -1
  10. solace_agent_mesh/agent/adk/tool_wrapper.py +10 -3
  11. solace_agent_mesh/agent/agent_llm.txt +355 -18
  12. solace_agent_mesh/agent/protocol/event_handlers.py +433 -296
  13. solace_agent_mesh/agent/protocol/protocol_llm.txt +54 -7
  14. solace_agent_mesh/agent/sac/app.py +1 -1
  15. solace_agent_mesh/agent/sac/component.py +212 -517
  16. solace_agent_mesh/agent/sac/sac_llm.txt +133 -63
  17. solace_agent_mesh/agent/testing/testing_llm.txt +25 -58
  18. solace_agent_mesh/agent/tools/peer_agent_tool.py +15 -11
  19. solace_agent_mesh/agent/tools/tools_llm.txt +234 -69
  20. solace_agent_mesh/agent/utils/artifact_helpers.py +35 -1
  21. solace_agent_mesh/agent/utils/utils_llm.txt +90 -105
  22. solace_agent_mesh/assets/docs/404.html +3 -3
  23. solace_agent_mesh/assets/docs/assets/js/{3d406171.7d02a73b.js → 3d406171.0b9eeed1.js} +1 -1
  24. solace_agent_mesh/assets/docs/assets/js/6e0db977.39a79ca9.js +1 -0
  25. solace_agent_mesh/assets/docs/assets/js/{75384d09.ccd480c4.js → 75384d09.bf78fbdb.js} +1 -1
  26. solace_agent_mesh/assets/docs/assets/js/90dd9cf6.88f385ea.js +1 -0
  27. solace_agent_mesh/assets/docs/assets/js/f284c35a.fb68323a.js +1 -0
  28. solace_agent_mesh/assets/docs/assets/js/main.a75ecc0d.js +2 -0
  29. solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +1 -0
  30. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +4 -4
  31. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +4 -4
  32. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +4 -4
  33. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
  34. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +4 -4
  35. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +4 -4
  36. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
  37. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +4 -4
  38. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +4 -4
  39. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +4 -4
  40. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +4 -4
  41. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +4 -4
  42. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
  43. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +4 -4
  44. 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
  45. solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html +53 -0
  46. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +4 -4
  47. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +8 -8
  48. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +4 -4
  49. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
  50. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +4 -4
  51. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +4 -4
  52. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +4 -4
  53. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +4 -4
  54. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +4 -4
  55. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +4 -4
  56. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +4 -4
  57. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +4 -4
  58. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +4 -4
  59. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +4 -4
  60. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +4 -4
  61. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +4 -4
  62. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +4 -4
  63. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +4 -4
  64. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
  65. solace_agent_mesh/assets/docs/lunr-index-1756992446316.json +1 -0
  66. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  67. solace_agent_mesh/assets/docs/search-doc-1756992446316.json +1 -0
  68. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  69. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  70. solace_agent_mesh/cli/__init__.py +1 -1
  71. solace_agent_mesh/cli/commands/add_cmd/web_add_agent_step.py +12 -3
  72. solace_agent_mesh/cli/commands/add_cmd/web_add_gateway_step.py +10 -14
  73. solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +2 -15
  74. solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +6 -2
  75. solace_agent_mesh/cli/utils.py +15 -0
  76. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-DvlO62me.js → authCallback-BmF2l6vg.js} +1 -1
  77. solace_agent_mesh/client/webui/frontend/static/assets/{client-bp6u3qVZ.js → client-D881Dttc.js} +4 -4
  78. solace_agent_mesh/client/webui/frontend/static/assets/main-C0jZjYa8.js +699 -0
  79. solace_agent_mesh/client/webui/frontend/static/assets/main-CCeG324-.css +1 -0
  80. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +2 -2
  81. solace_agent_mesh/client/webui/frontend/static/index.html +3 -3
  82. solace_agent_mesh/common/a2a/__init__.py +213 -0
  83. solace_agent_mesh/common/a2a/a2a_llm.txt +182 -0
  84. solace_agent_mesh/common/a2a/artifact.py +328 -0
  85. solace_agent_mesh/common/a2a/events.py +183 -0
  86. solace_agent_mesh/common/a2a/message.py +307 -0
  87. solace_agent_mesh/common/a2a/protocol.py +513 -0
  88. solace_agent_mesh/common/a2a/task.py +127 -0
  89. solace_agent_mesh/common/a2a/translation.py +653 -0
  90. solace_agent_mesh/common/a2a/types.py +54 -0
  91. solace_agent_mesh/common/a2a_spec/a2a.json +2576 -0
  92. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +407 -0
  93. solace_agent_mesh/common/a2a_spec/schemas/agent_progress_update.json +18 -0
  94. solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +31 -0
  95. solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +18 -0
  96. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +235 -0
  97. solace_agent_mesh/common/a2a_spec/schemas/tool_invocation_start.json +26 -0
  98. solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +25 -0
  99. solace_agent_mesh/common/agent_registry.py +1 -1
  100. solace_agent_mesh/common/common_llm.txt +192 -70
  101. solace_agent_mesh/common/data_parts.py +99 -0
  102. solace_agent_mesh/common/middleware/middleware_llm.txt +17 -17
  103. solace_agent_mesh/common/sac/__init__.py +0 -0
  104. solace_agent_mesh/common/sac/sac_llm.txt +71 -0
  105. solace_agent_mesh/common/sac/sam_component_base.py +252 -0
  106. solace_agent_mesh/common/services/providers/providers_llm.txt +51 -84
  107. solace_agent_mesh/common/services/services_llm.txt +206 -26
  108. solace_agent_mesh/common/utils/artifact_utils.py +29 -0
  109. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +176 -80
  110. solace_agent_mesh/common/utils/utils_llm.txt +323 -42
  111. solace_agent_mesh/config_portal/backend/common.py +1 -1
  112. solace_agent_mesh/config_portal/frontend/static/client/assets/{_index-MqsrTd6g.js → _index-Bym6YkMd.js} +74 -24
  113. solace_agent_mesh/config_portal/frontend/static/client/assets/{components-B7lKcHVY.js → components-Rk0n-9cK.js} +1 -1
  114. solace_agent_mesh/config_portal/frontend/static/client/assets/{entry.client-CEumGClk.js → entry.client-mvZjNKiz.js} +1 -1
  115. solace_agent_mesh/config_portal/frontend/static/client/assets/{index-DSo1AH_7.js → index-DzNKzXrc.js} +1 -1
  116. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-d845808d.js +1 -0
  117. solace_agent_mesh/config_portal/frontend/static/client/assets/{root-C4XmHinv.js → root-BWvk5-gF.js} +1 -1
  118. solace_agent_mesh/config_portal/frontend/static/client/index.html +3 -3
  119. solace_agent_mesh/core_a2a/core_a2a_llm.txt +10 -8
  120. solace_agent_mesh/core_a2a/service.py +20 -44
  121. solace_agent_mesh/gateway/base/app.py +27 -1
  122. solace_agent_mesh/gateway/base/base_llm.txt +177 -72
  123. solace_agent_mesh/gateway/base/component.py +294 -523
  124. solace_agent_mesh/gateway/gateway_llm.txt +299 -58
  125. solace_agent_mesh/gateway/http_sse/component.py +156 -183
  126. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +29 -29
  127. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +272 -36
  128. solace_agent_mesh/gateway/http_sse/main.py +8 -10
  129. solace_agent_mesh/gateway/http_sse/routers/agents.py +1 -1
  130. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +18 -4
  131. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +231 -5
  132. solace_agent_mesh/gateway/http_sse/routers/sessions.py +12 -7
  133. solace_agent_mesh/gateway/http_sse/routers/tasks.py +116 -169
  134. solace_agent_mesh/gateway/http_sse/services/agent_service.py +1 -1
  135. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +89 -135
  136. solace_agent_mesh/gateway/http_sse/services/task_service.py +2 -5
  137. solace_agent_mesh/solace_agent_mesh_llm.txt +362 -0
  138. solace_agent_mesh/templates/gateway_component_template.py +149 -98
  139. {solace_agent_mesh-1.0.7.dist-info → solace_agent_mesh-1.1.0.dist-info}/METADATA +5 -4
  140. {solace_agent_mesh-1.0.7.dist-info → solace_agent_mesh-1.1.0.dist-info}/RECORD +144 -127
  141. solace_agent_mesh/assets/docs/assets/js/f284c35a.731836ad.js +0 -1
  142. solace_agent_mesh/assets/docs/assets/js/main.d79f063b.js +0 -2
  143. solace_agent_mesh/assets/docs/assets/js/runtime~main.6415ad00.js +0 -1
  144. solace_agent_mesh/assets/docs/lunr-index-1756146501924.json +0 -1
  145. solace_agent_mesh/assets/docs/search-doc-1756146501924.json +0 -1
  146. solace_agent_mesh/client/webui/frontend/static/assets/main-BCpII1-0.css +0 -1
  147. solace_agent_mesh/client/webui/frontend/static/assets/main-BucUdn9m.js +0 -673
  148. solace_agent_mesh/common/a2a_protocol.py +0 -564
  149. solace_agent_mesh/common/client/__init__.py +0 -4
  150. solace_agent_mesh/common/client/card_resolver.py +0 -21
  151. solace_agent_mesh/common/client/client.py +0 -85
  152. solace_agent_mesh/common/client/client_llm.txt +0 -133
  153. solace_agent_mesh/common/server/__init__.py +0 -4
  154. solace_agent_mesh/common/server/server.py +0 -122
  155. solace_agent_mesh/common/server/server_llm.txt +0 -169
  156. solace_agent_mesh/common/server/task_manager.py +0 -291
  157. solace_agent_mesh/common/server/utils.py +0 -28
  158. solace_agent_mesh/common/types.py +0 -411
  159. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-28271392.js +0 -1
  160. /solace_agent_mesh/assets/docs/assets/js/{main.d79f063b.js.LICENSE.txt → main.a75ecc0d.js.LICENSE.txt} +0 -0
  161. {solace_agent_mesh-1.0.7.dist-info → solace_agent_mesh-1.1.0.dist-info}/WHEEL +0 -0
  162. {solace_agent_mesh-1.0.7.dist-info → solace_agent_mesh-1.1.0.dist-info}/entry_points.txt +0 -0
  163. {solace_agent_mesh-1.0.7.dist-info → solace_agent_mesh-1.1.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,133 +0,0 @@
1
- ## Quick Summary
2
- The `client` directory provides a Python-based client library for Agent-to-Agent (A2A) communication. It allows developers to discover remote agent capabilities via an "Agent Card" and then interact with that agent by sending tasks, receiving streaming responses, and managing the task lifecycle (getting status, cancelling, setting callbacks).
3
-
4
- ## Files Overview
5
- - `__init__.py`: Exposes the primary `A2AClient` and `A2ACardResolver` classes for easy importing.
6
- - `card_resolver.py`: Contains the `A2ACardResolver` class, used to discover and fetch an agent's capabilities from a well-known endpoint.
7
- - `client.py`: Contains the main `A2AClient` class for all communication with a remote agent, including sending tasks and managing them.
8
-
9
- ## Developer API Reference
10
-
11
- ### __init__.py
12
- **Purpose:** This file makes the main client classes available directly under the `client` package, simplifying imports for developers.
13
- **Import:** `from src.solace_agent_mesh.common.client import A2AClient, A2ACardResolver`
14
-
15
- **Constants/Variables:**
16
- - `__all__: list[str]` - A list of the public objects that are exported from this module: `["A2AClient", "A2ACardResolver"]`.
17
-
18
- ---
19
-
20
- ### card_resolver.py
21
- **Purpose:** This file provides a utility to resolve and fetch an agent's "Agent Card". The Agent Card is a JSON file that describes the agent's capabilities, its endpoint URL, and other metadata.
22
- **Import:** `from src.solace_agent_mesh.common.client import A2ACardResolver`
23
-
24
- **Classes:**
25
- - `A2ACardResolver(base_url: str, agent_card_path: str = "/.well-known/agent.json")` - A client to discover and fetch an agent's capability card.
26
- - `get_agent_card() -> AgentCard` - Makes an HTTP GET request to the constructed agent card URL, parses the JSON response, and returns it as an `AgentCard` object. Raises `A2AClientHTTPError` on network/status errors and `A2AClientJSONError` on parsing errors.
27
-
28
- **Usage Examples:**
29
- ```python
30
- from src.solace_agent_mesh.common.client import A2ACardResolver
31
- from src.solace_agent_mesh.common.types import AgentCard, A2AClientHTTPError
32
-
33
- # --- Example 1: Standard usage ---
34
- # Create a resolver for an agent hosted at a specific domain
35
- resolver = A2ACardResolver(base_url="https://some-agent.ai")
36
-
37
- try:
38
- # Fetch the agent's capability card from the default path
39
- # (https://some-agent.ai/.well-known/agent.json)
40
- agent_card: AgentCard = resolver.get_agent_card()
41
- print(f"Successfully fetched card for agent: {agent_card.name}")
42
- print(f"Agent API URL: {agent_card.url}")
43
- print(f"Supported capabilities: {agent_card.capabilities}")
44
-
45
- except A2AClientHTTPError as e:
46
- print(f"Error fetching agent card: {e.status_code} - {e.message}")
47
-
48
-
49
- # --- Example 2: Using a custom path for the agent card ---
50
- custom_path_resolver = A2ACardResolver(
51
- base_url="https://another-agent.com",
52
- agent_card_path="/api/v1/agent-info.json"
53
- )
54
- # This will fetch from https://another-agent.com/api/v1/agent-info.json
55
- custom_agent_card = custom_path_resolver.get_agent_card()
56
- print(f"Agent name from custom path: {custom_agent_card.name}")
57
- ```
58
-
59
- ---
60
-
61
- ### client.py
62
- **Purpose:** This file contains the core `A2AClient`, which is used to communicate with a remote agent's API endpoint. It handles sending various types of JSON-RPC requests for task management. All methods are asynchronous.
63
- **Import:** `from src.solace_agent_mesh.common.client import A2AClient`
64
-
65
- **Classes:**
66
- - `A2AClient(agent_card: AgentCard = None, url: str = None)` - The main client for interacting with a remote agent. You must provide either an `AgentCard` object (from `A2ACardResolver`) or a direct `url` string to its API endpoint.
67
- - `async send_task(self, payload: dict[str, Any]) -> SendTaskResponse` - Sends a task to the agent for processing. The `payload` should contain the action and its parameters. Returns a response typically containing a `task_id`.
68
- - `async send_task_streaming(self, payload: dict[str, Any]) -> AsyncIterable[SendTaskStreamingResponse]` - Sends a task that is expected to return a stream of events (Server-Sent Events). The `payload` is the same as `send_task`. Returns an async iterator that yields response chunks as they arrive.
69
- - `async get_task(self, payload: dict[str, Any]) -> GetTaskResponse` - Retrieves the current status and/or result of a previously submitted task. The `payload` must contain the `task_id`.
70
- - `async cancel_task(self, payload: dict[str, Any]) -> CancelTaskResponse` - Requests the cancellation of a running task. The `payload` must contain the `task_id`.
71
- - `async set_task_callback(self, payload: dict[str, Any]) -> SetTaskPushNotificationResponse` - Sets a callback URL for a specific task. The agent will send a notification to this URL upon task completion. The `payload` must contain the `task_id` and `callback_url`.
72
- - `async get_task_callback(self, payload: dict[str, Any]) -> GetTaskPushNotificationResponse` - Retrieves the currently configured callback URL for a task. The `payload` must contain the `task_id`.
73
-
74
- **Usage Examples:**
75
- ```python
76
- import asyncio
77
- from src.solace_agent_mesh.common.client import A2AClient, A2ACardResolver
78
-
79
- # Assume these types are available for type hinting
80
- # from src.solace_agent_mesh.common.types import SendTaskResponse, SendTaskStreamingResponse
81
-
82
- async def main():
83
- # First, discover the agent's capabilities and endpoint URL
84
- resolver = A2ACardResolver(base_url="https://some-agent.ai")
85
- agent_card = resolver.get_agent_card()
86
-
87
- # --- Initialization ---
88
- # Method 1: Initialize client using the discovered AgentCard
89
- client = A2AClient(agent_card=agent_card)
90
-
91
- # Method 2: Initialize client with a direct URL (if known)
92
- # client = A2AClient(url="https://some-agent.ai/api/v1/a2a")
93
-
94
- # --- Send a simple task ---
95
- print("--- Sending a simple task ---")
96
- task_payload = {"action": "summarize_text", "text": "A long article..."}
97
- send_response = await client.send_task(payload=task_payload)
98
- task_id = send_response.result.task_id
99
- print(f"Task created with ID: {task_id}")
100
-
101
- # --- Get task status ---
102
- print("\n--- Checking task status ---")
103
- status_response = await client.get_task(payload={"task_id": task_id})
104
- print(f"Task status: {status_response.result.status}")
105
-
106
- # --- Send a streaming task ---
107
- print("\n--- Sending a streaming task ---")
108
- stream_payload = {"action": "generate_story", "prompt": "A robot who discovers music"}
109
- async for chunk in client.send_task_streaming(payload=stream_payload):
110
- # Each chunk is a SendTaskStreamingResponse object
111
- print(f"Received stream chunk: {chunk.result.content_chunk}")
112
-
113
- # --- Set a callback URL for the task ---
114
- print("\n--- Setting a callback URL ---")
115
- await client.set_task_callback(
116
- payload={"task_id": task_id, "callback_url": "https://my-app.com/webhook"}
117
- )
118
- print("Callback URL set.")
119
-
120
- # --- Cancel a task ---
121
- print("\n--- Cancelling a task ---")
122
- cancel_response = await client.cancel_task(payload={"task_id": task_id})
123
- print(f"Task cancellation requested. Success: {cancel_response.result.cancelled}")
124
-
125
-
126
- if __name__ == "__main__":
127
- # Note: In a real application, you would use a running event loop.
128
- # This example assumes the agent endpoint is available and working.
129
- # To run this, you would need a live agent to connect to.
130
- # asyncio.run(main())
131
- print("Developer guide example executed.")
132
-
133
- ```
@@ -1,4 +0,0 @@
1
- from .server import A2AServer
2
- from .task_manager import TaskManager, InMemoryTaskManager
3
-
4
- __all__ = ["A2AServer", "TaskManager", "InMemoryTaskManager"]
@@ -1,122 +0,0 @@
1
- from starlette.applications import Starlette
2
- from starlette.responses import JSONResponse
3
- from sse_starlette.sse import EventSourceResponse
4
- from starlette.requests import Request
5
- from ...common.types import (
6
- A2ARequest,
7
- JSONRPCResponse,
8
- InvalidRequestError,
9
- JSONParseError,
10
- GetTaskRequest,
11
- CancelTaskRequest,
12
- SendTaskRequest,
13
- SetTaskPushNotificationRequest,
14
- GetTaskPushNotificationRequest,
15
- InternalError,
16
- AgentCard,
17
- TaskResubscriptionRequest,
18
- SendTaskStreamingRequest,
19
- )
20
- from pydantic import ValidationError
21
- import json
22
- from typing import AsyncIterable, Any
23
- from solace_ai_connector.common.log import log
24
-
25
- from ...common.server.task_manager import TaskManager
26
-
27
-
28
- class A2AServer:
29
- def __init__(
30
- self,
31
- host="0.0.0.0",
32
- port=5000,
33
- endpoint="/",
34
- agent_card: AgentCard = None,
35
- task_manager: TaskManager = None,
36
- ):
37
- self.host = host
38
- self.port = port
39
- self.endpoint = endpoint
40
- self.task_manager = task_manager
41
- self.agent_card = agent_card
42
- self.app = Starlette()
43
- self.app.add_route(self.endpoint, self._process_request, methods=["POST"])
44
- self.app.add_route(
45
- "/.well-known/agent.json", self._get_agent_card, methods=["GET"]
46
- )
47
-
48
- def start(self):
49
- if self.agent_card is None:
50
- raise ValueError("agent_card is not defined")
51
-
52
- if self.task_manager is None:
53
- raise ValueError("request_handler is not defined")
54
-
55
- import uvicorn
56
-
57
- uvicorn.run(self.app, host=self.host, port=self.port)
58
-
59
- def _get_agent_card(self, request: Request) -> JSONResponse:
60
- return JSONResponse(self.agent_card.model_dump(exclude_none=True))
61
-
62
- async def _process_request(self, request: Request):
63
- try:
64
- body = await request.json()
65
- json_rpc_request = A2ARequest.validate_python(body)
66
-
67
- if isinstance(json_rpc_request, GetTaskRequest):
68
- result = await self.task_manager.on_get_task(json_rpc_request)
69
- elif isinstance(json_rpc_request, SendTaskRequest):
70
- result = await self.task_manager.on_send_task(json_rpc_request)
71
- elif isinstance(json_rpc_request, SendTaskStreamingRequest):
72
- result = await self.task_manager.on_send_task_subscribe(
73
- json_rpc_request
74
- )
75
- elif isinstance(json_rpc_request, CancelTaskRequest):
76
- result = await self.task_manager.on_cancel_task(json_rpc_request)
77
- elif isinstance(json_rpc_request, SetTaskPushNotificationRequest):
78
- result = await self.task_manager.on_set_task_push_notification(
79
- json_rpc_request
80
- )
81
- elif isinstance(json_rpc_request, GetTaskPushNotificationRequest):
82
- result = await self.task_manager.on_get_task_push_notification(
83
- json_rpc_request
84
- )
85
- elif isinstance(json_rpc_request, TaskResubscriptionRequest):
86
- result = await self.task_manager.on_resubscribe_to_task(
87
- json_rpc_request
88
- )
89
- else:
90
- log.warning("Unexpected request type: %s", type(json_rpc_request))
91
- raise ValueError("Unexpected request type: %s" % type(request))
92
-
93
- return self._create_response(result)
94
-
95
- except Exception as e:
96
- return self._handle_exception(e)
97
-
98
- def _handle_exception(self, e: Exception) -> JSONResponse:
99
- if isinstance(e, json.decoder.JSONDecodeError):
100
- json_rpc_error = JSONParseError()
101
- elif isinstance(e, ValidationError):
102
- json_rpc_error = InvalidRequestError(data=json.loads(e.json()))
103
- else:
104
- log.error("Unhandled exception: %s", e, exc_info=True)
105
- json_rpc_error = InternalError()
106
-
107
- response = JSONRPCResponse(id=None, error=json_rpc_error)
108
- return JSONResponse(response.model_dump(exclude_none=True), status_code=400)
109
-
110
- def _create_response(self, result: Any) -> JSONResponse | EventSourceResponse:
111
- if isinstance(result, AsyncIterable):
112
-
113
- async def event_generator(result) -> AsyncIterable[dict[str, str]]:
114
- async for item in result:
115
- yield {"data": item.model_dump_json(exclude_none=True)}
116
-
117
- return EventSourceResponse(event_generator(result))
118
- elif isinstance(result, JSONRPCResponse):
119
- return JSONResponse(result.model_dump(exclude_none=True))
120
- else:
121
- log.error("Unexpected result type: %s", type(result))
122
- raise ValueError("Unexpected result type: %s" % type(result))
@@ -1,169 +0,0 @@
1
- ## Quick Summary
2
- The `server` directory provides a complete, stand-alone Agent-to-Agent (A2A) communication server. It is built using Starlette and implements the JSON-RPC 2.0 protocol for handling various task-related requests, including standard request-response, task streaming via Server-Sent Events (SSE), and push notification management. It features an extensible task management system with a default in-memory implementation.
3
-
4
- ## Files Overview
5
- - `__init__.py`: Exposes the primary public classes (`A2AServer`, `TaskManager`, `InMemoryTaskManager`) for easy access.
6
- - `server.py`: Contains the main `A2AServer` class, which sets up the Starlette web application, defines HTTP endpoints, and routes incoming A2A requests to the task manager.
7
- - `task_manager.py`: Defines the `TaskManager` abstract base class, which outlines the contract for handling all task operations, and provides a concrete `InMemoryTaskManager` implementation.
8
- - `utils.py`: A collection of utility functions for creating standardized error responses and checking modality compatibility.
9
-
10
- ## Developer API Reference
11
-
12
- ### __init__.py
13
- **Purpose:** This file makes the core server components available for direct import from the `server` package, simplifying access for developers.
14
- **Import:** `from solace_ai_connector.common.server import A2AServer, TaskManager, InMemoryTaskManager`
15
-
16
- ---
17
-
18
- ### server.py
19
- **Purpose:** Implements the core HTTP server for Agent-to-Agent (A2A) communication. It handles JSON-RPC request parsing, routing to the appropriate task manager methods, and response generation, including support for Server-Sent Events (SSE).
20
- **Import:** `from solace_ai_connector.common.server import A2AServer`
21
-
22
- **Classes:**
23
- - `A2AServer(host: str = "0.0.0.0", port: int = 5000, endpoint: str = "/", agent_card: AgentCard = None, task_manager: TaskManager = None)` - A Starlette-based web server that exposes A2A endpoints.
24
- - `start() -> None` - Starts the web server using uvicorn. Raises a `ValueError` if `agent_card` or `task_manager` are not set.
25
- - `host: str` - The host address the server will bind to.
26
- - `port: int` - The port the server will listen on.
27
- - `endpoint: str` - The main API endpoint path for receiving JSON-RPC requests.
28
- - `task_manager: TaskManager` - The handler responsible for all task-related business logic.
29
- - `agent_card: AgentCard` - The metadata for the agent, served at `/.well-known/agent.json`.
30
-
31
- **Usage Examples:**
32
- ```python
33
- # main.py
34
- from solace_ai_connector.common.server import A2AServer, InMemoryTaskManager
35
- from solace_ai_connector.common.types import AgentCard
36
-
37
- # 1. Define the agent's capabilities and metadata
38
- my_agent_card = AgentCard(
39
- id="my-awesome-agent-v1",
40
- name="Awesome Agent",
41
- version="1.0.0",
42
- description="An agent that does awesome things.",
43
- documentation_url="https://example.com/docs",
44
- supported_tasks=["summarize", "translate"],
45
- input_modalities=["text/plain"],
46
- output_modalities=["text/plain"]
47
- )
48
-
49
- # 2. Instantiate a task manager (or use your own custom implementation)
50
- # This example uses a basic in-memory manager.
51
- # For a real agent, you would extend InMemoryTaskManager to implement your logic.
52
- class MyAgentTaskManager(InMemoryTaskManager):
53
- async def on_send_task(self, request):
54
- # Implement your agent's logic here
55
- pass
56
- async def on_send_task_subscribe(self, request):
57
- # Implement your agent's streaming logic here
58
- pass
59
-
60
- task_manager = MyAgentTaskManager()
61
-
62
- # 3. Create and configure the server
63
- server = A2AServer(
64
- host="127.0.0.1",
65
- port=8080,
66
- endpoint="/api/v1/a2a",
67
- agent_card=my_agent_card,
68
- task_manager=task_manager
69
- )
70
-
71
- # 4. Start the server
72
- if __name__ == "__main__":
73
- print("Starting A2A Server...")
74
- server.start()
75
- ```
76
-
77
- ---
78
-
79
- ### task_manager.py
80
- **Purpose:** Defines the abstract interface for task management and provides a ready-to-use, in-memory implementation. This is the core component for implementing an agent's business logic.
81
- **Import:** `from solace_ai_connector.common.server import TaskManager, InMemoryTaskManager`
82
-
83
- **Classes:**
84
- - `TaskManager()` - An abstract base class that defines the interface for handling all A2A task-related operations. Developers must implement these methods in a subclass.
85
- - `on_get_task(request: GetTaskRequest) -> GetTaskResponse` - Handles a request to retrieve the status and details of a task.
86
- - `on_cancel_task(request: CancelTaskRequest) -> CancelTaskResponse` - Handles a request to cancel an ongoing task.
87
- - `on_send_task(request: SendTaskRequest) -> SendTaskResponse` - Handles a standard request-response task submission.
88
- - `on_send_task_subscribe(request: SendTaskStreamingRequest) -> Union[AsyncIterable[SendTaskStreamingResponse], JSONRPCResponse]` - Handles a task submission that requires a streaming response (SSE).
89
- - `on_set_task_push_notification(request: SetTaskPushNotificationRequest) -> SetTaskPushNotificationResponse` - Handles a request to configure push notifications for a task.
90
- - `on_get_task_push_notification(request: GetTaskPushNotificationRequest) -> GetTaskPushNotificationResponse` - Handles a request to retrieve the push notification configuration for a task.
91
- - `on_resubscribe_to_task(request: TaskResubscriptionRequest) -> Union[AsyncIterable[SendTaskResponse], JSONRPCResponse]` - Handles a request to resubscribe to a streaming task.
92
-
93
- - `InMemoryTaskManager()` - A concrete implementation of `TaskManager` that stores tasks and push notification configurations in memory. It provides helper methods to manage task state and SSE subscriptions. It is designed to be extended.
94
- - `upsert_task(task_send_params: TaskSendParams) -> Task` - Creates a new task or retrieves an existing one by its ID, adding the new message to its history.
95
- - `update_store(task_id: str, status: TaskStatus, artifacts: list[Artifact]) -> Task` - Updates the status, message history, and artifacts of a specific task.
96
- - `set_push_notification_info(task_id: str, notification_config: PushNotificationConfig) -> None` - Stores the push notification configuration for a given task.
97
- - `get_push_notification_info(task_id: str) -> PushNotificationConfig` - Retrieves the push notification configuration for a given task.
98
- - `has_push_notification_info(task_id: str) -> bool` - Checks if a push notification configuration exists for a task.
99
- - `setup_sse_consumer(task_id: str, is_resubscribe: bool = False) -> asyncio.Queue` - Creates and registers an `asyncio.Queue` for a new SSE subscriber for a given task.
100
- - `enqueue_events_for_sse(task_id: str, task_update_event: Any) -> None` - Puts a new event (e.g., `TaskStatusUpdateEvent`) into the queues of all active SSE subscribers for a task.
101
- - `dequeue_events_for_sse(request_id: str, task_id: str, sse_event_queue: asyncio.Queue) -> AsyncIterable[SendTaskStreamingResponse]` - An async generator that yields events from an SSE queue, wrapping them in `SendTaskStreamingResponse` objects.
102
-
103
- **Usage Examples:**
104
- ```python
105
- # custom_task_manager.py
106
- import asyncio
107
- from solace_ai_connector.common.server import InMemoryTaskManager
108
- from solace_ai_connector.common.types import (
109
- SendTaskRequest, SendTaskResponse, Task, TaskStatus, TaskState,
110
- SendTaskStreamingRequest, SendTaskStreamingResponse, TaskStatusUpdateEvent
111
- )
112
- from typing import AsyncIterable, Union
113
-
114
- class MyCustomTaskManager(InMemoryTaskManager):
115
- # Implement the core logic for a standard task
116
- async def on_send_task(self, request: SendTaskRequest) -> SendTaskResponse:
117
- task = await self.upsert_task(request.params)
118
- print(f"Received task {task.id} with message: {request.params.message.content}")
119
-
120
- # Simulate work
121
- await asyncio.sleep(2)
122
-
123
- # Update task status to completed
124
- final_status = TaskStatus(state=TaskState.COMPLETED)
125
- await self.update_store(task.id, final_status, [])
126
-
127
- return SendTaskResponse(id=request.id, result=task)
128
-
129
- # Implement the core logic for a streaming task
130
- async def on_send_task_subscribe(
131
- self, request: SendTaskStreamingRequest
132
- ) -> Union[AsyncIterable[SendTaskStreamingResponse], JSONRPCResponse]:
133
-
134
- await self.upsert_task(request.params)
135
- sse_queue = await self.setup_sse_consumer(request.params.id)
136
-
137
- # Start the background task processing
138
- asyncio.create_task(self._process_streaming_task(request.params.id))
139
-
140
- # Return the async generator that will stream responses
141
- return self.dequeue_events_for_sse(request.id, request.params.id, sse_queue)
142
-
143
- async def _process_streaming_task(self, task_id: str):
144
- # Simulate streaming work
145
- for i in range(5):
146
- await asyncio.sleep(1)
147
- update = TaskStatusUpdateEvent(
148
- status=TaskStatus(state=TaskState.IN_PROGRESS),
149
- message={"content": f"Step {i+1} complete"}
150
- )
151
- # Enqueue the update for all subscribers
152
- await self.enqueue_events_for_sse(task_id, update)
153
-
154
- # Send final event
155
- final_update = TaskStatusUpdateEvent(
156
- status=TaskStatus(state=TaskState.COMPLETED),
157
- final=True
158
- )
159
- await self.enqueue_events_for_sse(task_id, final_update)
160
- ```
161
-
162
- ---
163
-
164
- ### utils.py
165
- **Purpose:** Provides common utility functions used within the server, primarily for creating standardized JSON-RPC error responses and performing compatibility checks.
166
- **Import:** `from solace_ai_connector.common.server.utils import are_modalities_compatible, new_incompatible_types_error, new_not_implemented_error`
167
-
168
- **Functions:**
169
- - `are_modalities_compatible(server_output_