solace-agent-mesh 1.4.12__py3-none-any.whl → 1.5.1__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 (359) hide show
  1. solace_agent_mesh/agent/adk/adk_llm.txt +3 -4
  2. solace_agent_mesh/agent/adk/adk_llm_detail.txt +566 -0
  3. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +1 -1
  4. solace_agent_mesh/agent/adk/callbacks.py +56 -5
  5. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +3 -1
  6. solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +2 -1
  7. solace_agent_mesh/agent/adk/mcp_content_processor.py +2 -1
  8. solace_agent_mesh/agent/adk/models/lite_llm.py +1 -0
  9. solace_agent_mesh/agent/adk/models/models_llm.txt +1 -2
  10. solace_agent_mesh/agent/adk/runner.py +3 -1
  11. solace_agent_mesh/agent/adk/services.py +4 -1
  12. solace_agent_mesh/agent/adk/setup.py +3 -1
  13. solace_agent_mesh/agent/adk/tool_wrapper.py +2 -2
  14. solace_agent_mesh/agent/agent_llm.txt +1 -1
  15. solace_agent_mesh/agent/agent_llm_detail.txt +1702 -0
  16. solace_agent_mesh/agent/protocol/event_handlers.py +4 -14
  17. solace_agent_mesh/agent/protocol/protocol_llm.txt +15 -2
  18. solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +92 -0
  19. solace_agent_mesh/agent/sac/app.py +3 -1
  20. solace_agent_mesh/agent/sac/component.py +55 -22
  21. solace_agent_mesh/agent/sac/sac_llm.txt +15 -1
  22. solace_agent_mesh/agent/sac/sac_llm_detail.txt +200 -0
  23. solace_agent_mesh/agent/sac/task_execution_context.py +73 -0
  24. solace_agent_mesh/agent/testing/testing_llm_detail.txt +68 -0
  25. solace_agent_mesh/agent/tools/audio_tools.py +2 -1
  26. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +3 -1
  27. solace_agent_mesh/agent/tools/builtin_data_analysis_tools.py +3 -1
  28. solace_agent_mesh/agent/tools/dynamic_tool.py +2 -1
  29. solace_agent_mesh/agent/tools/general_agent_tools.py +2 -1
  30. solace_agent_mesh/agent/tools/image_tools.py +2 -1
  31. solace_agent_mesh/agent/tools/peer_agent_tool.py +2 -1
  32. solace_agent_mesh/agent/tools/registry.py +3 -1
  33. solace_agent_mesh/agent/tools/test_tools.py +2 -1
  34. solace_agent_mesh/agent/tools/tools_llm.txt +148 -154
  35. solace_agent_mesh/agent/tools/tools_llm_detail.txt +274 -0
  36. solace_agent_mesh/agent/tools/web_tools.py +2 -1
  37. solace_agent_mesh/agent/utils/artifact_helpers.py +3 -1
  38. solace_agent_mesh/agent/utils/config_parser.py +3 -1
  39. solace_agent_mesh/agent/utils/utils_llm.txt +1 -1
  40. solace_agent_mesh/agent/utils/utils_llm_detail.txt +149 -0
  41. solace_agent_mesh/assets/docs/404.html +3 -3
  42. solace_agent_mesh/assets/docs/assets/js/{b7006a3a.73a79653.js → 032c2d61.f3d37824.js} +1 -1
  43. solace_agent_mesh/assets/docs/assets/js/0bcf40b7.c019ad46.js +1 -0
  44. solace_agent_mesh/assets/docs/assets/js/15ba94aa.932dd2db.js +1 -0
  45. solace_agent_mesh/assets/docs/assets/js/2131ec11.5c7a1f6e.js +1 -0
  46. solace_agent_mesh/assets/docs/assets/js/{2334.622a6395.js → 2334.1cf50a20.js} +1 -1
  47. solace_agent_mesh/assets/docs/assets/js/240a0364.7eac6021.js +1 -0
  48. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +1 -0
  49. solace_agent_mesh/assets/docs/assets/js/341393d4.0fac2613.js +1 -0
  50. solace_agent_mesh/assets/docs/assets/js/{3624.b524e433.js → 3624.0eaa1fd0.js} +1 -1
  51. solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +1 -0
  52. solace_agent_mesh/assets/docs/assets/js/3ac1795d.76654dd9.js +1 -0
  53. solace_agent_mesh/assets/docs/assets/js/3ff0015d.2be20244.js +1 -0
  54. solace_agent_mesh/assets/docs/assets/js/509e993c.4c7a1a6d.js +1 -0
  55. solace_agent_mesh/assets/docs/assets/js/547e15cc.2cbb060a.js +1 -0
  56. solace_agent_mesh/assets/docs/assets/js/55b7b518.f2b1d1ba.js +1 -0
  57. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.e49689dd.js +1 -0
  58. solace_agent_mesh/assets/docs/assets/js/6063ff4c.ef84f702.js +1 -0
  59. solace_agent_mesh/assets/docs/assets/js/631738c7.a8b1ef8b.js +1 -0
  60. solace_agent_mesh/assets/docs/assets/js/6a520c9d.ba015d81.js +1 -0
  61. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.39d5851d.js +1 -0
  62. solace_agent_mesh/assets/docs/assets/js/6d84eae0.4a5fbf39.js +1 -0
  63. solace_agent_mesh/assets/docs/assets/js/6fdfefc7.99de744e.js +1 -0
  64. solace_agent_mesh/assets/docs/assets/js/71da7b71.804d6567.js +1 -0
  65. solace_agent_mesh/assets/docs/assets/js/722f809d.965da774.js +1 -0
  66. solace_agent_mesh/assets/docs/assets/js/742f027b.46c07808.js +1 -0
  67. solace_agent_mesh/assets/docs/assets/js/77cf947d.64c9bd6c.js +1 -0
  68. solace_agent_mesh/assets/docs/assets/js/8024126c.56e59919.js +1 -0
  69. solace_agent_mesh/assets/docs/assets/js/81a99df0.07034dd9.js +1 -0
  70. solace_agent_mesh/assets/docs/assets/js/82fbfb93.139a1a1f.js +1 -0
  71. solace_agent_mesh/assets/docs/assets/js/{8591.d7c16be6.js → 8591.5d015485.js} +2 -2
  72. solace_agent_mesh/assets/docs/assets/js/{8731.49e930c2.js → 8731.6c1dbf0c.js} +1 -1
  73. solace_agent_mesh/assets/docs/assets/js/945fb41e.6f4cdffd.js +1 -0
  74. solace_agent_mesh/assets/docs/assets/js/94e8668d.b5ddb7a1.js +1 -0
  75. solace_agent_mesh/assets/docs/assets/js/9bb13469.dd1c9b54.js +1 -0
  76. solace_agent_mesh/assets/docs/assets/js/9e9d0a82.dd810042.js +1 -0
  77. solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e6dd091.js +1 -0
  78. solace_agent_mesh/assets/docs/assets/js/ad71b5ed.60668e9e.js +1 -0
  79. solace_agent_mesh/assets/docs/assets/js/c198a0dc.8f31f867.js +1 -0
  80. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.eaff365e.js +1 -0
  81. solace_agent_mesh/assets/docs/assets/js/da0b5bad.9d369087.js +1 -0
  82. solace_agent_mesh/assets/docs/assets/js/db924877.cbc66f02.js +1 -0
  83. solace_agent_mesh/assets/docs/assets/js/dd817ffc.0aa9630a.js +1 -0
  84. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.d590bc9e.js +1 -0
  85. solace_agent_mesh/assets/docs/assets/js/de5f4c65.e8241890.js +1 -0
  86. solace_agent_mesh/assets/docs/assets/js/de915948.139b4b9c.js +1 -0
  87. solace_agent_mesh/assets/docs/assets/js/e3d9abda.2b916f9e.js +1 -0
  88. solace_agent_mesh/assets/docs/assets/js/e6f9706b.582a78ca.js +1 -0
  89. solace_agent_mesh/assets/docs/assets/js/e92d0134.cf6d6522.js +1 -0
  90. solace_agent_mesh/assets/docs/assets/js/f284c35a.5766a13d.js +1 -0
  91. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.9c0297a6.js +1 -0
  92. solace_agent_mesh/assets/docs/assets/js/main.bd3c34f3.js +2 -0
  93. solace_agent_mesh/assets/docs/assets/js/runtime~main.18dc45dd.js +1 -0
  94. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +143 -0
  95. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/artifact-management/index.html +7 -7
  96. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/audio-tools/index.html +7 -7
  97. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/data-analysis-tools/index.html +8 -8
  98. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/embeds/index.html +6 -6
  99. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/index.html +11 -11
  100. solace_agent_mesh/assets/docs/docs/documentation/{concepts → components}/cli/index.html +25 -25
  101. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +91 -0
  102. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +29 -0
  103. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +55 -0
  104. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +110 -0
  105. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +104 -0
  106. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +57 -0
  107. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +25 -0
  108. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +59 -0
  109. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → developing}/create-agents/index.html +113 -152
  110. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → developing}/create-gateways/index.html +9 -9
  111. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → developing}/creating-python-tools/index.html +12 -12
  112. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +54 -0
  113. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +32 -0
  114. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +55 -0
  115. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/bedrock-agents/index.html +25 -25
  116. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/custom-agent/index.html +13 -13
  117. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/event-mesh-gateway/index.html +11 -11
  118. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/mcp-integration/index.html +10 -10
  119. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/mongodb-integration/index.html +13 -13
  120. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/rag-integration/index.html +13 -13
  121. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/rest-gateway/index.html +10 -10
  122. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +72 -0
  123. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/sql-database/index.html +14 -14
  124. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +33 -0
  125. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +83 -0
  126. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +222 -0
  127. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +161 -0
  128. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +75 -0
  129. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +53 -0
  130. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +35 -100
  131. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +41 -0
  132. solace_agent_mesh/assets/docs/docs/documentation/{getting-started → installing-and-configuring}/configurations/index.html +56 -50
  133. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +25 -0
  134. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +76 -0
  135. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +63 -0
  136. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +142 -0
  137. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +100 -0
  138. solace_agent_mesh/assets/docs/docs/documentation/{Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html → migrations/a2a-upgrade/a2a-technical-migration-map/index.html} +10 -11
  139. solace_agent_mesh/assets/docs/img/solace-logo.png +0 -0
  140. solace_agent_mesh/assets/docs/lunr-index-1760121512891.json +1 -0
  141. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  142. solace_agent_mesh/assets/docs/search-doc-1760121512891.json +1 -0
  143. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  144. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  145. solace_agent_mesh/cli/__init__.py +1 -1
  146. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-j1LW-wlq.js → authCallback-DwrxZE0E.js} +1 -1
  147. solace_agent_mesh/client/webui/frontend/static/assets/{client-B9p_nFNA.js → client-DarGQzyw.js} +1 -1
  148. solace_agent_mesh/client/webui/frontend/static/assets/main-2nd1gbaH.js +339 -0
  149. solace_agent_mesh/client/webui/frontend/static/assets/main-DoKXctCM.css +1 -0
  150. solace_agent_mesh/client/webui/frontend/static/assets/{vendor-CS5YMf8a.js → vendor-BKIeiHj_.js} +80 -70
  151. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  152. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  153. solace_agent_mesh/common/a2a/a2a_llm.txt +1 -1
  154. solace_agent_mesh/common/a2a/a2a_llm_detail.txt +193 -0
  155. solace_agent_mesh/common/a2a/artifact.py +2 -1
  156. solace_agent_mesh/common/a2a/protocol.py +3 -2
  157. solace_agent_mesh/common/a2a/translation.py +3 -1
  158. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +1 -1
  159. solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +736 -0
  160. solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +23 -0
  161. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +93 -15
  162. solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +23 -0
  163. solace_agent_mesh/common/common_llm.txt +24 -39
  164. solace_agent_mesh/common/common_llm_detail.txt +2562 -0
  165. solace_agent_mesh/common/data_parts.py +9 -1
  166. solace_agent_mesh/common/middleware/config_resolver.py +3 -1
  167. solace_agent_mesh/common/middleware/middleware_llm_detail.txt +185 -0
  168. solace_agent_mesh/common/middleware/registry.py +3 -1
  169. solace_agent_mesh/common/sac/sac_llm.txt +1 -1
  170. solace_agent_mesh/common/sac/sac_llm_detail.txt +82 -0
  171. solace_agent_mesh/common/sac/sam_component_base.py +2 -1
  172. solace_agent_mesh/common/sam_events/event_service.py +3 -2
  173. solace_agent_mesh/common/sam_events/sam_events_llm.txt +104 -0
  174. solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +115 -0
  175. solace_agent_mesh/common/services/employee_service.py +3 -1
  176. solace_agent_mesh/common/services/identity_service.py +2 -1
  177. solace_agent_mesh/common/services/providers/local_file_identity_service.py +2 -1
  178. solace_agent_mesh/common/services/services_llm.txt +57 -6
  179. solace_agent_mesh/common/services/services_llm_detail.txt +459 -0
  180. solace_agent_mesh/common/utils/artifact_utils.py +3 -1
  181. solace_agent_mesh/common/utils/asyncio_macos_fix.py +3 -1
  182. solace_agent_mesh/common/utils/embeds/converter.py +3 -1
  183. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +1 -1
  184. solace_agent_mesh/common/utils/embeds/evaluators.py +2 -1
  185. solace_agent_mesh/common/utils/embeds/modifiers.py +3 -2
  186. solace_agent_mesh/common/utils/embeds/resolver.py +2 -1
  187. solace_agent_mesh/common/utils/initializer.py +3 -1
  188. solace_agent_mesh/common/utils/message_utils.py +2 -1
  189. solace_agent_mesh/common/utils/push_notification_auth.py +3 -2
  190. solace_agent_mesh/common/utils/utils_llm.txt +75 -87
  191. solace_agent_mesh/common/utils/utils_llm_detail.txt +572 -0
  192. solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +101 -0
  193. solace_agent_mesh/core_a2a/service.py +2 -2
  194. solace_agent_mesh/gateway/base/app.py +3 -2
  195. solace_agent_mesh/gateway/base/base_llm.txt +1 -1
  196. solace_agent_mesh/gateway/base/base_llm_detail.txt +235 -0
  197. solace_agent_mesh/gateway/base/component.py +3 -1
  198. solace_agent_mesh/gateway/base/task_context.py +2 -1
  199. solace_agent_mesh/gateway/gateway_llm.txt +242 -235
  200. solace_agent_mesh/gateway/gateway_llm_detail.txt +3885 -0
  201. solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +295 -0
  202. solace_agent_mesh/gateway/http_sse/alembic/env.py +10 -1
  203. solace_agent_mesh/gateway/http_sse/alembic/versions/20251006_98882922fa59_add_tasks_events_feedback_chat_tasks.py +190 -0
  204. solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +155 -0
  205. solace_agent_mesh/gateway/http_sse/alembic.ini +1 -1
  206. solace_agent_mesh/gateway/http_sse/app.py +150 -3
  207. solace_agent_mesh/gateway/http_sse/component.py +372 -61
  208. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +46 -6
  209. solace_agent_mesh/gateway/http_sse/components/task_logger_forwarder.py +109 -0
  210. solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +4 -2
  211. solace_agent_mesh/gateway/http_sse/dependencies.py +119 -27
  212. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +172 -172
  213. solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +3278 -0
  214. solace_agent_mesh/gateway/http_sse/main.py +149 -42
  215. solace_agent_mesh/gateway/http_sse/repository/__init__.py +3 -12
  216. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +103 -0
  217. solace_agent_mesh/gateway/http_sse/repository/entities/__init__.py +5 -3
  218. solace_agent_mesh/gateway/http_sse/repository/entities/chat_task.py +75 -0
  219. solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +263 -0
  220. solace_agent_mesh/gateway/http_sse/repository/entities/feedback.py +20 -0
  221. solace_agent_mesh/gateway/http_sse/repository/entities/session_history.py +0 -16
  222. solace_agent_mesh/gateway/http_sse/repository/entities/task.py +25 -0
  223. solace_agent_mesh/gateway/http_sse/repository/entities/task_event.py +21 -0
  224. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +81 -0
  225. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +73 -18
  226. solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -5
  227. solace_agent_mesh/gateway/http_sse/repository/models/chat_task_model.py +31 -0
  228. solace_agent_mesh/gateway/http_sse/repository/models/feedback_model.py +21 -0
  229. solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +266 -0
  230. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +3 -3
  231. solace_agent_mesh/gateway/http_sse/repository/models/task_event_model.py +25 -0
  232. solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +32 -0
  233. solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +340 -0
  234. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +4 -53
  235. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +173 -0
  236. solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +3 -2
  237. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +3 -3
  238. solace_agent_mesh/gateway/http_sse/routers/auth.py +3 -1
  239. solace_agent_mesh/gateway/http_sse/routers/config.py +29 -6
  240. solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +346 -0
  241. solace_agent_mesh/gateway/http_sse/routers/dto/requests/__init__.py +3 -3
  242. solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +83 -0
  243. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +2 -10
  244. solace_agent_mesh/gateway/http_sse/routers/dto/requests/task_requests.py +58 -0
  245. solace_agent_mesh/gateway/http_sse/routers/dto/responses/__init__.py +5 -3
  246. solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +107 -0
  247. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +1 -15
  248. solace_agent_mesh/gateway/http_sse/routers/dto/responses/task_responses.py +30 -0
  249. solace_agent_mesh/gateway/http_sse/routers/feedback.py +37 -0
  250. solace_agent_mesh/gateway/http_sse/routers/people.py +3 -1
  251. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +255 -204
  252. solace_agent_mesh/gateway/http_sse/routers/sessions.py +223 -41
  253. solace_agent_mesh/gateway/http_sse/routers/sse.py +3 -2
  254. solace_agent_mesh/gateway/http_sse/routers/tasks.py +170 -43
  255. solace_agent_mesh/gateway/http_sse/routers/users.py +3 -1
  256. solace_agent_mesh/gateway/http_sse/routers/visualization.py +2 -1
  257. solace_agent_mesh/gateway/http_sse/services/agent_card_service.py +3 -1
  258. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +273 -0
  259. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +242 -0
  260. solace_agent_mesh/gateway/http_sse/services/people_service.py +2 -82
  261. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +177 -13
  262. solace_agent_mesh/gateway/http_sse/services/session_service.py +154 -85
  263. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +318 -0
  264. solace_agent_mesh/gateway/http_sse/services/task_service.py +3 -2
  265. solace_agent_mesh/gateway/http_sse/session_manager.py +2 -1
  266. solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +25 -14
  267. solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +285 -0
  268. solace_agent_mesh/gateway/http_sse/shared/types.py +7 -0
  269. solace_agent_mesh/gateway/http_sse/sse_event_buffer.py +2 -1
  270. solace_agent_mesh/gateway/http_sse/sse_manager.py +2 -2
  271. solace_agent_mesh/gateway/http_sse/utils/__init__.py +1 -0
  272. solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +32 -0
  273. solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +47 -0
  274. solace_agent_mesh/solace_agent_mesh_llm.txt +1 -1
  275. solace_agent_mesh/solace_agent_mesh_llm_detail.txt +8599 -0
  276. solace_agent_mesh/templates/gateway_app_template.py +4 -2
  277. solace_agent_mesh/templates/gateway_component_template.py +3 -1
  278. solace_agent_mesh/templates/logging_config_template.ini +22 -45
  279. solace_agent_mesh/templates/plugin_tools_template.py +2 -2
  280. {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.1.dist-info}/METADATA +2 -2
  281. solace_agent_mesh-1.5.1.dist-info/RECORD +504 -0
  282. solace_agent_mesh/agent/adk/invocation_monitor.py +0 -295
  283. solace_agent_mesh/assets/docs/assets/images/sac-flows-80d5b603c6aafd33e87945680ce0abf3.png +0 -0
  284. solace_agent_mesh/assets/docs/assets/images/sac_parts_of_a_component-cb3d0424b1d0c17734c5435cca6b4082.png +0 -0
  285. solace_agent_mesh/assets/docs/assets/js/04989206.a248f00c.js +0 -1
  286. solace_agent_mesh/assets/docs/assets/js/0e682baa.d54b8668.js +0 -1
  287. solace_agent_mesh/assets/docs/assets/js/1023fc19.8a8a9309.js +0 -1
  288. solace_agent_mesh/assets/docs/assets/js/1523c6b4.2645ef68.js +0 -1
  289. solace_agent_mesh/assets/docs/assets/js/166ab619.e27886d9.js +0 -1
  290. solace_agent_mesh/assets/docs/assets/js/1c6e87d2.e056b7e0.js +0 -1
  291. solace_agent_mesh/assets/docs/assets/js/21ceee5f.3bf39250.js +0 -1
  292. solace_agent_mesh/assets/docs/assets/js/2a9cab12.2afaee76.js +0 -1
  293. solace_agent_mesh/assets/docs/assets/js/332e10b5.f7629851.js +0 -1
  294. solace_agent_mesh/assets/docs/assets/js/3d406171.5560fdf9.js +0 -1
  295. solace_agent_mesh/assets/docs/assets/js/42b3f8d8.508ae8db.js +0 -1
  296. solace_agent_mesh/assets/docs/assets/js/442a8107.b5c2532a.js +0 -1
  297. solace_agent_mesh/assets/docs/assets/js/453a82a6.3c6bb61d.js +0 -1
  298. solace_agent_mesh/assets/docs/assets/js/483cef9a.4736f2d8.js +0 -1
  299. solace_agent_mesh/assets/docs/assets/js/4c2787c2.c1290a40.js +0 -1
  300. solace_agent_mesh/assets/docs/assets/js/55f47984.bcd00a86.js +0 -1
  301. solace_agent_mesh/assets/docs/assets/js/5b4258a4.fdfd2325.js +0 -1
  302. solace_agent_mesh/assets/docs/assets/js/664b740a.ba305a89.js +0 -1
  303. solace_agent_mesh/assets/docs/assets/js/75384d09.c19e8b51.js +0 -1
  304. solace_agent_mesh/assets/docs/assets/js/768e31b0.9abcdc48.js +0 -1
  305. solace_agent_mesh/assets/docs/assets/js/85387663.be2bc838.js +0 -1
  306. solace_agent_mesh/assets/docs/assets/js/945fb41e.16e00776.js +0 -1
  307. solace_agent_mesh/assets/docs/assets/js/9a09e75d.92de8cf5.js +0 -1
  308. solace_agent_mesh/assets/docs/assets/js/9eff14a2.d62aad71.js +0 -1
  309. solace_agent_mesh/assets/docs/assets/js/a12a4955.25fbed32.js +0 -1
  310. solace_agent_mesh/assets/docs/assets/js/a3a92b25.af35e313.js +0 -1
  311. solace_agent_mesh/assets/docs/assets/js/aba87c2f.4ddf32f2.js +0 -1
  312. solace_agent_mesh/assets/docs/assets/js/ae0e903d.5fe5203f.js +0 -1
  313. solace_agent_mesh/assets/docs/assets/js/ae4415af.16cc58d3.js +0 -1
  314. solace_agent_mesh/assets/docs/assets/js/bac0be12.17de4316.js +0 -1
  315. solace_agent_mesh/assets/docs/assets/js/c2c06897.87cb1f47.js +0 -1
  316. solace_agent_mesh/assets/docs/assets/js/c835a94d.ce21f0bf.js +0 -1
  317. solace_agent_mesh/assets/docs/assets/js/cc969b05.feef7dcc.js +0 -1
  318. solace_agent_mesh/assets/docs/assets/js/cd3d4052.a19e7d78.js +0 -1
  319. solace_agent_mesh/assets/docs/assets/js/ced92a13.fb92e7ca.js +0 -1
  320. solace_agent_mesh/assets/docs/assets/js/cee5d587.47904f5e.js +0 -1
  321. solace_agent_mesh/assets/docs/assets/js/d6a81ee7.829198f1.js +0 -1
  322. solace_agent_mesh/assets/docs/assets/js/f284c35a.ed8dd236.js +0 -1
  323. solace_agent_mesh/assets/docs/assets/js/f897a61a.126663fe.js +0 -1
  324. solace_agent_mesh/assets/docs/assets/js/fbfa3e75.e144b16c.js +0 -1
  325. solace_agent_mesh/assets/docs/assets/js/main.f67fc9f4.js +0 -2
  326. solace_agent_mesh/assets/docs/assets/js/runtime~main.40527046.js +0 -1
  327. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +0 -46
  328. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/rbac-setup-guilde/index.html +0 -201
  329. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +0 -25
  330. solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +0 -105
  331. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +0 -144
  332. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +0 -91
  333. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +0 -91
  334. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +0 -55
  335. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +0 -111
  336. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +0 -77
  337. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +0 -48
  338. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +0 -54
  339. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +0 -45
  340. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/litellm_models/index.html +0 -49
  341. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +0 -76
  342. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +0 -73
  343. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +0 -72
  344. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +0 -54
  345. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +0 -69
  346. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +0 -59
  347. solace_agent_mesh/assets/docs/lunr-index-1759936913198.json +0 -1
  348. solace_agent_mesh/assets/docs/search-doc-1759936913198.json +0 -1
  349. solace_agent_mesh/client/webui/frontend/static/assets/main-ChRwcV89.css +0 -1
  350. solace_agent_mesh/client/webui/frontend/static/assets/main-DnnE01OM.js +0 -339
  351. solace_agent_mesh/gateway/http_sse/repository/entities/message.py +0 -41
  352. solace_agent_mesh/gateway/http_sse/repository/message_repository.py +0 -84
  353. solace_agent_mesh/gateway/http_sse/repository/models/message_model.py +0 -45
  354. solace_agent_mesh-1.4.12.dist-info/RECORD +0 -448
  355. /solace_agent_mesh/assets/docs/assets/js/{8591.d7c16be6.js.LICENSE.txt → 8591.5d015485.js.LICENSE.txt} +0 -0
  356. /solace_agent_mesh/assets/docs/assets/js/{main.f67fc9f4.js.LICENSE.txt → main.bd3c34f3.js.LICENSE.txt} +0 -0
  357. {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.1.dist-info}/WHEEL +0 -0
  358. {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.1.dist-info}/entry_points.txt +0 -0
  359. {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,21 +1,22 @@
1
+ import logging
1
2
  import uuid
2
- from typing import TYPE_CHECKING, Optional
3
+ from typing import TYPE_CHECKING, Optional, List, Dict, Any
3
4
 
4
- from solace_ai_connector.common.log import log
5
5
  from sqlalchemy.orm import Session as DbSession
6
6
 
7
7
  from ..repository import (
8
- IMessageRepository,
9
8
  ISessionRepository,
10
- Message,
11
9
  Session,
12
- SessionHistory,
13
10
  )
14
- from ..shared.enums import MessageType, SenderType
15
- from ..shared.types import PaginationInfo, SessionId, UserId
11
+ from ..repository.chat_task_repository import ChatTaskRepository
12
+ from ..repository.entities import ChatTask
13
+ from ..shared.enums import SenderType
14
+ from ..shared.types import SessionId, UserId
16
15
  from ..shared import now_epoch_ms
17
16
  from ..shared.pagination import PaginationParams, PaginatedResponse, get_pagination_or_default
18
17
 
18
+ log = logging.getLogger(__name__)
19
+
19
20
  if TYPE_CHECKING:
20
21
  from ..component import WebUIBackendComponent
21
22
 
@@ -28,11 +29,10 @@ class SessionService:
28
29
  self.component = component
29
30
 
30
31
  def _get_repositories(self, db: DbSession):
31
- """Create repositories for the given database session."""
32
- from ..repository import SessionRepository, MessageRepository
32
+ """Create session repository for the given database session."""
33
+ from ..repository import SessionRepository
33
34
  session_repository = SessionRepository(db)
34
- message_repository = MessageRepository(db)
35
- return session_repository, message_repository
35
+ return session_repository
36
36
 
37
37
  def is_persistence_enabled(self) -> bool:
38
38
  """Checks if the service is configured with a persistent backend."""
@@ -54,18 +54,10 @@ class SessionService:
54
54
  raise ValueError("User ID cannot be empty")
55
55
 
56
56
  pagination = get_pagination_or_default(pagination)
57
- session_repository, _ = self._get_repositories(db)
58
-
59
- pagination_info = PaginationInfo(
60
- page=pagination.page_number,
61
- page_size=pagination.page_size,
62
- total_items=0,
63
- total_pages=0,
64
- has_next=False,
65
- has_previous=False,
66
- )
57
+ session_repository = self._get_repositories(db)
67
58
 
68
- sessions = session_repository.find_by_user(user_id, pagination_info)
59
+ # Pass pagination params directly - repository will handle offset calculation
60
+ sessions = session_repository.find_by_user(user_id, pagination)
69
61
  total_count = session_repository.count_by_user(user_id)
70
62
 
71
63
  return PaginatedResponse.create(sessions, total_count, pagination)
@@ -76,33 +68,9 @@ class SessionService:
76
68
  if not self._is_valid_session_id(session_id):
77
69
  return None
78
70
 
79
- session_repository, _ = self._get_repositories(db)
71
+ session_repository = self._get_repositories(db)
80
72
  return session_repository.find_user_session(session_id, user_id)
81
73
 
82
- def get_session_history(
83
- self,
84
- db: DbSession,
85
- session_id: SessionId,
86
- user_id: UserId,
87
- pagination: PaginationInfo | None = None,
88
- ) -> SessionHistory | None:
89
- if not self._is_valid_session_id(session_id):
90
- return None
91
-
92
- session_repository, _ = self._get_repositories(db)
93
- result = session_repository.find_user_session_with_messages(
94
- session_id, user_id, pagination
95
- )
96
- if not result:
97
- return None
98
-
99
- session, messages = result
100
- return SessionHistory(
101
- session=session,
102
- messages=messages,
103
- total_message_count=len(messages),
104
- )
105
-
106
74
  def create_session(
107
75
  self,
108
76
  db: DbSession,
@@ -131,7 +99,7 @@ class SessionService:
131
99
  updated_time=now_ms,
132
100
  )
133
101
 
134
- session_repository, _ = self._get_repositories(db)
102
+ session_repository = self._get_repositories(db)
135
103
  created_session = session_repository.save(session)
136
104
  log.info("Created new session %s for user %s", created_session.id, user_id)
137
105
 
@@ -152,7 +120,7 @@ class SessionService:
152
120
  if len(name.strip()) > 255:
153
121
  raise ValueError("Session name cannot exceed 255 characters")
154
122
 
155
- session_repository, _ = self._get_repositories(db)
123
+ session_repository = self._get_repositories(db)
156
124
  session = session_repository.find_user_session(session_id, user_id)
157
125
  if not session:
158
126
  return None
@@ -169,7 +137,7 @@ class SessionService:
169
137
  if not self._is_valid_session_id(session_id):
170
138
  raise ValueError("Invalid session ID")
171
139
 
172
- session_repository, _ = self._get_repositories(db)
140
+ session_repository = self._get_repositories(db)
173
141
  session = session_repository.find_user_session(session_id, user_id)
174
142
  if not session:
175
143
  log.warning(
@@ -198,50 +166,151 @@ class SessionService:
198
166
 
199
167
  return True
200
168
 
201
- def add_message_to_session(
169
+ def save_task(
202
170
  self,
203
171
  db: DbSession,
204
- session_id: SessionId,
205
- user_id: UserId,
206
- message: str,
207
- sender_type: SenderType,
208
- sender_name: str,
209
- agent_id: str | None = None,
210
- message_type: MessageType = MessageType.TEXT,
211
- ) -> Message:
212
- if not self._is_valid_session_id(session_id):
213
- raise ValueError("Invalid session ID")
214
-
215
- if not message or message.strip() == "":
216
- raise ValueError("Message cannot be empty")
217
-
218
- session_repository, message_repository = self._get_repositories(db)
172
+ task_id: str,
173
+ session_id: str,
174
+ user_id: str,
175
+ user_message: Optional[str],
176
+ message_bubbles: str, # JSON string (opaque)
177
+ task_metadata: Optional[str] = None # JSON string (opaque)
178
+ ) -> ChatTask:
179
+ """
180
+ Save a complete task interaction.
181
+
182
+ Args:
183
+ db: Database session
184
+ task_id: A2A task ID
185
+ session_id: Session ID
186
+ user_id: User ID
187
+ user_message: Original user input text
188
+ message_bubbles: Array of all message bubbles displayed during this task
189
+ task_metadata: Task-level metadata (status, feedback, agent name, etc.)
190
+
191
+ Returns:
192
+ Saved ChatTask entity
193
+
194
+ Raises:
195
+ ValueError: If session not found or validation fails
196
+ """
197
+ # Validate session exists and belongs to user
198
+ session_repository = self._get_repositories(db)
219
199
  session = session_repository.find_user_session(session_id, user_id)
220
200
  if not session:
221
- session = self.create_session(
222
- db=db,
223
- user_id=user_id,
224
- agent_id=agent_id,
225
- session_id=session_id,
226
- )
227
-
228
- message_entity = Message(
229
- id=str(uuid.uuid4()),
201
+ raise ValueError(f"Session {session_id} not found for user {user_id}")
202
+
203
+ # Create task entity - pass strings directly
204
+ task = ChatTask(
205
+ id=task_id,
230
206
  session_id=session_id,
231
- message=message.strip(),
232
- sender_type=sender_type,
233
- sender_name=sender_name,
234
- message_type=message_type,
207
+ user_id=user_id,
208
+ user_message=user_message,
209
+ message_bubbles=message_bubbles, # Already a string
210
+ task_metadata=task_metadata, # Already a string
235
211
  created_time=now_epoch_ms(),
212
+ updated_time=None
236
213
  )
237
-
238
- saved_message = message_repository.save(message_entity)
239
-
214
+
215
+ # Save via repository
216
+ task_repo = ChatTaskRepository(db)
217
+ saved_task = task_repo.save(task)
218
+
219
+ # Update session activity
240
220
  session.mark_activity()
241
221
  session_repository.save(session)
222
+
223
+ log.info(f"Saved task {task_id} for session {session_id}")
224
+ return saved_task
242
225
 
243
- log.info("Added message to session %s from %s", session_id, sender_name)
244
- return saved_message
226
+ def get_session_tasks(
227
+ self,
228
+ db: DbSession,
229
+ session_id: str,
230
+ user_id: str
231
+ ) -> List[ChatTask]:
232
+ """
233
+ Get all tasks for a session.
234
+
235
+ Args:
236
+ db: Database session
237
+ session_id: Session ID
238
+ user_id: User ID
239
+
240
+ Returns:
241
+ List of ChatTask entities in chronological order
242
+
243
+ Raises:
244
+ ValueError: If session not found
245
+ """
246
+ # Validate session exists and belongs to user
247
+ session_repository = self._get_repositories(db)
248
+ session = session_repository.find_user_session(session_id, user_id)
249
+ if not session:
250
+ raise ValueError(f"Session {session_id} not found for user {user_id}")
251
+
252
+ # Load tasks
253
+ task_repo = ChatTaskRepository(db)
254
+ return task_repo.find_by_session(session_id, user_id)
255
+
256
+ def get_session_messages_from_tasks(
257
+ self,
258
+ db: DbSession,
259
+ session_id: str,
260
+ user_id: str
261
+ ) -> List[Dict[str, Any]]:
262
+ """
263
+ Get session messages by flattening task message_bubbles.
264
+ This provides backward compatibility with the old message-based API.
265
+
266
+ Args:
267
+ db: Database session
268
+ session_id: Session ID
269
+ user_id: User ID
270
+
271
+ Returns:
272
+ List of message dictionaries flattened from tasks
273
+
274
+ Raises:
275
+ ValueError: If session not found
276
+ """
277
+ # Load tasks
278
+ tasks = self.get_session_tasks(db, session_id, user_id)
279
+
280
+ # Flatten message_bubbles from all tasks
281
+ messages = []
282
+ for task in tasks:
283
+ import json
284
+ message_bubbles = json.loads(task.message_bubbles) if isinstance(task.message_bubbles, str) else task.message_bubbles
285
+
286
+ for bubble in message_bubbles:
287
+ # Determine sender type from bubble type
288
+ bubble_type = bubble.get("type", "agent")
289
+ sender_type = "user" if bubble_type == "user" else "agent"
290
+
291
+ # Get sender name
292
+ if bubble_type == "user":
293
+ sender_name = user_id
294
+ else:
295
+ # Try to get agent name from task metadata, fallback to "agent"
296
+ sender_name = "agent"
297
+ if task.task_metadata:
298
+ task_metadata = json.loads(task.task_metadata) if isinstance(task.task_metadata, str) else task.task_metadata
299
+ sender_name = task_metadata.get("agent_name", "agent")
300
+
301
+ # Create message dictionary
302
+ message = {
303
+ "id": bubble.get("id", str(uuid.uuid4())),
304
+ "session_id": session_id,
305
+ "message": bubble.get("text", ""),
306
+ "sender_type": sender_type,
307
+ "sender_name": sender_name,
308
+ "message_type": "text",
309
+ "created_time": task.created_time
310
+ }
311
+ messages.append(message)
312
+
313
+ return messages
245
314
 
246
315
  def _is_valid_session_id(self, session_id: SessionId) -> bool:
247
316
  return (
@@ -289,4 +358,4 @@ class SessionService:
289
358
  "Failed to publish session deletion event to agent %s: %s",
290
359
  agent_id,
291
360
  e,
292
- )
361
+ )
@@ -0,0 +1,318 @@
1
+ """
2
+ Service for logging A2A tasks and events to the database.
3
+ """
4
+
5
+ import copy
6
+ import logging
7
+ import uuid
8
+ from typing import Any, Callable, Dict, Union
9
+
10
+ from a2a.types import (
11
+ A2ARequest,
12
+ JSONRPCError,
13
+ JSONRPCResponse,
14
+ Task as A2ATask,
15
+ TaskArtifactUpdateEvent,
16
+ TaskStatusUpdateEvent,
17
+ )
18
+ from sqlalchemy.orm import Session as DBSession
19
+
20
+ from ....common import a2a
21
+ from ..repository.entities import Task, TaskEvent
22
+ from ..repository.task_repository import TaskRepository
23
+ from ..shared import now_epoch_ms
24
+
25
+ log = logging.getLogger(__name__)
26
+
27
+ class TaskLoggerService:
28
+ """Service for logging A2A tasks and events to the database."""
29
+
30
+ def __init__(
31
+ self, session_factory: Callable[[], DBSession] | None, config: Dict[str, Any]
32
+ ):
33
+ self.session_factory = session_factory
34
+ self.config = config
35
+ self.log_identifier = "[TaskLoggerService]"
36
+ log.info(f"{self.log_identifier} Initialized.")
37
+
38
+ def log_event(self, event_data: Dict[str, Any]):
39
+ """
40
+ Parses a raw A2A message and logs it as a task event.
41
+ Creates or updates the master task record as needed.
42
+ """
43
+ if not self.config.get("enabled", False):
44
+ return
45
+
46
+ if not self.session_factory:
47
+ log.warning(
48
+ f"{self.log_identifier} Task logging is enabled but no database is configured. Skipping event."
49
+ )
50
+ return
51
+
52
+ topic = event_data.get("topic")
53
+ payload = event_data.get("payload")
54
+ user_properties = event_data.get("user_properties", {})
55
+
56
+ if not topic or not payload:
57
+ log.warning(
58
+ f"{self.log_identifier} Received event with missing topic or payload."
59
+ )
60
+ return
61
+
62
+ if "discovery" in topic:
63
+ # Ignore discovery messages
64
+ return
65
+
66
+ # Parse the event into a Pydantic model first.
67
+ parsed_event = self._parse_a2a_event(topic, payload)
68
+ if parsed_event is None:
69
+ # Parsing failed or event should be ignored.
70
+ return
71
+
72
+ db = self.session_factory()
73
+ try:
74
+ repo = TaskRepository(db)
75
+
76
+ # Infer details from the parsed event
77
+ direction, task_id, user_id = self._infer_event_details(
78
+ topic, parsed_event, user_properties
79
+ )
80
+
81
+ if not task_id:
82
+ log.debug(
83
+ f"{self.log_identifier} Could not determine task_id for event on topic {topic}. Skipping."
84
+ )
85
+ return
86
+
87
+ # Check if we should log this event type
88
+ if not self._should_log_event(topic, parsed_event):
89
+ log.debug(
90
+ f"{self.log_identifier} Event on topic {topic} is configured to be skipped."
91
+ )
92
+ return
93
+
94
+ # Sanitize the original raw payload before storing
95
+ sanitized_payload = self._sanitize_payload(payload)
96
+
97
+ # Check for existing task or create a new one
98
+ task = repo.find_by_id(task_id)
99
+ if not task:
100
+ if direction == "request":
101
+ initial_text = self._extract_initial_text(parsed_event)
102
+ new_task = Task(
103
+ id=task_id,
104
+ user_id=user_id or "unknown",
105
+ start_time=now_epoch_ms(),
106
+ initial_request_text=(
107
+ initial_text[:1024] if initial_text else None
108
+ ), # Truncate
109
+ )
110
+ repo.save_task(new_task)
111
+ log.info(
112
+ f"{self.log_identifier} Created new task record for ID: {task_id}"
113
+ )
114
+ else:
115
+ # We received an event for a task we haven't seen the start of.
116
+ # This can happen if the logger starts mid-conversation. Create a placeholder.
117
+ placeholder_task = Task(
118
+ id=task_id,
119
+ user_id=user_id or "unknown",
120
+ start_time=now_epoch_ms(),
121
+ initial_request_text="[Task started before logger was active]",
122
+ )
123
+ repo.save_task(placeholder_task)
124
+ log.info(
125
+ f"{self.log_identifier} Created placeholder task record for ID: {task_id}"
126
+ )
127
+
128
+ # Create and save the event using the sanitized raw payload
129
+ task_event = TaskEvent(
130
+ id=str(uuid.uuid4()),
131
+ task_id=task_id,
132
+ user_id=user_id,
133
+ created_time=now_epoch_ms(),
134
+ topic=topic,
135
+ direction=direction,
136
+ payload=sanitized_payload,
137
+ )
138
+ repo.save_event(task_event)
139
+
140
+ # If it's a final event, update the master task record
141
+ final_status = self._get_final_status(parsed_event)
142
+ if final_status:
143
+ task_to_update = repo.find_by_id(task_id)
144
+ if task_to_update:
145
+ task_to_update.end_time = now_epoch_ms()
146
+ task_to_update.status = final_status
147
+
148
+ # Extract and store token usage if present
149
+ if isinstance(parsed_event, A2ATask) and parsed_event.metadata:
150
+ token_usage = parsed_event.metadata.get("token_usage")
151
+ if token_usage and isinstance(token_usage, dict):
152
+ task_to_update.total_input_tokens = token_usage.get("total_input_tokens")
153
+ task_to_update.total_output_tokens = token_usage.get("total_output_tokens")
154
+ task_to_update.total_cached_input_tokens = token_usage.get("total_cached_input_tokens")
155
+ task_to_update.token_usage_details = token_usage
156
+ log.info(
157
+ f"{self.log_identifier} Stored token usage for task {task_id}: "
158
+ f"input={token_usage.get('total_input_tokens')}, "
159
+ f"output={token_usage.get('total_output_tokens')}, "
160
+ f"cached={token_usage.get('total_cached_input_tokens')}"
161
+ )
162
+
163
+ repo.save_task(task_to_update)
164
+ log.info(
165
+ f"{self.log_identifier} Finalized task record for ID: {task_id} with status: {final_status}"
166
+ )
167
+ db.commit()
168
+ except Exception as e:
169
+ log.exception(
170
+ f"{self.log_identifier} Error logging event on topic {topic}: {e}"
171
+ )
172
+ db.rollback()
173
+ finally:
174
+ db.close()
175
+
176
+ def _parse_a2a_event(self, topic: str, payload: dict) -> Union[
177
+ A2ARequest,
178
+ A2ATask,
179
+ TaskStatusUpdateEvent,
180
+ TaskArtifactUpdateEvent,
181
+ JSONRPCError,
182
+ None,
183
+ ]:
184
+ """
185
+ Safely parses a raw A2A message payload into a Pydantic model.
186
+ Returns the parsed model or None if parsing fails or is not applicable.
187
+ """
188
+ # Ignore discovery messages
189
+ if "/discovery/agentcards" in topic:
190
+ return None
191
+
192
+ try:
193
+ # Check if it's a response (has 'result' or 'error')
194
+ if "result" in payload or "error" in payload:
195
+ rpc_response = JSONRPCResponse.model_validate(payload)
196
+ error = a2a.get_response_error(rpc_response)
197
+ if error:
198
+ return error
199
+ result = a2a.get_response_result(rpc_response)
200
+ if result:
201
+ # The result is already a parsed Pydantic model
202
+ return result
203
+ # Check if it's a request
204
+ elif "method" in payload:
205
+ return A2ARequest.model_validate(payload)
206
+
207
+ log.warning(
208
+ f"{self.log_identifier} Payload for topic '{topic}' is not a recognizable JSON-RPC request or response. Payload: {payload}"
209
+ )
210
+ return None
211
+
212
+ except Exception as e:
213
+ log.error(
214
+ f"{self.log_identifier} Failed to parse A2A event for topic '{topic}': {e}. Payload: {payload}"
215
+ )
216
+ return None
217
+
218
+ def _infer_event_details(
219
+ self, topic: str, parsed_event: Any, user_props: Dict | None
220
+ ) -> tuple[str, str | None, str | None]:
221
+ """Infers direction, task_id, and user_id from a parsed A2A event."""
222
+ direction = "unknown"
223
+ task_id = None
224
+ # Ensure user_props is a dict, not None
225
+ user_props = user_props or {}
226
+ user_id = user_props.get("userId")
227
+
228
+ if isinstance(parsed_event, A2ARequest):
229
+ direction = "request"
230
+ task_id = a2a.get_request_id(parsed_event)
231
+ elif isinstance(
232
+ parsed_event, (A2ATask, TaskStatusUpdateEvent, TaskArtifactUpdateEvent)
233
+ ):
234
+ direction = "response" if isinstance(parsed_event, A2ATask) else "status"
235
+ task_id = getattr(parsed_event, "task_id", None) or getattr(
236
+ parsed_event, "id", None
237
+ )
238
+ elif isinstance(parsed_event, JSONRPCError):
239
+ direction = "error"
240
+ if isinstance(parsed_event.data, dict):
241
+ task_id = parsed_event.data.get("taskId")
242
+
243
+ if not user_id:
244
+ user_config = user_props.get("a2aUserConfig") or user_props.get("a2a_user_config")
245
+ if isinstance(user_config, dict):
246
+ user_profile = user_config.get("user_profile", {})
247
+ if isinstance(user_profile, dict):
248
+ user_id = user_profile.get("id")
249
+
250
+ return direction, str(task_id) if task_id else None, user_id
251
+
252
+ def _extract_initial_text(self, parsed_event: Any) -> str | None:
253
+ """Extracts the initial text from a send message request."""
254
+ try:
255
+ if isinstance(parsed_event, A2ARequest):
256
+ message = a2a.get_message_from_send_request(parsed_event)
257
+ if message:
258
+ return a2a.get_text_from_message(message)
259
+ except Exception:
260
+ return None
261
+ return None
262
+
263
+ def _get_final_status(self, parsed_event: Any) -> str | None:
264
+ """Checks if a parsed event represents a final task status and returns the state."""
265
+ if isinstance(parsed_event, A2ATask):
266
+ return parsed_event.status.state.value
267
+ elif isinstance(parsed_event, JSONRPCError):
268
+ return "failed"
269
+ return None
270
+
271
+ def _should_log_event(self, topic: str, parsed_event: Any) -> bool:
272
+ """Determines if an event should be logged based on configuration."""
273
+ if not self.config.get("log_status_updates", True):
274
+ if "status" in topic:
275
+ return False
276
+ if not self.config.get("log_artifact_events", True):
277
+ if isinstance(parsed_event, TaskArtifactUpdateEvent):
278
+ return False
279
+ return True
280
+
281
+ def _sanitize_payload(self, payload: Dict) -> Dict:
282
+ """Strips or truncates file content from payload based on configuration."""
283
+ new_payload = copy.deepcopy(payload)
284
+
285
+ def walk_and_sanitize(node):
286
+ if isinstance(node, dict):
287
+ for key, value in list(node.items()):
288
+ if key == "parts" and isinstance(value, list):
289
+ new_parts = []
290
+ for part in value:
291
+ if isinstance(part, dict) and "file" in part:
292
+ if not self.config.get("log_file_parts", True):
293
+ continue # Skip this part entirely
294
+
295
+ file_dict = part.get("file")
296
+ if isinstance(file_dict, dict) and "bytes" in file_dict:
297
+ max_bytes = self.config.get(
298
+ "max_file_part_size_bytes", 102400
299
+ )
300
+ file_bytes_b64 = file_dict.get("bytes")
301
+ if isinstance(file_bytes_b64, str):
302
+ if (len(file_bytes_b64) * 3 / 4) > max_bytes:
303
+ file_dict["bytes"] = (
304
+ f"[Content stripped, size > {max_bytes} bytes]"
305
+ )
306
+ new_parts.append(part)
307
+ else:
308
+ walk_and_sanitize(part)
309
+ new_parts.append(part)
310
+ node["parts"] = new_parts
311
+ else:
312
+ walk_and_sanitize(value)
313
+ elif isinstance(node, list):
314
+ for item in node:
315
+ walk_and_sanitize(item)
316
+
317
+ walk_and_sanitize(new_payload)
318
+ return new_payload
@@ -3,15 +3,16 @@ Service layer for handling A2A task submissions and cancellations.
3
3
  Uses CoreA2AService for logic and a provided function for publishing.
4
4
  """
5
5
 
6
+ import logging
6
7
  import threading
7
8
  from typing import Callable, Dict, Optional
8
9
 
9
- from solace_ai_connector.common.log import log
10
-
11
10
  from ....common import a2a
12
11
  from ....gateway.http_sse.sse_manager import SSEManager
13
12
  from ....core_a2a.service import CoreA2AService
14
13
 
14
+ log = logging.getLogger(__name__)
15
+
15
16
  PublishFunc = Callable[[str, Dict, Optional[Dict]], None]
16
17
 
17
18
 
@@ -2,13 +2,14 @@
2
2
  Manages web user sessions and mapping to A2A Client IDs.
3
3
  """
4
4
 
5
+ import logging
5
6
  import uuid
6
7
  from collections.abc import Callable
7
8
  from typing import Any
8
9
 
9
- from solace_ai_connector.common.log import log
10
10
  from starlette.requests import Request
11
11
 
12
+ log = logging.getLogger(__name__)
12
13
 
13
14
  SESSION_KEY_CLIENT_ID = "a2a_client_id"
14
15
  SESSION_KEY_SESSION_ID = "a2a_session_id"