solace-agent-mesh 1.7.1__py3-none-any.whl → 1.13.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of solace-agent-mesh might be problematic. Click here for more details.

Files changed (447) hide show
  1. solace_agent_mesh/agent/adk/alembic/README +74 -0
  2. solace_agent_mesh/agent/adk/alembic/env.py +77 -0
  3. solace_agent_mesh/agent/adk/alembic/script.py.mako +28 -0
  4. solace_agent_mesh/agent/adk/alembic/versions/e2902798564d_adk_session_db_upgrade.py +52 -0
  5. solace_agent_mesh/agent/adk/alembic.ini +112 -0
  6. solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +164 -0
  7. solace_agent_mesh/agent/adk/artifacts/s3_artifact_service.py +163 -0
  8. solace_agent_mesh/agent/adk/callbacks.py +752 -127
  9. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +99 -7
  10. solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +52 -5
  11. solace_agent_mesh/agent/adk/mcp_content_processor.py +1 -1
  12. solace_agent_mesh/agent/adk/models/lite_llm.py +34 -16
  13. solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +24 -137
  14. solace_agent_mesh/agent/adk/runner.py +66 -8
  15. solace_agent_mesh/agent/adk/schema_migration.py +88 -0
  16. solace_agent_mesh/agent/adk/services.py +41 -1
  17. solace_agent_mesh/agent/adk/setup.py +220 -32
  18. solace_agent_mesh/agent/adk/stream_parser.py +229 -40
  19. solace_agent_mesh/agent/protocol/event_handlers.py +219 -33
  20. solace_agent_mesh/agent/proxies/a2a/component.py +572 -75
  21. solace_agent_mesh/agent/proxies/a2a/config.py +80 -4
  22. solace_agent_mesh/agent/proxies/base/component.py +188 -22
  23. solace_agent_mesh/agent/proxies/base/proxy_task_context.py +3 -1
  24. solace_agent_mesh/agent/sac/app.py +37 -12
  25. solace_agent_mesh/agent/sac/component.py +322 -52
  26. solace_agent_mesh/agent/sac/patch_adk.py +8 -16
  27. solace_agent_mesh/agent/sac/task_execution_context.py +90 -0
  28. solace_agent_mesh/agent/tools/__init__.py +3 -0
  29. solace_agent_mesh/agent/tools/audio_tools.py +3 -3
  30. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +698 -24
  31. solace_agent_mesh/agent/tools/deep_research_tools.py +2161 -0
  32. solace_agent_mesh/agent/tools/peer_agent_tool.py +82 -15
  33. solace_agent_mesh/agent/tools/time_tools.py +126 -0
  34. solace_agent_mesh/agent/tools/tool_config_types.py +54 -2
  35. solace_agent_mesh/agent/tools/web_search_tools.py +279 -0
  36. solace_agent_mesh/agent/tools/web_tools.py +125 -17
  37. solace_agent_mesh/agent/utils/artifact_helpers.py +243 -5
  38. solace_agent_mesh/agent/utils/context_helpers.py +17 -0
  39. solace_agent_mesh/assets/docs/404.html +6 -6
  40. solace_agent_mesh/assets/docs/assets/css/{styles.906a1503.css → styles.8162edfb.css} +1 -1
  41. solace_agent_mesh/assets/docs/assets/js/05749d90.19ac4f35.js +1 -0
  42. solace_agent_mesh/assets/docs/assets/js/15ba94aa.e186750d.js +1 -0
  43. solace_agent_mesh/assets/docs/assets/js/15e40e79.434bb30f.js +1 -0
  44. solace_agent_mesh/assets/docs/assets/js/17896441.e612dfb4.js +1 -0
  45. solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js +2 -0
  46. solace_agent_mesh/assets/docs/assets/js/{17896441.a5e82f9b.js.LICENSE.txt → 2279.550aa580.js.LICENSE.txt} +6 -0
  47. solace_agent_mesh/assets/docs/assets/js/240a0364.83e37aa8.js +1 -0
  48. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.2f0db237.js +1 -0
  49. solace_agent_mesh/assets/docs/assets/js/3a6c6137.7e61915d.js +1 -0
  50. solace_agent_mesh/assets/docs/assets/js/3ac1795d.7f7ab1c1.js +1 -0
  51. solace_agent_mesh/assets/docs/assets/js/3ff0015d.e53c9b78.js +1 -0
  52. solace_agent_mesh/assets/docs/assets/js/41adc471.0e95b87c.js +1 -0
  53. solace_agent_mesh/assets/docs/assets/js/4667dc50.bf2ad456.js +1 -0
  54. solace_agent_mesh/assets/docs/assets/js/49eed117.493d6f99.js +1 -0
  55. solace_agent_mesh/assets/docs/assets/js/{509e993c.4c7a1a6d.js → 509e993c.a1fbf45a.js} +1 -1
  56. solace_agent_mesh/assets/docs/assets/js/547e15cc.8e6da617.js +1 -0
  57. solace_agent_mesh/assets/docs/assets/js/55b7b518.29d6e75d.js +1 -0
  58. solace_agent_mesh/assets/docs/assets/js/5b8d9c11.d4eb37b8.js +1 -0
  59. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.1ee87753.js +1 -0
  60. solace_agent_mesh/assets/docs/assets/js/60702c0e.a8bdd79b.js +1 -0
  61. solace_agent_mesh/assets/docs/assets/js/64195356.09dbd087.js +1 -0
  62. solace_agent_mesh/assets/docs/assets/js/66d4869e.30340bd3.js +1 -0
  63. solace_agent_mesh/assets/docs/assets/js/6aaedf65.7253541d.js +1 -0
  64. solace_agent_mesh/assets/docs/assets/js/6d84eae0.fd23ba4a.js +1 -0
  65. solace_agent_mesh/assets/docs/assets/js/729898df.7249e9fd.js +1 -0
  66. solace_agent_mesh/assets/docs/assets/js/7e294c01.7c5f6906.js +1 -0
  67. solace_agent_mesh/assets/docs/assets/js/8024126c.e3467286.js +1 -0
  68. solace_agent_mesh/assets/docs/assets/js/81a99df0.7ed65d45.js +1 -0
  69. solace_agent_mesh/assets/docs/assets/js/82fbfb93.161823a5.js +1 -0
  70. solace_agent_mesh/assets/docs/assets/js/924ffdeb.975e428a.js +1 -0
  71. solace_agent_mesh/assets/docs/assets/js/94e8668d.16083b3f.js +1 -0
  72. solace_agent_mesh/assets/docs/assets/js/9bb13469.4523ae20.js +1 -0
  73. solace_agent_mesh/assets/docs/assets/js/a7d42657.a956689d.js +1 -0
  74. solace_agent_mesh/assets/docs/assets/js/a94703ab.3e5fbcb3.js +1 -0
  75. solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e563275.js +1 -0
  76. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.0e0d8baf.js +1 -0
  77. solace_agent_mesh/assets/docs/assets/js/cab03b5b.6a073091.js +1 -0
  78. solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.07e170dd.js +1 -0
  79. solace_agent_mesh/assets/docs/assets/js/e04b235d.06d23db6.js +1 -0
  80. solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.deb2b62e.js +1 -0
  81. solace_agent_mesh/assets/docs/assets/js/e3d9abda.1476f570.js +1 -0
  82. solace_agent_mesh/assets/docs/assets/js/e6f9706b.acc800d3.js +1 -0
  83. solace_agent_mesh/assets/docs/assets/js/e92d0134.c147a429.js +1 -0
  84. solace_agent_mesh/assets/docs/assets/js/ee0c2fe7.94d0a351.js +1 -0
  85. solace_agent_mesh/assets/docs/assets/js/f284c35a.cc97854c.js +1 -0
  86. solace_agent_mesh/assets/docs/assets/js/main.d634009f.js +2 -0
  87. solace_agent_mesh/assets/docs/assets/js/runtime~main.27bb82a7.js +1 -0
  88. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +68 -68
  89. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +50 -50
  90. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +42 -42
  91. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +55 -55
  92. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +75 -75
  93. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/image-tools/index.html +81 -0
  94. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +67 -50
  95. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/research-tools/index.html +136 -0
  96. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +178 -144
  97. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +43 -42
  98. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +20 -18
  99. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +23 -23
  100. solace_agent_mesh/assets/docs/docs/documentation/components/platform-service/index.html +33 -0
  101. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +45 -45
  102. solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +98 -112
  103. solace_agent_mesh/assets/docs/docs/documentation/components/prompts/index.html +147 -0
  104. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +208 -125
  105. solace_agent_mesh/assets/docs/docs/documentation/components/speech/index.html +52 -0
  106. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +28 -28
  107. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +29 -29
  108. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +14 -14
  109. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/index.html +47 -0
  110. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/kubernetes-deployment-guide/index.html +197 -0
  111. solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +67 -53
  112. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +17 -17
  113. solace_agent_mesh/assets/docs/docs/documentation/deploying/proxy_configuration/index.html +49 -0
  114. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +38 -38
  115. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +87 -87
  116. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +67 -49
  117. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +17 -17
  118. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +51 -51
  119. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +22 -22
  120. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +27 -27
  121. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +135 -135
  122. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +66 -66
  123. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +51 -51
  124. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +50 -38
  125. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +86 -86
  126. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +51 -51
  127. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +24 -24
  128. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +30 -30
  129. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +44 -44
  130. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/teams-integration/index.html +115 -0
  131. solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +50 -23
  132. solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +29 -24
  133. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +21 -21
  134. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +40 -37
  135. solace_agent_mesh/assets/docs/docs/documentation/enterprise/openapi-tools/index.html +324 -0
  136. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +96 -66
  137. solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +181 -181
  138. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +75 -75
  139. solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +27 -27
  140. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +44 -44
  141. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +39 -38
  142. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +30 -30
  143. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +18 -18
  144. solace_agent_mesh/assets/docs/docs/documentation/getting-started/vibe_coding/index.html +62 -0
  145. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +135 -114
  146. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +37 -37
  147. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +14 -14
  148. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +27 -25
  149. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +69 -69
  150. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +72 -72
  151. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +112 -112
  152. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +28 -28
  153. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +42 -42
  154. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +20 -20
  155. solace_agent_mesh/assets/docs/docs/documentation/migrations/platform-service-split/index.html +85 -0
  156. solace_agent_mesh/assets/docs/lunr-index-1768329217460.json +1 -0
  157. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  158. solace_agent_mesh/assets/docs/search-doc-1768329217460.json +1 -0
  159. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  160. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  161. solace_agent_mesh/cli/__init__.py +1 -1
  162. solace_agent_mesh/cli/commands/add_cmd/__init__.py +3 -1
  163. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +6 -1
  164. solace_agent_mesh/cli/commands/add_cmd/proxy_cmd.py +100 -0
  165. solace_agent_mesh/cli/commands/eval_cmd.py +1 -1
  166. solace_agent_mesh/cli/commands/init_cmd/__init__.py +15 -0
  167. solace_agent_mesh/cli/commands/init_cmd/directory_step.py +1 -1
  168. solace_agent_mesh/cli/commands/init_cmd/env_step.py +30 -3
  169. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +3 -4
  170. solace_agent_mesh/cli/commands/init_cmd/platform_service_step.py +85 -0
  171. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +16 -3
  172. solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +2 -1
  173. solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +1 -0
  174. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +3 -3
  175. solace_agent_mesh/cli/commands/run_cmd.py +64 -49
  176. solace_agent_mesh/cli/commands/tools_cmd.py +315 -0
  177. solace_agent_mesh/cli/main.py +15 -0
  178. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-tcIFZLis.js → authCallback-KnKMP_vb.js} +1 -1
  179. solace_agent_mesh/client/webui/frontend/static/assets/client-DpBL2stg.js +25 -0
  180. solace_agent_mesh/client/webui/frontend/static/assets/main-Cd498TV2.js +435 -0
  181. solace_agent_mesh/client/webui/frontend/static/assets/main-rSf8Vu29.css +1 -0
  182. solace_agent_mesh/client/webui/frontend/static/assets/{vendor-CINwxvwV.js → vendor-CGk8Suyh.js} +189 -94
  183. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  184. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  185. solace_agent_mesh/client/webui/frontend/static/mockServiceWorker.js +336 -0
  186. solace_agent_mesh/client/webui/frontend/static/ui-version.json +6 -0
  187. solace_agent_mesh/common/a2a/types.py +1 -1
  188. solace_agent_mesh/common/agent_registry.py +38 -11
  189. solace_agent_mesh/common/data_parts.py +124 -0
  190. solace_agent_mesh/common/error_handlers.py +83 -0
  191. solace_agent_mesh/common/exceptions.py +24 -0
  192. solace_agent_mesh/common/oauth/__init__.py +17 -0
  193. solace_agent_mesh/common/oauth/oauth_client.py +408 -0
  194. solace_agent_mesh/common/oauth/utils.py +50 -0
  195. solace_agent_mesh/common/rag_dto.py +156 -0
  196. solace_agent_mesh/common/sac/sam_component_base.py +73 -1
  197. solace_agent_mesh/common/sam_events/event_service.py +2 -2
  198. solace_agent_mesh/common/utils/embeds/converter.py +1 -8
  199. solace_agent_mesh/common/utils/embeds/modifiers.py +2 -27
  200. solace_agent_mesh/common/utils/embeds/resolver.py +94 -25
  201. solace_agent_mesh/common/utils/embeds/types.py +1 -0
  202. solace_agent_mesh/common/utils/log_formatters.py +20 -0
  203. solace_agent_mesh/common/utils/mime_helpers.py +12 -5
  204. solace_agent_mesh/common/utils/rbac_utils.py +69 -0
  205. solace_agent_mesh/common/utils/templates/__init__.py +8 -0
  206. solace_agent_mesh/common/utils/templates/liquid_renderer.py +210 -0
  207. solace_agent_mesh/common/utils/templates/template_resolver.py +161 -0
  208. solace_agent_mesh/config_portal/backend/common.py +12 -0
  209. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-CljP4_mv.js +103 -0
  210. solace_agent_mesh/config_portal/frontend/static/client/assets/{components-Rk0n-9cK.js → components-CaC6hG8d.js} +22 -22
  211. solace_agent_mesh/config_portal/frontend/static/client/assets/{entry.client-mvZjNKiz.js → entry.client-H_TM0YBt.js} +3 -3
  212. solace_agent_mesh/config_portal/frontend/static/client/assets/{index-DzNKzXrc.js → index-CnFykb2v.js} +16 -16
  213. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-f8439d40.js +1 -0
  214. solace_agent_mesh/config_portal/frontend/static/client/assets/root-BIMqslJB.css +1 -0
  215. solace_agent_mesh/config_portal/frontend/static/client/assets/root-mJmTIdIk.js +10 -0
  216. solace_agent_mesh/config_portal/frontend/static/client/index.html +3 -3
  217. solace_agent_mesh/core_a2a/service.py +3 -2
  218. solace_agent_mesh/gateway/adapter/base.py +28 -1
  219. solace_agent_mesh/gateway/adapter/types.py +9 -0
  220. solace_agent_mesh/gateway/base/app.py +10 -0
  221. solace_agent_mesh/gateway/base/auth_interface.py +103 -0
  222. solace_agent_mesh/gateway/base/component.py +451 -10
  223. solace_agent_mesh/gateway/generic/component.py +274 -30
  224. solace_agent_mesh/gateway/http_sse/alembic/env.py +0 -7
  225. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +2 -43
  226. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +2 -2
  227. solace_agent_mesh/gateway/http_sse/alembic/versions/20251108_create_prompt_tables_with_sharing.py +154 -0
  228. solace_agent_mesh/gateway/http_sse/alembic/versions/20251115_add_parent_task_id.py +32 -0
  229. solace_agent_mesh/gateway/http_sse/alembic/versions/20251126_add_background_task_fields.py +47 -0
  230. solace_agent_mesh/gateway/http_sse/alembic/versions/20251202_add_versioned_fields_to_prompts.py +52 -0
  231. solace_agent_mesh/gateway/http_sse/alembic.ini +0 -36
  232. solace_agent_mesh/gateway/http_sse/app.py +23 -6
  233. solace_agent_mesh/gateway/http_sse/component.py +158 -73
  234. solace_agent_mesh/gateway/http_sse/dependencies.py +50 -57
  235. solace_agent_mesh/gateway/http_sse/main.py +58 -482
  236. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +2 -2
  237. solace_agent_mesh/gateway/http_sse/repository/entities/project.py +1 -1
  238. solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +1 -1
  239. solace_agent_mesh/gateway/http_sse/repository/entities/session.py +3 -2
  240. solace_agent_mesh/gateway/http_sse/repository/entities/task.py +7 -0
  241. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +2 -2
  242. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +2 -2
  243. solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +5 -0
  244. solace_agent_mesh/gateway/http_sse/repository/models/prompt_model.py +159 -0
  245. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +1 -1
  246. solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +8 -1
  247. solace_agent_mesh/gateway/http_sse/repository/project_repository.py +1 -1
  248. solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +1 -1
  249. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +12 -107
  250. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +86 -2
  251. solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +38 -7
  252. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +113 -7
  253. solace_agent_mesh/gateway/http_sse/routers/auth.py +69 -132
  254. solace_agent_mesh/gateway/http_sse/routers/config.py +235 -10
  255. solace_agent_mesh/gateway/http_sse/routers/dto/project_dto.py +69 -0
  256. solace_agent_mesh/gateway/http_sse/routers/dto/prompt_dto.py +255 -0
  257. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +1 -1
  258. solace_agent_mesh/gateway/http_sse/routers/dto/responses/base_responses.py +1 -1
  259. solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +1 -0
  260. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +3 -2
  261. solace_agent_mesh/gateway/http_sse/routers/dto/responses/version_responses.py +31 -0
  262. solace_agent_mesh/gateway/http_sse/routers/feedback.py +2 -2
  263. solace_agent_mesh/gateway/http_sse/routers/people.py +2 -2
  264. solace_agent_mesh/gateway/http_sse/routers/projects.py +250 -24
  265. solace_agent_mesh/gateway/http_sse/routers/prompts.py +1416 -0
  266. solace_agent_mesh/gateway/http_sse/routers/sessions.py +14 -5
  267. solace_agent_mesh/gateway/http_sse/routers/speech.py +355 -0
  268. solace_agent_mesh/gateway/http_sse/routers/sse.py +117 -4
  269. solace_agent_mesh/gateway/http_sse/routers/tasks.py +509 -149
  270. solace_agent_mesh/gateway/http_sse/routers/users.py +1 -1
  271. solace_agent_mesh/gateway/http_sse/routers/version.py +343 -0
  272. solace_agent_mesh/gateway/http_sse/routers/visualization.py +2 -1
  273. solace_agent_mesh/gateway/http_sse/services/audio_service.py +1227 -0
  274. solace_agent_mesh/gateway/http_sse/services/background_task_monitor.py +186 -0
  275. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +1 -1
  276. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +1 -1
  277. solace_agent_mesh/gateway/http_sse/services/project_service.py +539 -12
  278. solace_agent_mesh/gateway/http_sse/services/prompt_builder_assistant.py +303 -0
  279. solace_agent_mesh/gateway/http_sse/services/session_service.py +198 -21
  280. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +354 -4
  281. solace_agent_mesh/gateway/http_sse/sse_manager.py +280 -169
  282. solace_agent_mesh/gateway/http_sse/utils/artifact_copy_utils.py +370 -0
  283. solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +41 -1
  284. solace_agent_mesh/services/__init__.py +0 -0
  285. solace_agent_mesh/services/platform/__init__.py +29 -0
  286. solace_agent_mesh/services/platform/alembic/env.py +85 -0
  287. solace_agent_mesh/services/platform/alembic/script.py.mako +28 -0
  288. solace_agent_mesh/services/platform/alembic.ini +109 -0
  289. solace_agent_mesh/services/platform/api/__init__.py +3 -0
  290. solace_agent_mesh/services/platform/api/dependencies.py +154 -0
  291. solace_agent_mesh/services/platform/api/main.py +314 -0
  292. solace_agent_mesh/services/platform/api/middleware.py +51 -0
  293. solace_agent_mesh/services/platform/api/routers/__init__.py +33 -0
  294. solace_agent_mesh/services/platform/api/routers/health_router.py +31 -0
  295. solace_agent_mesh/services/platform/app.py +215 -0
  296. solace_agent_mesh/services/platform/component.py +777 -0
  297. solace_agent_mesh/shared/__init__.py +14 -0
  298. solace_agent_mesh/shared/api/__init__.py +42 -0
  299. solace_agent_mesh/shared/auth/__init__.py +26 -0
  300. solace_agent_mesh/shared/auth/dependencies.py +204 -0
  301. solace_agent_mesh/shared/auth/middleware.py +347 -0
  302. solace_agent_mesh/shared/database/__init__.py +20 -0
  303. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/base_repository.py +1 -1
  304. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_exceptions.py +1 -1
  305. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_helpers.py +1 -1
  306. solace_agent_mesh/shared/exceptions/__init__.py +36 -0
  307. solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exception_handlers.py +1 -1
  308. solace_agent_mesh/shared/utils/__init__.py +21 -0
  309. solace_agent_mesh/templates/logging_config_template.yaml +48 -0
  310. solace_agent_mesh/templates/main_orchestrator.yaml +12 -1
  311. solace_agent_mesh/templates/platform.yaml +49 -0
  312. solace_agent_mesh/templates/plugin_readme_template.md +3 -25
  313. solace_agent_mesh/templates/plugin_tool_config_template.yaml +109 -0
  314. solace_agent_mesh/templates/proxy_template.yaml +62 -0
  315. solace_agent_mesh/templates/webui.yaml +148 -6
  316. solace_agent_mesh/tools/web_search/__init__.py +18 -0
  317. solace_agent_mesh/tools/web_search/base.py +84 -0
  318. solace_agent_mesh/tools/web_search/google_search.py +247 -0
  319. solace_agent_mesh/tools/web_search/models.py +99 -0
  320. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/METADATA +29 -8
  321. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/RECORD +334 -313
  322. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/WHEEL +1 -1
  323. solace_agent_mesh/agent/adk/adk_llm.txt +0 -226
  324. solace_agent_mesh/agent/adk/adk_llm_detail.txt +0 -566
  325. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +0 -171
  326. solace_agent_mesh/agent/adk/models/models_llm.txt +0 -189
  327. solace_agent_mesh/agent/agent_llm.txt +0 -369
  328. solace_agent_mesh/agent/agent_llm_detail.txt +0 -1702
  329. solace_agent_mesh/agent/protocol/protocol_llm.txt +0 -81
  330. solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +0 -92
  331. solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +0 -190
  332. solace_agent_mesh/agent/proxies/base/base_llm.txt +0 -148
  333. solace_agent_mesh/agent/proxies/proxies_llm.txt +0 -283
  334. solace_agent_mesh/agent/sac/sac_llm.txt +0 -189
  335. solace_agent_mesh/agent/sac/sac_llm_detail.txt +0 -200
  336. solace_agent_mesh/agent/testing/testing_llm.txt +0 -58
  337. solace_agent_mesh/agent/testing/testing_llm_detail.txt +0 -68
  338. solace_agent_mesh/agent/tools/tools_llm.txt +0 -276
  339. solace_agent_mesh/agent/tools/tools_llm_detail.txt +0 -275
  340. solace_agent_mesh/agent/utils/utils_llm.txt +0 -152
  341. solace_agent_mesh/agent/utils/utils_llm_detail.txt +0 -149
  342. solace_agent_mesh/assets/docs/assets/js/05749d90.c70b2be9.js +0 -1
  343. solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +0 -1
  344. solace_agent_mesh/assets/docs/assets/js/15e40e79.36003774.js +0 -1
  345. solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js +0 -2
  346. solace_agent_mesh/assets/docs/assets/js/240a0364.c39f8388.js +0 -1
  347. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +0 -1
  348. solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +0 -1
  349. solace_agent_mesh/assets/docs/assets/js/3ac1795d.e4870a49.js +0 -1
  350. solace_agent_mesh/assets/docs/assets/js/3ff0015d.b63ee53a.js +0 -1
  351. solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +0 -1
  352. solace_agent_mesh/assets/docs/assets/js/55b7b518.f2b1d1ba.js +0 -1
  353. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.45b32c2b.js +0 -1
  354. solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +0 -1
  355. solace_agent_mesh/assets/docs/assets/js/66d4869e.830d443f.js +0 -1
  356. solace_agent_mesh/assets/docs/assets/js/6d84eae0.4a5fbf39.js +0 -1
  357. solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +0 -1
  358. solace_agent_mesh/assets/docs/assets/js/81a99df0.07034dd9.js +0 -1
  359. solace_agent_mesh/assets/docs/assets/js/82fbfb93.139a1a1f.js +0 -1
  360. solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +0 -1
  361. solace_agent_mesh/assets/docs/assets/js/94e8668d.09ed9234.js +0 -1
  362. solace_agent_mesh/assets/docs/assets/js/9bb13469.dd1c9b54.js +0 -1
  363. solace_agent_mesh/assets/docs/assets/js/a94703ab.0438dbc2.js +0 -1
  364. solace_agent_mesh/assets/docs/assets/js/ab9708a8.245ae0ef.js +0 -1
  365. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.eaff365e.js +0 -1
  366. solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.f902fad8.js +0 -1
  367. solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +0 -1
  368. solace_agent_mesh/assets/docs/assets/js/e04b235d.c9c50c7b.js +0 -1
  369. solace_agent_mesh/assets/docs/assets/js/e3d9abda.d11c67a7.js +0 -1
  370. solace_agent_mesh/assets/docs/assets/js/e6f9706b.045d0fa1.js +0 -1
  371. solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +0 -1
  372. solace_agent_mesh/assets/docs/assets/js/f284c35a.5099c51e.js +0 -1
  373. solace_agent_mesh/assets/docs/assets/js/main.f213fe0c.js +0 -2
  374. solace_agent_mesh/assets/docs/assets/js/runtime~main.d9606d6a.js +0 -1
  375. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes-deployment/index.html +0 -47
  376. solace_agent_mesh/assets/docs/lunr-index-1762283454666.json +0 -1
  377. solace_agent_mesh/assets/docs/search-doc-1762283454666.json +0 -1
  378. solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +0 -250
  379. solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +0 -365
  380. solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +0 -305
  381. solace_agent_mesh/client/webui/frontend/static/assets/client-CRYdKo2Q.js +0 -25
  382. solace_agent_mesh/client/webui/frontend/static/assets/main-CojeY_1w.css +0 -1
  383. solace_agent_mesh/client/webui/frontend/static/assets/main-ILja9MCG.js +0 -353
  384. solace_agent_mesh/common/a2a/a2a_llm.txt +0 -175
  385. solace_agent_mesh/common/a2a/a2a_llm_detail.txt +0 -193
  386. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +0 -445
  387. solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +0 -736
  388. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +0 -330
  389. solace_agent_mesh/common/common_llm.txt +0 -230
  390. solace_agent_mesh/common/common_llm_detail.txt +0 -2562
  391. solace_agent_mesh/common/middleware/middleware_llm.txt +0 -174
  392. solace_agent_mesh/common/middleware/middleware_llm_detail.txt +0 -185
  393. solace_agent_mesh/common/sac/sac_llm.txt +0 -71
  394. solace_agent_mesh/common/sac/sac_llm_detail.txt +0 -82
  395. solace_agent_mesh/common/sam_events/sam_events_llm.txt +0 -104
  396. solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +0 -115
  397. solace_agent_mesh/common/services/providers/providers_llm.txt +0 -81
  398. solace_agent_mesh/common/services/services_llm.txt +0 -368
  399. solace_agent_mesh/common/services/services_llm_detail.txt +0 -459
  400. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +0 -220
  401. solace_agent_mesh/common/utils/utils_llm.txt +0 -335
  402. solace_agent_mesh/common/utils/utils_llm_detail.txt +0 -572
  403. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +0 -98
  404. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-61038fc6.js +0 -1
  405. solace_agent_mesh/config_portal/frontend/static/client/assets/root-BWvk5-gF.js +0 -10
  406. solace_agent_mesh/config_portal/frontend/static/client/assets/root-DxRwaWiE.css +0 -1
  407. solace_agent_mesh/core_a2a/core_a2a_llm.txt +0 -90
  408. solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +0 -101
  409. solace_agent_mesh/gateway/base/base_llm.txt +0 -226
  410. solace_agent_mesh/gateway/base/base_llm_detail.txt +0 -235
  411. solace_agent_mesh/gateway/gateway_llm.txt +0 -369
  412. solace_agent_mesh/gateway/gateway_llm_detail.txt +0 -3885
  413. solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +0 -345
  414. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_fulltext_search_indexes.py +0 -92
  415. solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +0 -161
  416. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +0 -105
  417. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +0 -299
  418. solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +0 -3278
  419. solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +0 -221
  420. solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +0 -257
  421. solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +0 -308
  422. solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +0 -450
  423. solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +0 -133
  424. solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +0 -123
  425. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +0 -312
  426. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +0 -303
  427. solace_agent_mesh/gateway/http_sse/shared/__init__.py +0 -146
  428. solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +0 -319
  429. solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +0 -47
  430. solace_agent_mesh/llm.txt +0 -228
  431. solace_agent_mesh/llm_detail.txt +0 -2835
  432. solace_agent_mesh/solace_agent_mesh_llm.txt +0 -362
  433. solace_agent_mesh/solace_agent_mesh_llm_detail.txt +0 -8599
  434. solace_agent_mesh/templates/logging_config_template.ini +0 -45
  435. solace_agent_mesh/templates/templates_llm.txt +0 -147
  436. /solace_agent_mesh/assets/docs/assets/js/{main.f213fe0c.js.LICENSE.txt → main.d634009f.js.LICENSE.txt} +0 -0
  437. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/auth_utils.py +0 -0
  438. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/pagination.py +0 -0
  439. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/response_utils.py +0 -0
  440. /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/error_dto.py +0 -0
  441. /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exceptions.py +0 -0
  442. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/enums.py +0 -0
  443. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/timestamp_utils.py +0 -0
  444. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/types.py +0 -0
  445. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/utils.py +0 -0
  446. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/entry_points.txt +0 -0
  447. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/licenses/LICENSE +0 -0
@@ -3,18 +3,30 @@ A stateful stream parser for identifying and extracting fenced artifact blocks
3
3
  from an LLM's text stream.
4
4
  """
5
5
 
6
+ import logging
6
7
  import re
7
8
  from enum import Enum, auto
8
9
  from dataclasses import dataclass, field
9
10
  from typing import List, Dict, Any
10
11
 
12
+ from ...common.utils.embeds.constants import (
13
+ EMBED_DELIMITER_OPEN,
14
+ EMBED_DELIMITER_CLOSE,
15
+ )
16
+
17
+ log = logging.getLogger(__name__)
18
+
11
19
  # --- Constants ---
12
20
  # These are duplicated from callbacks for now to keep the parser self-contained.
13
21
  # They should eventually live in a shared constants module.
14
22
  ARTIFACT_BLOCK_DELIMITER_OPEN = "«««"
15
23
  ARTIFACT_BLOCK_DELIMITER_CLOSE = "»»»"
16
- # The full sequence that must be matched to start a block.
17
- BLOCK_START_SEQUENCE = f"{ARTIFACT_BLOCK_DELIMITER_OPEN}save_artifact:"
24
+ # The full sequences that must be matched to start a block.
25
+ SAVE_ARTIFACT_START_SEQUENCE = f"{ARTIFACT_BLOCK_DELIMITER_OPEN}save_artifact:"
26
+ TEMPLATE_START_SEQUENCE = f"{ARTIFACT_BLOCK_DELIMITER_OPEN}template:"
27
+ TEMPLATE_LIQUID_START_SEQUENCE = f"{ARTIFACT_BLOCK_DELIMITER_OPEN}template_liquid:"
28
+ # For backward compatibility
29
+ BLOCK_START_SEQUENCE = SAVE_ARTIFACT_START_SEQUENCE
18
30
  # Regex to parse parameters from a confirmed start line.
19
31
  PARAMS_REGEX = re.compile(r'(\w+)\s*=\s*"(.*?)"')
20
32
 
@@ -66,6 +78,21 @@ class BlockInvalidatedEvent(ParserEvent):
66
78
  rolled_back_text: str
67
79
 
68
80
 
81
+ @dataclass
82
+ class TemplateBlockStartedEvent(ParserEvent):
83
+ """Emitted when a template block's start is confirmed."""
84
+
85
+ params: Dict[str, Any]
86
+
87
+
88
+ @dataclass
89
+ class TemplateBlockCompletedEvent(ParserEvent):
90
+ """Emitted when a template block is successfully closed."""
91
+
92
+ params: Dict[str, Any]
93
+ template_content: str
94
+
95
+
69
96
  @dataclass
70
97
  class ParserResult:
71
98
  """The result of processing a single text chunk."""
@@ -93,6 +120,14 @@ class FencedBlockStreamParser:
93
120
  self._block_params: Dict[str, Any] = {}
94
121
  self._progress_update_interval = progress_update_interval_bytes
95
122
  self._last_progress_update_size = 0
123
+ self._last_progress_chunk_end = 0 # Character position in buffer where last chunk ended
124
+ # Track block type and nesting for template handling
125
+ self._current_block_type: str = None # "save_artifact" or "template"
126
+ self._nesting_depth = 0 # Track if we're inside a block
127
+ self._previous_state: ParserState = None # Track state before POTENTIAL_BLOCK
128
+ # Safety limit: force emission after this many pending bytes (to handle unclosed embeds)
129
+ # Use minimum of 8KB to handle long templates/embeds
130
+ self._max_pending_bytes = max(progress_update_interval_bytes * 4, 8192) # Min 8KB
96
131
 
97
132
  def _reset_state(self):
98
133
  """Resets the parser to its initial IDLE state."""
@@ -101,6 +136,36 @@ class FencedBlockStreamParser:
101
136
  self._artifact_buffer = ""
102
137
  self._block_params = {}
103
138
  self._last_progress_update_size = 0
139
+ self._last_progress_chunk_end = 0
140
+ self._current_block_type = None
141
+ self._nesting_depth = 0
142
+ self._previous_state = None
143
+
144
+ def _is_safe_to_emit_chunk(self) -> bool:
145
+ """
146
+ Check if current buffer position is safe for chunking (not inside an embed).
147
+
148
+ Looks at the content since the last chunk emission to see if there's an
149
+ unclosed embed delimiter. If so, waits until the embed is closed before emitting.
150
+
151
+ Returns:
152
+ True if safe to emit chunk (no partial embeds), False otherwise.
153
+ """
154
+ # Check the portion of buffer we're about to emit
155
+ buffer_to_check = self._artifact_buffer[self._last_progress_chunk_end:]
156
+
157
+ # Find last occurrence of opening delimiter
158
+ last_open = buffer_to_check.rfind(EMBED_DELIMITER_OPEN)
159
+
160
+ if last_open == -1:
161
+ # No embed delimiter found in this portion
162
+ return True
163
+
164
+ # Found an opening delimiter - check if it's closed
165
+ last_close = buffer_to_check.rfind(EMBED_DELIMITER_CLOSE, last_open)
166
+
167
+ # Safe only if there's a closing delimiter after the opening one
168
+ return last_close > last_open
104
169
 
105
170
  def process_chunk(self, text_chunk: str) -> ParserResult:
106
171
  """
@@ -142,14 +207,28 @@ class FencedBlockStreamParser:
142
207
  events.append(BlockInvalidatedEvent(rolled_back_text=rolled_back_text))
143
208
  elif self._state == ParserState.IN_BLOCK:
144
209
  # The turn ended while inside a block. This is an error/failure.
145
- # The orchestrator (callback) will see this and know to fail the artifact.
146
- # We emit a BlockCompletedEvent so the orchestrator knows what was buffered.
210
+ # The orchestrator (callback) will see this and know to fail the artifact/template.
211
+ # We emit the appropriate completion event so the orchestrator knows what was buffered.
147
212
  # The orchestrator is responsible for interpreting this as a failure.
148
- events.append(
149
- BlockCompletedEvent(
150
- params=self._block_params, content=self._artifact_buffer
151
- )
213
+ log.warning(
214
+ "[StreamParser] finalize() found unterminated block! Type: %s, buffer length: %d, nesting_depth: %d",
215
+ self._current_block_type,
216
+ len(self._artifact_buffer),
217
+ self._nesting_depth,
152
218
  )
219
+ if self._current_block_type == "template":
220
+ events.append(
221
+ TemplateBlockCompletedEvent(
222
+ params=self._block_params,
223
+ template_content=self._artifact_buffer,
224
+ )
225
+ )
226
+ else:
227
+ events.append(
228
+ BlockCompletedEvent(
229
+ params=self._block_params, content=self._artifact_buffer
230
+ )
231
+ )
153
232
 
154
233
  self._reset_state()
155
234
  return ParserResult("".join(user_text_parts), events)
@@ -157,6 +236,7 @@ class FencedBlockStreamParser:
157
236
  def _process_idle(self, char: str, user_text_parts: List[str]):
158
237
  """State handler for when the parser is outside any block."""
159
238
  if char == BLOCK_START_SEQUENCE[0]:
239
+ self._previous_state = ParserState.IDLE
160
240
  self._state = ParserState.POTENTIAL_BLOCK
161
241
  self._speculative_buffer += char
162
242
  else:
@@ -168,59 +248,168 @@ class FencedBlockStreamParser:
168
248
  """State handler for when a block might be starting."""
169
249
  self._speculative_buffer += char
170
250
 
171
- # If we have the full start sequence, we are now looking for the newline.
172
- if self._speculative_buffer.startswith(BLOCK_START_SEQUENCE):
251
+ # Check if we match save_artifact or template start sequences
252
+ matched_sequence = None
253
+ matched_type = None
254
+
255
+ if self._speculative_buffer.startswith(SAVE_ARTIFACT_START_SEQUENCE):
256
+ matched_sequence = SAVE_ARTIFACT_START_SEQUENCE
257
+ matched_type = "save_artifact"
258
+ elif self._speculative_buffer.startswith(TEMPLATE_LIQUID_START_SEQUENCE):
259
+ matched_sequence = TEMPLATE_LIQUID_START_SEQUENCE
260
+ matched_type = "template"
261
+ elif self._speculative_buffer.startswith(TEMPLATE_START_SEQUENCE):
262
+ matched_sequence = TEMPLATE_START_SEQUENCE
263
+ matched_type = "template"
264
+
265
+ if matched_sequence:
173
266
  if char == "\n":
174
267
  # We found the newline, the block is officially started.
268
+
269
+ # If we're already inside a save_artifact block and this is a template,
270
+ # we need to pass it through as literal text (preserve nesting)
271
+ if self._nesting_depth > 0 and matched_type == "template":
272
+ # Preserve template literally inside artifact
273
+ self._artifact_buffer += self._speculative_buffer
274
+ # Increment nesting depth so we know to skip the next »»»
275
+ # (it will close the nested template, not the outer artifact)
276
+ self._nesting_depth += 1
277
+ # Don't reset state! We're still inside the save_artifact block.
278
+ # Just clear the speculative buffer and stay IN_BLOCK to continue
279
+ # buffering the rest of the artifact content.
280
+ self._speculative_buffer = ""
281
+ self._state = ParserState.IN_BLOCK
282
+ return
283
+
175
284
  self._state = ParserState.IN_BLOCK
285
+ self._current_block_type = matched_type
286
+ self._nesting_depth += 1
287
+
176
288
  # Extract the parameters string between the start sequence and the newline
177
- params_str = self._speculative_buffer[len(BLOCK_START_SEQUENCE) : -1]
289
+ params_str = self._speculative_buffer[len(matched_sequence) : -1]
178
290
  self._block_params = dict(PARAMS_REGEX.findall(params_str))
179
- events.append(BlockStartedEvent(params=self._block_params))
291
+
292
+ if matched_type == "save_artifact":
293
+ events.append(BlockStartedEvent(params=self._block_params))
294
+ elif matched_type == "template":
295
+ events.append(TemplateBlockStartedEvent(params=self._block_params))
296
+
180
297
  self._speculative_buffer = "" # Clear buffer, we are done with it.
181
298
  # else, we are still buffering the parameters line.
182
299
  return
183
300
 
184
- # If we are still building up the start sequence itself
185
- if BLOCK_START_SEQUENCE.startswith(self._speculative_buffer):
301
+ # If we are still building up a start sequence (could be either)
302
+ if (SAVE_ARTIFACT_START_SEQUENCE.startswith(self._speculative_buffer) or
303
+ TEMPLATE_LIQUID_START_SEQUENCE.startswith(self._speculative_buffer) or
304
+ TEMPLATE_START_SEQUENCE.startswith(self._speculative_buffer)):
186
305
  # It's still a potential match. Continue buffering.
187
306
  return
188
307
 
189
308
  # If we've reached here, the sequence is invalid.
190
309
  # Rollback: The sequence was invalid.
191
310
  rolled_back_text = self._speculative_buffer
192
- user_text_parts.append(rolled_back_text)
193
- events.append(BlockInvalidatedEvent(rolled_back_text=rolled_back_text))
194
- self._reset_state()
311
+
312
+ # Check if we were IN_BLOCK before transitioning to POTENTIAL_BLOCK
313
+ # If so, add the rolled-back text to the artifact buffer, not user-visible text
314
+ if self._previous_state == ParserState.IN_BLOCK:
315
+ log.debug(
316
+ "[StreamParser] Invalid sequence '%s' detected while IN_BLOCK. Adding to artifact buffer.",
317
+ repr(rolled_back_text),
318
+ )
319
+ self._artifact_buffer += rolled_back_text
320
+ self._speculative_buffer = ""
321
+ self._state = ParserState.IN_BLOCK
322
+ # Don't emit BlockInvalidatedEvent - this is just normal artifact content
323
+ else:
324
+ # We were IDLE, so this is user-facing text
325
+ user_text_parts.append(rolled_back_text)
326
+ events.append(BlockInvalidatedEvent(rolled_back_text=rolled_back_text))
327
+ self._speculative_buffer = ""
328
+ self._state = ParserState.IDLE
329
+
330
+ self._previous_state = None
195
331
 
196
332
  def _process_in_block(self, char: str, events: List[ParserEvent]):
197
333
  """State handler for when the parser is inside a block, buffering content."""
334
+ # Check if this might be the start of a nested block
335
+ if char == BLOCK_START_SEQUENCE[0]:
336
+ # This might be the start of a nested template block
337
+ # Transition to POTENTIAL_BLOCK to check
338
+ self._previous_state = ParserState.IN_BLOCK
339
+ self._state = ParserState.POTENTIAL_BLOCK
340
+ self._speculative_buffer += char
341
+ return
342
+
198
343
  self._artifact_buffer += char
199
344
 
200
345
  # Check for the closing delimiter
201
346
  if self._artifact_buffer.endswith(ARTIFACT_BLOCK_DELIMITER_CLOSE):
202
- # Block is complete.
203
- final_content = self._artifact_buffer[
204
- : -len(ARTIFACT_BLOCK_DELIMITER_CLOSE)
205
- ]
206
- events.append(
207
- BlockCompletedEvent(params=self._block_params, content=final_content)
208
- )
209
- self._reset_state()
210
- else:
211
- # Check if we should emit a progress update
212
- current_size = len(self._artifact_buffer.encode("utf-8"))
213
- if (
214
- current_size - self._last_progress_update_size
215
- ) >= self._progress_update_interval:
216
- new_chunk = self._artifact_buffer[
217
- self._last_progress_update_size : current_size
347
+ # Check if this is closing a nested block or the current block
348
+ if self._nesting_depth > 1:
349
+ # This »»» is closing a nested template block, not the outer save_artifact
350
+ # Keep it in the buffer and just decrement nesting
351
+ self._nesting_depth -= 1
352
+ # Don't emit events, don't strip the delimiter, just continue buffering
353
+ else:
354
+ # This is closing the outermost block (nesting_depth == 1)
355
+ # Block is complete.
356
+ final_content = self._artifact_buffer[
357
+ : -len(ARTIFACT_BLOCK_DELIMITER_CLOSE)
218
358
  ]
219
- events.append(
220
- BlockProgressedEvent(
221
- params=self._block_params,
222
- buffered_size=current_size,
223
- chunk=new_chunk,
359
+
360
+ # Emit the appropriate completion event based on block type
361
+ if self._current_block_type == "template":
362
+ events.append(
363
+ TemplateBlockCompletedEvent(
364
+ params=self._block_params, template_content=final_content
365
+ )
224
366
  )
225
- )
226
- self._last_progress_update_size = current_size
367
+ else:
368
+ # Default to save_artifact behavior
369
+ events.append(
370
+ BlockCompletedEvent(
371
+ params=self._block_params, content=final_content
372
+ )
373
+ )
374
+
375
+ # Decrement nesting depth
376
+ self._nesting_depth = max(0, self._nesting_depth - 1)
377
+ self._reset_state()
378
+ else:
379
+ # Check if we should emit a progress update (only for save_artifact blocks)
380
+ if self._current_block_type == "save_artifact":
381
+ # Calculate current total size in bytes (for threshold check)
382
+ current_size_bytes = len(self._artifact_buffer.encode("utf-8"))
383
+
384
+ # Check if we've accumulated enough new bytes since last update
385
+ bytes_since_last = current_size_bytes - self._last_progress_update_size
386
+ if bytes_since_last >= self._progress_update_interval:
387
+ # Check if it's safe to emit (not inside an embed)
388
+ # OR force emit if we've exceeded safety limit (very long unclosed embed)
389
+ force_emit = bytes_since_last >= self._max_pending_bytes
390
+
391
+ if force_emit:
392
+ log.warning(
393
+ "[StreamParser] Forcing chunk emission due to safety limit (%d bytes pending). "
394
+ "Possible unclosed embed or very long embed.",
395
+ bytes_since_last
396
+ )
397
+
398
+ if self._is_safe_to_emit_chunk() or force_emit:
399
+ # Extract all new content since last progress update
400
+ # Slice by character position (not bytes) to avoid UTF-8 issues
401
+ current_char_position = len(self._artifact_buffer)
402
+ new_chunk = self._artifact_buffer[self._last_progress_chunk_end:]
403
+
404
+ events.append(
405
+ BlockProgressedEvent(
406
+ params=self._block_params,
407
+ buffered_size=current_size_bytes, # Total bytes accumulated so far
408
+ chunk=new_chunk, # All new content since last update
409
+ )
410
+ )
411
+
412
+ # Update tracking: character position for slicing, bytes for threshold
413
+ self._last_progress_chunk_end = current_char_position
414
+ self._last_progress_update_size = current_size_bytes
415
+ # else: wait for embed to close before emitting
@@ -8,6 +8,8 @@ import json
8
8
  import logging
9
9
  from typing import TYPE_CHECKING, Any, Dict
10
10
 
11
+ from litellm.exceptions import BadRequestError
12
+
11
13
  from a2a.types import (
12
14
  A2ARequest,
13
15
  AgentCapabilities,
@@ -25,11 +27,17 @@ from google.adk.agents import RunConfig
25
27
  from google.adk.agents.run_config import StreamingMode
26
28
  from solace_ai_connector.common.event import Event, EventType
27
29
  from solace_ai_connector.common.message import Message as SolaceMessage
30
+ from sqlalchemy.exc import OperationalError
28
31
 
29
32
  from ...agent.adk.callbacks import _publish_data_part_status_update
30
33
  from ...agent.adk.runner import TaskCancelledError, run_adk_async_task_thread_wrapper
31
34
  from ...agent.utils.artifact_helpers import generate_artifact_metadata_summary
32
35
  from ...common import a2a
36
+ from ...common.error_handlers import get_error_message
37
+ from ...common.utils.embeds.constants import (
38
+ EMBED_DELIMITER_OPEN,
39
+ EMBED_DELIMITER_CLOSE,
40
+ )
33
41
  from ...common.a2a import (
34
42
  get_agent_request_topic,
35
43
  get_agent_response_subscription_topic,
@@ -753,6 +761,7 @@ async def handle_a2a_request(component, message: SolaceMessage):
753
761
  "system_purpose": system_purpose,
754
762
  "response_format": response_format,
755
763
  "host_agent_name": agent_name,
764
+ "original_message_metadata": task_metadata, # Store original message metadata for tools
756
765
  }
757
766
 
758
767
  # Store verified user identity claims in a2a_context (not the raw token)
@@ -970,6 +979,101 @@ async def handle_a2a_request(component, message: SolaceMessage):
970
979
  component.handle_error(e, Event(EventType.MESSAGE, message))
971
980
  return None
972
981
 
982
+ except BadRequestError as e:
983
+ log.error(
984
+ "%s Bad Request error handling A2A request: %s", component.log_identifier, e
985
+ )
986
+
987
+ # Use centralized error handler
988
+ error_message, is_context_limit = get_error_message(e)
989
+
990
+ if is_context_limit:
991
+ log.error(
992
+ "%s Context limit exceeded for task %s",
993
+ component.log_identifier,
994
+ logical_task_id,
995
+ )
996
+
997
+ error_response = a2a.create_invalid_request_error_response(
998
+ message=error_message,
999
+ request_id=jsonrpc_request_id,
1000
+ data={"taskId": logical_task_id},
1001
+ )
1002
+ target_topic = reply_topic_from_peer or (
1003
+ get_client_response_topic(namespace, client_id) if client_id else None
1004
+ )
1005
+ if target_topic:
1006
+ component.publish_a2a_message(
1007
+ error_response.model_dump(exclude_none=True),
1008
+ target_topic,
1009
+ )
1010
+
1011
+ try:
1012
+ message.call_negative_acknowledgements()
1013
+ log.warning(
1014
+ "%s NACKed original A2A request due to bad request error.",
1015
+ component.log_identifier,
1016
+ )
1017
+ except Exception as nack_e:
1018
+ log.error(
1019
+ "%s Failed to NACK message after bad request error: %s",
1020
+ component.log_identifier,
1021
+ nack_e,
1022
+ )
1023
+
1024
+ component.handle_error(e, Event(EventType.MESSAGE, message))
1025
+ return None
1026
+
1027
+ except OperationalError as e:
1028
+ log.error(
1029
+ "%s Database error while processing A2A request: %s",
1030
+ component.log_identifier,
1031
+ e,
1032
+ )
1033
+
1034
+ # Check if it's a schema error
1035
+ error_msg = str(e).lower()
1036
+ if "no such column" in error_msg or "no such table" in error_msg:
1037
+ user_message = (
1038
+ "Database schema update required. "
1039
+ "Please contact your administrator to run database migrations."
1040
+ )
1041
+ else:
1042
+ user_message = (
1043
+ "Database error occurred. Please try again or contact support."
1044
+ )
1045
+
1046
+ error_response = a2a.create_internal_error_response(
1047
+ message=user_message,
1048
+ request_id=jsonrpc_request_id,
1049
+ data={"taskId": logical_task_id} if logical_task_id else None,
1050
+ )
1051
+
1052
+ target_topic = reply_topic_from_peer or (
1053
+ get_client_response_topic(namespace, client_id) if client_id else None
1054
+ )
1055
+ if target_topic:
1056
+ component.publish_a2a_message(
1057
+ error_response.model_dump(exclude_none=True),
1058
+ target_topic,
1059
+ )
1060
+
1061
+ try:
1062
+ message.call_negative_acknowledgements()
1063
+ log.warning(
1064
+ "%s NACKed A2A request due to database error.",
1065
+ component.log_identifier,
1066
+ )
1067
+ except Exception as nack_e:
1068
+ log.error(
1069
+ "%s Failed to NACK message after database error: %s",
1070
+ component.log_identifier,
1071
+ nack_e,
1072
+ )
1073
+
1074
+ component.handle_error(e, Event(EventType.MESSAGE, message))
1075
+ return None
1076
+
973
1077
  except Exception as e:
974
1078
  log.exception(
975
1079
  "%s Unexpected error handling A2A request: %s", component.log_identifier, e
@@ -1296,43 +1400,96 @@ async def handle_a2a_response(component, message: SolaceMessage):
1296
1400
  peer_agent_name=peer_agent_name,
1297
1401
  message=message,
1298
1402
  )
1403
+ # Reset the timeout since we received a status update
1404
+ await component.reset_peer_timeout(sub_task_id)
1299
1405
  return
1300
1406
 
1407
+ # Filter out artifact creation progress from peer agents.
1408
+ # These are implementation details that should not leak across
1409
+ # agent boundaries. Artifacts are properly bubbled up in the
1410
+ # final Task response metadata.
1411
+ filtered_data_parts = []
1412
+ has_deep_research_report = False
1301
1413
  for data_part in data_parts:
1302
- log.info(
1303
- "%s Received DataPart signal from peer for sub-task %s. Forwarding...",
1304
- component.log_identifier,
1305
- sub_task_id,
1306
- )
1414
+ if isinstance(data_part.data, dict):
1415
+ data_type = data_part.data.get("type")
1416
+ if data_type == "artifact_creation_progress":
1417
+ log.debug(
1418
+ "%s Filtered out artifact_creation_progress DataPart from peer sub-task %s. Not forwarding to user.",
1419
+ component.log_identifier,
1420
+ sub_task_id,
1421
+ )
1422
+ continue
1423
+ if data_type == "deep_research_report":
1424
+ # Track that we've seen a deep research report
1425
+ # This will be used to suppress text content in the final response
1426
+ has_deep_research_report = True
1427
+ log.info(
1428
+ "%s Detected deep_research_report DataPart from peer sub-task %s. Will suppress text in final response.",
1429
+ component.log_identifier,
1430
+ sub_task_id,
1431
+ )
1432
+ filtered_data_parts.append(data_part)
1433
+
1434
+ # Store the deep research report flag in correlation data for later use
1435
+ if has_deep_research_report:
1436
+ main_logical_task_id_for_flag = original_task_context.get("logical_task_id")
1437
+ with component.active_tasks_lock:
1438
+ task_context_for_flag = component.active_tasks.get(main_logical_task_id_for_flag)
1439
+ if task_context_for_flag:
1440
+ # Store flag in task context to suppress text in final response
1441
+ task_context_for_flag.set_flag("peer_sent_deep_research_report", True)
1442
+ log.info(
1443
+ "%s Set peer_sent_deep_research_report flag for task %s",
1444
+ component.log_identifier,
1445
+ main_logical_task_id_for_flag,
1446
+ )
1447
+
1448
+ # Only forward if there are non-filtered data parts
1449
+ if filtered_data_parts:
1450
+ for data_part in filtered_data_parts:
1451
+ log.info(
1452
+ "%s Received DataPart signal from peer for sub-task %s. Forwarding...",
1453
+ component.log_identifier,
1454
+ sub_task_id,
1455
+ )
1307
1456
 
1308
- forwarded_message = a2a.create_agent_parts_message(
1309
- parts=[data_part],
1310
- metadata=event_metadata,
1311
- )
1457
+ forwarded_message = a2a.create_agent_parts_message(
1458
+ parts=[data_part],
1459
+ metadata=event_metadata,
1460
+ )
1312
1461
 
1313
- forwarded_event = a2a.create_status_update(
1314
- task_id=main_logical_task_id,
1315
- context_id=main_context_id,
1316
- message=forwarded_message,
1317
- is_final=False,
1318
- )
1319
- if (
1320
- status_event.status
1321
- and status_event.status.timestamp
1322
- ):
1323
- forwarded_event.status.timestamp = (
1324
- status_event.status.timestamp
1462
+ forwarded_event = a2a.create_status_update(
1463
+ task_id=main_logical_task_id,
1464
+ context_id=main_context_id,
1465
+ message=forwarded_message,
1466
+ is_final=False,
1325
1467
  )
1326
- _forward_jsonrpc_response(
1327
- component=component,
1328
- original_jsonrpc_request_id=original_jsonrpc_request_id,
1329
- result_data=forwarded_event,
1330
- target_topic=target_topic_for_forward,
1331
- main_logical_task_id=main_logical_task_id,
1332
- peer_agent_name=peer_agent_name,
1333
- message=message,
1334
- )
1468
+ if (
1469
+ status_event.status
1470
+ and status_event.status.timestamp
1471
+ ):
1472
+ forwarded_event.status.timestamp = (
1473
+ status_event.status.timestamp
1474
+ )
1475
+ _forward_jsonrpc_response(
1476
+ component=component,
1477
+ original_jsonrpc_request_id=original_jsonrpc_request_id,
1478
+ result_data=forwarded_event,
1479
+ target_topic=target_topic_for_forward,
1480
+ main_logical_task_id=main_logical_task_id,
1481
+ peer_agent_name=peer_agent_name,
1482
+ message=message,
1483
+ )
1484
+ # Reset the timeout since we received a status update
1485
+ await component.reset_peer_timeout(sub_task_id)
1335
1486
  return
1487
+ else:
1488
+ log.debug(
1489
+ "%s All DataParts from peer sub-task %s were filtered. Not forwarding.",
1490
+ component.log_identifier,
1491
+ sub_task_id,
1492
+ )
1336
1493
 
1337
1494
  payload_to_queue = status_event.model_dump(
1338
1495
  by_alias=True, exclude_none=True
@@ -1613,6 +1770,16 @@ async def handle_a2a_response(component, message: SolaceMessage):
1613
1770
  header_text=header_text,
1614
1771
  )
1615
1772
  )
1773
+
1774
+ # Add guidance about artifact_return responsibility
1775
+ artifact_return_guidance = (
1776
+ f"\n\n**Note:** If any of these artifacts fulfill the user's request, "
1777
+ f"you should return them directly to the user using the "
1778
+ f"{EMBED_DELIMITER_OPEN}artifact_return:filename:version{EMBED_DELIMITER_CLOSE} embed. "
1779
+ f"This is more convenient for the user than just describing the artifacts. "
1780
+ f"Replace 'filename' and 'version' with the actual values from the artifact metadata above."
1781
+ )
1782
+ artifact_summary += artifact_return_guidance
1616
1783
  else:
1617
1784
  log.warning(
1618
1785
  "%s Could not generate artifact summary: missing user_id or session_id in correlation data.",
@@ -1633,9 +1800,28 @@ async def handle_a2a_response(component, message: SolaceMessage):
1633
1800
  else:
1634
1801
  final_text = str(payload_to_queue)
1635
1802
 
1636
- full_response_text = final_text
1637
- if artifact_summary:
1638
- full_response_text = f"{artifact_summary}\n\n{full_response_text}"
1803
+ # Check if a deep research report was sent by the peer agent
1804
+ # If so, suppress the verbose text but keep artifact info to use
1805
+ peer_sent_deep_research = task_context.get_flag("peer_sent_deep_research_report", False)
1806
+ if peer_sent_deep_research:
1807
+ # Clear the flag after using it
1808
+ task_context.set_flag("peer_sent_deep_research_report", False)
1809
+ if artifact_summary:
1810
+ full_response_text = (
1811
+ f"{artifact_summary}\n---\n\n"
1812
+ "SUCCESS: Deep research task completed. The report has been delivered to the user "
1813
+ "and is being displayed. Use artifact_return to include the artifact reference "
1814
+ "in your response so users can click on it."
1815
+ )
1816
+ else:
1817
+ full_response_text = (
1818
+ "SUCCESS: Deep research task completed successfully. "
1819
+ "The research report has been delivered to the user."
1820
+ )
1821
+ else:
1822
+ full_response_text = final_text
1823
+ if artifact_summary:
1824
+ full_response_text = f"{artifact_summary}\n---\n\nPeer Agent Response:\n\n{full_response_text}"
1639
1825
 
1640
1826
  await _publish_peer_tool_result_notification(
1641
1827
  component=component,