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.

Files changed (220) 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 +25 -17
  7. solace_agent_mesh/agent/adk/services.py +3 -3
  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 +460 -317
  13. solace_agent_mesh/agent/protocol/protocol_llm.txt +54 -7
  14. solace_agent_mesh/agent/sac/app.py +2 -2
  15. solace_agent_mesh/agent/sac/component.py +211 -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/6e0db977.39a79ca9.js +1 -0
  24. solace_agent_mesh/assets/docs/assets/js/{75384d09.ccd480c4.js → 75384d09.bf78fbdb.js} +1 -1
  25. solace_agent_mesh/assets/docs/assets/js/90dd9cf6.88f385ea.js +1 -0
  26. solace_agent_mesh/assets/docs/assets/js/f284c35a.fb68323a.js +1 -0
  27. solace_agent_mesh/assets/docs/assets/js/main.08d30374.js +2 -0
  28. solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +1 -0
  29. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +4 -4
  30. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +4 -4
  31. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +4 -4
  32. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
  33. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +4 -4
  34. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +4 -4
  35. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
  36. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +4 -4
  37. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +4 -4
  38. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +4 -4
  39. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +4 -4
  40. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +4 -4
  41. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
  42. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +4 -4
  43. 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
  44. solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html +53 -0
  45. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +4 -4
  46. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +4 -4
  47. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +4 -4
  48. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
  49. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +4 -4
  50. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +4 -4
  51. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +4 -4
  52. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +4 -4
  53. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +4 -4
  54. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +4 -4
  55. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +4 -4
  56. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +4 -4
  57. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +4 -4
  58. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +4 -4
  59. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +4 -4
  60. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +4 -4
  61. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +4 -4
  62. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +4 -4
  63. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
  64. solace_agent_mesh/assets/docs/lunr-index-1757433031159.json +1 -0
  65. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  66. solace_agent_mesh/assets/docs/search-doc-1757433031159.json +1 -0
  67. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  68. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  69. solace_agent_mesh/cli/__init__.py +1 -1
  70. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +125 -48
  71. solace_agent_mesh/cli/commands/eval_cmd.py +14 -0
  72. solace_agent_mesh/cli/commands/init_cmd/__init__.py +53 -31
  73. solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
  74. solace_agent_mesh/cli/commands/init_cmd/env_step.py +19 -8
  75. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +80 -25
  76. solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +32 -10
  77. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +74 -15
  78. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +0 -2
  79. solace_agent_mesh/cli/commands/run_cmd.py +5 -3
  80. solace_agent_mesh/cli/utils.py +68 -12
  81. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-vY5eu2lI.js +1 -0
  82. solace_agent_mesh/client/webui/frontend/static/assets/client-BeBkzgWW.js +25 -0
  83. solace_agent_mesh/client/webui/frontend/static/assets/main-Bjys1KQs.js +339 -0
  84. solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
  85. solace_agent_mesh/client/webui/frontend/static/assets/vendor-CE0AeXyK.js +395 -0
  86. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -2
  87. solace_agent_mesh/client/webui/frontend/static/index.html +4 -3
  88. solace_agent_mesh/common/a2a/__init__.py +213 -0
  89. solace_agent_mesh/common/a2a/a2a_llm.txt +182 -0
  90. solace_agent_mesh/common/a2a/artifact.py +328 -0
  91. solace_agent_mesh/common/a2a/events.py +183 -0
  92. solace_agent_mesh/common/a2a/message.py +307 -0
  93. solace_agent_mesh/common/a2a/protocol.py +513 -0
  94. solace_agent_mesh/common/a2a/task.py +127 -0
  95. solace_agent_mesh/common/a2a/translation.py +653 -0
  96. solace_agent_mesh/common/a2a/types.py +54 -0
  97. solace_agent_mesh/common/a2a_spec/a2a.json +2576 -0
  98. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +407 -0
  99. solace_agent_mesh/common/a2a_spec/schemas/agent_progress_update.json +18 -0
  100. solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +31 -0
  101. solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +18 -0
  102. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +235 -0
  103. solace_agent_mesh/common/a2a_spec/schemas/tool_invocation_start.json +26 -0
  104. solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +25 -0
  105. solace_agent_mesh/common/agent_registry.py +1 -1
  106. solace_agent_mesh/common/common_llm.txt +192 -70
  107. solace_agent_mesh/common/data_parts.py +99 -0
  108. solace_agent_mesh/common/middleware/middleware_llm.txt +17 -17
  109. solace_agent_mesh/common/sac/__init__.py +0 -0
  110. solace_agent_mesh/common/sac/sac_llm.txt +71 -0
  111. solace_agent_mesh/common/sac/sam_component_base.py +252 -0
  112. solace_agent_mesh/common/services/providers/providers_llm.txt +51 -84
  113. solace_agent_mesh/common/services/services_llm.txt +206 -26
  114. solace_agent_mesh/common/utils/artifact_utils.py +29 -0
  115. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +176 -80
  116. solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
  117. solace_agent_mesh/common/utils/utils_llm.txt +323 -42
  118. solace_agent_mesh/config_portal/backend/common.py +2 -2
  119. solace_agent_mesh/config_portal/backend/plugin_catalog/constants.py +1 -1
  120. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-bFMKlzKf.js +98 -0
  121. solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d845808d.js → manifest-89db7c30.js} +1 -1
  122. solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
  123. solace_agent_mesh/core_a2a/core_a2a_llm.txt +10 -8
  124. solace_agent_mesh/core_a2a/service.py +20 -44
  125. solace_agent_mesh/evaluation/message_organizer.py +35 -56
  126. solace_agent_mesh/evaluation/run.py +26 -5
  127. solace_agent_mesh/evaluation/subscriber.py +35 -10
  128. solace_agent_mesh/evaluation/summary_builder.py +27 -34
  129. solace_agent_mesh/gateway/base/app.py +27 -1
  130. solace_agent_mesh/gateway/base/base_llm.txt +177 -72
  131. solace_agent_mesh/gateway/base/component.py +294 -523
  132. solace_agent_mesh/gateway/gateway_llm.txt +299 -58
  133. solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +676 -0
  134. solace_agent_mesh/gateway/http_sse/alembic/env.py +85 -0
  135. solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
  136. solace_agent_mesh/gateway/http_sse/alembic/versions/b1c2d3e4f5g6_add_database_indexes.py +83 -0
  137. solace_agent_mesh/gateway/http_sse/alembic/versions/d5b3f8f2e9a0_create_initial_database.py +58 -0
  138. solace_agent_mesh/gateway/http_sse/alembic.ini +147 -0
  139. solace_agent_mesh/gateway/http_sse/api/__init__.py +11 -0
  140. solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +9 -0
  141. solace_agent_mesh/gateway/http_sse/api/controllers/session_controller.py +355 -0
  142. solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +279 -0
  143. solace_agent_mesh/gateway/http_sse/api/controllers/user_controller.py +35 -0
  144. solace_agent_mesh/gateway/http_sse/api/dto/__init__.py +10 -0
  145. solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +37 -0
  146. solace_agent_mesh/gateway/http_sse/api/dto/requests/session_requests.py +49 -0
  147. solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +66 -0
  148. solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +43 -0
  149. solace_agent_mesh/gateway/http_sse/api/dto/responses/session_responses.py +68 -0
  150. solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +74 -0
  151. solace_agent_mesh/gateway/http_sse/app.py +31 -1
  152. solace_agent_mesh/gateway/http_sse/application/__init__.py +3 -0
  153. solace_agent_mesh/gateway/http_sse/application/services/__init__.py +3 -0
  154. solace_agent_mesh/gateway/http_sse/application/services/session_service.py +135 -0
  155. solace_agent_mesh/gateway/http_sse/component.py +371 -236
  156. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +29 -29
  157. solace_agent_mesh/gateway/http_sse/dependencies.py +142 -39
  158. solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +3 -0
  159. solace_agent_mesh/gateway/http_sse/domain/entities/session.py +90 -0
  160. solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +3 -0
  161. solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +54 -0
  162. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +272 -36
  163. solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +4 -0
  164. solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +3 -0
  165. solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +123 -0
  166. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +4 -0
  167. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +16 -0
  168. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +119 -0
  169. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +31 -0
  170. solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +12 -0
  171. solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +3 -0
  172. solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +174 -0
  173. solace_agent_mesh/gateway/http_sse/main.py +293 -91
  174. solace_agent_mesh/gateway/http_sse/routers/agents.py +1 -1
  175. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +137 -56
  176. solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
  177. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +231 -5
  178. solace_agent_mesh/gateway/http_sse/routers/tasks.py +199 -171
  179. solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
  180. solace_agent_mesh/gateway/http_sse/services/agent_service.py +1 -1
  181. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +89 -135
  182. solace_agent_mesh/gateway/http_sse/services/task_service.py +2 -5
  183. solace_agent_mesh/gateway/http_sse/session_manager.py +64 -30
  184. solace_agent_mesh/gateway/http_sse/shared/__init__.py +9 -0
  185. solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
  186. solace_agent_mesh/gateway/http_sse/shared/enums.py +45 -0
  187. solace_agent_mesh/gateway/http_sse/shared/types.py +45 -0
  188. solace_agent_mesh/solace_agent_mesh_llm.txt +362 -0
  189. solace_agent_mesh/templates/gateway_component_template.py +149 -98
  190. solace_agent_mesh/templates/shared_config.yaml +4 -5
  191. solace_agent_mesh/templates/webui.yaml +8 -10
  192. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/METADATA +9 -6
  193. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/RECORD +197 -141
  194. solace_agent_mesh/assets/docs/assets/js/f284c35a.731836ad.js +0 -1
  195. solace_agent_mesh/assets/docs/assets/js/main.3d0e7879.js +0 -2
  196. solace_agent_mesh/assets/docs/assets/js/runtime~main.05d19492.js +0 -1
  197. solace_agent_mesh/assets/docs/lunr-index-1757091012487.json +0 -1
  198. solace_agent_mesh/assets/docs/search-doc-1757091012487.json +0 -1
  199. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-BmF2l6vg.js +0 -1
  200. solace_agent_mesh/client/webui/frontend/static/assets/client-D881Dttc.js +0 -49
  201. solace_agent_mesh/client/webui/frontend/static/assets/main-D0FnP_W4.css +0 -1
  202. solace_agent_mesh/client/webui/frontend/static/assets/main-Do32sFPX.js +0 -708
  203. solace_agent_mesh/common/a2a_protocol.py +0 -564
  204. solace_agent_mesh/common/client/__init__.py +0 -4
  205. solace_agent_mesh/common/client/card_resolver.py +0 -21
  206. solace_agent_mesh/common/client/client.py +0 -85
  207. solace_agent_mesh/common/client/client_llm.txt +0 -133
  208. solace_agent_mesh/common/server/__init__.py +0 -4
  209. solace_agent_mesh/common/server/server.py +0 -122
  210. solace_agent_mesh/common/server/server_llm.txt +0 -169
  211. solace_agent_mesh/common/server/task_manager.py +0 -291
  212. solace_agent_mesh/common/server/utils.py +0 -28
  213. solace_agent_mesh/common/types.py +0 -411
  214. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
  215. solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -80
  216. solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
  217. /solace_agent_mesh/assets/docs/assets/js/{main.3d0e7879.js.LICENSE.txt → main.08d30374.js.LICENSE.txt} +0 -0
  218. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/WHEEL +0 -0
  219. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/entry_points.txt +0 -0
  220. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -8,30 +8,28 @@ from fastapi import (
8
8
  HTTPException,
9
9
  Request as FastAPIRequest,
10
10
  status,
11
- Form,
12
- File,
13
- UploadFile,
14
11
  )
15
- from pydantic import BaseModel, Field
16
- from typing import List
12
+ from typing import Union
17
13
 
18
14
  from solace_ai_connector.common.log import log
19
15
 
20
16
  from ....gateway.http_sse.session_manager import SessionManager
21
17
  from ....gateway.http_sse.services.task_service import TaskService
22
18
 
23
- from ....common.types import (
24
- JSONRPCResponse,
25
- InternalError,
26
- InvalidRequestError,
19
+ from a2a.types import (
20
+ CancelTaskRequest,
21
+ SendMessageRequest,
22
+ SendStreamingMessageRequest,
23
+ SendMessageSuccessResponse,
24
+ SendStreamingMessageSuccessResponse,
27
25
  )
26
+ from ....common import a2a
28
27
 
29
28
  from ....gateway.http_sse.dependencies import (
30
29
  get_session_manager,
31
30
  get_sac_component,
32
31
  get_task_service,
33
32
  )
34
- from ....gateway.http_sse.routers.users import get_current_user
35
33
 
36
34
  from typing import TYPE_CHECKING
37
35
 
@@ -41,29 +39,26 @@ if TYPE_CHECKING:
41
39
  router = APIRouter()
42
40
 
43
41
 
44
- class CancelTaskApiPayload(BaseModel):
45
- """Request body for the task cancellation endpoint."""
42
+ async def _submit_task(
43
+ request: FastAPIRequest,
44
+ payload: Union[SendMessageRequest, SendStreamingMessageRequest],
45
+ session_manager: SessionManager,
46
+ component: "WebUIBackendComponent",
47
+ is_streaming: bool,
48
+ ):
49
+ """Helper to submit a task, handling both streaming and non-streaming cases."""
50
+ log_prefix = f"[POST /api/v1/message:{'stream' if is_streaming else 'send'}] "
46
51
 
47
- agent_name: str = Field(
48
- ..., description="The name of the agent currently handling the task."
49
- )
50
- task_id: str = Field(..., description="The ID of the task to cancel.")
52
+ agent_name = None
53
+ if payload.params and payload.params.message and payload.params.message.metadata:
54
+ agent_name = payload.params.message.metadata.get("agent_name")
51
55
 
56
+ if not agent_name:
57
+ raise HTTPException(
58
+ status_code=status.HTTP_400_BAD_REQUEST,
59
+ detail="Missing 'agent_name' in request payload message metadata.",
60
+ )
52
61
 
53
- @router.post("/send", response_model=JSONRPCResponse)
54
- async def send_task_to_agent(
55
- request: FastAPIRequest,
56
- agent_name: str = Form(...),
57
- message: str = Form(...),
58
- files: List[UploadFile] = File([]),
59
- session_manager: SessionManager = Depends(get_session_manager),
60
- component: "WebUIBackendComponent" = Depends(get_sac_component),
61
- ):
62
- """
63
- Submits a non-streaming task request to the specified agent.
64
- Accepts multipart/form-data.
65
- """
66
- log_prefix = "[POST /api/v1/tasks/send] "
67
62
  log.info("%sReceived request for agent: %s", log_prefix, agent_name)
68
63
 
69
64
  try:
@@ -81,213 +76,246 @@ async def send_task_to_agent(
81
76
  )
82
77
 
83
78
  client_id = session_manager.get_a2a_client_id(request)
84
- session_id = session_manager.ensure_a2a_session(request)
79
+
80
+ # Use session ID from frontend request (contextId) instead of cookie-based session
81
+ # Handle various falsy values: None, empty string, whitespace-only string
82
+ log.info("%s[DEBUG] payload.params.message: %s", log_prefix, payload.params.message)
83
+ log.info("%s[DEBUG] hasattr context_id: %s", log_prefix, hasattr(payload.params.message, 'context_id'))
84
+ if hasattr(payload.params.message, 'context_id'):
85
+ log.info("%s[DEBUG] context_id value: %s", log_prefix, payload.params.message.context_id)
86
+
87
+ frontend_session_id = None
88
+ if hasattr(payload.params.message, 'context_id') and payload.params.message.context_id:
89
+ context_id = payload.params.message.context_id
90
+ if isinstance(context_id, str) and context_id.strip():
91
+ frontend_session_id = context_id.strip()
92
+ log.info("%s[DEBUG] Extracted frontend_session_id: %s", log_prefix, frontend_session_id)
93
+
94
+ if frontend_session_id:
95
+ session_id = frontend_session_id
96
+ log.info("%sUsing session ID from frontend request: %s", log_prefix, session_id)
97
+ else:
98
+ # Create new session when frontend doesn't provide one (None, empty, or whitespace-only)
99
+ session_id = session_manager.create_new_session_id(request)
100
+ log.info("%sNo valid session ID from frontend, created new session: %s", log_prefix, session_id)
85
101
 
86
102
  log.info(
87
103
  "%sUsing ClientID: %s, SessionID: %s", log_prefix, client_id, session_id
88
104
  )
89
105
 
90
- external_event_data = {
91
- "agent_name": agent_name,
92
- "message": message,
93
- "files": files,
94
- "client_id": client_id,
95
- "a2a_session_id": session_id,
106
+ # Store message in persistence layer if available
107
+ user_id = user_identity.get("id")
108
+ if is_streaming and hasattr(component, "persistence_service") and component.persistence_service:
109
+ try:
110
+ from ....gateway.http_sse.dependencies import get_session_service
111
+ from ....gateway.http_sse.shared.enums import SenderType
112
+
113
+ session_service = get_session_service(component)
114
+
115
+ # First ensure session exists in database - create it with the SessionManager's ID
116
+ # Handle race condition where multiple requests might try to create the same session
117
+ existing_session = session_service.get_session(session_id=session_id, user_id=user_id)
118
+ if not existing_session:
119
+ log.info("%sCreating new session in database: %s", log_prefix, session_id)
120
+ try:
121
+ session_service.create_session(
122
+ user_id=user_id,
123
+ agent_id=agent_name,
124
+ name=None, # Will be auto-generated if needed
125
+ session_id=session_id # Use the SessionManager's session ID
126
+ )
127
+ except Exception as create_error:
128
+ # Another request may have created the session concurrently
129
+ log.warning("%sSession creation failed, checking if session exists: %s", log_prefix, create_error)
130
+ existing_session = session_service.get_session(session_id=session_id, user_id=user_id)
131
+ if not existing_session:
132
+ # If session still doesn't exist, re-raise the original error
133
+ raise create_error
134
+ log.info("%sSession was created by another request: %s", log_prefix, session_id)
135
+
136
+ # Extract text content from the message for storage
137
+ message_text = ""
138
+ if payload.params and payload.params.message:
139
+ parts = a2a.get_parts_from_message(payload.params.message)
140
+ for part in parts:
141
+ if hasattr(part, 'text'):
142
+ message_text = part.text
143
+ break
144
+
145
+ # Now store the message in the existing session
146
+ message_domain = session_service.add_message_to_session(
147
+ session_id=session_id,
148
+ user_id=user_id,
149
+ message=message_text or "Task submitted",
150
+ sender_type=SenderType.USER,
151
+ sender_name=user_id or "user",
152
+ agent_id=agent_name,
153
+ )
154
+
155
+ if message_domain:
156
+ log.info("%sMessage stored in session %s", log_prefix, session_id)
157
+ else:
158
+ log.warning("%sFailed to store message in session %s", log_prefix, session_id)
159
+ except Exception as e:
160
+ log.error("%sFailed to store message in session service: %s", log_prefix, e)
161
+ # Don't fail the request, just log the error
162
+ else:
163
+ log.debug("%sNo persistence available or non-streaming - skipping message storage", log_prefix)
164
+
165
+ # Use the helper to get the unwrapped parts from the incoming message.
166
+ a2a_parts = a2a.get_parts_from_message(payload.params.message)
167
+
168
+ external_req_ctx = {
169
+ "app_name_for_artifacts": component.gateway_id,
170
+ "user_id_for_artifacts": client_id,
171
+ "a2a_session_id": session_id, # This may have been updated by persistence layer
172
+ "user_id_for_a2a": client_id,
173
+ "target_agent_name": agent_name,
96
174
  }
97
175
 
98
- target_agent, a2a_parts, external_req_ctx = (
99
- await component._translate_external_input(external_event_data)
100
- )
101
-
102
176
  task_id = await component.submit_a2a_task(
103
- target_agent_name=target_agent,
177
+ target_agent_name=agent_name,
104
178
  a2a_parts=a2a_parts,
105
179
  external_request_context=external_req_ctx,
106
180
  user_identity=user_identity,
107
- is_streaming=False,
181
+ is_streaming=is_streaming,
108
182
  )
109
183
 
110
184
  log.info("%sTask submitted successfully. TaskID: %s", log_prefix, task_id)
111
185
 
112
- return JSONRPCResponse(result={"taskId": task_id})
113
-
114
- except InvalidRequestError as e:
115
- log.warning("%sInvalid request: %s", log_prefix, e.message, exc_info=True)
116
- raise HTTPException(
117
- status_code=status.HTTP_400_BAD_REQUEST,
118
- detail=e.model_dump(exclude_none=True),
186
+ task_object = a2a.create_initial_task(
187
+ task_id=task_id,
188
+ context_id=session_id,
189
+ agent_name=agent_name,
119
190
  )
191
+
192
+ if is_streaming:
193
+ # The task_object already contains the contextId from create_initial_task
194
+ return a2a.create_send_streaming_message_success_response(
195
+ result=task_object, request_id=payload.id
196
+ )
197
+ else:
198
+ return a2a.create_send_message_success_response(
199
+ result=task_object, request_id=payload.id
200
+ )
201
+
120
202
  except PermissionError as pe:
121
203
  log.warning("%sPermission denied: %s", log_prefix, str(pe))
122
204
  raise HTTPException(
123
205
  status_code=status.HTTP_403_FORBIDDEN,
124
206
  detail=str(pe),
125
207
  )
126
- except InternalError as e:
127
- log.error(
128
- "%sInternal error submitting task: %s", log_prefix, e.message, exc_info=True
129
- )
130
- raise HTTPException(
131
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
132
- detail=e.model_dump(exclude_none=True),
133
- )
134
208
  except Exception as e:
135
209
  log.exception("%sUnexpected error submitting task: %s", log_prefix, e)
136
- error_resp = InternalError(message="Unexpected server error: %s" % e)
210
+ error_resp = a2a.create_internal_error(
211
+ message="Unexpected server error: %s" % e
212
+ )
137
213
  raise HTTPException(
138
214
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
139
215
  detail=error_resp.model_dump(exclude_none=True),
140
216
  )
141
217
 
142
218
 
143
- @router.post("/subscribe", response_model=JSONRPCResponse)
144
- async def subscribe_task_from_agent(
219
+ @router.post("/message:send", response_model=SendMessageSuccessResponse)
220
+ async def send_task_to_agent(
145
221
  request: FastAPIRequest,
146
- agent_name: str = Form(...),
147
- message: str = Form(...),
148
- files: List[UploadFile] = File([]),
222
+ payload: SendMessageRequest,
149
223
  session_manager: SessionManager = Depends(get_session_manager),
150
224
  component: "WebUIBackendComponent" = Depends(get_sac_component),
151
- user: dict = Depends(get_current_user),
152
225
  ):
153
226
  """
154
- Submits a streaming task request (`tasks/sendSubscribe`) to the specified agent.
155
- Accepts multipart/form-data.
156
- The client should subsequently connect to the SSE endpoint using the returned taskId.
227
+ Submits a non-streaming task request to the specified agent.
228
+ Accepts application/json.
157
229
  """
158
- log_prefix = "[POST /api/v1/tasks/subscribe] "
159
- log.info("%sReceived streaming request for agent: %s", log_prefix, agent_name)
160
-
161
- try:
162
- user_identity = await component.authenticate_and_enrich_user(request)
163
- if user_identity is None:
164
- log.warning("%sUser authentication failed. Denying request.", log_prefix)
165
- raise HTTPException(
166
- status_code=status.HTTP_401_UNAUTHORIZED,
167
- detail="User authentication failed or identity not found.",
168
- )
169
- log.info(
170
- "%sAuthenticated user identity: %s",
171
- log_prefix,
172
- user_identity.get("id", "unknown"),
173
- )
174
-
175
- client_id = session_manager.get_a2a_client_id(request)
176
- session_id = session_manager.ensure_a2a_session(request)
177
-
178
- log.info(
179
- "%sUsing ClientID: %s, SessionID: %s", log_prefix, client_id, session_id
180
- )
230
+ return await _submit_task(
231
+ request=request,
232
+ payload=payload,
233
+ session_manager=session_manager,
234
+ component=component,
235
+ is_streaming=False,
236
+ )
181
237
 
182
- external_event_data = {
183
- "agent_name": agent_name,
184
- "message": message,
185
- "files": files,
186
- "client_id": client_id,
187
- "a2a_session_id": session_id,
188
- }
189
238
 
190
- target_agent, a2a_parts, external_req_ctx = (
191
- await component._translate_external_input(external_event_data)
192
- )
193
-
194
- task_id = await component.submit_a2a_task(
195
- target_agent_name=target_agent,
196
- a2a_parts=a2a_parts,
197
- external_request_context=external_req_ctx,
198
- user_identity=user_identity,
199
- is_streaming=True,
200
- )
239
+ @router.post("/message:stream", response_model=SendStreamingMessageSuccessResponse)
240
+ async def subscribe_task_from_agent(
241
+ request: FastAPIRequest,
242
+ payload: SendStreamingMessageRequest,
243
+ session_manager: SessionManager = Depends(get_session_manager),
244
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
245
+ ):
246
+ """
247
+ Submits a streaming task request to the specified agent.
248
+ Accepts application/json.
249
+ The client should subsequently connect to the SSE endpoint using the returned taskId.
250
+ """
251
+ return await _submit_task(
252
+ request=request,
253
+ payload=payload,
254
+ session_manager=session_manager,
255
+ component=component,
256
+ is_streaming=True,
257
+ )
201
258
 
202
- log.info(
203
- "%sStreaming task submitted successfully. TaskID: %s", log_prefix, task_id
204
- )
205
259
 
206
- return JSONRPCResponse(result={"taskId": task_id})
260
+ @router.post("/tasks/{taskId}:cancel", status_code=status.HTTP_202_ACCEPTED)
261
+ async def cancel_agent_task(
262
+ request: FastAPIRequest,
263
+ taskId: str,
264
+ payload: CancelTaskRequest,
265
+ session_manager: SessionManager = Depends(get_session_manager),
266
+ task_service: TaskService = Depends(get_task_service),
267
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
268
+ ):
269
+ """
270
+ Sends a cancellation request for a specific task to the specified agent.
271
+ Returns 202 Accepted, as cancellation is asynchronous.
272
+ """
273
+ log_prefix = f"[POST /api/v1/tasks/{taskId}:cancel] "
274
+ log.info("%sReceived cancellation request.", log_prefix)
207
275
 
208
- except InvalidRequestError as e:
209
- log.warning("%sInvalid request: %s", log_prefix, e.message, exc_info=True)
276
+ if taskId != payload.params.id:
210
277
  raise HTTPException(
211
278
  status_code=status.HTTP_400_BAD_REQUEST,
212
- detail=e.model_dump(exclude_none=True),
279
+ detail="Task ID in URL path does not match task ID in payload.",
213
280
  )
214
- except PermissionError as pe:
215
- log.warning("%sPermission denied: %s", log_prefix, str(pe))
281
+
282
+ context = component.task_context_manager.get_context(taskId)
283
+ if not context:
216
284
  raise HTTPException(
217
- status_code=status.HTTP_403_FORBIDDEN,
218
- detail=str(pe),
285
+ status_code=status.HTTP_404_NOT_FOUND,
286
+ detail=f"No active task context found for task ID: {taskId}",
219
287
  )
220
- except InternalError as e:
288
+
289
+ agent_name = context.get("target_agent_name")
290
+ if not agent_name:
221
291
  log.error(
222
- "%sInternal error submitting streaming task: %s",
292
+ "%sCould not determine target agent for task %s. Context is missing 'target_agent_name'.",
223
293
  log_prefix,
224
- e.message,
225
- exc_info=True,
226
- )
227
- raise HTTPException(
228
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
229
- detail=e.model_dump(exclude_none=True),
294
+ taskId,
230
295
  )
231
- except Exception as e:
232
- log.exception("%sUnexpected error submitting streaming task: %s", log_prefix, e)
233
- error_resp = InternalError(message="Unexpected server error: %s" % e)
234
296
  raise HTTPException(
235
297
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
236
- detail=error_resp.model_dump(exclude_none=True),
298
+ detail="Could not determine target agent for the task.",
237
299
  )
238
300
 
239
-
240
- @router.post("/cancel", status_code=status.HTTP_202_ACCEPTED)
241
- async def cancel_agent_task(
242
- request: FastAPIRequest,
243
- payload: CancelTaskApiPayload,
244
- session_manager: SessionManager = Depends(get_session_manager),
245
- task_service: TaskService = Depends(get_task_service),
246
- ):
247
- """
248
- Sends a cancellation request for a specific task to the specified agent.
249
- Returns 202 Accepted, as cancellation is asynchronous.
250
- """
251
- log_prefix = "[POST /api/v1/tasks/cancel][Task:%s] " % payload.task_id
252
- log.info(
253
- "%sReceived cancellation request for agent: %s", log_prefix, payload.agent_name
254
- )
301
+ log.info("%sTarget agent for cancellation is '%s'", log_prefix, agent_name)
255
302
 
256
303
  try:
257
304
  client_id = session_manager.get_a2a_client_id(request)
258
305
 
259
306
  log.info("%sUsing ClientID: %s", log_prefix, client_id)
260
307
 
261
- await task_service.cancel_task(
262
- payload.agent_name, payload.task_id, client_id, client_id
263
- )
308
+ await task_service.cancel_task(agent_name, taskId, client_id, client_id)
264
309
 
265
310
  log.info("%sCancellation request published successfully.", log_prefix)
266
311
 
267
312
  return {"message": "Cancellation request sent"}
268
313
 
269
- except InvalidRequestError as e:
270
- log.warning(
271
- "%sInvalid cancellation request: %s", log_prefix, e.message, exc_info=True
272
- )
273
- raise HTTPException(
274
- status_code=status.HTTP_400_BAD_REQUEST,
275
- detail=e.model_dump(exclude_none=True),
276
- )
277
- except InternalError as e:
278
- log.error(
279
- "%sInternal error sending cancellation: %s",
280
- log_prefix,
281
- e.message,
282
- exc_info=True,
283
- )
284
- raise HTTPException(
285
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
286
- detail=e.model_dump(exclude_none=True),
287
- )
288
314
  except Exception as e:
289
315
  log.exception("%sUnexpected error sending cancellation: %s", log_prefix, e)
290
- error_resp = InternalError(message="Unexpected server error: %s" % e)
316
+ error_resp = a2a.create_internal_error(
317
+ message="Unexpected server error: %s" % e
318
+ )
291
319
  raise HTTPException(
292
320
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
293
321
  detail=error_resp.model_dump(exclude_none=True),
@@ -212,19 +212,19 @@ def _resolve_user_identity_for_authorization(
212
212
  return user_identity
213
213
 
214
214
  if not user_identity:
215
- default_user_identity = component.get_config("default_user_identity")
216
- if default_user_identity:
217
- user_identity = default_user_identity
215
+ use_authorization = component.get_config("frontend_use_authorization", False)
216
+ if not use_authorization:
217
+ user_identity = "sam_dev_user"
218
218
  log.info(
219
- "%s No user_identity provided, using configured default_user_identity: '%s' for visualization",
219
+ "%s No user_identity provided and auth is disabled, using sam_dev_user for visualization",
220
220
  log_id_prefix,
221
- user_identity,
222
221
  )
223
222
  else:
224
- log.warning(
225
- "%s No user_identity and no default_user_identity configured for visualization",
223
+ log.error(
224
+ "%s No user_identity provided but authorization is enabled. This should not happen.",
226
225
  log_id_prefix,
227
226
  )
227
+ raise ValueError("No user identity available when authorization is required")
228
228
 
229
229
  return user_identity
230
230
 
@@ -8,7 +8,7 @@ from typing import List, Optional
8
8
  from solace_ai_connector.common.log import log
9
9
 
10
10
  from ....common.agent_registry import AgentRegistry
11
- from ....common.types import AgentCard
11
+ from a2a.types import AgentCard
12
12
 
13
13
 
14
14
  class AgentService: