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
@@ -0,0 +1,83 @@
1
+ """Centralized error handlers for Solace Agent Mesh."""
2
+
3
+ from typing import Tuple
4
+ from litellm.exceptions import BadRequestError
5
+
6
+
7
+ # User-facing error messages
8
+ CONTEXT_LIMIT_ERROR_MESSAGE = (
9
+ "The conversation history has become too long for the AI model to process. "
10
+ "This can happen after extended conversations. "
11
+ "To continue, please start a new conversation."
12
+ )
13
+
14
+ DEFAULT_BAD_REQUEST_MESSAGE = (
15
+ "An unexpected error occurred during tool execution. "
16
+ "Please try your request again. If the problem persists, "
17
+ "contact an administrator."
18
+ )
19
+
20
+
21
+ def _is_context_limit_error(exception: Exception) -> bool:
22
+ """
23
+ Detects if an exception is a context/token limit error from LiteLLM.
24
+
25
+ Args:
26
+ exception: The exception to check
27
+
28
+ Returns:
29
+ True if the exception indicates a context limit error
30
+ """
31
+ if not isinstance(exception, BadRequestError):
32
+ return False
33
+
34
+ error_str = str(exception).lower()
35
+
36
+ # Context limit error patterns from various LLM providers
37
+ context_limit_patterns = [
38
+ "too many tokens",
39
+ "expected maxlength:",
40
+ "input is too long",
41
+ "prompt is too long",
42
+ "prompt: length: 1..",
43
+ "too many input tokens",
44
+ ]
45
+
46
+ return any(pattern in error_str for pattern in context_limit_patterns)
47
+
48
+
49
+ def _get_user_friendly_error_message(exception: Exception) -> str:
50
+ """
51
+ Returns a user-friendly error message for the given exception.
52
+
53
+ Args:
54
+ exception: The exception to get a message for
55
+
56
+ Returns:
57
+ User-friendly error message string
58
+ """
59
+ if _is_context_limit_error(exception):
60
+ return CONTEXT_LIMIT_ERROR_MESSAGE
61
+
62
+ if isinstance(exception, BadRequestError):
63
+ return f"Bad request: {exception}"
64
+
65
+ return DEFAULT_BAD_REQUEST_MESSAGE
66
+
67
+
68
+ def get_error_message(
69
+ exception: BadRequestError,
70
+ ) -> Tuple[str, bool]:
71
+ """
72
+ Handles BadRequestError and returns error information.
73
+
74
+ Args:
75
+ exception: The BadRequestError to handle
76
+
77
+ Returns:
78
+ Tuple of (error_message, is_context_limit_error)
79
+ """
80
+ is_context_limit = _is_context_limit_error(exception)
81
+ error_message = _get_user_friendly_error_message(exception)
82
+
83
+ return error_message, is_context_limit
@@ -23,3 +23,27 @@ class MessageSizeExceededError(Exception):
23
23
  )
24
24
 
25
25
  super().__init__(message)
26
+
27
+
28
+ class ComponentInitializationError(Exception):
29
+ """Raised when a SAM component fails to initialize."""
30
+
31
+ def __init__(self, component_identifier: str, original_error: Exception, message: str = None):
32
+ """Initialize the ComponentInitializationError.
33
+
34
+ Args:
35
+ component_identifier: The identifier of the component that failed to initialize.
36
+ original_error: The original exception that caused the failure.
37
+ message: Optional custom error message. If None, a default message
38
+ will be generated.
39
+ """
40
+ self.component_identifier = component_identifier
41
+ self.original_error = original_error
42
+
43
+ if message is None:
44
+ message = (
45
+ f"Component {component_identifier} failed to initialize: "
46
+ f"{original_error}"
47
+ )
48
+
49
+ super().__init__(message)
@@ -0,0 +1,17 @@
1
+ """Common OAuth 2.0 components for Solace Agent Mesh.
2
+
3
+ This module provides pure OAuth 2.0 protocol implementations that can be
4
+ used across different components (LLM providers, A2A proxies, etc.) without
5
+ domain-specific logic.
6
+ """
7
+
8
+ from .oauth_client import OAuth2Client, OAuth2RetryClient
9
+ from .utils import calculate_expires_at, is_token_expired, validate_https_url
10
+
11
+ __all__ = [
12
+ "OAuth2Client",
13
+ "OAuth2RetryClient",
14
+ "calculate_expires_at",
15
+ "is_token_expired",
16
+ "validate_https_url",
17
+ ]
@@ -0,0 +1,408 @@
1
+ """Pure OAuth 2.0 protocol implementation.
2
+
3
+ This module provides stateless OAuth 2.0 flow implementations without any
4
+ caching, retry logic, or domain-specific behavior. It implements the core
5
+ OAuth 2.0 flows as defined in RFC 6749.
6
+ """
7
+
8
+ import asyncio
9
+ import logging
10
+ import random
11
+ from typing import Any, Dict, Optional, Union
12
+
13
+ import httpx
14
+
15
+ from .utils import calculate_expires_at
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class OAuth2Client:
21
+ """Pure OAuth 2.0 protocol implementation.
22
+
23
+ This class provides stateless OAuth 2.0 flow implementations without any
24
+ caching, retry logic, or domain-specific behavior. Each method makes a
25
+ single HTTP request to the token endpoint and returns the parsed response.
26
+
27
+ All OAuth 2.0 flows follow RFC 6749 specification.
28
+ """
29
+
30
+ async def fetch_client_credentials_token(
31
+ self,
32
+ token_url: str,
33
+ client_id: str,
34
+ client_secret: str,
35
+ scope: Optional[str] = None,
36
+ verify: Union[bool, str] = True,
37
+ timeout: float = 30.0,
38
+ ) -> Dict[str, Any]:
39
+ """Execute OAuth 2.0 Client Credentials flow (RFC 6749 Section 4.4).
40
+
41
+ This flow is used for server-to-server authentication where the client
42
+ acts on its own behalf rather than on behalf of a user.
43
+
44
+ Args:
45
+ token_url: OAuth 2.0 token endpoint URL
46
+ client_id: OAuth 2.0 client identifier
47
+ client_secret: OAuth 2.0 client secret
48
+ scope: Optional space-separated list of scopes
49
+ verify: SSL certificate verification (True, False, or path to CA bundle)
50
+ timeout: Request timeout in seconds
51
+
52
+ Returns:
53
+ Token response dictionary containing:
54
+ - access_token: The access token string
55
+ - expires_in: Token lifetime in seconds
56
+ - token_type: Token type (usually "Bearer")
57
+ - scope: Granted scopes (optional)
58
+ - expires_at: Unix timestamp when token expires (added by this method)
59
+
60
+ Raises:
61
+ httpx.HTTPStatusError: If the token request fails
62
+ ValueError: If the response is missing required fields
63
+ """
64
+ payload = {
65
+ "grant_type": "client_credentials",
66
+ "client_id": client_id,
67
+ "client_secret": client_secret,
68
+ }
69
+
70
+ if scope:
71
+ payload["scope"] = scope
72
+
73
+ return await self._execute_token_request(
74
+ token_url=token_url,
75
+ payload=payload,
76
+ verify=verify,
77
+ timeout=timeout,
78
+ )
79
+
80
+ async def fetch_authorization_code_token(
81
+ self,
82
+ token_url: str,
83
+ client_id: str,
84
+ client_secret: str,
85
+ code: str,
86
+ redirect_uri: str,
87
+ verify: Union[bool, str] = True,
88
+ timeout: float = 30.0,
89
+ ) -> Dict[str, Any]:
90
+ """Execute OAuth 2.0 Authorization Code flow (RFC 6749 Section 4.1).
91
+
92
+ This flow is used for user-delegated authentication where the application
93
+ acts on behalf of a user who has granted permission.
94
+
95
+ Args:
96
+ token_url: OAuth 2.0 token endpoint URL
97
+ client_id: OAuth 2.0 client identifier
98
+ client_secret: OAuth 2.0 client secret
99
+ code: Authorization code received from authorization server
100
+ redirect_uri: Redirect URI used in authorization request (must match)
101
+ verify: SSL certificate verification (True, False, or path to CA bundle)
102
+ timeout: Request timeout in seconds
103
+
104
+ Returns:
105
+ Token response dictionary containing:
106
+ - access_token: The access token string
107
+ - expires_in: Token lifetime in seconds
108
+ - refresh_token: Refresh token for obtaining new access tokens (optional)
109
+ - token_type: Token type (usually "Bearer")
110
+ - scope: Granted scopes (optional)
111
+ - expires_at: Unix timestamp when token expires (added by this method)
112
+
113
+ Raises:
114
+ httpx.HTTPStatusError: If the token request fails
115
+ ValueError: If the response is missing required fields
116
+ """
117
+ payload = {
118
+ "grant_type": "authorization_code",
119
+ "code": code,
120
+ "redirect_uri": redirect_uri,
121
+ "client_id": client_id,
122
+ "client_secret": client_secret,
123
+ }
124
+
125
+ return await self._execute_token_request(
126
+ token_url=token_url,
127
+ payload=payload,
128
+ verify=verify,
129
+ timeout=timeout,
130
+ )
131
+
132
+ async def fetch_refresh_token(
133
+ self,
134
+ token_url: str,
135
+ client_id: str,
136
+ client_secret: str,
137
+ refresh_token: str,
138
+ scope: Optional[str] = None,
139
+ verify: Union[bool, str] = True,
140
+ timeout: float = 30.0,
141
+ ) -> Dict[str, Any]:
142
+ """Execute OAuth 2.0 Refresh Token flow (RFC 6749 Section 6).
143
+
144
+ This flow is used to obtain a new access token using a refresh token,
145
+ without requiring user interaction.
146
+
147
+ Args:
148
+ token_url: OAuth 2.0 token endpoint URL
149
+ client_id: OAuth 2.0 client identifier
150
+ client_secret: OAuth 2.0 client secret
151
+ refresh_token: The refresh token
152
+ scope: Optional space-separated list of scopes (must not exceed original grant)
153
+ verify: SSL certificate verification (True, False, or path to CA bundle)
154
+ timeout: Request timeout in seconds
155
+
156
+ Returns:
157
+ Token response dictionary containing:
158
+ - access_token: The new access token string
159
+ - expires_in: Token lifetime in seconds
160
+ - refresh_token: New refresh token (optional, may be same as input)
161
+ - token_type: Token type (usually "Bearer")
162
+ - scope: Granted scopes (optional)
163
+ - expires_at: Unix timestamp when token expires (added by this method)
164
+
165
+ Raises:
166
+ httpx.HTTPStatusError: If the token request fails
167
+ ValueError: If the response is missing required fields
168
+ """
169
+ payload = {
170
+ "grant_type": "refresh_token",
171
+ "refresh_token": refresh_token,
172
+ "client_id": client_id,
173
+ "client_secret": client_secret,
174
+ }
175
+
176
+ if scope:
177
+ payload["scope"] = scope
178
+
179
+ return await self._execute_token_request(
180
+ token_url=token_url,
181
+ payload=payload,
182
+ verify=verify,
183
+ timeout=timeout,
184
+ )
185
+
186
+ async def _execute_token_request(
187
+ self,
188
+ token_url: str,
189
+ payload: Dict[str, str],
190
+ verify: Union[bool, str],
191
+ timeout: float,
192
+ ) -> Dict[str, Any]:
193
+ """Execute a token request to the OAuth 2.0 token endpoint.
194
+
195
+ This is the core HTTP operation shared by all OAuth flows.
196
+
197
+ Args:
198
+ token_url: OAuth 2.0 token endpoint URL
199
+ payload: Request payload (grant-specific parameters)
200
+ verify: SSL certificate verification
201
+ timeout: Request timeout in seconds
202
+
203
+ Returns:
204
+ Token response dictionary with added expires_at field
205
+
206
+ Raises:
207
+ httpx.HTTPStatusError: If the token request fails
208
+ ValueError: If the response is missing required fields
209
+ """
210
+ headers = {
211
+ "Content-Type": "application/x-www-form-urlencoded",
212
+ "Accept": "application/json",
213
+ }
214
+
215
+ async with httpx.AsyncClient(verify=verify) as client:
216
+ response = await client.post(
217
+ token_url,
218
+ data=payload,
219
+ headers=headers,
220
+ timeout=timeout,
221
+ )
222
+ response.raise_for_status()
223
+
224
+ token_data = response.json()
225
+
226
+ # Validate response contains required fields
227
+ if "access_token" not in token_data:
228
+ raise ValueError(
229
+ f"Token response missing 'access_token' field. "
230
+ f"Response keys: {list(token_data.keys())}"
231
+ )
232
+
233
+ # Add expiration timestamp for convenience
234
+ expires_in = token_data.get("expires_in", 3600) # Default 1 hour
235
+ token_data["expires_at"] = calculate_expires_at(expires_in)
236
+
237
+ return token_data
238
+
239
+
240
+ class OAuth2RetryClient:
241
+ """OAuth 2.0 client with configurable retry logic.
242
+
243
+ This class wraps OAuth2Client and adds retry logic with exponential backoff
244
+ for handling transient failures. Retry behavior:
245
+ - 4xx errors (client errors): No retry - fail immediately
246
+ - 5xx errors (server errors): Retry with exponential backoff
247
+ - Network errors: Retry with exponential backoff
248
+ """
249
+
250
+ def __init__(
251
+ self,
252
+ max_retries: int = 0,
253
+ backoff_base: float = 2.0,
254
+ backoff_jitter: bool = True,
255
+ ):
256
+ """Initialize the retry client.
257
+
258
+ Args:
259
+ max_retries: Maximum number of retry attempts (0 = no retries)
260
+ backoff_base: Base for exponential backoff (delay = base^attempt)
261
+ backoff_jitter: Whether to add random jitter to backoff delay
262
+ """
263
+ self._base_client = OAuth2Client()
264
+ self._max_retries = max_retries
265
+ self._backoff_base = backoff_base
266
+ self._backoff_jitter = backoff_jitter
267
+
268
+ async def fetch_client_credentials_token(
269
+ self,
270
+ token_url: str,
271
+ client_id: str,
272
+ client_secret: str,
273
+ scope: Optional[str] = None,
274
+ verify: Union[bool, str] = True,
275
+ timeout: float = 30.0,
276
+ ) -> Dict[str, Any]:
277
+ """Execute Client Credentials flow with retry logic.
278
+
279
+ See OAuth2Client.fetch_client_credentials_token for parameter details.
280
+ """
281
+ return await self._execute_with_retry(
282
+ self._base_client.fetch_client_credentials_token,
283
+ token_url=token_url,
284
+ client_id=client_id,
285
+ client_secret=client_secret,
286
+ scope=scope,
287
+ verify=verify,
288
+ timeout=timeout,
289
+ )
290
+
291
+ async def fetch_authorization_code_token(
292
+ self,
293
+ token_url: str,
294
+ client_id: str,
295
+ client_secret: str,
296
+ code: str,
297
+ redirect_uri: str,
298
+ verify: Union[bool, str] = True,
299
+ timeout: float = 30.0,
300
+ ) -> Dict[str, Any]:
301
+ """Execute Authorization Code flow with retry logic.
302
+
303
+ See OAuth2Client.fetch_authorization_code_token for parameter details.
304
+ """
305
+ return await self._execute_with_retry(
306
+ self._base_client.fetch_authorization_code_token,
307
+ token_url=token_url,
308
+ client_id=client_id,
309
+ client_secret=client_secret,
310
+ code=code,
311
+ redirect_uri=redirect_uri,
312
+ verify=verify,
313
+ timeout=timeout,
314
+ )
315
+
316
+ async def fetch_refresh_token(
317
+ self,
318
+ token_url: str,
319
+ client_id: str,
320
+ client_secret: str,
321
+ refresh_token: str,
322
+ scope: Optional[str] = None,
323
+ verify: Union[bool, str] = True,
324
+ timeout: float = 30.0,
325
+ ) -> Dict[str, Any]:
326
+ """Execute Refresh Token flow with retry logic.
327
+
328
+ See OAuth2Client.fetch_refresh_token for parameter details.
329
+ """
330
+ return await self._execute_with_retry(
331
+ self._base_client.fetch_refresh_token,
332
+ token_url=token_url,
333
+ client_id=client_id,
334
+ client_secret=client_secret,
335
+ refresh_token=refresh_token,
336
+ scope=scope,
337
+ verify=verify,
338
+ timeout=timeout,
339
+ )
340
+
341
+ async def _execute_with_retry(self, func, **kwargs) -> Dict[str, Any]:
342
+ """Execute a function with retry logic.
343
+
344
+ Args:
345
+ func: Async function to execute
346
+ **kwargs: Arguments to pass to the function
347
+
348
+ Returns:
349
+ Result from the function
350
+
351
+ Raises:
352
+ Exception: Last exception if all retries are exhausted
353
+ """
354
+ last_exception = None
355
+
356
+ for attempt in range(self._max_retries + 1):
357
+ try:
358
+ return await func(**kwargs)
359
+
360
+ except httpx.HTTPStatusError as e:
361
+ last_exception = e
362
+ # Don't retry on 4xx errors (client errors)
363
+ if 400 <= e.response.status_code < 500:
364
+ logger.error(
365
+ "OAuth token request failed with client error %d: %s",
366
+ e.response.status_code,
367
+ e.response.text,
368
+ )
369
+ raise
370
+
371
+ logger.warning(
372
+ "OAuth token request failed with status %d (attempt %d/%d): %s",
373
+ e.response.status_code,
374
+ attempt + 1,
375
+ self._max_retries + 1,
376
+ e.response.text,
377
+ )
378
+
379
+ except httpx.RequestError as e:
380
+ last_exception = e
381
+ logger.warning(
382
+ "OAuth token request failed (attempt %d/%d): %s",
383
+ attempt + 1,
384
+ self._max_retries + 1,
385
+ str(e),
386
+ )
387
+
388
+ except Exception as e:
389
+ last_exception = e
390
+ logger.error("Unexpected error during OAuth token fetch: %s", str(e))
391
+ raise
392
+
393
+ # Exponential backoff with optional jitter
394
+ if attempt < self._max_retries:
395
+ delay = self._backoff_base**attempt
396
+ if self._backoff_jitter:
397
+ delay += random.uniform(0, 1)
398
+ logger.info("Retrying OAuth token request in %.2f seconds", delay)
399
+ await asyncio.sleep(delay)
400
+
401
+ # All retries exhausted
402
+ logger.error(
403
+ "OAuth token request failed after %d attempts", self._max_retries + 1
404
+ )
405
+ if last_exception:
406
+ raise last_exception
407
+ else:
408
+ raise RuntimeError("OAuth token request failed after all retries")
@@ -0,0 +1,50 @@
1
+ """Utility functions for OAuth 2.0 operations."""
2
+
3
+ import time
4
+ from urllib.parse import urlparse
5
+
6
+
7
+ def validate_https_url(url: str) -> None:
8
+ """Validate that a URL uses HTTPS scheme.
9
+
10
+ OAuth 2.0 requires HTTPS for security when transmitting credentials.
11
+
12
+ Args:
13
+ url: The URL to validate
14
+
15
+ Raises:
16
+ ValueError: If the URL does not use HTTPS scheme
17
+ """
18
+ parsed_url = urlparse(url)
19
+ if parsed_url.scheme != "https":
20
+ raise ValueError(
21
+ f"OAuth 2.0 URLs must use HTTPS for security. "
22
+ f"Got scheme: {parsed_url.scheme}"
23
+ )
24
+
25
+
26
+ def calculate_expires_at(expires_in: int) -> float:
27
+ """Calculate expiration timestamp from expires_in seconds.
28
+
29
+ Args:
30
+ expires_in: Number of seconds until token expires
31
+
32
+ Returns:
33
+ Unix timestamp (float) when the token will expire
34
+ """
35
+ return time.time() + expires_in
36
+
37
+
38
+ def is_token_expired(expires_at: float, buffer_seconds: int = 0) -> bool:
39
+ """Check if a token is expired or will expire within buffer time.
40
+
41
+ Args:
42
+ expires_at: Unix timestamp when token expires
43
+ buffer_seconds: Optional buffer to consider token expired early
44
+ (useful for proactive refresh)
45
+
46
+ Returns:
47
+ True if token is expired or within buffer time of expiring
48
+ """
49
+ current_time = time.time()
50
+ return current_time >= (expires_at - buffer_seconds)