solace-agent-mesh 1.5.0__py3-none-any.whl → 1.6.0__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (326) hide show
  1. solace_agent_mesh/agent/adk/callbacks.py +14 -17
  2. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +3 -1
  3. solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +2 -1
  4. solace_agent_mesh/agent/adk/mcp_content_processor.py +2 -1
  5. solace_agent_mesh/agent/adk/models/lite_llm.py +123 -8
  6. solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +245 -0
  7. solace_agent_mesh/agent/adk/runner.py +3 -1
  8. solace_agent_mesh/agent/adk/services.py +4 -1
  9. solace_agent_mesh/agent/adk/setup.py +3 -1
  10. solace_agent_mesh/agent/adk/tool_wrapper.py +2 -2
  11. solace_agent_mesh/agent/protocol/event_handlers.py +42 -2
  12. solace_agent_mesh/agent/proxies/__init__.py +0 -0
  13. solace_agent_mesh/agent/proxies/a2a/__init__.py +3 -0
  14. solace_agent_mesh/agent/proxies/a2a/app.py +55 -0
  15. solace_agent_mesh/agent/proxies/a2a/component.py +1115 -0
  16. solace_agent_mesh/agent/proxies/a2a/config.py +140 -0
  17. solace_agent_mesh/agent/proxies/a2a/oauth_token_cache.py +104 -0
  18. solace_agent_mesh/agent/proxies/base/__init__.py +3 -0
  19. solace_agent_mesh/agent/proxies/base/app.py +99 -0
  20. solace_agent_mesh/agent/proxies/base/component.py +619 -0
  21. solace_agent_mesh/agent/proxies/base/config.py +85 -0
  22. solace_agent_mesh/agent/proxies/base/proxy_task_context.py +17 -0
  23. solace_agent_mesh/agent/sac/app.py +12 -4
  24. solace_agent_mesh/agent/sac/component.py +164 -9
  25. solace_agent_mesh/agent/tools/audio_tools.py +127 -9
  26. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +3 -1
  27. solace_agent_mesh/agent/tools/builtin_data_analysis_tools.py +3 -1
  28. solace_agent_mesh/agent/tools/dynamic_tool.py +2 -1
  29. solace_agent_mesh/agent/tools/general_agent_tools.py +2 -1
  30. solace_agent_mesh/agent/tools/image_tools.py +2 -1
  31. solace_agent_mesh/agent/tools/peer_agent_tool.py +2 -1
  32. solace_agent_mesh/agent/tools/registry.py +3 -1
  33. solace_agent_mesh/agent/tools/test_tools.py +2 -1
  34. solace_agent_mesh/agent/tools/web_tools.py +12 -6
  35. solace_agent_mesh/agent/utils/artifact_helpers.py +144 -4
  36. solace_agent_mesh/agent/utils/config_parser.py +3 -1
  37. solace_agent_mesh/assets/docs/404.html +3 -3
  38. solace_agent_mesh/assets/docs/assets/js/{b7006a3a.73a79653.js → 032c2d61.f3d37824.js} +1 -1
  39. solace_agent_mesh/assets/docs/assets/js/0bcf40b7.c019ad46.js +1 -0
  40. solace_agent_mesh/assets/docs/assets/js/15ba94aa.932dd2db.js +1 -0
  41. solace_agent_mesh/assets/docs/assets/js/2131ec11.5c7a1f6e.js +1 -0
  42. solace_agent_mesh/assets/docs/assets/js/{2334.622a6395.js → 2334.1cf50a20.js} +1 -1
  43. solace_agent_mesh/assets/docs/assets/js/240a0364.7eac6021.js +1 -0
  44. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +1 -0
  45. solace_agent_mesh/assets/docs/assets/js/341393d4.0fac2613.js +1 -0
  46. solace_agent_mesh/assets/docs/assets/js/{3624.b524e433.js → 3624.0eaa1fd0.js} +1 -1
  47. solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +1 -0
  48. solace_agent_mesh/assets/docs/assets/js/3ac1795d.76654dd9.js +1 -0
  49. solace_agent_mesh/assets/docs/assets/js/3ff0015d.2be20244.js +1 -0
  50. solace_agent_mesh/assets/docs/assets/js/509e993c.4c7a1a6d.js +1 -0
  51. solace_agent_mesh/assets/docs/assets/js/547e15cc.2cbb060a.js +1 -0
  52. solace_agent_mesh/assets/docs/assets/js/55b7b518.f2b1d1ba.js +1 -0
  53. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +1 -0
  54. solace_agent_mesh/assets/docs/assets/js/6063ff4c.ef84f702.js +1 -0
  55. solace_agent_mesh/assets/docs/assets/js/631738c7.a8b1ef8b.js +1 -0
  56. solace_agent_mesh/assets/docs/assets/js/6a520c9d.ba015d81.js +1 -0
  57. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +1 -0
  58. solace_agent_mesh/assets/docs/assets/js/6d84eae0.4a5fbf39.js +1 -0
  59. solace_agent_mesh/assets/docs/assets/js/6fdfefc7.99de744e.js +1 -0
  60. solace_agent_mesh/assets/docs/assets/js/71da7b71.38583438.js +1 -0
  61. solace_agent_mesh/assets/docs/assets/js/722f809d.965da774.js +1 -0
  62. solace_agent_mesh/assets/docs/assets/js/742f027b.46c07808.js +1 -0
  63. solace_agent_mesh/assets/docs/assets/js/77cf947d.48cb18a2.js +1 -0
  64. solace_agent_mesh/assets/docs/assets/js/8024126c.56e59919.js +1 -0
  65. solace_agent_mesh/assets/docs/assets/js/81a99df0.07034dd9.js +1 -0
  66. solace_agent_mesh/assets/docs/assets/js/82fbfb93.139a1a1f.js +1 -0
  67. solace_agent_mesh/assets/docs/assets/js/{8591.d7c16be6.js → 8591.5d015485.js} +2 -2
  68. solace_agent_mesh/assets/docs/assets/js/{8731.49e930c2.js → 8731.6c1dbf0c.js} +1 -1
  69. solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +1 -0
  70. solace_agent_mesh/assets/docs/assets/js/945fb41e.6f4cdffd.js +1 -0
  71. solace_agent_mesh/assets/docs/assets/js/94e8668d.b5ddb7a1.js +1 -0
  72. solace_agent_mesh/assets/docs/assets/js/9bb13469.dd1c9b54.js +1 -0
  73. solace_agent_mesh/assets/docs/assets/js/9e9d0a82.570c057b.js +1 -0
  74. solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e6dd091.js +1 -0
  75. solace_agent_mesh/assets/docs/assets/js/ad71b5ed.af3ecfd1.js +1 -0
  76. solace_agent_mesh/assets/docs/assets/js/c198a0dc.8f31f867.js +1 -0
  77. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.eaff365e.js +1 -0
  78. solace_agent_mesh/assets/docs/assets/js/ceb2a7a6.5d92d7d0.js +1 -0
  79. solace_agent_mesh/assets/docs/assets/js/da0b5bad.d08a9466.js +1 -0
  80. solace_agent_mesh/assets/docs/assets/js/db924877.e98d12a1.js +1 -0
  81. solace_agent_mesh/assets/docs/assets/js/dd817ffc.0aa9630a.js +1 -0
  82. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.d590bc9e.js +1 -0
  83. solace_agent_mesh/assets/docs/assets/js/de5f4c65.e8241890.js +1 -0
  84. solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +1 -0
  85. solace_agent_mesh/assets/docs/assets/js/e3d9abda.2b916f9e.js +1 -0
  86. solace_agent_mesh/assets/docs/assets/js/e6f9706b.e74a984d.js +1 -0
  87. solace_agent_mesh/assets/docs/assets/js/e92d0134.cf6d6522.js +1 -0
  88. solace_agent_mesh/assets/docs/assets/js/f284c35a.42f59cdd.js +1 -0
  89. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +1 -0
  90. solace_agent_mesh/assets/docs/assets/js/main.20feee82.js +2 -0
  91. solace_agent_mesh/assets/docs/assets/js/runtime~main.0d198646.js +1 -0
  92. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +154 -0
  93. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/artifact-management/index.html +7 -7
  94. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/audio-tools/index.html +7 -7
  95. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/data-analysis-tools/index.html +8 -8
  96. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/embeds/index.html +6 -6
  97. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/index.html +11 -11
  98. solace_agent_mesh/assets/docs/docs/documentation/{concepts → components}/cli/index.html +25 -25
  99. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +91 -0
  100. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +29 -0
  101. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +55 -0
  102. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +110 -0
  103. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +262 -0
  104. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +104 -0
  105. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +85 -0
  106. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +25 -0
  107. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +59 -0
  108. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → developing}/create-agents/index.html +113 -152
  109. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → developing}/create-gateways/index.html +10 -10
  110. solace_agent_mesh/assets/docs/docs/documentation/{user-guide → developing}/creating-python-tools/index.html +12 -12
  111. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +54 -0
  112. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +135 -0
  113. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +34 -0
  114. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +55 -0
  115. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/bedrock-agents/index.html +25 -25
  116. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/custom-agent/index.html +13 -13
  117. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/event-mesh-gateway/index.html +12 -12
  118. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/mcp-integration/index.html +10 -10
  119. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/mongodb-integration/index.html +13 -13
  120. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/rag-integration/index.html +13 -13
  121. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/rest-gateway/index.html +10 -10
  122. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +72 -0
  123. solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/sql-database/index.html +14 -14
  124. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +33 -0
  125. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +83 -0
  126. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +222 -0
  127. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +161 -0
  128. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +75 -0
  129. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +53 -0
  130. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +35 -100
  131. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +41 -0
  132. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +81 -0
  133. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +25 -0
  134. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +76 -0
  135. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +160 -0
  136. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +142 -0
  137. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +100 -0
  138. solace_agent_mesh/assets/docs/docs/documentation/{Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html → migrations/a2a-upgrade/a2a-technical-migration-map/index.html} +10 -11
  139. solace_agent_mesh/assets/docs/img/solace-logo.png +0 -0
  140. solace_agent_mesh/assets/docs/lunr-index-1761165361160.json +1 -0
  141. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  142. solace_agent_mesh/assets/docs/search-doc-1761165361160.json +1 -0
  143. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  144. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  145. solace_agent_mesh/cli/__init__.py +1 -1
  146. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +2 -69
  147. solace_agent_mesh/cli/commands/eval_cmd.py +11 -49
  148. solace_agent_mesh/cli/commands/init_cmd/__init__.py +0 -5
  149. solace_agent_mesh/cli/commands/init_cmd/env_step.py +10 -12
  150. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +9 -61
  151. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +9 -49
  152. solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +1 -2
  153. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-DwrxZE0E.js → authCallback-BTf6dqwp.js} +1 -1
  154. solace_agent_mesh/client/webui/frontend/static/assets/{client-DarGQzyw.js → client-CaY59VuC.js} +1 -1
  155. solace_agent_mesh/client/webui/frontend/static/assets/main-BGTaW0uv.js +342 -0
  156. solace_agent_mesh/client/webui/frontend/static/assets/main-DHJKSW1S.css +1 -0
  157. solace_agent_mesh/client/webui/frontend/static/assets/{vendor-BKIeiHj_.js → vendor-BEmvJSYz.js} +1 -1
  158. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  159. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  160. solace_agent_mesh/common/a2a/__init__.py +24 -0
  161. solace_agent_mesh/common/a2a/artifact.py +41 -1
  162. solace_agent_mesh/common/a2a/events.py +29 -0
  163. solace_agent_mesh/common/a2a/message.py +68 -0
  164. solace_agent_mesh/common/a2a/protocol.py +76 -3
  165. solace_agent_mesh/common/a2a/translation.py +3 -1
  166. solace_agent_mesh/common/agent_registry.py +83 -3
  167. solace_agent_mesh/common/constants.py +3 -1
  168. solace_agent_mesh/common/middleware/config_resolver.py +3 -1
  169. solace_agent_mesh/common/middleware/registry.py +3 -1
  170. solace_agent_mesh/common/sac/sam_component_base.py +2 -1
  171. solace_agent_mesh/common/sam_events/event_service.py +3 -2
  172. solace_agent_mesh/common/services/employee_service.py +3 -1
  173. solace_agent_mesh/common/services/identity_service.py +2 -1
  174. solace_agent_mesh/common/services/providers/local_file_identity_service.py +2 -1
  175. solace_agent_mesh/common/utils/artifact_utils.py +3 -1
  176. solace_agent_mesh/common/utils/asyncio_macos_fix.py +3 -1
  177. solace_agent_mesh/common/utils/embeds/converter.py +3 -1
  178. solace_agent_mesh/common/utils/embeds/evaluators.py +2 -1
  179. solace_agent_mesh/common/utils/embeds/modifiers.py +3 -2
  180. solace_agent_mesh/common/utils/embeds/resolver.py +2 -1
  181. solace_agent_mesh/common/utils/initializer.py +3 -1
  182. solace_agent_mesh/common/utils/message_utils.py +2 -1
  183. solace_agent_mesh/common/utils/push_notification_auth.py +3 -2
  184. solace_agent_mesh/common/utils/pydantic_utils.py +12 -0
  185. solace_agent_mesh/config_portal/backend/common.py +1 -1
  186. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +98 -0
  187. solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-44d62be6.js → manifest-61038fc6.js} +1 -1
  188. solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
  189. solace_agent_mesh/core_a2a/service.py +2 -2
  190. solace_agent_mesh/evaluation/evaluator.py +128 -104
  191. solace_agent_mesh/evaluation/message_organizer.py +116 -110
  192. solace_agent_mesh/evaluation/report_data_processor.py +84 -86
  193. solace_agent_mesh/evaluation/report_generator.py +73 -79
  194. solace_agent_mesh/evaluation/run.py +421 -235
  195. solace_agent_mesh/evaluation/shared/__init__.py +92 -0
  196. solace_agent_mesh/evaluation/shared/constants.py +47 -0
  197. solace_agent_mesh/evaluation/shared/exceptions.py +50 -0
  198. solace_agent_mesh/evaluation/shared/helpers.py +35 -0
  199. solace_agent_mesh/evaluation/shared/test_case_loader.py +167 -0
  200. solace_agent_mesh/evaluation/shared/test_suite_loader.py +280 -0
  201. solace_agent_mesh/evaluation/subscriber.py +111 -232
  202. solace_agent_mesh/evaluation/summary_builder.py +227 -117
  203. solace_agent_mesh/gateway/base/app.py +3 -2
  204. solace_agent_mesh/gateway/base/component.py +11 -2
  205. solace_agent_mesh/gateway/base/task_context.py +2 -1
  206. solace_agent_mesh/gateway/http_sse/alembic/versions/20251015_add_session_performance_indexes.py +70 -0
  207. solace_agent_mesh/gateway/http_sse/app.py +2 -1
  208. solace_agent_mesh/gateway/http_sse/component.py +102 -3
  209. solace_agent_mesh/gateway/http_sse/components/task_logger_forwarder.py +3 -2
  210. solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +3 -1
  211. solace_agent_mesh/gateway/http_sse/dependencies.py +7 -5
  212. solace_agent_mesh/gateway/http_sse/main.py +5 -2
  213. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +12 -13
  214. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +15 -18
  215. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +25 -18
  216. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +30 -26
  217. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +35 -44
  218. solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +7 -5
  219. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +97 -205
  220. solace_agent_mesh/gateway/http_sse/routers/auth.py +3 -1
  221. solace_agent_mesh/gateway/http_sse/routers/config.py +3 -2
  222. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +4 -3
  223. solace_agent_mesh/gateway/http_sse/routers/people.py +3 -1
  224. solace_agent_mesh/gateway/http_sse/routers/sessions.py +5 -3
  225. solace_agent_mesh/gateway/http_sse/routers/sse.py +3 -2
  226. solace_agent_mesh/gateway/http_sse/routers/tasks.py +35 -42
  227. solace_agent_mesh/gateway/http_sse/routers/users.py +3 -1
  228. solace_agent_mesh/gateway/http_sse/routers/visualization.py +19 -12
  229. solace_agent_mesh/gateway/http_sse/services/agent_card_service.py +3 -1
  230. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +6 -5
  231. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +53 -44
  232. solace_agent_mesh/gateway/http_sse/services/people_service.py +2 -2
  233. solace_agent_mesh/gateway/http_sse/services/session_service.py +23 -21
  234. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +10 -9
  235. solace_agent_mesh/gateway/http_sse/services/task_service.py +3 -2
  236. solace_agent_mesh/gateway/http_sse/session_manager.py +2 -1
  237. solace_agent_mesh/gateway/http_sse/shared/base_repository.py +45 -71
  238. solace_agent_mesh/gateway/http_sse/shared/types.py +0 -18
  239. solace_agent_mesh/gateway/http_sse/sse_event_buffer.py +2 -1
  240. solace_agent_mesh/gateway/http_sse/sse_manager.py +2 -2
  241. solace_agent_mesh/templates/gateway_app_template.py +4 -2
  242. solace_agent_mesh/templates/gateway_component_template.py +3 -1
  243. solace_agent_mesh/templates/gateway_config_template.yaml +0 -5
  244. solace_agent_mesh/templates/logging_config_template.ini +27 -46
  245. solace_agent_mesh/templates/plugin_gateway_config_template.yaml +0 -3
  246. solace_agent_mesh/templates/plugin_tools_template.py +2 -2
  247. solace_agent_mesh/templates/shared_config.yaml +40 -0
  248. {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/METADATA +47 -21
  249. {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/RECORD +254 -225
  250. solace_agent_mesh/assets/docs/assets/images/sac-flows-80d5b603c6aafd33e87945680ce0abf3.png +0 -0
  251. solace_agent_mesh/assets/docs/assets/images/sac_parts_of_a_component-cb3d0424b1d0c17734c5435cca6b4082.png +0 -0
  252. solace_agent_mesh/assets/docs/assets/js/04989206.a248f00c.js +0 -1
  253. solace_agent_mesh/assets/docs/assets/js/0e682baa.d54b8668.js +0 -1
  254. solace_agent_mesh/assets/docs/assets/js/1023fc19.8a8a9309.js +0 -1
  255. solace_agent_mesh/assets/docs/assets/js/1523c6b4.2645ef68.js +0 -1
  256. solace_agent_mesh/assets/docs/assets/js/166ab619.e27886d9.js +0 -1
  257. solace_agent_mesh/assets/docs/assets/js/1c6e87d2.e056b7e0.js +0 -1
  258. solace_agent_mesh/assets/docs/assets/js/21ceee5f.3bf39250.js +0 -1
  259. solace_agent_mesh/assets/docs/assets/js/2a9cab12.2afaee76.js +0 -1
  260. solace_agent_mesh/assets/docs/assets/js/332e10b5.f7629851.js +0 -1
  261. solace_agent_mesh/assets/docs/assets/js/3d406171.5560fdf9.js +0 -1
  262. solace_agent_mesh/assets/docs/assets/js/42b3f8d8.508ae8db.js +0 -1
  263. solace_agent_mesh/assets/docs/assets/js/442a8107.b5c2532a.js +0 -1
  264. solace_agent_mesh/assets/docs/assets/js/453a82a6.3c6bb61d.js +0 -1
  265. solace_agent_mesh/assets/docs/assets/js/483cef9a.bf9398af.js +0 -1
  266. solace_agent_mesh/assets/docs/assets/js/4c2787c2.c1290a40.js +0 -1
  267. solace_agent_mesh/assets/docs/assets/js/55f47984.bcd00a86.js +0 -1
  268. solace_agent_mesh/assets/docs/assets/js/5b4258a4.fdfd2325.js +0 -1
  269. solace_agent_mesh/assets/docs/assets/js/664b740a.ba305a89.js +0 -1
  270. solace_agent_mesh/assets/docs/assets/js/75384d09.c19e8b51.js +0 -1
  271. solace_agent_mesh/assets/docs/assets/js/768e31b0.9abcdc48.js +0 -1
  272. solace_agent_mesh/assets/docs/assets/js/85387663.be2bc838.js +0 -1
  273. solace_agent_mesh/assets/docs/assets/js/945fb41e.16e00776.js +0 -1
  274. solace_agent_mesh/assets/docs/assets/js/9a09e75d.92de8cf5.js +0 -1
  275. solace_agent_mesh/assets/docs/assets/js/9eff14a2.d62aad71.js +0 -1
  276. solace_agent_mesh/assets/docs/assets/js/a12a4955.25fbed32.js +0 -1
  277. solace_agent_mesh/assets/docs/assets/js/a3a92b25.af35e313.js +0 -1
  278. solace_agent_mesh/assets/docs/assets/js/aba87c2f.4ddf32f2.js +0 -1
  279. solace_agent_mesh/assets/docs/assets/js/ae0e903d.5fe5203f.js +0 -1
  280. solace_agent_mesh/assets/docs/assets/js/ae4415af.16cc58d3.js +0 -1
  281. solace_agent_mesh/assets/docs/assets/js/bac0be12.17de4316.js +0 -1
  282. solace_agent_mesh/assets/docs/assets/js/c2c06897.87cb1f47.js +0 -1
  283. solace_agent_mesh/assets/docs/assets/js/c835a94d.ce21f0bf.js +0 -1
  284. solace_agent_mesh/assets/docs/assets/js/cc969b05.feef7dcc.js +0 -1
  285. solace_agent_mesh/assets/docs/assets/js/cd3d4052.a19e7d78.js +0 -1
  286. solace_agent_mesh/assets/docs/assets/js/ced92a13.fb92e7ca.js +0 -1
  287. solace_agent_mesh/assets/docs/assets/js/cee5d587.47904f5e.js +0 -1
  288. solace_agent_mesh/assets/docs/assets/js/d6a81ee7.829198f1.js +0 -1
  289. solace_agent_mesh/assets/docs/assets/js/f284c35a.ed8dd236.js +0 -1
  290. solace_agent_mesh/assets/docs/assets/js/f897a61a.126663fe.js +0 -1
  291. solace_agent_mesh/assets/docs/assets/js/fbfa3e75.e144b16c.js +0 -1
  292. solace_agent_mesh/assets/docs/assets/js/main.0c149855.js +0 -2
  293. solace_agent_mesh/assets/docs/assets/js/runtime~main.c66557e4.js +0 -1
  294. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +0 -46
  295. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/rbac-setup-guilde/index.html +0 -201
  296. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +0 -29
  297. solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +0 -105
  298. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +0 -144
  299. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +0 -91
  300. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +0 -91
  301. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +0 -55
  302. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +0 -111
  303. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +0 -77
  304. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +0 -48
  305. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +0 -54
  306. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +0 -45
  307. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +0 -74
  308. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/litellm_models/index.html +0 -49
  309. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +0 -76
  310. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +0 -73
  311. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +0 -72
  312. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +0 -54
  313. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +0 -69
  314. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +0 -59
  315. solace_agent_mesh/assets/docs/lunr-index-1760032255022.json +0 -1
  316. solace_agent_mesh/assets/docs/search-doc-1760032255022.json +0 -1
  317. solace_agent_mesh/client/webui/frontend/static/assets/main-CZbpmwfA.css +0 -1
  318. solace_agent_mesh/client/webui/frontend/static/assets/main-C__uuUkB.js +0 -339
  319. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-BNuqpWDc.js +0 -98
  320. solace_agent_mesh/evaluation/config_loader.py +0 -657
  321. solace_agent_mesh/evaluation/test_case_loader.py +0 -714
  322. /solace_agent_mesh/assets/docs/assets/js/{8591.d7c16be6.js.LICENSE.txt → 8591.5d015485.js.LICENSE.txt} +0 -0
  323. /solace_agent_mesh/assets/docs/assets/js/{main.0c149855.js.LICENSE.txt → main.20feee82.js.LICENSE.txt} +0 -0
  324. {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/WHEEL +0 -0
  325. {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/entry_points.txt +0 -0
  326. {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -4,6 +4,7 @@ Includes dynamic instruction injection, artifact metadata injection,
4
4
  embed resolution, and logging.
5
5
  """
6
6
 
7
+ import logging
7
8
  import json
8
9
  import asyncio
9
10
  import uuid
@@ -18,7 +19,7 @@ from google.adk.models.llm_request import LlmRequest
18
19
  from google.adk.models.llm_response import LlmResponse
19
20
  from google.genai import types as adk_types
20
21
  from google.adk.tools.mcp_tool import MCPTool
21
- from solace_ai_connector.common.log import log
22
+
22
23
  from .intelligent_mcp_callbacks import (
23
24
  save_mcp_response_as_artifact_intelligent,
24
25
  McpSaveStatus,
@@ -76,6 +77,8 @@ from ...agent.adk.stream_parser import (
76
77
  ARTIFACT_BLOCK_DELIMITER_CLOSE,
77
78
  )
78
79
 
80
+ log = logging.getLogger(__name__)
81
+
79
82
  A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY = "temp:llm_stream_chunks_processed"
80
83
 
81
84
  if TYPE_CHECKING:
@@ -775,17 +778,16 @@ def _generate_fenced_artifact_instruction() -> str:
775
778
  To create an artifact from content you generate (like code, a report, or a document), you MUST use a special `save_artifact` block. This is the only reliable way to ensure your content is saved correctly.
776
779
 
777
780
  **Syntax:**
778
- ```
779
781
  {open_delim}save_artifact: filename="your_filename.ext" mime_type="text/plain" description="A brief description."
780
782
  The full content you want to save goes here.
781
783
  It can span multiple lines.
782
784
  {close_delim}
783
- ```
784
785
 
785
786
  - **Rules:**
786
787
  - The parameters `filename` and `mime_type` are required. `description` is optional but recommended.
787
788
  - All parameter values **MUST** be enclosed in double quotes.
788
789
  - You **MUST NOT** use double quotes `"` inside the parameter values (e.g., within the description string). Use single quotes or rephrase instead.
790
+ - Do not surround a save_artifact block with '```' (triple backticks). This will create rendering issues.
789
791
 
790
792
  The system will automatically save the content and give you a confirmation in the next turn."""
791
793
 
@@ -1092,11 +1094,6 @@ If a plan is created:
1092
1094
  e_last_call,
1093
1095
  )
1094
1096
 
1095
- if host_component.get_config("inject_current_time", True):
1096
- current_time = datetime.now(timezone.utc).strftime("%A, %d %b %Y %H:%M:%S UTC")
1097
- instruction = f"Current time {current_time}."
1098
- injected_instructions.append(instruction)
1099
-
1100
1097
  if injected_instructions:
1101
1098
  combined_instructions = "\n\n---\n\n".join(injected_instructions)
1102
1099
  if llm_request.config is None:
@@ -1484,32 +1481,32 @@ def solace_llm_response_callback(
1484
1481
  "type": "llm_response",
1485
1482
  "data": llm_response.model_dump(exclude_none=True),
1486
1483
  }
1487
-
1484
+
1488
1485
  # Extract and record token usage
1489
1486
  if llm_response.usage_metadata:
1490
1487
  usage = llm_response.usage_metadata
1491
1488
  model_name = callback_context.state.get("model_name", "unknown")
1492
-
1489
+
1493
1490
  usage_dict = {
1494
1491
  "input_tokens": usage.prompt_token_count,
1495
1492
  "output_tokens": usage.candidates_token_count,
1496
1493
  "model": model_name,
1497
1494
  }
1498
-
1495
+
1499
1496
  # Check for cached tokens (provider-specific)
1500
1497
  cached_tokens = 0
1501
- if hasattr(usage, 'prompt_tokens_details') and usage.prompt_tokens_details:
1502
- cached_tokens = getattr(usage.prompt_tokens_details, 'cached_tokens', 0)
1498
+ if hasattr(usage, "prompt_tokens_details") and usage.prompt_tokens_details:
1499
+ cached_tokens = getattr(usage.prompt_tokens_details, "cached_tokens", 0)
1503
1500
  if cached_tokens > 0:
1504
1501
  usage_dict["cached_input_tokens"] = cached_tokens
1505
-
1502
+
1506
1503
  # Add to response data
1507
1504
  llm_response_data["usage"] = usage_dict
1508
-
1505
+
1509
1506
  # Record in task context for aggregation
1510
1507
  with host_component.active_tasks_lock:
1511
1508
  task_context = host_component.active_tasks.get(logical_task_id)
1512
-
1509
+
1513
1510
  if task_context:
1514
1511
  task_context.record_token_usage(
1515
1512
  input_tokens=usage.prompt_token_count,
@@ -1526,7 +1523,7 @@ def solace_llm_response_callback(
1526
1523
  cached_tokens,
1527
1524
  model_name,
1528
1525
  )
1529
-
1526
+
1530
1527
  # This signal doesn't have a dedicated Pydantic model, so we create the
1531
1528
  # DataPart directly and use the lower-level helpers.
1532
1529
  data_part = a2a.create_data_part(data=llm_response_data)
@@ -2,6 +2,7 @@
2
2
  Custom MCPToolset that resolves embeds in tool parameters before calling MCP tools.
3
3
  """
4
4
 
5
+ import logging
5
6
  import asyncio
6
7
  from typing import Dict, List, Optional, Any
7
8
 
@@ -12,7 +13,7 @@ from google.adk.tools.mcp_tool.mcp_session_manager import (
12
13
  StreamableHTTPConnectionParams,
13
14
  )
14
15
  from google.adk.tools.tool_context import ToolContext
15
- from solace_ai_connector.common.log import log
16
+
16
17
 
17
18
  from ..utils.context_helpers import get_original_session_id
18
19
  from ...common.utils.embeds import (
@@ -23,6 +24,7 @@ from ...common.utils.embeds import (
23
24
  EMBED_DELIMITER_OPEN,
24
25
  )
25
26
 
27
+ log = logging.getLogger(__name__)
26
28
 
27
29
  class EmbedResolvingMCPTool(MCPTool):
28
30
  """
@@ -5,6 +5,7 @@ This module contains the refactored MCP callback functions that use intelligent
5
5
  content processing to save MCP tool responses as appropriately typed artifacts.
6
6
  """
7
7
 
8
+ import logging
8
9
  import json
9
10
  import uuid
10
11
  from datetime import datetime, timezone
@@ -13,7 +14,6 @@ from enum import Enum
13
14
  from pydantic import BaseModel
14
15
 
15
16
  from google.adk.tools import ToolContext, BaseTool
16
- from solace_ai_connector.common.log import log
17
17
 
18
18
  from .mcp_content_processor import MCPContentProcessor, MCPContentProcessorConfig
19
19
  from ...agent.utils.artifact_helpers import (
@@ -22,6 +22,7 @@ from ...agent.utils.artifact_helpers import (
22
22
  )
23
23
  from ...agent.utils.context_helpers import get_original_session_id
24
24
 
25
+ log = logging.getLogger(__name__)
25
26
 
26
27
  if TYPE_CHECKING:
27
28
  from ...agent.sac.component import SamAgentComponent
@@ -12,6 +12,7 @@ Supports:
12
12
  - Resource content with URI-based filename extraction
13
13
  """
14
14
 
15
+ import logging
15
16
  import base64
16
17
  import csv
17
18
  import json
@@ -23,7 +24,7 @@ from io import StringIO
23
24
  from typing import Any, Dict, List, Optional, Tuple, Union
24
25
  from urllib.parse import urlparse
25
26
 
26
- from solace_ai_connector.common.log import log
27
+ log = logging.getLogger(__name__)
27
28
 
28
29
  from ...common.utils.mime_helpers import (
29
30
  is_text_based_mime_type,
@@ -53,6 +53,7 @@ from typing_extensions import override
53
53
  from google.adk.models.base_llm import BaseLlm
54
54
  from google.adk.models.llm_request import LlmRequest
55
55
  from google.adk.models.llm_response import LlmResponse
56
+ from .oauth2_token_manager import OAuth2ClientCredentialsTokenManager
56
57
 
57
58
  logger = logging.getLogger("google_adk." + __name__)
58
59
 
@@ -479,6 +480,7 @@ def _message_to_generate_content_response(
479
480
 
480
481
  def _get_completion_inputs(
481
482
  llm_request: LlmRequest,
483
+ cache_strategy: str = "5m",
482
484
  ) -> Tuple[
483
485
  List[Message],
484
486
  Optional[List[Dict]],
@@ -489,6 +491,7 @@ def _get_completion_inputs(
489
491
 
490
492
  Args:
491
493
  llm_request: The LlmRequest to convert.
494
+ cache_strategy: Cache strategy to apply ("none", "5m", "1h").
492
495
 
493
496
  Returns:
494
497
  The litellm inputs (message list, tool dictionary and response format).
@@ -501,16 +504,32 @@ def _get_completion_inputs(
501
504
  elif message_param_or_list: # Ensure it's not None before appending
502
505
  messages.append(message_param_or_list)
503
506
 
504
- if llm_request.config.system_instruction:
507
+ if llm_request.config and llm_request.config.system_instruction:
508
+ # Build system instruction content with optional cache control
509
+ system_content = {
510
+ "type": "text",
511
+ "text": llm_request.config.system_instruction,
512
+ }
513
+
514
+ # Add cache control based on strategy
515
+ # LiteLLM translates this to provider-specific format (Anthropic, OpenAI, Bedrock, Deepseek)
516
+ if cache_strategy == "5m":
517
+ # 5-minute ephemeral cache (Anthropic default)
518
+ system_content["cache_control"] = {"type": "ephemeral"}
519
+ elif cache_strategy == "1h":
520
+ # 1-hour extended cache (Anthropic extended)
521
+ system_content["cache_control"] = {"type": "ephemeral", "ttl": "1h"}
522
+ # For "none", no cache_control is added
523
+
505
524
  messages.insert(
506
525
  0,
507
526
  ChatCompletionDeveloperMessage(
508
527
  role="developer",
509
- content=llm_request.config.system_instruction,
528
+ content=[system_content],
510
529
  ),
511
530
  )
512
531
 
513
- # 2. Convert tool declarations
532
+ # 2. Convert tool declarations with caching support
514
533
  tools: Optional[List[Dict]] = None
515
534
  if (
516
535
  llm_request.config
@@ -522,6 +541,16 @@ def _get_completion_inputs(
522
541
  for tool in llm_request.config.tools[0].function_declarations
523
542
  ]
524
543
 
544
+ # Enable tool caching via LiteLLM's generic interface
545
+ # LiteLLM handles provider-specific translation (Anthropic, OpenAI, Bedrock, Deepseek)
546
+ # Tools are stable because peer agents are alphabetically sorted (component.py)
547
+ if tools and cache_strategy != "none":
548
+ # Add cache_control to the LAST tool (required by caching providers)
549
+ if cache_strategy == "5m":
550
+ tools[-1]["cache_control"] = {"type": "ephemeral"}
551
+ elif cache_strategy == "1h":
552
+ tools[-1]["cache_control"] = {"type": "ephemeral", "ttl": "1h"}
553
+
525
554
  # 3. Handle response format
526
555
  response_format: Optional[types.SchemaUnion] = None
527
556
  if llm_request.config and llm_request.config.response_schema:
@@ -595,7 +624,7 @@ def _build_request_log(req: LlmRequest) -> str:
595
624
 
596
625
  function_decls: list[types.FunctionDeclaration] = cast(
597
626
  list[types.FunctionDeclaration],
598
- req.config.tools[0].function_declarations if req.config.tools else [],
627
+ req.config.tools[0].function_declarations if req.config and req.config.tools else [],
599
628
  )
600
629
  function_logs = (
601
630
  [_build_function_declaration_log(func_decl) for func_decl in function_decls]
@@ -616,7 +645,7 @@ def _build_request_log(req: LlmRequest) -> str:
616
645
  LLM Request:
617
646
  -----------------------------------------------------------
618
647
  System Instruction:
619
- {req.config.system_instruction}
648
+ {req.config.system_instruction if req.config else None}
620
649
  -----------------------------------------------------------
621
650
  Contents:
622
651
  {_NEW_LINE.join(contents_logs)}
@@ -654,16 +683,42 @@ class LiteLlm(BaseLlm):
654
683
  """The LLM client to use for the model."""
655
684
 
656
685
  _additional_args: Dict[str, Any] = None
686
+ _oauth_token_manager: Optional[OAuth2ClientCredentialsTokenManager] = None
687
+ _cache_strategy: str = "5m" # Default to 5-minute ephemeral cache
657
688
 
658
- def __init__(self, model: str, **kwargs):
689
+ def __init__(self, model: str, cache_strategy: str = "5m", **kwargs):
659
690
  """Initializes the LiteLlm class.
660
691
 
661
692
  Args:
662
693
  model: The name of the LiteLlm model.
694
+ cache_strategy: Cache strategy to use. Options: "none", "5m" (ephemeral), "1h" (extended).
695
+ Defaults to "5m" for backward compatibility.
663
696
  **kwargs: Additional arguments to pass to the litellm completion api.
697
+ Can include OAuth configuration parameters.
664
698
  """
665
699
  super().__init__(model=model, **kwargs)
666
- self._additional_args = kwargs
700
+ self._additional_args = kwargs.copy()
701
+
702
+ # Validate and store cache strategy
703
+ valid_strategies = ["none", "5m", "1h"]
704
+ if cache_strategy not in valid_strategies:
705
+ logger.warning(
706
+ "Invalid cache_strategy '%s'. Valid options are: %s. Defaulting to '5m'.",
707
+ cache_strategy,
708
+ valid_strategies,
709
+ )
710
+ cache_strategy = "5m"
711
+ self._cache_strategy = cache_strategy
712
+ logger.info("LiteLlm initialized with cache strategy: %s", self._cache_strategy)
713
+
714
+ # Extract OAuth configuration if present
715
+ oauth_config = self._extract_oauth_config(self._additional_args)
716
+ if oauth_config:
717
+ self._oauth_token_manager = OAuth2ClientCredentialsTokenManager(**oauth_config)
718
+ logger.info("OAuth2 token manager initialized for model: %s", model)
719
+ else:
720
+ self._oauth_token_manager = None
721
+
667
722
  # preventing generation call with llm_client
668
723
  # and overriding messages, tools and stream which are managed internally
669
724
  self._additional_args.pop("llm_client", None)
@@ -672,6 +727,48 @@ class LiteLlm(BaseLlm):
672
727
  # public api called from runner determines to stream or not
673
728
  self._additional_args.pop("stream", None)
674
729
 
730
+ def _extract_oauth_config(self, kwargs: Dict[str, Any]) -> Optional[Dict[str, Any]]:
731
+ """Extract OAuth configuration from kwargs.
732
+
733
+ Args:
734
+ kwargs: Keyword arguments that may contain OAuth parameters
735
+
736
+ Returns:
737
+ OAuth configuration dictionary or None if no OAuth config found
738
+ """
739
+ oauth_params = [
740
+ "oauth_token_url",
741
+ "oauth_client_id",
742
+ "oauth_client_secret",
743
+ "oauth_scope",
744
+ "oauth_ca_cert",
745
+ "oauth_token_refresh_buffer_seconds",
746
+ "oauth_max_retries"
747
+ ]
748
+
749
+ oauth_config = {}
750
+ for param in oauth_params:
751
+ if param in kwargs:
752
+ # Map parameter names to OAuth2ClientCredentialsTokenManager constructor
753
+ if param == "oauth_ca_cert":
754
+ oauth_config["ca_cert_path"] = kwargs.pop(param)
755
+ elif param == "oauth_token_refresh_buffer_seconds":
756
+ oauth_config["refresh_buffer_seconds"] = kwargs.pop(param)
757
+ elif param == "oauth_max_retries":
758
+ oauth_config["max_retries"] = kwargs.pop(param)
759
+ else:
760
+ # Remove oauth_ prefix for the token manager
761
+ key = param.replace("oauth_", "")
762
+ oauth_config[key] = kwargs.pop(param)
763
+
764
+ # Return config only if we have the required parameters
765
+ if "token_url" in oauth_config and "client_id" in oauth_config and "client_secret" in oauth_config:
766
+ return oauth_config
767
+ elif oauth_config:
768
+ logger.warning("Incomplete OAuth configuration found, missing required parameters")
769
+
770
+ return None
771
+
675
772
  async def generate_content_async(
676
773
  self, llm_request: LlmRequest, stream: bool = False
677
774
  ) -> AsyncGenerator[LlmResponse, None]:
@@ -693,7 +790,7 @@ class LiteLlm(BaseLlm):
693
790
  logger.debug(_build_request_log(llm_request))
694
791
 
695
792
  messages, tools, response_format, generation_params = _get_completion_inputs(
696
- llm_request
793
+ llm_request, self._cache_strategy
697
794
  )
698
795
  completion_args = {
699
796
  "model": self.model,
@@ -704,6 +801,24 @@ class LiteLlm(BaseLlm):
704
801
  }
705
802
  completion_args.update(self._additional_args)
706
803
 
804
+ # Inject OAuth token if OAuth is configured
805
+ if self._oauth_token_manager:
806
+ try:
807
+ access_token = await self._oauth_token_manager.get_token()
808
+ # Inject Bearer token via extra_headers
809
+ extra_headers = completion_args.get("extra_headers", {})
810
+ extra_headers["Authorization"] = f"Bearer {access_token}"
811
+ completion_args["extra_headers"] = extra_headers
812
+ logger.debug("OAuth token injected into request headers")
813
+ except Exception as e:
814
+ logger.error("Failed to get OAuth token: %s", str(e))
815
+ # Check if we have a fallback API key
816
+ if "api_key" in completion_args:
817
+ logger.info("Falling back to API key authentication")
818
+ else:
819
+ logger.error("No fallback authentication available")
820
+ raise
821
+
707
822
  if generation_params:
708
823
  completion_args.update(generation_params)
709
824
 
@@ -0,0 +1,245 @@
1
+ """OAuth 2.0 Client Credentials Token Manager.
2
+
3
+ This module provides OAuth 2.0 Client Credentials flow implementation for LLM authentication.
4
+ It handles token acquisition, caching, and automatic refresh with proper error handling.
5
+ """
6
+
7
+ import asyncio
8
+ import logging
9
+ import random
10
+ import time
11
+ from typing import Any, Dict, Optional
12
+
13
+ import httpx
14
+
15
+ from solace_agent_mesh.common.utils.in_memory_cache import InMemoryCache
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class OAuth2ClientCredentialsTokenManager:
21
+ """Manages OAuth 2.0 Client Credentials tokens with caching and automatic refresh.
22
+
23
+ This class implements the OAuth 2.0 Client Credentials flow as defined in RFC 6749.
24
+ It provides thread-safe token management with automatic refresh before expiration
25
+ and integrates with the existing InMemoryCache for token storage.
26
+
27
+ Attributes:
28
+ token_url: OAuth 2.0 token endpoint URL
29
+ client_id: OAuth client identifier
30
+ client_secret: OAuth client secret
31
+ scope: OAuth scope (optional)
32
+ ca_cert_path: Path to custom CA certificate (optional)
33
+ refresh_buffer_seconds: Seconds before expiry to refresh token
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ token_url: str,
39
+ client_id: str,
40
+ client_secret: str,
41
+ scope: Optional[str] = None,
42
+ ca_cert_path: Optional[str] = None,
43
+ refresh_buffer_seconds: int = 300,
44
+ max_retries: int = 3,
45
+ ):
46
+ """Initialize the OAuth2 Client Credentials Token Manager.
47
+
48
+ Args:
49
+ token_url: OAuth 2.0 token endpoint URL
50
+ client_id: OAuth client identifier
51
+ client_secret: OAuth client secret
52
+ scope: OAuth scope (optional, space-separated string)
53
+ ca_cert_path: Path to custom CA certificate file (optional)
54
+ refresh_buffer_seconds: Seconds before actual expiry to refresh token
55
+ max_retries: Maximum number of retry attempts for token requests
56
+
57
+ Raises:
58
+ ValueError: If required parameters are missing or invalid
59
+ """
60
+ if not token_url:
61
+ raise ValueError("token_url is required")
62
+ if not client_id:
63
+ raise ValueError("client_id is required")
64
+ if not client_secret:
65
+ raise ValueError("client_secret is required")
66
+ if refresh_buffer_seconds < 0:
67
+ raise ValueError("refresh_buffer_seconds must be non-negative")
68
+
69
+ self.token_url = token_url
70
+ self.client_id = client_id
71
+ self.client_secret = client_secret
72
+ self.scope = scope
73
+ self.ca_cert_path = ca_cert_path
74
+ self.refresh_buffer_seconds = refresh_buffer_seconds
75
+ self.max_retries = max_retries
76
+
77
+ # Thread-safe token access
78
+ self._lock = asyncio.Lock()
79
+
80
+ # Token cache using existing InMemoryCache singleton
81
+ self._cache = InMemoryCache()
82
+
83
+ # Cache key for this token manager instance
84
+ self._cache_key = f"oauth_token_{hash((token_url, client_id))}"
85
+
86
+ logger.info(
87
+ "OAuth2ClientCredentialsTokenManager initialized for endpoint: %s",
88
+ token_url
89
+ )
90
+
91
+ async def get_token(self) -> str:
92
+ """Get a valid OAuth 2.0 access token.
93
+
94
+ This method checks the cache first and returns a cached token if it's still valid.
95
+ If no token exists or the token is expired/near expiry, it fetches a new token.
96
+
97
+ Returns:
98
+ Valid OAuth 2.0 access token
99
+
100
+ Raises:
101
+ httpx.HTTPError: If token request fails
102
+ ValueError: If token response is invalid
103
+ """
104
+ async with self._lock:
105
+ # Check if we have a cached token
106
+ cached_token_data = self._cache.get(self._cache_key)
107
+
108
+ if cached_token_data and not self._is_token_expired(cached_token_data):
109
+ logger.debug("Using cached OAuth token")
110
+ return cached_token_data["access_token"]
111
+
112
+ # Fetch new token
113
+ logger.info("Fetching new OAuth token from %s", self.token_url)
114
+ token_data = await self._fetch_token()
115
+
116
+ # Cache the token with TTL
117
+ expires_in = token_data.get("expires_in", 3600) # Default 1 hour
118
+ cache_ttl = max(expires_in - self.refresh_buffer_seconds, 60) # Min 1 minute
119
+
120
+ self._cache.set(self._cache_key, token_data, ttl=cache_ttl)
121
+
122
+ logger.info("OAuth token cached with TTL: %d seconds", cache_ttl)
123
+ return token_data["access_token"]
124
+
125
+ def _is_token_expired(self, token_data: Dict[str, Any]) -> bool:
126
+ """Check if a token is expired or near expiry.
127
+
128
+ Args:
129
+ token_data: Token data dictionary with 'expires_at' timestamp
130
+
131
+ Returns:
132
+ True if token is expired or near expiry, False otherwise
133
+ """
134
+ if "expires_at" not in token_data:
135
+ return True
136
+
137
+ current_time = time.time()
138
+ expires_at = token_data["expires_at"]
139
+
140
+ # Consider token expired if it expires within the buffer time
141
+ return current_time >= (expires_at - self.refresh_buffer_seconds)
142
+
143
+ async def _fetch_token(self) -> Dict[str, Any]:
144
+ """Fetch a new OAuth 2.0 access token from the token endpoint.
145
+
146
+ Implements retry logic with exponential backoff for transient failures.
147
+
148
+ Returns:
149
+ Token data dictionary containing access_token, expires_in, etc.
150
+
151
+ Raises:
152
+ httpx.HTTPError: If HTTP request fails after all retries
153
+ ValueError: If response is invalid or missing required fields
154
+ """
155
+ # Prepare request payload
156
+ payload = {
157
+ "grant_type": "client_credentials",
158
+ "client_id": self.client_id,
159
+ "client_secret": self.client_secret,
160
+ }
161
+
162
+ if self.scope:
163
+ payload["scope"] = self.scope
164
+
165
+ # Configure HTTP client with SSL settings
166
+ verify = True
167
+ if self.ca_cert_path:
168
+ verify = self.ca_cert_path
169
+
170
+ headers = {
171
+ "Content-Type": "application/x-www-form-urlencoded",
172
+ "Accept": "application/json",
173
+ }
174
+
175
+ last_exception = None
176
+
177
+ for attempt in range(self.max_retries + 1):
178
+ try:
179
+ async with httpx.AsyncClient(verify=verify) as client:
180
+ response = await client.post(
181
+ self.token_url,
182
+ data=payload,
183
+ headers=headers,
184
+ timeout=30.0,
185
+ )
186
+ response.raise_for_status()
187
+
188
+ token_data = response.json()
189
+
190
+ # Validate response
191
+ if "access_token" not in token_data:
192
+ raise ValueError("Token response missing 'access_token' field")
193
+
194
+ # Add expiration timestamp for cache management
195
+ expires_in = token_data.get("expires_in", 3600)
196
+ token_data["expires_at"] = time.time() + expires_in
197
+
198
+ logger.info("Successfully fetched OAuth token, expires in %d seconds", expires_in)
199
+ return token_data
200
+
201
+ except httpx.HTTPStatusError as e:
202
+ last_exception = e
203
+ # Don't retry on 4xx errors (client errors)
204
+ if 400 <= e.response.status_code < 500:
205
+ logger.error(
206
+ "OAuth token request failed with client error %d: %s",
207
+ e.response.status_code,
208
+ e.response.text
209
+ )
210
+ raise
211
+
212
+ logger.warning(
213
+ "OAuth token request failed with status %d (attempt %d/%d): %s",
214
+ e.response.status_code,
215
+ attempt + 1,
216
+ self.max_retries + 1,
217
+ e.response.text
218
+ )
219
+
220
+ except httpx.RequestError as e:
221
+ last_exception = e
222
+ logger.warning(
223
+ "OAuth token request failed (attempt %d/%d): %s",
224
+ attempt + 1,
225
+ self.max_retries + 1,
226
+ str(e)
227
+ )
228
+
229
+ except Exception as e:
230
+ last_exception = e
231
+ logger.error("Unexpected error during OAuth token fetch: %s", str(e))
232
+ raise
233
+
234
+ # Exponential backoff with jitter for retries
235
+ if attempt < self.max_retries:
236
+ delay = (2 ** attempt) + random.uniform(0, 1)
237
+ logger.info("Retrying OAuth token request in %.2f seconds", delay)
238
+ await asyncio.sleep(delay)
239
+
240
+ # All retries exhausted
241
+ logger.error("OAuth token request failed after %d attempts", self.max_retries + 1)
242
+ if last_exception:
243
+ raise last_exception
244
+ else:
245
+ raise RuntimeError("OAuth token request failed after all retries")
@@ -2,6 +2,7 @@
2
2
  Manages the asynchronous execution of the ADK Runner.
3
3
  """
4
4
 
5
+ import logging
5
6
  import asyncio
6
7
 
7
8
  from google.adk.agents.invocation_context import LlmCallsLimitExceededError
@@ -21,10 +22,11 @@ from google.adk.events import Event as ADKEvent
21
22
  from google.adk.events.event_actions import EventActions
22
23
  from google.adk.sessions import Session as ADKSession
23
24
  from google.genai import types as adk_types
24
- from solace_ai_connector.common.log import log
25
25
 
26
26
  from ...common import a2a
27
27
 
28
+ log = logging.getLogger(__name__)
29
+
28
30
  if TYPE_CHECKING:
29
31
  from ..sac.component import SamAgentComponent
30
32
  from ..sac.task_execution_context import TaskExecutionContext
@@ -2,13 +2,14 @@
2
2
  Initializes ADK Services based on configuration.
3
3
  """
4
4
 
5
+ import logging
5
6
  import os
6
7
  import re
7
8
  from typing import Dict, Optional, List, Any
8
9
  from typing_extensions import override
9
10
 
10
11
  from google.genai import types as adk_types
11
- from solace_ai_connector.common.log import log
12
+
12
13
 
13
14
  from google.adk.sessions import (
14
15
  BaseSessionService,
@@ -29,6 +30,8 @@ from google.adk.memory import (
29
30
 
30
31
  from .artifacts.filesystem_artifact_service import FilesystemArtifactService
31
32
 
33
+ log = logging.getLogger(__name__)
34
+
32
35
  try:
33
36
  from sam_test_infrastructure.artifact_service.service import (
34
37
  TestInMemoryArtifactService,